Netdev List
 help / color / mirror / Atom feed
* [PATCH 04/32] sfc: Always start Falcon using the XMAC
From: Ben Hutchings @ 2009-11-28  3:44 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, linux-net-drivers

From: Steve Hodgson <shodgson@solarflare.com>

The strap bits are only important on Falcon A and all production
boards using it have fixed-speed 10G PHYs.

Replace dummy MAC operations with default MAC operations.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 drivers/net/sfc/efx.c        |    6 +-----
 drivers/net/sfc/falcon.c     |   15 ++++++++++++---
 drivers/net/sfc/net_driver.h |    3 +++
 3 files changed, 16 insertions(+), 8 deletions(-)

diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index 6338ad8..bed45a5 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -1891,10 +1891,6 @@ bool efx_port_dummy_op_poll(struct efx_nic *efx)
 	return false;
 }
 
-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,
@@ -1936,7 +1932,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->stats_lock);
 	mutex_init(&efx->mac_lock);
-	efx->mac_op = &efx_dummy_mac_operations;
+	efx->mac_op = type->default_mac_ops;
 	efx->phy_op = &efx_dummy_phy_operations;
 	efx->mdio.dev = net_dev;
 	INIT_WORK(&efx->mac_work, efx_mac_work);
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index 372dbbc..9c4f898 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -2291,6 +2291,10 @@ int falcon_probe_port(struct efx_nic *efx)
 	efx->mdio.mdio_read = falcon_mdio_read;
 	efx->mdio.mdio_write = falcon_mdio_write;
 
+	/* Initial assumption */
+	efx->link_state.speed = 10000;
+	efx->link_state.fd = true;
+
 	/* Hardware flow ctrl. FalconA RX FIFO too small for pause generation */
 	if (falcon_rev(efx) >= FALCON_REV_B0)
 		efx->wanted_fc = EFX_FC_RX | EFX_FC_TX;
@@ -2809,6 +2813,10 @@ static int falcon_probe_nic_variant(struct efx_nic *efx)
 		return -ENODEV;
 
 	case FALCON_REV_A1:
+		if (EFX_OWORD_FIELD(nic_stat, FRF_AB_STRAP_10G) == 0) {
+			EFX_ERR(efx, "Falcon rev A1 1G not supported\n");
+			return -ENODEV;
+		}
 		if (EFX_OWORD_FIELD(nic_stat, FRF_AA_STRAP_PCIE) == 0) {
 			EFX_ERR(efx, "Falcon rev A1 PCI-X not supported\n");
 			return -ENODEV;
@@ -2823,9 +2831,6 @@ static int falcon_probe_nic_variant(struct efx_nic *efx)
 		return -ENODEV;
 	}
 
-	/* Initial assumed speed */
-	efx->link_state.speed = EFX_OWORD_FIELD(nic_stat, FRF_AB_STRAP_10G) ? 10000 : 1000;
-
 	return 0;
 }
 
@@ -3238,6 +3243,8 @@ void falcon_stop_nic_stats(struct efx_nic *efx)
  */
 
 struct efx_nic_type falcon_a_nic_type = {
+	.default_mac_ops = &falcon_xmac_operations,
+
 	.mem_map_size = 0x20000,
 	.txd_ptr_tbl_base = FR_AA_TX_DESC_PTR_TBL_KER,
 	.rxd_ptr_tbl_base = FR_AA_RX_DESC_PTR_TBL_KER,
@@ -3251,6 +3258,8 @@ struct efx_nic_type falcon_a_nic_type = {
 };
 
 struct efx_nic_type falcon_b_nic_type = {
+	.default_mac_ops = &falcon_xmac_operations,
+
 	/* Map everything up to and including the RSS indirection
 	 * table.  Don't map MSI-X table, MSI-X PBA since Linux
 	 * requires that they not be mapped.  */
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index 0aeaeda..57f8614 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -843,6 +843,7 @@ static inline const char *efx_dev_name(struct efx_nic *efx)
 
 /**
  * struct efx_nic_type - Efx device type definition
+ * @default_mac_ops: efx_mac_operations to set at startup
  * @mem_map_size: Memory BAR mapped size
  * @txd_ptr_tbl_base: TX descriptor ring base address
  * @rxd_ptr_tbl_base: RX descriptor ring base address
@@ -857,6 +858,8 @@ static inline const char *efx_dev_name(struct efx_nic *efx)
  *	descriptors
  */
 struct efx_nic_type {
+	struct efx_mac_operations *default_mac_ops;
+
 	unsigned int mem_map_size;
 	unsigned int txd_ptr_tbl_base;
 	unsigned int rxd_ptr_tbl_base;

-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.


^ permalink raw reply related

* [PATCH 05/32] sfc: Limit some hardware workarounds to Falcon
From: Ben Hutchings @ 2009-11-28  3:45 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, linux-net-drivers

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 drivers/net/sfc/ethtool.c     |    2 +-
 drivers/net/sfc/workarounds.h |    5 +++--
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c
index bb9abf2..6515b8a 100644
--- a/drivers/net/sfc/ethtool.c
+++ b/drivers/net/sfc/ethtool.c
@@ -683,7 +683,7 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev,
 	 * 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) {
+		if (falcon_rev(efx) == FALCON_REV_B0) {
 			/* Recover by resetting the EM block */
 			if (efx->link_state.up)
 				falcon_drain_tx_fifo(efx);
diff --git a/drivers/net/sfc/workarounds.h b/drivers/net/sfc/workarounds.h
index 3250299..84e579e 100644
--- a/drivers/net/sfc/workarounds.h
+++ b/drivers/net/sfc/workarounds.h
@@ -17,6 +17,7 @@
 
 #define EFX_WORKAROUND_ALWAYS(efx) 1
 #define EFX_WORKAROUND_FALCON_A(efx) (falcon_rev(efx) <= FALCON_REV_A1)
+#define EFX_WORKAROUND_FALCON_AB(efx) (falcon_rev(efx) <= FALCON_REV_B0)
 #define EFX_WORKAROUND_10G(efx) EFX_IS10G(efx)
 #define EFX_WORKAROUND_SFT9001(efx) ((efx)->phy_type == PHY_TYPE_SFT9001A || \
 				     (efx)->phy_type == PHY_TYPE_SFT9001B)
@@ -33,11 +34,11 @@
  * or a PCIe error (bug 11028) */
 #define EFX_WORKAROUND_10727 EFX_WORKAROUND_ALWAYS
 /* Transmit flow control may get disabled */
-#define EFX_WORKAROUND_11482 EFX_WORKAROUND_ALWAYS
+#define EFX_WORKAROUND_11482 EFX_WORKAROUND_FALCON_AB
 /* Flush events can take a very long time to appear */
 #define EFX_WORKAROUND_11557 EFX_WORKAROUND_ALWAYS
 /* Truncated IPv4 packets can confuse the TX packet parser */
-#define EFX_WORKAROUND_15592 EFX_WORKAROUND_ALWAYS
+#define EFX_WORKAROUND_15592 EFX_WORKAROUND_FALCON_AB
 
 /* Spurious parity errors in TSORT buffers */
 #define EFX_WORKAROUND_5129 EFX_WORKAROUND_FALCON_A

-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.


^ permalink raw reply related

* [PATCH 06/32] sfc: Remove EFX_WORKAROUND_9141 macro
From: Ben Hutchings @ 2009-11-28  3:45 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, linux-net-drivers

From: Matthew Slattery <mslattery@solarflare.com>

The "bug9141 workaround" of setting TX_FLUSH_MIN_LEN_EN should really
be considered as a normal bit of configuration rather than a
workaround.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 drivers/net/sfc/falcon.c      |    2 +-
 drivers/net/sfc/workarounds.h |    2 --
 2 files changed, 1 insertions(+), 3 deletions(-)

diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index 9c4f898..b186fd2 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -3128,7 +3128,7 @@ int falcon_init_nic(struct efx_nic *efx)
 	/* Prefetch threshold 2 => fetch when descriptor cache half empty */
 	EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_PREF_THRESHOLD, 2);
 	/* Squash TX of packets of 16 bytes or less */
-	if (falcon_rev(efx) >= FALCON_REV_B0 && EFX_WORKAROUND_9141(efx))
+	if (falcon_rev(efx) >= FALCON_REV_B0)
 		EFX_SET_OWORD_FIELD(temp, FRF_BZ_TX_FLUSH_MIN_LEN_EN, 1);
 	efx_writeo(efx, &temp, FR_AZ_TX_RESERVED);
 
diff --git a/drivers/net/sfc/workarounds.h b/drivers/net/sfc/workarounds.h
index 84e579e..bad0932 100644
--- a/drivers/net/sfc/workarounds.h
+++ b/drivers/net/sfc/workarounds.h
@@ -28,8 +28,6 @@
 #define EFX_WORKAROUND_7575 EFX_WORKAROUND_ALWAYS
 /* Bit-bashed I2C reads cause performance drop */
 #define EFX_WORKAROUND_7884 EFX_WORKAROUND_10G
-/* TX pkt parser problem with <= 16 byte TXes */
-#define EFX_WORKAROUND_9141 EFX_WORKAROUND_ALWAYS
 /* TX_EV_PKT_ERR can be caused by a dangling TX descriptor
  * or a PCIe error (bug 11028) */
 #define EFX_WORKAROUND_10727 EFX_WORKAROUND_ALWAYS

-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.


^ permalink raw reply related

* [PATCH 07/32] sfc: Remove another unused workaround macro
From: Ben Hutchings @ 2009-11-28  3:46 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, linux-net-drivers

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 drivers/net/sfc/workarounds.h |    2 --
 1 files changed, 0 insertions(+), 2 deletions(-)

diff --git a/drivers/net/sfc/workarounds.h b/drivers/net/sfc/workarounds.h
index bad0932..209ee1e 100644
--- a/drivers/net/sfc/workarounds.h
+++ b/drivers/net/sfc/workarounds.h
@@ -33,8 +33,6 @@
 #define EFX_WORKAROUND_10727 EFX_WORKAROUND_ALWAYS
 /* Transmit flow control may get disabled */
 #define EFX_WORKAROUND_11482 EFX_WORKAROUND_FALCON_AB
-/* Flush events can take a very long time to appear */
-#define EFX_WORKAROUND_11557 EFX_WORKAROUND_ALWAYS
 /* Truncated IPv4 packets can confuse the TX packet parser */
 #define EFX_WORKAROUND_15592 EFX_WORKAROUND_FALCON_AB
 


-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.


^ permalink raw reply related

* [PATCH 08/32] sfc: Remove some redundant whitespace
From: Ben Hutchings @ 2009-11-28  3:46 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, linux-net-drivers

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 drivers/net/sfc/net_driver.h |    2 --
 1 files changed, 0 insertions(+), 2 deletions(-)

diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index 57f8614..ca7dff2 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -866,9 +866,7 @@ struct efx_nic_type {
 	unsigned int buf_tbl_base;
 	unsigned int evq_ptr_tbl_base;
 	unsigned int evq_rptr_tbl_base;
-
 	u64 max_dma_mask;
-
 	unsigned int rx_buffer_padding;
 	unsigned int max_interrupt_mode;
 	unsigned int phys_addr_channels;

-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.


^ permalink raw reply related

* [PATCH 09/32] sfc: Decouple NIC revision number from Falcon PCI revision number
From: Ben Hutchings @ 2009-11-28  3:46 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, linux-net-drivers

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 drivers/net/sfc/efx.c         |    4 +-
 drivers/net/sfc/ethtool.c     |    2 +-
 drivers/net/sfc/falcon.c      |   68 ++++++++++++++++++----------------------
 drivers/net/sfc/falcon.h      |   16 +++++-----
 drivers/net/sfc/falcon_xmac.c |    2 +-
 drivers/net/sfc/net_driver.h  |    2 +
 drivers/net/sfc/selftest.c    |    2 +-
 drivers/net/sfc/workarounds.h |    4 +-
 8 files changed, 48 insertions(+), 52 deletions(-)

diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index bed45a5..f5e8111 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -1863,9 +1863,9 @@ void efx_schedule_reset(struct efx_nic *efx, enum reset_type type)
 /* PCI device ID table */
 static struct pci_device_id efx_pci_table[] __devinitdata = {
 	{PCI_DEVICE(EFX_VENDID_SFC, FALCON_A_P_DEVID),
-	 .driver_data = (unsigned long) &falcon_a_nic_type},
+	 .driver_data = (unsigned long) &falcon_a1_nic_type},
 	{PCI_DEVICE(EFX_VENDID_SFC, FALCON_B_P_DEVID),
-	 .driver_data = (unsigned long) &falcon_b_nic_type},
+	 .driver_data = (unsigned long) &falcon_b0_nic_type},
 	{0}			/* end of list */
 };
 
diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c
index 6515b8a..5d2e186 100644
--- a/drivers/net/sfc/ethtool.c
+++ b/drivers/net/sfc/ethtool.c
@@ -683,7 +683,7 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev,
 	 * 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) {
+		if (efx_nic_rev(efx) == EFX_REV_FALCON_B0) {
 			/* Recover by resetting the EM block */
 			if (efx->link_state.up)
 				falcon_drain_tx_fifo(efx);
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index b186fd2..7c9c9c9 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -111,7 +111,7 @@ MODULE_PARM_DESC(rx_xon_thresh_bytes, "RX fifo XON threshold");
 #define FALCON_RX_FLUSH_COUNT 4
 
 #define FALCON_IS_DUAL_FUNC(efx)		\
-	(falcon_rev(efx) < FALCON_REV_B0)
+	(efx_nic_rev(efx) < EFX_REV_FALCON_B0)
 
 /**************************************************************************
  *
@@ -447,7 +447,7 @@ void falcon_init_tx(struct efx_tx_queue *tx_queue)
 			      FRF_AZ_TX_DESCQ_TYPE, 0,
 			      FRF_BZ_TX_NON_IP_DROP_DIS, 1);
 
-	if (falcon_rev(efx) >= FALCON_REV_B0) {
+	if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) {
 		int csum = tx_queue->queue == EFX_TX_QUEUE_OFFLOAD_CSUM;
 		EFX_SET_OWORD_FIELD(tx_desc_ptr, FRF_BZ_TX_IP_CHKSM_DIS, !csum);
 		EFX_SET_OWORD_FIELD(tx_desc_ptr, FRF_BZ_TX_TCP_CHKSM_DIS,
@@ -457,7 +457,7 @@ void falcon_init_tx(struct efx_tx_queue *tx_queue)
 	efx_writeo_table(efx, &tx_desc_ptr, efx->type->txd_ptr_tbl_base,
 			 tx_queue->queue);
 
-	if (falcon_rev(efx) < FALCON_REV_B0) {
+	if (efx_nic_rev(efx) < EFX_REV_FALCON_B0) {
 		efx_oword_t reg;
 
 		/* Only 128 bits in this register */
@@ -574,7 +574,7 @@ void falcon_init_rx(struct efx_rx_queue *rx_queue)
 {
 	efx_oword_t rx_desc_ptr;
 	struct efx_nic *efx = rx_queue->efx;
-	bool is_b0 = falcon_rev(efx) >= FALCON_REV_B0;
+	bool is_b0 = efx_nic_rev(efx) >= EFX_REV_FALCON_B0;
 	bool iscsi_digest_en = is_b0;
 
 	EFX_LOG(efx, "RX queue %d ring in special buffers %d-%d\n",
@@ -752,7 +752,7 @@ static void falcon_handle_rx_not_ok(struct efx_rx_queue *rx_queue,
 						   FSF_AZ_RX_EV_TCP_UDP_CHKSUM_ERR);
 	rx_ev_eth_crc_err = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_ETH_CRC_ERR);
 	rx_ev_frm_trunc = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_FRM_TRUNC);
-	rx_ev_drib_nib = ((falcon_rev(efx) >= FALCON_REV_B0) ?
+	rx_ev_drib_nib = ((efx_nic_rev(efx) >= EFX_REV_FALCON_B0) ?
 			  0 : EFX_QWORD_FIELD(*event, FSF_AA_RX_EV_DRIB_NIB));
 	rx_ev_pause_frm = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_PAUSE_FRM_ERR);
 
@@ -897,13 +897,13 @@ static void falcon_handle_global_event(struct efx_channel *channel,
 		handled = true;
 	}
 
-	if ((falcon_rev(efx) >= FALCON_REV_B0) &&
+	if ((efx_nic_rev(efx) >= EFX_REV_FALCON_B0) &&
 	    EFX_QWORD_FIELD(*event, FSF_BB_GLB_EV_XG_MGT_INTR)) {
 		efx->xmac_poll_required = true;
 		handled = true;
 	}
 
-	if (falcon_rev(efx) <= FALCON_REV_A1 ?
+	if (efx_nic_rev(efx) <= EFX_REV_FALCON_A1 ?
 	    EFX_QWORD_FIELD(*event, FSF_AA_GLB_EV_RX_RECOVERY) :
 	    EFX_QWORD_FIELD(*event, FSF_BB_GLB_EV_RX_RECOVERY)) {
 		EFX_ERR(efx, "channel %d seen global RX_RESET "
@@ -1531,7 +1531,7 @@ static void falcon_setup_rss_indir_table(struct efx_nic *efx)
 	unsigned long offset;
 	efx_dword_t dword;
 
-	if (falcon_rev(efx) < FALCON_REV_B0)
+	if (efx_nic_rev(efx) < EFX_REV_FALCON_B0)
 		return;
 
 	for (offset = FR_BZ_RX_INDIRECTION_TBL;
@@ -1554,7 +1554,7 @@ int falcon_init_interrupt(struct efx_nic *efx)
 
 	if (!EFX_INT_MODE_USE_MSI(efx)) {
 		irq_handler_t handler;
-		if (falcon_rev(efx) >= FALCON_REV_B0)
+		if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0)
 			handler = falcon_legacy_interrupt_b0;
 		else
 			handler = falcon_legacy_interrupt_a1;
@@ -1601,7 +1601,7 @@ void falcon_fini_interrupt(struct efx_nic *efx)
 	}
 
 	/* ACK legacy interrupt */
-	if (falcon_rev(efx) >= FALCON_REV_B0)
+	if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0)
 		efx_reado(efx, &reg, FR_BZ_INT_ISR0);
 	else
 		falcon_irq_ack_a1(efx);
@@ -1841,7 +1841,7 @@ static int falcon_reset_macs(struct efx_nic *efx)
 	efx_oword_t reg;
 	int count;
 
-	if (falcon_rev(efx) < FALCON_REV_B0) {
+	if (efx_nic_rev(efx) < EFX_REV_FALCON_B0) {
 		/* It's not safe to use GLB_CTL_REG to reset the
 		 * macs, so instead use the internal MAC resets
 		 */
@@ -1917,7 +1917,7 @@ void falcon_drain_tx_fifo(struct efx_nic *efx)
 {
 	efx_oword_t reg;
 
-	if ((falcon_rev(efx) < FALCON_REV_B0) ||
+	if ((efx_nic_rev(efx) < EFX_REV_FALCON_B0) ||
 	    (efx->loopback_mode != LOOPBACK_NONE))
 		return;
 
@@ -1933,7 +1933,7 @@ void falcon_deconfigure_mac_wrapper(struct efx_nic *efx)
 {
 	efx_oword_t reg;
 
-	if (falcon_rev(efx) < FALCON_REV_B0)
+	if (efx_nic_rev(efx) < EFX_REV_FALCON_B0)
 		return;
 
 	/* Isolate the MAC -> RX */
@@ -1970,7 +1970,7 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
 			     FRF_AB_MAC_SPEED, link_speed);
 	/* On B0, MAC backpressure can be disabled and packets get
 	 * discarded. */
-	if (falcon_rev(efx) >= FALCON_REV_B0) {
+	if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) {
 		EFX_SET_OWORD_FIELD(reg, FRF_BB_TXFIFO_DRAIN_EN,
 				    !link_state->up);
 	}
@@ -1988,7 +1988,7 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
 	EFX_SET_OWORD_FIELD(reg, FRF_AZ_RX_XOFF_MAC_EN, tx_fc);
 
 	/* Unisolate the MAC -> RX */
-	if (falcon_rev(efx) >= FALCON_REV_B0)
+	if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0)
 		EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, 1);
 	efx_writeo(efx, &reg, FR_AZ_RX_CFG);
 }
@@ -2207,7 +2207,7 @@ static void falcon_clock_mac(struct efx_nic *efx)
 	/* Configure the NIC generated MAC clock correctly */
 	efx_reado(efx, &nic_stat, FR_AB_NIC_STAT);
 	strap_val = EFX_IS10G(efx) ? 5 : 3;
-	if (falcon_rev(efx) >= FALCON_REV_B0) {
+	if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) {
 		EFX_SET_OWORD_FIELD(nic_stat, FRF_BB_EE_STRAP_EN, 1);
 		EFX_SET_OWORD_FIELD(nic_stat, FRF_BB_EE_STRAP, strap_val);
 		efx_writeo(efx, &nic_stat, FR_AB_NIC_STAT);
@@ -2296,7 +2296,7 @@ int falcon_probe_port(struct efx_nic *efx)
 	efx->link_state.fd = true;
 
 	/* Hardware flow ctrl. FalconA RX FIFO too small for pause generation */
-	if (falcon_rev(efx) >= FALCON_REV_B0)
+	if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0)
 		efx->wanted_fc = EFX_FC_RX | EFX_FC_TX;
 	else
 		efx->wanted_fc = EFX_FC_RX;
@@ -2806,13 +2806,13 @@ static int falcon_probe_nic_variant(struct efx_nic *efx)
 
 	efx_reado(efx, &nic_stat, FR_AB_NIC_STAT);
 
-	switch (falcon_rev(efx)) {
-	case FALCON_REV_A0:
-	case 0xff:
-		EFX_ERR(efx, "Falcon rev A0 not supported\n");
-		return -ENODEV;
+	if (efx_nic_rev(efx) <= EFX_REV_FALCON_A1) {
+		u8 pci_rev = efx->pci_dev->revision;
 
-	case FALCON_REV_A1:
+		if ((pci_rev == 0xff) || (pci_rev == 0)) {
+			EFX_ERR(efx, "Falcon rev A0 not supported\n");
+			return -ENODEV;
+		}
 		if (EFX_OWORD_FIELD(nic_stat, FRF_AB_STRAP_10G) == 0) {
 			EFX_ERR(efx, "Falcon rev A1 1G not supported\n");
 			return -ENODEV;
@@ -2821,14 +2821,6 @@ static int falcon_probe_nic_variant(struct efx_nic *efx)
 			EFX_ERR(efx, "Falcon rev A1 PCI-X not supported\n");
 			return -ENODEV;
 		}
-		break;
-
-	case FALCON_REV_B0:
-		break;
-
-	default:
-		EFX_ERR(efx, "Unknown Falcon rev %d\n", falcon_rev(efx));
-		return -ENODEV;
 	}
 
 	return 0;
@@ -2991,7 +2983,7 @@ static void falcon_init_rx_cfg(struct efx_nic *efx)
 	efx_oword_t reg;
 
 	efx_reado(efx, &reg, FR_AZ_RX_CFG);
-	if (falcon_rev(efx) <= FALCON_REV_A1) {
+	if (efx_nic_rev(efx) <= EFX_REV_FALCON_A1) {
 		/* Data FIFO size is 5.5K */
 		if (data_xon_thr < 0)
 			data_xon_thr = 512 >> 8;
@@ -3037,7 +3029,7 @@ int falcon_init_nic(struct efx_nic *efx)
 	efx_writeo(efx, &temp, FR_AB_NIC_STAT);
 
 	/* Set the source of the GMAC clock */
-	if (falcon_rev(efx) == FALCON_REV_B0) {
+	if (efx_nic_rev(efx) == EFX_REV_FALCON_B0) {
 		efx_reado(efx, &temp, FR_AB_GPIO_CTL);
 		EFX_SET_OWORD_FIELD(temp, FRF_AB_USE_NIC_CLK, true);
 		efx_writeo(efx, &temp, FR_AB_GPIO_CTL);
@@ -3128,7 +3120,7 @@ int falcon_init_nic(struct efx_nic *efx)
 	/* Prefetch threshold 2 => fetch when descriptor cache half empty */
 	EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_PREF_THRESHOLD, 2);
 	/* Squash TX of packets of 16 bytes or less */
-	if (falcon_rev(efx) >= FALCON_REV_B0)
+	if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0)
 		EFX_SET_OWORD_FIELD(temp, FRF_BZ_TX_FLUSH_MIN_LEN_EN, 1);
 	efx_writeo(efx, &temp, FR_AZ_TX_RESERVED);
 
@@ -3142,7 +3134,7 @@ int falcon_init_nic(struct efx_nic *efx)
 	falcon_init_rx_cfg(efx);
 
 	/* Set destination of both TX and RX Flush events */
-	if (falcon_rev(efx) >= FALCON_REV_B0) {
+	if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) {
 		EFX_POPULATE_OWORD_1(temp, FRF_BZ_FLS_EVQ_ID, 0);
 		efx_writeo(efx, &temp, FR_BZ_DP_CTRL);
 	}
@@ -3242,9 +3234,10 @@ void falcon_stop_nic_stats(struct efx_nic *efx)
  **************************************************************************
  */
 
-struct efx_nic_type falcon_a_nic_type = {
+struct efx_nic_type falcon_a1_nic_type = {
 	.default_mac_ops = &falcon_xmac_operations,
 
+	.revision = EFX_REV_FALCON_A1,
 	.mem_map_size = 0x20000,
 	.txd_ptr_tbl_base = FR_AA_TX_DESC_PTR_TBL_KER,
 	.rxd_ptr_tbl_base = FR_AA_RX_DESC_PTR_TBL_KER,
@@ -3257,9 +3250,10 @@ struct efx_nic_type falcon_a_nic_type = {
 	.phys_addr_channels = 4,
 };
 
-struct efx_nic_type falcon_b_nic_type = {
+struct efx_nic_type falcon_b0_nic_type = {
 	.default_mac_ops = &falcon_xmac_operations,
 
+	.revision = EFX_REV_FALCON_B0,
 	/* Map everything up to and including the RSS indirection
 	 * table.  Don't map MSI-X table, MSI-X PBA since Linux
 	 * requires that they not be mapped.  */
diff --git a/drivers/net/sfc/falcon.h b/drivers/net/sfc/falcon.h
index a561f67..81196a0 100644
--- a/drivers/net/sfc/falcon.h
+++ b/drivers/net/sfc/falcon.h
@@ -19,15 +19,15 @@
  * Falcon hardware control
  */
 
-enum falcon_revision {
-	FALCON_REV_A0 = 0,
-	FALCON_REV_A1 = 1,
-	FALCON_REV_B0 = 2,
+enum {
+	EFX_REV_FALCON_A0 = 0,
+	EFX_REV_FALCON_A1 = 1,
+	EFX_REV_FALCON_B0 = 2,
 };
 
-static inline int falcon_rev(struct efx_nic *efx)
+static inline int efx_nic_rev(struct efx_nic *efx)
 {
-	return efx->pci_dev->revision;
+	return efx->type->revision;
 }
 
 /**
@@ -95,8 +95,8 @@ static inline struct falcon_board *falcon_board(struct efx_nic *efx)
 	return &data->board;
 }
 
-extern struct efx_nic_type falcon_a_nic_type;
-extern struct efx_nic_type falcon_b_nic_type;
+extern struct efx_nic_type falcon_a1_nic_type;
+extern struct efx_nic_type falcon_b0_nic_type;
 
 /**************************************************************************
  *
diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c
index 784260f..1523efd 100644
--- a/drivers/net/sfc/falcon_xmac.c
+++ b/drivers/net/sfc/falcon_xmac.c
@@ -89,7 +89,7 @@ static void falcon_mask_status_intr(struct efx_nic *efx, bool enable)
 {
 	efx_oword_t reg;
 
-	if ((falcon_rev(efx) != FALCON_REV_B0) || LOOPBACK_INTERNAL(efx))
+	if ((efx_nic_rev(efx) != EFX_REV_FALCON_B0) || LOOPBACK_INTERNAL(efx))
 		return;
 
 	/* We expect xgmii faults if the wireside link is up */
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index ca7dff2..a42a051 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -844,6 +844,7 @@ static inline const char *efx_dev_name(struct efx_nic *efx)
 /**
  * struct efx_nic_type - Efx device type definition
  * @default_mac_ops: efx_mac_operations to set at startup
+ * @revision: Hardware architecture revision
  * @mem_map_size: Memory BAR mapped size
  * @txd_ptr_tbl_base: TX descriptor ring base address
  * @rxd_ptr_tbl_base: RX descriptor ring base address
@@ -860,6 +861,7 @@ static inline const char *efx_dev_name(struct efx_nic *efx)
 struct efx_nic_type {
 	struct efx_mac_operations *default_mac_ops;
 
+	int revision;
 	unsigned int mem_map_size;
 	unsigned int txd_ptr_tbl_base;
 	unsigned int rxd_ptr_tbl_base;
diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c
index 1580607..74e84af 100644
--- a/drivers/net/sfc/selftest.c
+++ b/drivers/net/sfc/selftest.c
@@ -125,7 +125,7 @@ static int efx_test_chip(struct efx_nic *efx, struct efx_self_tests *tests)
 	int rc;
 
 	/* Not supported on A-series silicon */
-	if (falcon_rev(efx) < FALCON_REV_B0)
+	if (efx_nic_rev(efx) < EFX_REV_FALCON_B0)
 		return 0;
 
 	rc = falcon_test_registers(efx);
diff --git a/drivers/net/sfc/workarounds.h b/drivers/net/sfc/workarounds.h
index 209ee1e..021d0d2 100644
--- a/drivers/net/sfc/workarounds.h
+++ b/drivers/net/sfc/workarounds.h
@@ -16,8 +16,8 @@
  */
 
 #define EFX_WORKAROUND_ALWAYS(efx) 1
-#define EFX_WORKAROUND_FALCON_A(efx) (falcon_rev(efx) <= FALCON_REV_A1)
-#define EFX_WORKAROUND_FALCON_AB(efx) (falcon_rev(efx) <= FALCON_REV_B0)
+#define EFX_WORKAROUND_FALCON_A(efx) (efx_nic_rev(efx) <= EFX_REV_FALCON_A1)
+#define EFX_WORKAROUND_FALCON_AB(efx) (efx_nic_rev(efx) <= EFX_REV_FALCON_B0)
 #define EFX_WORKAROUND_10G(efx) EFX_IS10G(efx)
 #define EFX_WORKAROUND_SFT9001(efx) ((efx)->phy_type == PHY_TYPE_SFT9001A || \
 				     (efx)->phy_type == PHY_TYPE_SFT9001B)

-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.


^ permalink raw reply related

* [PATCH 10/32] sfc: Move descriptor cache base addresses to struct efx_nic_type
From: Ben Hutchings @ 2009-11-28  3:46 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, linux-net-drivers

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 drivers/net/sfc/falcon.c     |   12 ++++++++----
 drivers/net/sfc/net_driver.h |    4 ++++
 2 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index 7c9c9c9..539d022 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -45,11 +45,9 @@
  */
 #define TX_DC_ENTRIES 16
 #define TX_DC_ENTRIES_ORDER 1
-#define TX_DC_BASE 0x130000
 
 #define RX_DC_ENTRIES 64
 #define RX_DC_ENTRIES_ORDER 3
-#define RX_DC_BASE 0x100000
 
 static const unsigned int
 /* "Large" EEPROM device: Atmel AT25640 or similar
@@ -3043,9 +3041,11 @@ int falcon_init_nic(struct efx_nic *efx)
 		return rc;
 
 	/* Set positions of descriptor caches in SRAM. */
-	EFX_POPULATE_OWORD_1(temp, FRF_AZ_SRM_TX_DC_BASE_ADR, TX_DC_BASE / 8);
+	EFX_POPULATE_OWORD_1(temp, FRF_AZ_SRM_TX_DC_BASE_ADR,
+			     efx->type->tx_dc_base / 8);
 	efx_writeo(efx, &temp, FR_AZ_SRM_TX_DC_CFG);
-	EFX_POPULATE_OWORD_1(temp, FRF_AZ_SRM_RX_DC_BASE_ADR, RX_DC_BASE / 8);
+	EFX_POPULATE_OWORD_1(temp, FRF_AZ_SRM_RX_DC_BASE_ADR,
+			     efx->type->rx_dc_base / 8);
 	efx_writeo(efx, &temp, FR_AZ_SRM_RX_DC_CFG);
 
 	/* Set TX descriptor cache size. */
@@ -3248,6 +3248,8 @@ struct efx_nic_type falcon_a1_nic_type = {
 	.rx_buffer_padding = 0x24,
 	.max_interrupt_mode = EFX_INT_MODE_MSI,
 	.phys_addr_channels = 4,
+	.tx_dc_base = 0x130000,
+	.rx_dc_base = 0x100000,
 };
 
 struct efx_nic_type falcon_b0_nic_type = {
@@ -3271,5 +3273,7 @@ struct efx_nic_type falcon_b0_nic_type = {
 	.phys_addr_channels = 32, /* Hardware limit is 64, but the legacy
 				   * interrupt handler only supports 32
 				   * channels */
+	.tx_dc_base = 0x130000,
+	.rx_dc_base = 0x100000,
 };
 
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index a42a051..30fb21e 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -857,6 +857,8 @@ static inline const char *efx_dev_name(struct efx_nic *efx)
  *	from &enum efx_init_mode.
  * @phys_addr_channels: Number of channels with physically addressed
  *	descriptors
+ * @tx_dc_base: Base address in SRAM of TX queue descriptor caches
+ * @rx_dc_base: Base address in SRAM of RX queue descriptor caches
  */
 struct efx_nic_type {
 	struct efx_mac_operations *default_mac_ops;
@@ -872,6 +874,8 @@ struct efx_nic_type {
 	unsigned int rx_buffer_padding;
 	unsigned int max_interrupt_mode;
 	unsigned int phys_addr_channels;
+	unsigned int tx_dc_base;
+	unsigned int rx_dc_base;
 };
 
 /**************************************************************************

-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.


^ permalink raw reply related

* [PATCH 11/32] sfc: Allow for additional checksum offload features
From: Ben Hutchings @ 2009-11-28  3:46 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, linux-net-drivers

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 drivers/net/sfc/efx.c        |    2 +-
 drivers/net/sfc/ethtool.c    |   16 +++++++++++++++-
 drivers/net/sfc/falcon.c     |    2 ++
 drivers/net/sfc/net_driver.h |    3 +++
 4 files changed, 21 insertions(+), 2 deletions(-)

diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index f5e8111..f4eba45 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -2117,7 +2117,7 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev,
 	net_dev = alloc_etherdev(sizeof(*efx));
 	if (!net_dev)
 		return -ENOMEM;
-	net_dev->features |= (NETIF_F_IP_CSUM | NETIF_F_SG |
+	net_dev->features |= (type->offload_features | NETIF_F_SG |
 			      NETIF_F_HIGHDMA | NETIF_F_TSO |
 			      NETIF_F_GRO);
 	/* Mask for features that also apply to VLAN devices */
diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c
index 5d2e186..b3d0485 100644
--- a/drivers/net/sfc/ethtool.c
+++ b/drivers/net/sfc/ethtool.c
@@ -451,6 +451,19 @@ static void efx_ethtool_get_stats(struct net_device *net_dev,
 	}
 }
 
+static int efx_ethtool_set_tx_csum(struct net_device *net_dev, u32 enable)
+{
+	struct efx_nic *efx = netdev_priv(net_dev);
+	unsigned long features = efx->type->offload_features & NETIF_F_ALL_CSUM;
+
+	if (enable)
+		net_dev->features |= features;
+	else
+		net_dev->features &= ~features;
+
+	return 0;
+}
+
 static int efx_ethtool_set_rx_csum(struct net_device *net_dev, u32 enable)
 {
 	struct efx_nic *efx = netdev_priv(net_dev);
@@ -733,7 +746,8 @@ const struct ethtool_ops efx_ethtool_ops = {
 	.get_rx_csum		= efx_ethtool_get_rx_csum,
 	.set_rx_csum		= efx_ethtool_set_rx_csum,
 	.get_tx_csum		= ethtool_op_get_tx_csum,
-	.set_tx_csum		= ethtool_op_set_tx_csum,
+	/* Need to enable/disable IPv6 too */
+	.set_tx_csum		= efx_ethtool_set_tx_csum,
 	.get_sg			= ethtool_op_get_sg,
 	.set_sg			= ethtool_op_set_sg,
 	.get_tso		= ethtool_op_get_tso,
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index 539d022..2096753 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -3250,6 +3250,7 @@ struct efx_nic_type falcon_a1_nic_type = {
 	.phys_addr_channels = 4,
 	.tx_dc_base = 0x130000,
 	.rx_dc_base = 0x100000,
+	.offload_features = NETIF_F_IP_CSUM,
 };
 
 struct efx_nic_type falcon_b0_nic_type = {
@@ -3275,5 +3276,6 @@ struct efx_nic_type falcon_b0_nic_type = {
 				   * channels */
 	.tx_dc_base = 0x130000,
 	.rx_dc_base = 0x100000,
+	.offload_features = NETIF_F_IP_CSUM,
 };
 
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index 30fb21e..90f6a2a 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -859,6 +859,8 @@ static inline const char *efx_dev_name(struct efx_nic *efx)
  *	descriptors
  * @tx_dc_base: Base address in SRAM of TX queue descriptor caches
  * @rx_dc_base: Base address in SRAM of RX queue descriptor caches
+ * @offload_features: net_device feature flags for protocol offload
+ *	features implemented in hardware
  */
 struct efx_nic_type {
 	struct efx_mac_operations *default_mac_ops;
@@ -876,6 +878,7 @@ struct efx_nic_type {
 	unsigned int phys_addr_channels;
 	unsigned int tx_dc_base;
 	unsigned int rx_dc_base;
+	unsigned long offload_features;
 };
 
 /**************************************************************************

-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.


^ permalink raw reply related

* [PATCH 12/32] sfc: Clean up RX event handling
From: Ben Hutchings @ 2009-11-28  3:46 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, linux-net-drivers

Add 'likely' hint to test of rx_checksum_enabled.
Don't count IP fragments; the IP stack can do that.
Do count non-matching multicast packets.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 drivers/net/sfc/ethtool.c    |    1 +
 drivers/net/sfc/falcon.c     |   11 +++++------
 drivers/net/sfc/net_driver.h |    4 ++--
 3 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c
index b3d0485..8b91cd2 100644
--- a/drivers/net/sfc/ethtool.c
+++ b/drivers/net/sfc/ethtool.c
@@ -153,6 +153,7 @@ static struct efx_ethtool_stat efx_ethtool_stats[] = {
 	EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_tobe_disc),
 	EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_ip_hdr_chksum_err),
 	EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_tcp_udp_chksum_err),
+	EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_mcast_mismatch),
 	EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_frm_trunc),
 };
 
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index 2096753..b2509fc 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -734,7 +734,7 @@ static void falcon_handle_rx_not_ok(struct efx_rx_queue *rx_queue,
 	bool rx_ev_tcp_udp_chksum_err, rx_ev_eth_crc_err;
 	bool rx_ev_frm_trunc, rx_ev_drib_nib, rx_ev_tobe_disc;
 	bool rx_ev_other_err, rx_ev_pause_frm;
-	bool rx_ev_ip_frag_err, rx_ev_hdr_type, rx_ev_mcast_pkt;
+	bool rx_ev_hdr_type, rx_ev_mcast_pkt;
 	unsigned rx_ev_pkt_type;
 
 	rx_ev_hdr_type = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_HDR_TYPE);
@@ -743,7 +743,6 @@ static void falcon_handle_rx_not_ok(struct efx_rx_queue *rx_queue,
 	rx_ev_pkt_type = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_PKT_TYPE);
 	rx_ev_buf_owner_id_err = EFX_QWORD_FIELD(*event,
 						 FSF_AZ_RX_EV_BUF_OWNER_ID_ERR);
-	rx_ev_ip_frag_err = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_IP_FRAG_ERR);
 	rx_ev_ip_hdr_chksum_err = EFX_QWORD_FIELD(*event,
 						  FSF_AZ_RX_EV_IP_HDR_CHKSUM_ERR);
 	rx_ev_tcp_udp_chksum_err = EFX_QWORD_FIELD(*event,
@@ -771,8 +770,6 @@ static void falcon_handle_rx_not_ok(struct efx_rx_queue *rx_queue,
 		else if (rx_ev_tcp_udp_chksum_err)
 			++rx_queue->channel->n_rx_tcp_udp_chksum_err;
 	}
-	if (rx_ev_ip_frag_err)
-		++rx_queue->channel->n_rx_ip_frag_err;
 
 	/* The frame must be discarded if any of these are true. */
 	*discard = (rx_ev_eth_crc_err | rx_ev_frm_trunc | rx_ev_drib_nib |
@@ -855,7 +852,7 @@ static void falcon_handle_rx_event(struct efx_channel *channel,
 		 * UDP/IPv4, then we can rely on the hardware checksum.
 		 */
 		checksummed =
-			efx->rx_checksum_enabled &&
+			likely(efx->rx_checksum_enabled) &&
 			(rx_ev_hdr_type == FSE_AB_RX_EV_HDR_TYPE_IPV4_TCP ||
 			 rx_ev_hdr_type == FSE_AB_RX_EV_HDR_TYPE_IPV4_UDP);
 	} else {
@@ -870,8 +867,10 @@ static void falcon_handle_rx_event(struct efx_channel *channel,
 		unsigned int rx_ev_mcast_hash_match =
 			EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_MCAST_HASH_MATCH);
 
-		if (unlikely(!rx_ev_mcast_hash_match))
+		if (unlikely(!rx_ev_mcast_hash_match)) {
+			++channel->n_rx_mcast_mismatch;
 			discard = true;
+		}
 	}
 
 	channel->irq_mod_score += 2;
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index 90f6a2a..320ae7d 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -350,9 +350,9 @@ enum efx_rx_alloc_method {
  * @rx_alloc_push_pages: RX allocation method currently in use for pushing
  *	descriptors
  * @n_rx_tobe_disc: Count of RX_TOBE_DISC errors
- * @n_rx_ip_frag_err: Count of RX IP fragment errors
  * @n_rx_ip_hdr_chksum_err: Count of RX IP header checksum errors
  * @n_rx_tcp_udp_chksum_err: Count of RX TCP and UDP checksum errors
+ * @n_rx_mcast_mismatch: Count of unmatched multicast frames
  * @n_rx_frm_trunc: Count of RX_FRM_TRUNC errors
  * @n_rx_overlength: Count of RX_OVERLENGTH errors
  * @n_skbuff_leaks: Count of skbuffs leaked due to RX overrun
@@ -380,9 +380,9 @@ struct efx_channel {
 	int rx_alloc_push_pages;
 
 	unsigned n_rx_tobe_disc;
-	unsigned n_rx_ip_frag_err;
 	unsigned n_rx_ip_hdr_chksum_err;
 	unsigned n_rx_tcp_udp_chksum_err;
+	unsigned n_rx_mcast_mismatch;
 	unsigned n_rx_frm_trunc;
 	unsigned n_rx_overlength;
 	unsigned n_skbuff_leaks;

-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.


^ permalink raw reply related

* [PATCH 13/32] sfc: Remove redundant writes to INT_ADR_KER
From: Ben Hutchings @ 2009-11-28  3:48 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, linux-net-drivers

Steve Hodgson <shodgson@solarflare.com>

This register only needs to be written after reset, not each time we
enable interrupts.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 drivers/net/sfc/falcon.c |   15 +++++++--------
 1 files changed, 7 insertions(+), 8 deletions(-)

diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index b2509fc..5bbe842 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -1290,19 +1290,11 @@ static inline void falcon_interrupts(struct efx_nic *efx, int enabled,
 
 void falcon_enable_interrupts(struct efx_nic *efx)
 {
-	efx_oword_t int_adr_reg_ker;
 	struct efx_channel *channel;
 
 	EFX_ZERO_OWORD(*((efx_oword_t *) efx->irq_status.addr));
 	wmb(); /* Ensure interrupt vector is clear before interrupts enabled */
 
-	/* Program address */
-	EFX_POPULATE_OWORD_2(int_adr_reg_ker,
-			     FRF_AZ_NORM_INT_VEC_DIS_KER,
-			     EFX_INT_MODE_USE_MSI(efx),
-			     FRF_AZ_INT_ADR_KER, efx->irq_status.dma_addr);
-	efx_writeo(efx, &int_adr_reg_ker, FR_AZ_INT_ADR_KER);
-
 	/* Enable interrupts */
 	falcon_interrupts(efx, 1, 0);
 
@@ -3061,6 +3053,13 @@ int falcon_init_nic(struct efx_nic *efx)
 	EFX_POPULATE_OWORD_1(temp, FRF_AZ_RX_DC_PF_LWM, RX_DC_ENTRIES - 8);
 	efx_writeo(efx, &temp, FR_AZ_RX_DC_PF_WM);
 
+	/* Program INT_KER address */
+	EFX_POPULATE_OWORD_2(temp,
+			     FRF_AZ_NORM_INT_VEC_DIS_KER,
+			     EFX_INT_MODE_USE_MSI(efx),
+			     FRF_AZ_INT_ADR_KER, efx->irq_status.dma_addr);
+	efx_writeo(efx, &temp, FR_AZ_INT_ADR_KER);
+
 	/* Clear the parity enables on the TX data fifos as
 	 * they produce false parity errors because of timing issues
 	 */

-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.


^ permalink raw reply related

* [PATCH 14/32] sfc: Remove duplicate hardware structure definitions
From: Ben Hutchings @ 2009-11-28  3:48 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, linux-net-drivers

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 drivers/net/sfc/falcon.c |    6 +++---
 drivers/net/sfc/regs.h   |   12 ------------
 2 files changed, 3 insertions(+), 15 deletions(-)

diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index 5bbe842..9868e4a 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -1463,8 +1463,8 @@ static irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id)
 	/* Determine interrupting queues, clear interrupt status
 	 * register and acknowledge the device interrupt.
 	 */
-	BUILD_BUG_ON(INT_EVQS_WIDTH > EFX_MAX_CHANNELS);
-	queues = EFX_OWORD_FIELD(*int_ker, INT_EVQS);
+	BUILD_BUG_ON(FSF_AZ_NET_IVEC_INT_Q_WIDTH > EFX_MAX_CHANNELS);
+	queues = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_INT_Q);
 	EFX_ZERO_OWORD(*int_ker);
 	wmb(); /* Ensure the vector is cleared before interrupt ack */
 	falcon_irq_ack_a1(efx);
@@ -1500,7 +1500,7 @@ static irqreturn_t falcon_msi_interrupt(int irq, void *dev_id)
 		  irq, raw_smp_processor_id(), EFX_OWORD_VAL(*int_ker));
 
 	/* Check to see if we have a serious error condition */
-	syserr = EFX_OWORD_FIELD(*int_ker, FATAL_INT);
+	syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT);
 	if (unlikely(syserr))
 		return falcon_fatal_interrupt(efx);
 
diff --git a/drivers/net/sfc/regs.h b/drivers/net/sfc/regs.h
index f336d83..89d606f 100644
--- a/drivers/net/sfc/regs.h
+++ b/drivers/net/sfc/regs.h
@@ -3106,18 +3106,6 @@
 #define FALCON_STATS_NOT_DONE 0x00000000
 #define FALCON_STATS_DONE 0xffffffff
 
-/* Interrupt status register bits */
-#define FATAL_INT_LBN 64
-#define FATAL_INT_WIDTH 1
-#define INT_EVQS_LBN 40
-#define INT_EVQS_WIDTH 4
-#define INT_FLAG_LBN 32
-#define INT_FLAG_WIDTH 1
-#define EVQ_FIFO_HF_LBN 1
-#define EVQ_FIFO_HF_WIDTH 1
-#define EVQ_FIFO_AF_LBN 0
-#define EVQ_FIFO_AF_WIDTH 1
-
 /**************************************************************************
  *
  * Falcon non-volatile configuration

-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.


^ permalink raw reply related

* [PATCH 15/32] sfc: Turn pause frame generation on and off at the MAC, not the RX FIFO
From: Ben Hutchings @ 2009-11-28  3:49 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, linux-net-drivers

Pause frame generation is gated by both RX_XOFF_MAC_EN and an enable
bit in each MAC.  RX_XOFF_MAC_EN bit always reads back as 0 so we need
to set it correctly every time we modify RX_CFG_REG.  Simplify this by
always setting it to 1 and only changing the enable bits in the MACs.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 drivers/net/sfc/falcon.c      |   13 ++++++-------
 drivers/net/sfc/falcon_xmac.c |    3 ++-
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index 9868e4a..744fce9 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -1939,7 +1939,6 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
 	struct efx_link_state *link_state = &efx->link_state;
 	efx_oword_t reg;
 	int link_speed;
-	bool tx_fc;
 
 	switch (link_state->speed) {
 	case 10000: link_speed = 3; break;
@@ -1969,13 +1968,10 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
 	/* Restore the multicast hash registers. */
 	falcon_push_multicast_hash(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->link_state.fc & EFX_FC_TX);
 	efx_reado(efx, &reg, FR_AZ_RX_CFG);
-	EFX_SET_OWORD_FIELD(reg, FRF_AZ_RX_XOFF_MAC_EN, tx_fc);
-
+	/* Enable XOFF signal from RX FIFO (we enabled it during NIC
+	 * initialisation but it may read back as 0) */
+	EFX_SET_OWORD_FIELD(reg, FRF_AZ_RX_XOFF_MAC_EN, 1);
 	/* Unisolate the MAC -> RX */
 	if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0)
 		EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, 1);
@@ -3000,6 +2996,9 @@ static void falcon_init_rx_cfg(struct efx_nic *efx)
 		EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_XOFF_TX_TH, ctrl_xoff_thr);
 		EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, 1);
 	}
+	/* Always enable XOFF signal from RX FIFO.  We enable
+	 * or disable transmission of pause frames at the MAC. */
+	EFX_SET_OWORD_FIELD(reg, FRF_AZ_RX_XOFF_MAC_EN, 1);
 	efx_writeo(efx, &reg, FR_AZ_RX_CFG);
 }
 
diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c
index 1523efd..60dc097 100644
--- a/drivers/net/sfc/falcon_xmac.c
+++ b/drivers/net/sfc/falcon_xmac.c
@@ -148,6 +148,7 @@ static void falcon_reconfigure_xmac_core(struct efx_nic *efx)
 	unsigned int max_frame_len;
 	efx_oword_t reg;
 	bool rx_fc = !!(efx->link_state.fc & EFX_FC_RX);
+	bool tx_fc = !!(efx->link_state.fc & EFX_FC_TX);
 
 	/* Configure MAC  - cut-thru mode is hard wired on */
 	EFX_POPULATE_OWORD_3(reg,
@@ -162,7 +163,7 @@ static void falcon_reconfigure_xmac_core(struct efx_nic *efx)
 			     FRF_AB_XM_TX_PRMBL, 1,
 			     FRF_AB_XM_AUTO_PAD, 1,
 			     FRF_AB_XM_TXCRC, 1,
-			     FRF_AB_XM_FCNTL, 1,
+			     FRF_AB_XM_FCNTL, tx_fc,
 			     FRF_AB_XM_IPG, 0x3);
 	efx_writeo(efx, &reg, FR_AB_XM_TX_CFG);
 

-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.


^ permalink raw reply related

* [PATCH 16/32] sfc: Move Falcon NIC operations to efx_nic_type
From: Ben Hutchings @ 2009-11-28  3:49 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, linux-net-drivers

This is preparation for adding differing implementations for new NICs.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 drivers/net/sfc/efx.c        |   44 +++++++++++++----------
 drivers/net/sfc/ethtool.c    |    2 +-
 drivers/net/sfc/falcon.c     |   79 ++++++++++++++++++++++++++---------------
 drivers/net/sfc/falcon.h     |   12 ------
 drivers/net/sfc/net_driver.h |   29 +++++++++++++++
 drivers/net/sfc/selftest.c   |    2 +-
 6 files changed, 105 insertions(+), 63 deletions(-)

diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index f4eba45..ce8e447 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -274,14 +274,14 @@ static int efx_poll(struct napi_struct *napi, int budget)
 				     irq_adapt_low_thresh)) {
 				if (channel->irq_moderation > 1) {
 					channel->irq_moderation -= 1;
-					falcon_set_int_moderation(channel);
+					efx->type->push_irq_moderation(channel);
 				}
 			} else if (unlikely(channel->irq_mod_score >
 					    irq_adapt_high_thresh)) {
 				if (channel->irq_moderation <
 				    efx->irq_rx_moderation) {
 					channel->irq_moderation += 1;
-					falcon_set_int_moderation(channel);
+					efx->type->push_irq_moderation(channel);
 				}
 			}
 			channel->irq_count = 0;
@@ -637,7 +637,7 @@ void __efx_reconfigure_port(struct efx_nic *efx)
 		netif_addr_unlock_bh(efx->net_dev);
 	}
 
-	falcon_stop_nic_stats(efx);
+	efx->type->stop_stats(efx);
 	falcon_deconfigure_mac_wrapper(efx);
 
 	/* Reconfigure the PHY, disabling transmit in mac level loopback. */
@@ -652,7 +652,7 @@ void __efx_reconfigure_port(struct efx_nic *efx)
 
 	efx->mac_op->reconfigure(efx);
 
-	falcon_start_nic_stats(efx);
+	efx->type->start_stats(efx);
 
 	/* Inform kernel of loss/gain of carrier */
 	efx_link_status_changed(efx);
@@ -684,7 +684,7 @@ static void efx_mac_work(struct work_struct *data)
 
 	mutex_lock(&efx->mac_lock);
 	if (efx->port_enabled) {
-		falcon_push_multicast_hash(efx);
+		efx->type->push_multicast_hash(efx);
 		efx->mac_op->reconfigure(efx);
 	}
 	mutex_unlock(&efx->mac_lock);
@@ -696,8 +696,8 @@ static int efx_probe_port(struct efx_nic *efx)
 
 	EFX_LOG(efx, "create port\n");
 
-	/* Connect up MAC/PHY operations table and read MAC address */
-	rc = falcon_probe_port(efx);
+	/* Connect up MAC/PHY operations table */
+	rc = efx->type->probe_port(efx);
 	if (rc)
 		goto err;
 
@@ -765,7 +765,7 @@ static void efx_start_port(struct efx_nic *efx)
 
 	/* efx_mac_work() might have been scheduled after efx_stop_port(),
 	 * and then cancelled by efx_flush_all() */
-	falcon_push_multicast_hash(efx);
+	efx->type->push_multicast_hash(efx);
 	efx->mac_op->reconfigure(efx);
 
 	mutex_unlock(&efx->mac_lock);
@@ -805,7 +805,7 @@ static void efx_remove_port(struct efx_nic *efx)
 {
 	EFX_LOG(efx, "destroying port\n");
 
-	falcon_remove_port(efx);
+	efx->type->remove_port(efx);
 }
 
 /**************************************************************************
@@ -1042,7 +1042,7 @@ static int efx_probe_nic(struct efx_nic *efx)
 	EFX_LOG(efx, "creating NIC\n");
 
 	/* Carry out hardware-type specific initialisation */
-	rc = falcon_probe_nic(efx);
+	rc = efx->type->probe(efx);
 	if (rc)
 		return rc;
 
@@ -1063,7 +1063,7 @@ static void efx_remove_nic(struct efx_nic *efx)
 	EFX_LOG(efx, "destroying NIC\n");
 
 	efx_remove_interrupts(efx);
-	falcon_remove_nic(efx);
+	efx->type->remove(efx);
 }
 
 /**************************************************************************
@@ -1145,12 +1145,12 @@ static void efx_start_all(struct efx_nic *efx)
 
 	falcon_enable_interrupts(efx);
 
-	/* Start hardware monitor if we're in RUNNING */
-	if (efx->state == STATE_RUNNING)
+	/* Start the hardware monitor (if there is one) if we're in RUNNING */
+	if (efx->state == STATE_RUNNING && efx->type->monitor != NULL)
 		queue_delayed_work(efx->workqueue, &efx->monitor_work,
 				   efx_monitor_interval);
 
-	falcon_start_nic_stats(efx);
+	efx->type->start_stats(efx);
 }
 
 /* Flush all delayed work. Should only be called when no more delayed work
@@ -1186,7 +1186,7 @@ static void efx_stop_all(struct efx_nic *efx)
 	if (!efx->port_enabled)
 		return;
 
-	falcon_stop_nic_stats(efx);
+	efx->type->stop_stats(efx);
 
 	/* Disable interrupts and wait for ISR to complete */
 	falcon_disable_interrupts(efx);
@@ -1284,6 +1284,7 @@ static void efx_monitor(struct work_struct *data)
 
 	EFX_TRACE(efx, "hardware monitor executing on CPU %d\n",
 		  raw_smp_processor_id());
+	BUG_ON(efx->type->monitor == NULL);
 
 	/* If the mac_lock is already held then it is likely a port
 	 * reconfiguration is already in place, which will likely do
@@ -1292,7 +1293,7 @@ static void efx_monitor(struct work_struct *data)
 		goto out_requeue;
 	if (!efx->port_enabled)
 		goto out_unlock;
-	falcon_monitor(efx);
+	efx->type->monitor(efx);
 
 out_unlock:
 	mutex_unlock(&efx->mac_lock);
@@ -1430,7 +1431,7 @@ static struct net_device_stats *efx_net_stats(struct net_device *net_dev)
 	struct net_device_stats *stats = &net_dev->stats;
 
 	spin_lock_bh(&efx->stats_lock);
-	falcon_update_nic_stats(efx);
+	efx->type->update_stats(efx);
 	spin_unlock_bh(&efx->stats_lock);
 
 	stats->rx_packets = mac_stats->rx_packets;
@@ -1695,6 +1696,7 @@ void efx_reset_down(struct efx_nic *efx, enum reset_type method,
 	efx_fini_channels(efx);
 	if (efx->port_initialized && method != RESET_TYPE_INVISIBLE)
 		efx->phy_op->fini(efx);
+	efx->type->fini(efx);
 }
 
 /* This function will always ensure that the locks acquired in
@@ -1709,7 +1711,7 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method,
 
 	EFX_ASSERT_RESET_SERIALISED(efx);
 
-	rc = falcon_init_nic(efx);
+	rc = efx->type->init(efx);
 	if (rc) {
 		EFX_ERR(efx, "failed to initialise NIC\n");
 		ok = false;
@@ -1769,7 +1771,7 @@ static int efx_reset(struct efx_nic *efx)
 
 	efx_reset_down(efx, method, &ecmd);
 
-	rc = falcon_reset_hw(efx, method);
+	rc = efx->type->reset(efx, method);
 	if (rc) {
 		EFX_ERR(efx, "failed to reset hardware\n");
 		goto out_disable;
@@ -2005,6 +2007,7 @@ static void efx_pci_remove_main(struct efx_nic *efx)
 	falcon_fini_interrupt(efx);
 	efx_fini_channels(efx);
 	efx_fini_port(efx);
+	efx->type->fini(efx);
 	efx_fini_napi(efx);
 	efx_remove_all(efx);
 }
@@ -2064,7 +2067,7 @@ static int efx_pci_probe_main(struct efx_nic *efx)
 	if (rc)
 		goto fail2;
 
-	rc = falcon_init_nic(efx);
+	rc = efx->type->init(efx);
 	if (rc) {
 		EFX_ERR(efx, "failed to initialise NIC\n");
 		goto fail3;
@@ -2088,6 +2091,7 @@ static int efx_pci_probe_main(struct efx_nic *efx)
 	efx_fini_channels(efx);
 	efx_fini_port(efx);
  fail4:
+	efx->type->fini(efx);
  fail3:
 	efx_fini_napi(efx);
  fail2:
diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c
index 8b91cd2..0ac34b0 100644
--- a/drivers/net/sfc/ethtool.c
+++ b/drivers/net/sfc/ethtool.c
@@ -662,7 +662,7 @@ static int efx_ethtool_set_coalesce(struct net_device *net_dev,
 
 	efx_init_irq_moderation(efx, tx_usecs, rx_usecs, adaptive);
 	efx_for_each_channel(channel, efx)
-		falcon_set_int_moderation(channel);
+		efx->type->push_irq_moderation(channel);
 
 	return 0;
 }
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index 744fce9..23e2ec2 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -1041,7 +1041,7 @@ int falcon_process_eventq(struct efx_channel *channel, int rx_quota)
 	return rx_packets;
 }
 
-void falcon_set_int_moderation(struct efx_channel *channel)
+static void falcon_push_irq_moderation(struct efx_channel *channel)
 {
 	efx_dword_t timer_cmd;
 	struct efx_nic *efx = channel->efx;
@@ -1098,7 +1098,7 @@ void falcon_init_eventq(struct efx_channel *channel)
 	efx_writeo_table(efx, &evq_ptr, efx->type->evq_ptr_tbl_base,
 			 channel->channel);
 
-	falcon_set_int_moderation(channel);
+	falcon_push_irq_moderation(channel);
 }
 
 void falcon_fini_eventq(struct efx_channel *channel)
@@ -1212,7 +1212,8 @@ int falcon_flush_queues(struct efx_nic *efx)
 	struct efx_tx_queue *tx_queue;
 	int i, tx_pending, rx_pending;
 
-	falcon_prepare_flush(efx);
+	/* If necessary prepare the hardware for flushing */
+	efx->type->prepare_flush(efx);
 
 	/* Flush all tx queues in parallel */
 	efx_for_each_tx_queue(tx_queue, efx)
@@ -1825,6 +1826,16 @@ int falcon_spi_write(const struct efx_spi_device *spi, loff_t start,
  **************************************************************************
  */
 
+static void falcon_push_multicast_hash(struct efx_nic *efx)
+{
+	union efx_multicast_hash *mc_hash = &efx->multicast_hash;
+
+	WARN_ON(!mutex_is_locked(&efx->mac_lock));
+
+	efx_writeo(efx, &mc_hash->oword[0], FR_AB_MAC_MC_HASH_REG0);
+	efx_writeo(efx, &mc_hash->oword[1], FR_AB_MAC_MC_HASH_REG1);
+}
+
 static int falcon_reset_macs(struct efx_nic *efx)
 {
 	efx_oword_t reg;
@@ -2240,7 +2251,7 @@ out:
 }
 
 /* This call is responsible for hooking in the MAC and PHY operations */
-int falcon_probe_port(struct efx_nic *efx)
+static int falcon_probe_port(struct efx_nic *efx)
 {
 	int rc;
 
@@ -2299,31 +2310,13 @@ int falcon_probe_port(struct efx_nic *efx)
 	return 0;
 }
 
-void falcon_remove_port(struct efx_nic *efx)
+static void falcon_remove_port(struct efx_nic *efx)
 {
 	falcon_free_buffer(efx, &efx->stats_buffer);
 }
 
 /**************************************************************************
  *
- * Multicast filtering
- *
- **************************************************************************
- */
-
-void falcon_push_multicast_hash(struct efx_nic *efx)
-{
-	union efx_multicast_hash *mc_hash = &efx->multicast_hash;
-
-	WARN_ON(!mutex_is_locked(&efx->mac_lock));
-
-	efx_writeo(efx, &mc_hash->oword[0], FR_AB_MAC_MC_HASH_REG0);
-	efx_writeo(efx, &mc_hash->oword[1], FR_AB_MAC_MC_HASH_REG1);
-}
-
-
-/**************************************************************************
- *
  * Falcon test code
  *
  **************************************************************************/
@@ -2503,7 +2496,7 @@ fail:
 
 /* Resets NIC to known state.  This routine must be called in process
  * context and is allowed to sleep. */
-int falcon_reset_hw(struct efx_nic *efx, enum reset_type method)
+static int falcon_reset_hw(struct efx_nic *efx, enum reset_type method)
 {
 	struct falcon_nic_data *nic_data = efx->nic_data;
 	efx_oword_t glb_ctl_reg_ker;
@@ -2592,7 +2585,7 @@ fail5:
 	return rc;
 }
 
-void falcon_monitor(struct efx_nic *efx)
+static void falcon_monitor(struct efx_nic *efx)
 {
 	bool link_changed;
 	int rc;
@@ -2850,7 +2843,7 @@ static void falcon_probe_spi_devices(struct efx_nic *efx)
 				       large_eeprom_type);
 }
 
-int falcon_probe_nic(struct efx_nic *efx)
+static int falcon_probe_nic(struct efx_nic *efx)
 {
 	struct falcon_nic_data *nic_data;
 	struct falcon_board *board;
@@ -3006,7 +2999,7 @@ static void falcon_init_rx_cfg(struct efx_nic *efx)
  * defining the descriptor cache sizes and number of RSS channels.
  * It does not set up any buffers, descriptor rings or event queues.
  */
-int falcon_init_nic(struct efx_nic *efx)
+static int falcon_init_nic(struct efx_nic *efx)
 {
 	efx_oword_t temp;
 	int rc;
@@ -3139,7 +3132,7 @@ int falcon_init_nic(struct efx_nic *efx)
 	return 0;
 }
 
-void falcon_remove_nic(struct efx_nic *efx)
+static void falcon_remove_nic(struct efx_nic *efx)
 {
 	struct falcon_nic_data *nic_data = efx->nic_data;
 	struct falcon_board *board = falcon_board(efx);
@@ -3168,7 +3161,7 @@ void falcon_remove_nic(struct efx_nic *efx)
 	efx->nic_data = NULL;
 }
 
-void falcon_update_nic_stats(struct efx_nic *efx)
+static void falcon_update_nic_stats(struct efx_nic *efx)
 {
 	struct falcon_nic_data *nic_data = efx->nic_data;
 	efx_oword_t cnt;
@@ -3232,6 +3225,20 @@ void falcon_stop_nic_stats(struct efx_nic *efx)
  */
 
 struct efx_nic_type falcon_a1_nic_type = {
+	.probe = falcon_probe_nic,
+	.remove = falcon_remove_nic,
+	.init = falcon_init_nic,
+	.fini = efx_port_dummy_op_void,
+	.monitor = falcon_monitor,
+	.reset = falcon_reset_hw,
+	.probe_port = falcon_probe_port,
+	.remove_port = falcon_remove_port,
+	.prepare_flush = falcon_prepare_flush,
+	.update_stats = falcon_update_nic_stats,
+	.start_stats = falcon_start_nic_stats,
+	.stop_stats = falcon_stop_nic_stats,
+	.push_irq_moderation = falcon_push_irq_moderation,
+	.push_multicast_hash = falcon_push_multicast_hash,
 	.default_mac_ops = &falcon_xmac_operations,
 
 	.revision = EFX_REV_FALCON_A1,
@@ -3251,6 +3258,20 @@ struct efx_nic_type falcon_a1_nic_type = {
 };
 
 struct efx_nic_type falcon_b0_nic_type = {
+	.probe = falcon_probe_nic,
+	.remove = falcon_remove_nic,
+	.init = falcon_init_nic,
+	.fini = efx_port_dummy_op_void,
+	.monitor = falcon_monitor,
+	.reset = falcon_reset_hw,
+	.probe_port = falcon_probe_port,
+	.remove_port = falcon_remove_port,
+	.prepare_flush = falcon_prepare_flush,
+	.update_stats = falcon_update_nic_stats,
+	.start_stats = falcon_start_nic_stats,
+	.stop_stats = falcon_stop_nic_stats,
+	.push_irq_moderation = falcon_push_irq_moderation,
+	.push_multicast_hash = falcon_push_multicast_hash,
 	.default_mac_ops = &falcon_xmac_operations,
 
 	.revision = EFX_REV_FALCON_B0,
diff --git a/drivers/net/sfc/falcon.h b/drivers/net/sfc/falcon.h
index 81196a0..3fe6484 100644
--- a/drivers/net/sfc/falcon.h
+++ b/drivers/net/sfc/falcon.h
@@ -129,10 +129,6 @@ extern void falcon_remove_eventq(struct efx_channel *channel);
 extern int falcon_process_eventq(struct efx_channel *channel, int rx_quota);
 extern void falcon_eventq_read_ack(struct efx_channel *channel);
 
-/* Ports */
-extern int falcon_probe_port(struct efx_nic *efx);
-extern void falcon_remove_port(struct efx_nic *efx);
-
 /* MAC/PHY */
 extern int falcon_switch_mac(struct efx_nic *efx);
 extern bool falcon_xaui_link_ok(struct efx_nic *efx);
@@ -146,23 +142,15 @@ extern void falcon_enable_interrupts(struct efx_nic *efx);
 extern void falcon_generate_test_event(struct efx_channel *channel,
 				       unsigned int magic);
 extern void falcon_generate_interrupt(struct efx_nic *efx);
-extern void falcon_set_int_moderation(struct efx_channel *channel);
 extern void falcon_disable_interrupts(struct efx_nic *efx);
 extern void falcon_fini_interrupt(struct efx_nic *efx);
 
 #define FALCON_IRQ_MOD_RESOLUTION 5
 
 /* Global Resources */
-extern int falcon_probe_nic(struct efx_nic *efx);
-extern int falcon_init_nic(struct efx_nic *efx);
 extern int falcon_flush_queues(struct efx_nic *efx);
-extern int falcon_reset_hw(struct efx_nic *efx, enum reset_type method);
-extern void falcon_monitor(struct efx_nic *efx);
-extern void falcon_remove_nic(struct efx_nic *efx);
-extern void falcon_update_nic_stats(struct efx_nic *efx);
 extern void falcon_start_nic_stats(struct efx_nic *efx);
 extern void falcon_stop_nic_stats(struct efx_nic *efx);
-extern void falcon_push_multicast_hash(struct efx_nic *efx);
 extern int falcon_reset_xaui(struct efx_nic *efx);
 
 /* Tests */
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index 320ae7d..1b98cd0 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -843,6 +843,21 @@ static inline const char *efx_dev_name(struct efx_nic *efx)
 
 /**
  * struct efx_nic_type - Efx device type definition
+ * @probe: Probe the controller
+ * @remove: Free resources allocated by probe()
+ * @init: Initialise the controller
+ * @fini: Shut down the controller
+ * @monitor: Periodic function for polling link state and hardware monitor
+ * @reset: Reset the controller hardware and possibly the PHY.  This will
+ *	be called while the controller is uninitialised.
+ * @probe_port: Probe the MAC and PHY
+ * @remove_port: Free resources allocated by probe_port()
+ * @prepare_flush: Prepare the hardware for flushing the DMA queues
+ * @update_stats: Update statistics not provided by event handling
+ * @start_stats: Start the regular fetching of statistics
+ * @stop_stats: Stop the regular fetching of statistics
+ * @push_irq_moderation: Apply interrupt moderation value
+ * @push_multicast_hash: Apply multicast hash table
  * @default_mac_ops: efx_mac_operations to set at startup
  * @revision: Hardware architecture revision
  * @mem_map_size: Memory BAR mapped size
@@ -863,6 +878,20 @@ static inline const char *efx_dev_name(struct efx_nic *efx)
  *	features implemented in hardware
  */
 struct efx_nic_type {
+	int (*probe)(struct efx_nic *efx);
+	void (*remove)(struct efx_nic *efx);
+	int (*init)(struct efx_nic *efx);
+	void (*fini)(struct efx_nic *efx);
+	void (*monitor)(struct efx_nic *efx);
+	int (*reset)(struct efx_nic *efx, enum reset_type method);
+	int (*probe_port)(struct efx_nic *efx);
+	void (*remove_port)(struct efx_nic *efx);
+	void (*prepare_flush)(struct efx_nic *efx);
+	void (*update_stats)(struct efx_nic *efx);
+	void (*start_stats)(struct efx_nic *efx);
+	void (*stop_stats)(struct efx_nic *efx);
+	void (*push_irq_moderation)(struct efx_channel *channel);
+	void (*push_multicast_hash)(struct efx_nic *efx);
 	struct efx_mac_operations *default_mac_ops;
 
 	int revision;
diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c
index 74e84af..15d4d9c 100644
--- a/drivers/net/sfc/selftest.c
+++ b/drivers/net/sfc/selftest.c
@@ -719,7 +719,7 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests,
 		rc_test = rc;
 
 	/* reset the chip to recover from the register test */
-	rc_reset = falcon_reset_hw(efx, reset_method);
+	rc_reset = efx->type->reset(efx, reset_method);
 
 	/* Ensure that the phy is powered and out of loopback
 	 * for the bist and loopback tests */

-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.


^ permalink raw reply related

* [PATCH 17/32] sfc: Refactor link configuration
From: Ben Hutchings @ 2009-11-28  3:49 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, linux-net-drivers

Refactor PHY, MAC and NIC configuration operations so that the
existing link configuration can be re-pushed with:

	efx->phy_op->reconfigure(efx);
	efx->mac_op->reconfigure(efx);

and a new configuration with:

	efx->nic_op->reconfigure_port(efx);

(plus locking and error-checking).

We have not held the link settings in software (aside from flow
control), and have relied on asking the hardware what they are.  This
is a problem because in some cases the hardware may no longer be in a
state to tell us.  In particular, if an entire multi-port board is
reset through one port, the driver bindings to other ports have no
chance to save settings before recovering.

We only actually need to keep track of the autonegotiation settings,
so add an ethtool advertising mask to struct efx_nic, initialise it
in PHY init and update it as necessary.

Remove now-unneeded uses of efx_phy_op::{get,set}_settings() and
struct ethtool_cmd.

Much of this was done by Steve Hodgson <shodgson@solarflare.com>.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 drivers/net/sfc/efx.c           |  132 +++++++++++++++++++++++---------------
 drivers/net/sfc/efx.h           |   12 ++--
 drivers/net/sfc/ethtool.c       |   61 ++++++++++++------
 drivers/net/sfc/falcon.c        |   98 ++++++++++++++++++----------
 drivers/net/sfc/falcon.h        |    3 -
 drivers/net/sfc/falcon_boards.c |    3 +-
 drivers/net/sfc/falcon_gmac.c   |    4 +-
 drivers/net/sfc/falcon_xmac.c   |    8 ++-
 drivers/net/sfc/mac.h           |    1 +
 drivers/net/sfc/mdio_10g.c      |   41 ++++++++----
 drivers/net/sfc/mdio_10g.h      |    3 +
 drivers/net/sfc/net_driver.h    |    8 ++-
 drivers/net/sfc/qt202x_phy.c    |    4 +-
 drivers/net/sfc/selftest.c      |   11 ++--
 drivers/net/sfc/tenxpress.c     |   66 ++++++++------------
 15 files changed, 273 insertions(+), 182 deletions(-)

diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index ce8e447..c77338f 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -620,16 +620,49 @@ void efx_link_status_changed(struct efx_nic *efx)
 
 }
 
+void efx_link_set_advertising(struct efx_nic *efx, u32 advertising)
+{
+	efx->link_advertising = advertising;
+	if (advertising) {
+		if (advertising & ADVERTISED_Pause)
+			efx->wanted_fc |= (EFX_FC_TX | EFX_FC_RX);
+		else
+			efx->wanted_fc &= ~(EFX_FC_TX | EFX_FC_RX);
+		if (advertising & ADVERTISED_Asym_Pause)
+			efx->wanted_fc ^= EFX_FC_TX;
+	}
+}
+
+void efx_link_set_wanted_fc(struct efx_nic *efx, enum efx_fc_type wanted_fc)
+{
+	efx->wanted_fc = wanted_fc;
+	if (efx->link_advertising) {
+		if (wanted_fc & EFX_FC_RX)
+			efx->link_advertising |= (ADVERTISED_Pause |
+						  ADVERTISED_Asym_Pause);
+		else
+			efx->link_advertising &= ~(ADVERTISED_Pause |
+						   ADVERTISED_Asym_Pause);
+		if (wanted_fc & EFX_FC_TX)
+			efx->link_advertising ^= ADVERTISED_Asym_Pause;
+	}
+}
+
 static void efx_fini_port(struct efx_nic *efx);
 
-/* This call reinitialises the MAC to pick up new PHY settings. The
- * caller must hold the mac_lock */
-void __efx_reconfigure_port(struct efx_nic *efx)
+/* Push loopback/power/transmit disable settings to the PHY, and reconfigure
+ * the MAC appropriately. All other PHY configuration changes are pushed
+ * through phy_op->set_settings(), and pushed asynchronously to the MAC
+ * through efx_monitor().
+ *
+ * Callers must hold the mac_lock
+ */
+int __efx_reconfigure_port(struct efx_nic *efx)
 {
-	WARN_ON(!mutex_is_locked(&efx->mac_lock));
+	enum efx_phy_mode phy_mode;
+	int rc;
 
-	EFX_LOG(efx, "reconfiguring MAC from PHY settings on CPU %d\n",
-		raw_smp_processor_id());
+	WARN_ON(!mutex_is_locked(&efx->mac_lock));
 
 	/* Serialise the promiscuous flag with efx_set_multicast_list. */
 	if (efx_dev_registered(efx)) {
@@ -637,42 +670,34 @@ void __efx_reconfigure_port(struct efx_nic *efx)
 		netif_addr_unlock_bh(efx->net_dev);
 	}
 
-	efx->type->stop_stats(efx);
-	falcon_deconfigure_mac_wrapper(efx);
-
-	/* Reconfigure the PHY, disabling transmit in mac level loopback. */
+	/* Disable PHY transmit in mac level loopbacks */
+	phy_mode = efx->phy_mode;
 	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);
+	rc = efx->type->reconfigure_port(efx);
 
-	efx->type->start_stats(efx);
-
-	/* Inform kernel of loss/gain of carrier */
-	efx_link_status_changed(efx);
-	return;
+	if (rc)
+		efx->phy_mode = phy_mode;
 
-fail:
-	EFX_ERR(efx, "failed to reconfigure MAC\n");
-	efx->port_enabled = false;
-	efx_fini_port(efx);
+	return rc;
 }
 
 /* Reinitialise the MAC to pick up new PHY settings, even if the port is
  * disabled. */
-void efx_reconfigure_port(struct efx_nic *efx)
+int efx_reconfigure_port(struct efx_nic *efx)
 {
+	int rc;
+
 	EFX_ASSERT_RESET_SERIALISED(efx);
 
 	mutex_lock(&efx->mac_lock);
-	__efx_reconfigure_port(efx);
+	rc = __efx_reconfigure_port(efx);
 	mutex_unlock(&efx->mac_lock);
+
+	return rc;
 }
 
 /* Asynchronous work item for changing MAC promiscuity and multicast
@@ -737,14 +762,18 @@ static int efx_init_port(struct efx_nic *efx)
 	rc = efx->phy_op->init(efx);
 	if (rc)
 		goto fail1;
-	efx->phy_op->reconfigure(efx);
-	rc = falcon_switch_mac(efx);
-	if (rc)
-		goto fail2;
-	efx->mac_op->reconfigure(efx);
 
 	efx->port_initialized = true;
 
+	/* Reconfigure the MAC before creating dma queues (required for
+	 * Falcon/A1 where RX_INGR_EN/TX_DRAIN_EN isn't supported) */
+	efx->mac_op->reconfigure(efx);
+
+	/* Ensure the PHY advertises the correct flow control settings */
+	rc = efx->phy_op->reconfigure(efx);
+	if (rc)
+		goto fail2;
+
 	mutex_unlock(&efx->mac_lock);
 	return 0;
 
@@ -1209,12 +1238,6 @@ static void efx_stop_all(struct efx_nic *efx)
 	/* Flush efx_mac_work(), refill_workqueue, monitor_work */
 	efx_flush_all(efx);
 
-	/* Isolate the MAC from the TX and RX engines, so that queue
-	 * flushes will complete in a timely fashion. */
-	falcon_deconfigure_mac_wrapper(efx);
-	msleep(10); /* Let the Rx FIFO drain */
-	falcon_drain_tx_fifo(efx);
-
 	/* Stop the kernel transmit interface late, so the watchdog
 	 * timer isn't ticking over the flush */
 	if (efx_dev_registered(efx)) {
@@ -1491,7 +1514,14 @@ static int efx_change_mtu(struct net_device *net_dev, int new_mtu)
 	EFX_LOG(efx, "changing MTU to %d\n", new_mtu);
 
 	efx_fini_channels(efx);
+
+	mutex_lock(&efx->mac_lock);
+	/* Reconfigure the MAC before enabling the dma queues so that
+	 * the RX buffers don't overflow */
 	net_dev->mtu = new_mtu;
+	efx->mac_op->reconfigure(efx);
+	mutex_unlock(&efx->mac_lock);
+
 	efx_init_channels(efx);
 
 	efx_start_all(efx);
@@ -1515,7 +1545,9 @@ static int efx_set_mac_address(struct net_device *net_dev, void *data)
 	memcpy(net_dev->dev_addr, new_addr, net_dev->addr_len);
 
 	/* Reconfigure the MAC */
-	efx_reconfigure_port(efx);
+	mutex_lock(&efx->mac_lock);
+	efx->mac_op->reconfigure(efx);
+	mutex_unlock(&efx->mac_lock);
 
 	return 0;
 }
@@ -1682,8 +1714,7 @@ static void efx_unregister_netdev(struct efx_nic *efx)
 
 /* Tears down the entire software state and most of the hardware state
  * before reset.  */
-void efx_reset_down(struct efx_nic *efx, enum reset_type method,
-		    struct ethtool_cmd *ecmd)
+void efx_reset_down(struct efx_nic *efx, enum reset_type method)
 {
 	EFX_ASSERT_RESET_SERIALISED(efx);
 
@@ -1691,8 +1722,6 @@ void efx_reset_down(struct efx_nic *efx, enum reset_type method,
 	mutex_lock(&efx->mac_lock);
 	mutex_lock(&efx->spi_lock);
 
-	efx->phy_op->get_settings(efx, ecmd);
-
 	efx_fini_channels(efx);
 	if (efx->port_initialized && method != RESET_TYPE_INVISIBLE)
 		efx->phy_op->fini(efx);
@@ -1704,8 +1733,7 @@ void efx_reset_down(struct efx_nic *efx, enum reset_type method,
  * that we were unable to reinitialise the hardware, and the
  * driver should be disabled. If ok is false, then the rx and tx
  * engines are not restarted, pending a RESET_DISABLE. */
-int efx_reset_up(struct efx_nic *efx, enum reset_type method,
-		 struct ethtool_cmd *ecmd, bool ok)
+int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok)
 {
 	int rc;
 
@@ -1722,16 +1750,17 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method,
 			rc = efx->phy_op->init(efx);
 			if (rc)
 				ok = false;
+			if (efx->phy_op->reconfigure(efx))
+				EFX_ERR(efx, "could not restore PHY settings\n");
 		}
 		if (!ok)
 			efx->port_initialized = false;
 	}
 
 	if (ok) {
-		efx_init_channels(efx);
+		efx->mac_op->reconfigure(efx);
 
-		if (efx->phy_op->set_settings(efx, ecmd))
-			EFX_ERR(efx, "could not restore PHY settings\n");
+		efx_init_channels(efx);
 	}
 
 	mutex_unlock(&efx->spi_lock);
@@ -1753,7 +1782,6 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method,
  */
 static int efx_reset(struct efx_nic *efx)
 {
-	struct ethtool_cmd ecmd;
 	enum reset_type method = efx->reset_pending;
 	int rc = 0;
 
@@ -1769,7 +1797,7 @@ static int efx_reset(struct efx_nic *efx)
 
 	EFX_INFO(efx, "resetting (%s)\n", RESET_TYPE(method));
 
-	efx_reset_down(efx, method, &ecmd);
+	efx_reset_down(efx, method);
 
 	rc = efx->type->reset(efx, method);
 	if (rc) {
@@ -1788,10 +1816,10 @@ static int efx_reset(struct efx_nic *efx)
 
 	/* Leave device stopped if necessary */
 	if (method == RESET_TYPE_DISABLE) {
-		efx_reset_up(efx, method, &ecmd, false);
+		efx_reset_up(efx, method, false);
 		rc = -EIO;
 	} else {
-		rc = efx_reset_up(efx, method, &ecmd, true);
+		rc = efx_reset_up(efx, method, true);
 	}
 
 out_disable:
@@ -1895,7 +1923,7 @@ bool efx_port_dummy_op_poll(struct efx_nic *efx)
 
 static struct efx_phy_operations efx_dummy_phy_operations = {
 	.init		 = efx_port_dummy_op_int,
-	.reconfigure	 = efx_port_dummy_op_void,
+	.reconfigure	 = efx_port_dummy_op_int,
 	.poll		 = efx_port_dummy_op_poll,
 	.fini		 = efx_port_dummy_op_void,
 };
diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h
index 15edda2..c785003 100644
--- a/drivers/net/sfc/efx.h
+++ b/drivers/net/sfc/efx.h
@@ -60,8 +60,8 @@ extern void efx_process_channel_now(struct efx_channel *channel);
 #define EFX_EVQ_MASK (EFX_EVQ_SIZE - 1)
 
 /* Ports */
-extern void efx_reconfigure_port(struct efx_nic *efx);
-extern void __efx_reconfigure_port(struct efx_nic *efx);
+extern int efx_reconfigure_port(struct efx_nic *efx);
+extern int __efx_reconfigure_port(struct efx_nic *efx);
 
 /* Ethtool support */
 extern int efx_ethtool_get_settings(struct net_device *net_dev,
@@ -71,10 +71,8 @@ extern int efx_ethtool_set_settings(struct net_device *net_dev,
 extern const struct ethtool_ops efx_ethtool_ops;
 
 /* Reset handling */
-extern void efx_reset_down(struct efx_nic *efx, enum reset_type method,
-			   struct ethtool_cmd *ecmd);
-extern int efx_reset_up(struct efx_nic *efx, enum reset_type method,
-			struct ethtool_cmd *ecmd, bool ok);
+extern void efx_reset_down(struct efx_nic *efx, enum reset_type method);
+extern int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok);
 
 /* Global */
 extern void efx_schedule_reset(struct efx_nic *efx, enum reset_type type);
@@ -115,5 +113,7 @@ static inline void efx_schedule_channel(struct efx_channel *channel)
 }
 
 extern void efx_link_status_changed(struct efx_nic *efx);
+extern void efx_link_set_advertising(struct efx_nic *efx, u32);
+extern void efx_link_set_wanted_fc(struct efx_nic *efx, enum efx_fc_type);
 
 #endif /* EFX_EFX_H */
diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c
index 0ac34b0..92c5d8d 100644
--- a/drivers/net/sfc/ethtool.c
+++ b/drivers/net/sfc/ethtool.c
@@ -10,7 +10,6 @@
 
 #include <linux/netdevice.h>
 #include <linux/ethtool.h>
-#include <linux/mdio.h>
 #include <linux/rtnetlink.h>
 #include "net_driver.h"
 #include "workarounds.h"
@@ -191,6 +190,7 @@ int efx_ethtool_get_settings(struct net_device *net_dev,
 			     struct ethtool_cmd *ecmd)
 {
 	struct efx_nic *efx = netdev_priv(net_dev);
+	struct efx_link_state *link_state = &efx->link_state;
 
 	mutex_lock(&efx->mac_lock);
 	efx->phy_op->get_settings(efx, ecmd);
@@ -198,6 +198,13 @@ int efx_ethtool_get_settings(struct net_device *net_dev,
 
 	/* Falcon GMAC does not support 1000Mbps HD */
 	ecmd->supported &= ~SUPPORTED_1000baseT_Half;
+	/* Both MACs support pause frames (bidirectional and respond-only) */
+	ecmd->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
+
+	if (LOOPBACK_INTERNAL(efx)) {
+		ecmd->speed = link_state->speed;
+		ecmd->duplex = link_state->fd ? DUPLEX_FULL : DUPLEX_HALF;
+	}
 
 	return 0;
 }
@@ -219,9 +226,6 @@ int efx_ethtool_set_settings(struct net_device *net_dev,
 	mutex_lock(&efx->mac_lock);
 	rc = efx->phy_op->set_settings(efx, ecmd);
 	mutex_unlock(&efx->mac_lock);
-	if (!rc)
-		efx_reconfigure_port(efx);
-
 	return rc;
 }
 
@@ -671,8 +675,12 @@ 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 wanted_fc;
+	enum efx_fc_type wanted_fc, old_fc;
+	u32 old_adv;
 	bool reset;
+	int rc = 0;
+
+	mutex_lock(&efx->mac_lock);
 
 	wanted_fc = ((pause->rx_pause ? EFX_FC_RX : 0) |
 		     (pause->tx_pause ? EFX_FC_TX : 0) |
@@ -680,14 +688,14 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev,
 
 	if ((wanted_fc & EFX_FC_TX) && !(wanted_fc & EFX_FC_RX)) {
 		EFX_LOG(efx, "Flow control unsupported: tx ON rx OFF\n");
-		return -EINVAL;
+		rc = -EINVAL;
+		goto out;
 	}
 
-	if (!(efx->phy_op->mmds & MDIO_DEVS_AN) &&
-	    (wanted_fc & EFX_FC_AUTO)) {
-		EFX_LOG(efx, "PHY does not support flow control "
-			"autonegotiation\n");
-		return -EINVAL;
+	if ((wanted_fc & EFX_FC_AUTO) && !efx->link_advertising) {
+		EFX_LOG(efx, "Autonegotiation is disabled\n");
+		rc = -EINVAL;
+		goto out;
 	}
 
 	/* TX flow control may automatically turn itself off if the
@@ -699,25 +707,38 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev,
 	if (EFX_WORKAROUND_11482(efx) && reset) {
 		if (efx_nic_rev(efx) == EFX_REV_FALCON_B0) {
 			/* Recover by resetting the EM block */
-			if (efx->link_state.up)
-				falcon_drain_tx_fifo(efx);
+			falcon_stop_nic_stats(efx);
+			falcon_drain_tx_fifo(efx);
+			efx->mac_op->reconfigure(efx);
+			falcon_start_nic_stats(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);
+	old_adv = efx->link_advertising;
+	old_fc = efx->wanted_fc;
+	efx_link_set_wanted_fc(efx, wanted_fc);
+	if (efx->link_advertising != old_adv ||
+	    (efx->wanted_fc ^ old_fc) & EFX_FC_AUTO) {
+		rc = efx->phy_op->reconfigure(efx);
+		if (rc) {
+			EFX_ERR(efx, "Unable to advertise requested flow "
+				"control setting\n");
+			goto out;
+		}
+	}
 
-	efx->wanted_fc = wanted_fc;
-	if (efx->phy_op->mmds & MDIO_DEVS_AN)
-		mdio45_ethtool_spauseparam_an(&efx->mdio, pause);
-	__efx_reconfigure_port(efx);
+	/* Reconfigure the MAC. The PHY *may* generate a link state change event
+	 * if the user just changed the advertised capabilities, but there's no
+	 * harm doing this twice */
+	efx->mac_op->reconfigure(efx);
 
+out:
 	mutex_unlock(&efx->mac_lock);
 
-	return 0;
+	return rc;
 }
 
 static void efx_ethtool_get_pauseparam(struct net_device *net_dev,
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index 23e2ec2..85233c8 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -1193,6 +1193,8 @@ static void falcon_poll_flush_events(struct efx_nic *efx)
 	channel->eventq_read_ptr = read_ptr;
 }
 
+static void falcon_deconfigure_mac_wrapper(struct efx_nic *efx);
+
 static void falcon_prepare_flush(struct efx_nic *efx)
 {
 	falcon_deconfigure_mac_wrapper(efx);
@@ -1836,9 +1838,10 @@ static void falcon_push_multicast_hash(struct efx_nic *efx)
 	efx_writeo(efx, &mc_hash->oword[1], FR_AB_MAC_MC_HASH_REG1);
 }
 
-static int falcon_reset_macs(struct efx_nic *efx)
+static void falcon_reset_macs(struct efx_nic *efx)
 {
-	efx_oword_t reg;
+	struct falcon_nic_data *nic_data = efx->nic_data;
+	efx_oword_t reg, mac_ctrl;
 	int count;
 
 	if (efx_nic_rev(efx) < EFX_REV_FALCON_B0) {
@@ -1853,7 +1856,7 @@ static int falcon_reset_macs(struct efx_nic *efx)
 			EFX_POPULATE_OWORD_1(reg, FRF_AB_GM_SW_RST, 0);
 			efx_writeo(efx, &reg, FR_AB_GM_CFG1);
 			udelay(1000);
-			return 0;
+			return;
 		} else {
 			EFX_POPULATE_OWORD_1(reg, FRF_AB_XM_CORE_RST, 1);
 			efx_writeo(efx, &reg, FR_AB_XM_GLB_CFG);
@@ -1862,22 +1865,20 @@ static int falcon_reset_macs(struct efx_nic *efx)
 				efx_reado(efx, &reg, FR_AB_XM_GLB_CFG);
 				if (EFX_OWORD_FIELD(reg, FRF_AB_XM_CORE_RST) ==
 				    0)
-					return 0;
+					return;
 				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
-	 * the drain sequence with the statistics fetch */
-	falcon_stop_nic_stats(efx);
+	/* Mac stats will fail whist the TX fifo is draining */
+	WARN_ON(nic_data->stats_disable_count == 0);
 
-	efx_reado(efx, &reg, FR_AB_MAC_CTRL);
-	EFX_SET_OWORD_FIELD(reg, FRF_BB_TXFIFO_DRAIN_EN, 1);
-	efx_writeo(efx, &reg, FR_AB_MAC_CTRL);
+	efx_reado(efx, &mac_ctrl, FR_AB_MAC_CTRL);
+	EFX_SET_OWORD_FIELD(mac_ctrl, FRF_BB_TXFIFO_DRAIN_EN, 1);
+	efx_writeo(efx, &mac_ctrl, FR_AB_MAC_CTRL);
 
 	efx_reado(efx, &reg, FR_AB_GLB_CTL);
 	EFX_SET_OWORD_FIELD(reg, FRF_AB_RST_XGTX, 1);
@@ -1903,14 +1904,9 @@ static int falcon_reset_macs(struct efx_nic *efx)
 		udelay(10);
 	}
 
-	/* 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 */
-	if (efx->link_state.up && EFX_IS10G(efx) && EFX_WORKAROUND_5147(efx))
-		falcon_reset_xaui(efx);
-
-	falcon_start_nic_stats(efx);
-
-	return 0;
+	/* Ensure the correct MAC is selected before statistics
+	 * are re-enabled by the caller */
+	efx_writeo(efx, &mac_ctrl, FR_AB_MAC_CTRL);
 }
 
 void falcon_drain_tx_fifo(struct efx_nic *efx)
@@ -1929,7 +1925,7 @@ void falcon_drain_tx_fifo(struct efx_nic *efx)
 	falcon_reset_macs(efx);
 }
 
-void falcon_deconfigure_mac_wrapper(struct efx_nic *efx)
+static void falcon_deconfigure_mac_wrapper(struct efx_nic *efx)
 {
 	efx_oword_t reg;
 
@@ -1941,8 +1937,8 @@ void falcon_deconfigure_mac_wrapper(struct efx_nic *efx)
 	EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, 0);
 	efx_writeo(efx, &reg, FR_AZ_RX_CFG);
 
-	if (!efx->link_state.up)
-		falcon_drain_tx_fifo(efx);
+	/* Isolate TX -> MAC */
+	falcon_drain_tx_fifo(efx);
 }
 
 void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
@@ -2044,6 +2040,8 @@ static void falcon_stats_timer_func(unsigned long context)
 	spin_unlock(&efx->stats_lock);
 }
 
+static void falcon_switch_mac(struct efx_nic *efx);
+
 static bool falcon_loopback_link_poll(struct efx_nic *efx)
 {
 	struct efx_link_state old_state = efx->link_state;
@@ -2063,6 +2061,38 @@ static bool falcon_loopback_link_poll(struct efx_nic *efx)
 	return !efx_link_state_equal(&efx->link_state, &old_state);
 }
 
+static int falcon_reconfigure_port(struct efx_nic *efx)
+{
+	int rc;
+
+	WARN_ON(efx_nic_rev(efx) > EFX_REV_FALCON_B0);
+
+	/* Poll the PHY link state *before* reconfiguring it. This means we
+	 * will pick up the correct speed (in loopback) to select the correct
+	 * MAC.
+	 */
+	if (LOOPBACK_INTERNAL(efx))
+		falcon_loopback_link_poll(efx);
+	else
+		efx->phy_op->poll(efx);
+
+	falcon_stop_nic_stats(efx);
+	falcon_deconfigure_mac_wrapper(efx);
+
+	falcon_switch_mac(efx);
+
+	efx->phy_op->reconfigure(efx);
+	rc = efx->mac_op->reconfigure(efx);
+	BUG_ON(rc);
+
+	falcon_start_nic_stats(efx);
+
+	/* Synchronise efx->link_state with the kernel */
+	efx_link_status_changed(efx);
+
+	return 0;
+}
+
 /**************************************************************************
  *
  * PHY access via GMII
@@ -2215,17 +2245,15 @@ static void falcon_clock_mac(struct efx_nic *efx)
 	}
 }
 
-int falcon_switch_mac(struct efx_nic *efx)
+static void falcon_switch_mac(struct efx_nic *efx)
 {
 	struct efx_mac_operations *old_mac_op = efx->mac_op;
 	struct falcon_nic_data *nic_data = efx->nic_data;
 	unsigned int stats_done_offset;
-	int rc = 0;
-
-	/* Don't try to fetch MAC stats while we're switching MACs */
-	falcon_stop_nic_stats(efx);
 
 	WARN_ON(!mutex_is_locked(&efx->mac_lock));
+	WARN_ON(nic_data->stats_disable_count == 0);
+
 	efx->mac_op = (EFX_IS10G(efx) ?
 		       &falcon_xmac_operations : &falcon_gmac_operations);
 
@@ -2236,18 +2264,14 @@ int falcon_switch_mac(struct efx_nic *efx)
 	nic_data->stats_dma_done = efx->stats_buffer.addr + stats_done_offset;
 
 	if (old_mac_op == efx->mac_op)
-		goto out;
+		return;
 
 	falcon_clock_mac(efx);
 
 	EFX_LOG(efx, "selected %cMAC\n", EFX_IS10G(efx) ? 'X' : 'G');
 	/* Not all macs support a mac-level link state */
 	efx->xmac_poll_required = false;
-
-	rc = falcon_reset_macs(efx);
-out:
-	falcon_start_nic_stats(efx);
-	return rc;
+	falcon_reset_macs(efx);
 }
 
 /* This call is responsible for hooking in the MAC and PHY operations */
@@ -2597,7 +2621,8 @@ static void falcon_monitor(struct efx_nic *efx)
 		EFX_ERR(efx, "Board sensor %s; shutting down PHY\n",
 			(rc == -ERANGE) ? "reported fault" : "failed");
 		efx->phy_mode |= PHY_MODE_LOW_POWER;
-		__efx_reconfigure_port(efx);
+		rc = __efx_reconfigure_port(efx);
+		WARN_ON(rc);
 	}
 
 	if (LOOPBACK_INTERNAL(efx))
@@ -2610,7 +2635,8 @@ static void falcon_monitor(struct efx_nic *efx)
 		falcon_deconfigure_mac_wrapper(efx);
 
 		falcon_switch_mac(efx);
-		efx->mac_op->reconfigure(efx);
+		rc = efx->mac_op->reconfigure(efx);
+		BUG_ON(rc);
 
 		falcon_start_nic_stats(efx);
 
@@ -3239,6 +3265,7 @@ struct efx_nic_type falcon_a1_nic_type = {
 	.stop_stats = falcon_stop_nic_stats,
 	.push_irq_moderation = falcon_push_irq_moderation,
 	.push_multicast_hash = falcon_push_multicast_hash,
+	.reconfigure_port = falcon_reconfigure_port,
 	.default_mac_ops = &falcon_xmac_operations,
 
 	.revision = EFX_REV_FALCON_A1,
@@ -3272,6 +3299,7 @@ struct efx_nic_type falcon_b0_nic_type = {
 	.stop_stats = falcon_stop_nic_stats,
 	.push_irq_moderation = falcon_push_irq_moderation,
 	.push_multicast_hash = falcon_push_multicast_hash,
+	.reconfigure_port = falcon_reconfigure_port,
 	.default_mac_ops = &falcon_xmac_operations,
 
 	.revision = EFX_REV_FALCON_B0,
diff --git a/drivers/net/sfc/falcon.h b/drivers/net/sfc/falcon.h
index 3fe6484..560a3f9 100644
--- a/drivers/net/sfc/falcon.h
+++ b/drivers/net/sfc/falcon.h
@@ -130,10 +130,7 @@ extern int falcon_process_eventq(struct efx_channel *channel, int rx_quota);
 extern void falcon_eventq_read_ack(struct efx_channel *channel);
 
 /* MAC/PHY */
-extern int falcon_switch_mac(struct efx_nic *efx);
-extern bool falcon_xaui_link_ok(struct efx_nic *efx);
 extern void falcon_drain_tx_fifo(struct efx_nic *efx);
-extern void falcon_deconfigure_mac_wrapper(struct efx_nic *efx);
 extern void falcon_reconfigure_mac_wrapper(struct efx_nic *efx);
 
 /* Interrupts and test events */
diff --git a/drivers/net/sfc/falcon_boards.c b/drivers/net/sfc/falcon_boards.c
index da75095..b92decc 100644
--- a/drivers/net/sfc/falcon_boards.c
+++ b/drivers/net/sfc/falcon_boards.c
@@ -352,7 +352,8 @@ static ssize_t set_phy_flash_cfg(struct device *dev,
 			err = sfe4001_poweron(efx);
 		else
 			err = sfn4111t_reset(efx);
-		efx_reconfigure_port(efx);
+		if (!err)
+			err = efx_reconfigure_port(efx);
 		if (!(new_mode & PHY_MODE_SPECIAL))
 			falcon_start_nic_stats(efx);
 	}
diff --git a/drivers/net/sfc/falcon_gmac.c b/drivers/net/sfc/falcon_gmac.c
index 66d499c..19dd3ac 100644
--- a/drivers/net/sfc/falcon_gmac.c
+++ b/drivers/net/sfc/falcon_gmac.c
@@ -22,7 +22,7 @@
  *
  *************************************************************************/
 
-static void falcon_reconfigure_gmac(struct efx_nic *efx)
+static int falcon_reconfigure_gmac(struct efx_nic *efx)
 {
 	struct efx_link_state *link_state = &efx->link_state;
 	bool loopback, tx_fc, rx_fc, bytemode;
@@ -123,6 +123,8 @@ static void falcon_reconfigure_gmac(struct efx_nic *efx)
 	udelay(10);
 
 	falcon_reconfigure_mac_wrapper(efx);
+
+	return 0;
 }
 
 static void falcon_update_stats_gmac(struct efx_nic *efx)
diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c
index 60dc097..898afc1 100644
--- a/drivers/net/sfc/falcon_xmac.c
+++ b/drivers/net/sfc/falcon_xmac.c
@@ -112,7 +112,7 @@ static void falcon_mask_status_intr(struct efx_nic *efx, bool enable)
 }
 
 /* Get status of XAUI link */
-bool falcon_xaui_link_ok(struct efx_nic *efx)
+static bool falcon_xaui_link_ok(struct efx_nic *efx)
 {
 	efx_oword_t reg;
 	bool align_done, link_ok = false;
@@ -143,7 +143,7 @@ bool falcon_xaui_link_ok(struct efx_nic *efx)
 	return link_ok;
 }
 
-static void falcon_reconfigure_xmac_core(struct efx_nic *efx)
+void falcon_reconfigure_xmac_core(struct efx_nic *efx)
 {
 	unsigned int max_frame_len;
 	efx_oword_t reg;
@@ -275,7 +275,7 @@ static bool falcon_xmac_check_fault(struct efx_nic *efx)
 	return !falcon_check_xaui_link_up(efx, 5);
 }
 
-static void falcon_reconfigure_xmac(struct efx_nic *efx)
+static int falcon_reconfigure_xmac(struct efx_nic *efx)
 {
 	falcon_mask_status_intr(efx, false);
 
@@ -286,6 +286,8 @@ static void falcon_reconfigure_xmac(struct efx_nic *efx)
 
 	efx->xmac_poll_required = !falcon_check_xaui_link_up(efx, 5);
 	falcon_mask_status_intr(efx, true);
+
+	return 0;
 }
 
 static void falcon_update_stats_xmac(struct efx_nic *efx)
diff --git a/drivers/net/sfc/mac.h b/drivers/net/sfc/mac.h
index 4e70742..d2af50f 100644
--- a/drivers/net/sfc/mac.h
+++ b/drivers/net/sfc/mac.h
@@ -15,5 +15,6 @@
 
 extern struct efx_mac_operations falcon_gmac_operations;
 extern struct efx_mac_operations falcon_xmac_operations;
+extern void falcon_reconfigure_xmac_core(struct efx_nic *efx);
 
 #endif
diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c
index 231e580..1f62a5c 100644
--- a/drivers/net/sfc/mdio_10g.c
+++ b/drivers/net/sfc/mdio_10g.c
@@ -248,8 +248,6 @@ void efx_mdio_set_mmds_lpower(struct efx_nic *efx,
 int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
 {
 	struct ethtool_cmd prev;
-	bool xnp;
-	int reg;
 
 	efx->phy_op->get_settings(efx, &prev);
 
@@ -269,30 +267,47 @@ int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
 	    (ecmd->advertising | SUPPORTED_Autoneg) & ~prev.supported)
 		return -EINVAL;
 
-	xnp = (ecmd->advertising & ADVERTISED_10000baseT_Full
-	       || EFX_WORKAROUND_13204(efx));
+	efx_link_set_advertising(efx, ecmd->advertising | ADVERTISED_Autoneg);
+	efx_mdio_an_reconfigure(efx);
+	return 0;
+}
+
+/**
+ * efx_mdio_an_reconfigure - Push advertising flags and restart autonegotiation
+ * @efx:		Efx NIC
+ */
+void efx_mdio_an_reconfigure(struct efx_nic *efx)
+{
+	bool xnp = (efx->link_advertising & ADVERTISED_10000baseT_Full
+		    || EFX_WORKAROUND_13204(efx));
+	int reg;
+
+	WARN_ON(!(efx->mdio.mmds & MDIO_DEVS_AN));
 
 	/* Set up the base page */
 	reg = ADVERTISE_CSMA;
-	if (ecmd->advertising & ADVERTISED_10baseT_Half)
+	if (efx->link_advertising & ADVERTISED_10baseT_Half)
 		reg |= ADVERTISE_10HALF;
-	if (ecmd->advertising & ADVERTISED_10baseT_Full)
+	if (efx->link_advertising & ADVERTISED_10baseT_Full)
 		reg |= ADVERTISE_10FULL;
-	if (ecmd->advertising & ADVERTISED_100baseT_Half)
+	if (efx->link_advertising & ADVERTISED_100baseT_Half)
 		reg |= ADVERTISE_100HALF;
-	if (ecmd->advertising & ADVERTISED_100baseT_Full)
+	if (efx->link_advertising & ADVERTISED_100baseT_Full)
 		reg |= ADVERTISE_100FULL;
 	if (xnp)
 		reg |= ADVERTISE_RESV;
-	else if (ecmd->advertising & (ADVERTISED_1000baseT_Half |
-				      ADVERTISED_1000baseT_Full))
+	else if (efx->link_advertising & (ADVERTISED_1000baseT_Half |
+					  ADVERTISED_1000baseT_Full))
 		reg |= ADVERTISE_NPAGE;
-	reg |= mii_advertise_flowctrl(efx->wanted_fc);
+	if (efx->link_advertising & ADVERTISED_Pause)
+		reg |= ADVERTISE_PAUSE_CAP;
+	if (efx->link_advertising & ADVERTISED_Asym_Pause)
+		reg |= ADVERTISE_PAUSE_ASYM;
 	efx_mdio_write(efx, MDIO_MMD_AN, MDIO_AN_ADVERTISE, reg);
 
 	/* Set up the (extended) next page if necessary */
 	if (efx->phy_op->set_npage_adv)
-		efx->phy_op->set_npage_adv(efx, ecmd->advertising);
+		efx->phy_op->set_npage_adv(efx, efx->link_advertising);
 
 	/* Enable and restart AN */
 	reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_CTRL1);
@@ -305,8 +320,6 @@ int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
 	else
 		reg &= ~MDIO_AN_CTRL1_XNP;
 	efx_mdio_write(efx, MDIO_MMD_AN, MDIO_CTRL1, reg);
-
-	return 0;
 }
 
 enum efx_fc_type efx_mdio_get_pause(struct efx_nic *efx)
diff --git a/drivers/net/sfc/mdio_10g.h b/drivers/net/sfc/mdio_10g.h
index 75b37f1..dbc8e7d 100644
--- a/drivers/net/sfc/mdio_10g.h
+++ b/drivers/net/sfc/mdio_10g.h
@@ -86,6 +86,9 @@ extern void efx_mdio_set_mmds_lpower(struct efx_nic *efx,
 /* Set (some of) the PHY settings over MDIO */
 extern int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd);
 
+/* Push advertising flags and restart autonegotiation */
+extern void efx_mdio_an_reconfigure(struct efx_nic *efx);
+
 /* Get pause parameters from AN if available (otherwise return
  * requested pause parameters)
  */
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index 1b98cd0..ecb24b9 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -517,7 +517,7 @@ static inline bool efx_link_state_equal(const struct efx_link_state *left,
  * @check_fault: Check fault state. True if fault present.
  */
 struct efx_mac_operations {
-	void (*reconfigure) (struct efx_nic *efx);
+	int (*reconfigure) (struct efx_nic *efx);
 	void (*update_stats) (struct efx_nic *efx);
 	bool (*check_fault)(struct efx_nic *efx);
 };
@@ -544,7 +544,7 @@ struct efx_phy_operations {
 	enum efx_mac_type macs;
 	int (*init) (struct efx_nic *efx);
 	void (*fini) (struct efx_nic *efx);
-	void (*reconfigure) (struct efx_nic *efx);
+	int (*reconfigure) (struct efx_nic *efx);
 	bool (*poll) (struct efx_nic *efx);
 	void (*get_settings) (struct efx_nic *efx,
 			      struct ethtool_cmd *ecmd);
@@ -730,6 +730,7 @@ union efx_multicast_hash {
  * @mdio: PHY MDIO interface
  * @phy_mode: PHY operating mode. Serialised by @mac_lock.
  * @xmac_poll_required: XMAC link state needs polling
+ * @link_advertising: Autonegotiation advertising flags
  * @link_state: Current state of the link
  * @n_link_state_changes: Number of times the link has changed state
  * @promiscuous: Promiscuous flag. Protected by netif_tx_lock.
@@ -813,6 +814,7 @@ struct efx_nic {
 	enum efx_phy_mode phy_mode;
 
 	bool xmac_poll_required;
+	u32 link_advertising;
 	struct efx_link_state link_state;
 	unsigned int n_link_state_changes;
 
@@ -858,6 +860,7 @@ static inline const char *efx_dev_name(struct efx_nic *efx)
  * @stop_stats: Stop the regular fetching of statistics
  * @push_irq_moderation: Apply interrupt moderation value
  * @push_multicast_hash: Apply multicast hash table
+ * @reconfigure_port: Push loopback/power/txdis changes to the MAC and PHY
  * @default_mac_ops: efx_mac_operations to set at startup
  * @revision: Hardware architecture revision
  * @mem_map_size: Memory BAR mapped size
@@ -892,6 +895,7 @@ struct efx_nic_type {
 	void (*stop_stats)(struct efx_nic *efx);
 	void (*push_irq_moderation)(struct efx_channel *channel);
 	void (*push_multicast_hash)(struct efx_nic *efx);
+	int (*reconfigure_port)(struct efx_nic *efx);
 	struct efx_mac_operations *default_mac_ops;
 
 	int revision;
diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c
index 3d7370e..4c38516 100644
--- a/drivers/net/sfc/qt202x_phy.c
+++ b/drivers/net/sfc/qt202x_phy.c
@@ -178,7 +178,7 @@ static bool qt202x_phy_poll(struct efx_nic *efx)
 	return efx->link_state.up != was_up;
 }
 
-static void qt202x_phy_reconfigure(struct efx_nic *efx)
+static int qt202x_phy_reconfigure(struct efx_nic *efx)
 {
 	struct qt202x_phy_data *phy_data = efx->phy_data;
 
@@ -207,6 +207,8 @@ static void qt202x_phy_reconfigure(struct efx_nic *efx)
 	efx_mdio_phy_reconfigure(efx);
 
 	phy_data->phy_mode = efx->phy_mode;
+
+	return 0;
 }
 
 static void qt202x_phy_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c
index 15d4d9c..dddeb9d 100644
--- a/drivers/net/sfc/selftest.c
+++ b/drivers/net/sfc/selftest.c
@@ -659,7 +659,6 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests,
 	enum efx_loopback_mode loopback_mode = efx->loopback_mode;
 	int phy_mode = efx->phy_mode;
 	enum reset_type reset_method = RESET_TYPE_INVISIBLE;
-	struct ethtool_cmd ecmd;
 	struct efx_channel *channel;
 	int rc_test = 0, rc_reset = 0, rc;
 
@@ -712,7 +711,7 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests,
 	mutex_unlock(&efx->mac_lock);
 
 	/* free up all consumers of SRAM (including all the queues) */
-	efx_reset_down(efx, reset_method, &ecmd);
+	efx_reset_down(efx, reset_method);
 
 	rc = efx_test_chip(efx, tests);
 	if (rc && !rc_test)
@@ -726,7 +725,7 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests,
 	efx->phy_mode &= ~PHY_MODE_LOW_POWER;
 	efx->loopback_mode = LOOPBACK_NONE;
 
-	rc = efx_reset_up(efx, reset_method, &ecmd, rc_reset == 0);
+	rc = efx_reset_up(efx, reset_method, rc_reset == 0);
 	if (rc && !rc_reset)
 		rc_reset = rc;
 
@@ -745,10 +744,12 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests,
 		rc_test = rc;
 
 	/* restore the PHY to the previous state */
-	efx->loopback_mode = loopback_mode;
+	mutex_lock(&efx->mac_lock);
 	efx->phy_mode = phy_mode;
 	efx->port_inhibited = false;
-	efx_ethtool_set_settings(efx->net_dev, &ecmd);
+	efx->loopback_mode = loopback_mode;
+	__efx_reconfigure_port(efx);
+	mutex_unlock(&efx->mac_lock);
 
 	return rc_test;
 }
diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c
index 1bd7965..c301853 100644
--- a/drivers/net/sfc/tenxpress.c
+++ b/drivers/net/sfc/tenxpress.c
@@ -199,15 +199,16 @@ static ssize_t set_phy_short_reach(struct device *dev,
 				   const char *buf, size_t count)
 {
 	struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev));
+	int rc;
 
 	rtnl_lock();
 	efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, MDIO_PMA_10GBT_TXPWR,
 			  MDIO_PMA_10GBT_TXPWR_SHORT,
 			  count != 0 && *buf != '0');
-	efx_reconfigure_port(efx);
+	rc = efx_reconfigure_port(efx);
 	rtnl_unlock();
 
-	return count;
+	return rc < 0 ? rc : (ssize_t)count;
 }
 
 static DEVICE_ATTR(phy_short_reach, 0644, show_phy_short_reach,
@@ -300,7 +301,6 @@ static int tenxpress_init(struct efx_nic *efx)
 static int tenxpress_phy_init(struct efx_nic *efx)
 {
 	struct tenxpress_phy_data *phy_data;
-	u16 old_adv, adv;
 	int rc = 0;
 
 	falcon_board(efx)->type->init_phy(efx);
@@ -335,14 +335,14 @@ static int tenxpress_phy_init(struct efx_nic *efx)
 	if (rc < 0)
 		goto fail;
 
-	/* Set pause advertising */
-	old_adv = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
-	adv = ((old_adv & ~(ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM)) |
-	       mii_advertise_flowctrl(efx->wanted_fc));
-	if (adv != old_adv) {
-		efx_mdio_write(efx, MDIO_MMD_AN, MDIO_AN_ADVERTISE, adv);
-		mdio45_nway_restart(&efx->mdio);
-	}
+	/* Initialise advertising flags */
+	efx->link_advertising = (ADVERTISED_TP | ADVERTISED_Autoneg |
+				  ADVERTISED_10000baseT_Full);
+	if (efx->phy_type != PHY_TYPE_SFX7101)
+		efx->link_advertising |= (ADVERTISED_1000baseT_Full |
+					   ADVERTISED_100baseT_Full);
+	efx_link_set_wanted_fc(efx, efx->wanted_fc);
+	efx_mdio_an_reconfigure(efx);
 
 	if (efx->phy_type == PHY_TYPE_SFT9001B) {
 		rc = device_create_file(&efx->pci_dev->dev,
@@ -500,49 +500,41 @@ static void tenxpress_low_power(struct efx_nic *efx)
 			!!(efx->phy_mode & PHY_MODE_LOW_POWER));
 }
 
-static void tenxpress_phy_reconfigure(struct efx_nic *efx)
+static int tenxpress_phy_reconfigure(struct efx_nic *efx)
 {
 	struct tenxpress_phy_data *phy_data = efx->phy_data;
-	struct ethtool_cmd ecmd;
 	bool phy_mode_change, loop_reset;
 
 	if (efx->phy_mode & (PHY_MODE_OFF | PHY_MODE_SPECIAL)) {
 		phy_data->phy_mode = efx->phy_mode;
-		return;
+		return 0;
 	}
 
-	tenxpress_low_power(efx);
-
 	phy_mode_change = (efx->phy_mode == PHY_MODE_NORMAL &&
 			   phy_data->phy_mode != PHY_MODE_NORMAL);
 	loop_reset = (LOOPBACK_OUT_OF(phy_data, efx, efx->phy_op->loopbacks) ||
 		      LOOPBACK_CHANGED(phy_data, efx, 1 << LOOPBACK_GPHY));
 
 	if (loop_reset || phy_mode_change) {
-		int rc;
-
-		efx->phy_op->get_settings(efx, &ecmd);
+		tenxpress_special_reset(efx);
 
-		if (loop_reset || phy_mode_change) {
-			tenxpress_special_reset(efx);
-
-			/* Reset XAUI if we were in 10G, and are staying
-			 * in 10G. If we're moving into and out of 10G
-			 * then xaui will be reset anyway */
-			if (EFX_IS10G(efx))
-				falcon_reset_xaui(efx);
-		}
-
-		rc = efx->phy_op->set_settings(efx, &ecmd);
-		WARN_ON(rc);
+		/* Reset XAUI if we were in 10G, and are staying
+		 * in 10G. If we're moving into and out of 10G
+		 * then xaui will be reset anyway */
+		if (EFX_IS10G(efx))
+			falcon_reset_xaui(efx);
 	}
 
+	tenxpress_low_power(efx);
 	efx_mdio_transmit_disable(efx);
 	efx_mdio_phy_reconfigure(efx);
 	tenxpress_ext_loopback(efx);
+	efx_mdio_an_reconfigure(efx);
 
 	phy_data->loopback_mode = efx->loopback_mode;
 	phy_data->phy_mode = efx->phy_mode;
+
+	return 0;
 }
 
 static void
@@ -646,6 +638,9 @@ sfx7101_run_tests(struct efx_nic *efx, int *results, unsigned flags)
 	/* BIST is automatically run after a special software reset */
 	rc = tenxpress_special_reset(efx);
 	results[0] = rc ? -1 : 1;
+
+	efx_mdio_an_reconfigure(efx);
+
 	return rc;
 }
 
@@ -663,12 +658,8 @@ static const char *const sft9001_test_names[] = {
 
 static int sft9001_run_tests(struct efx_nic *efx, int *results, unsigned flags)
 {
-	struct ethtool_cmd ecmd;
 	int rc = 0, rc2, i, ctrl_reg, res_reg;
 
-	if (flags & ETH_TEST_FL_OFFLINE)
-		efx->phy_op->get_settings(efx, &ecmd);
-
 	/* Initialise cable diagnostic results to unknown failure */
 	for (i = 1; i < 9; ++i)
 		results[i] = -1;
@@ -720,9 +711,7 @@ out:
 		if (!rc)
 			rc = rc2;
 
-		rc2 = efx->phy_op->set_settings(efx, &ecmd);
-		if (!rc)
-			rc = rc2;
+		efx_mdio_an_reconfigure(efx);
 	}
 
 	return rc;
@@ -753,7 +742,6 @@ tenxpress_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
 
 	mdio45_ethtool_gset_npage(&efx->mdio, ecmd, adv, lpa);
 
-	ecmd->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
 	if (efx->phy_type != PHY_TYPE_SFX7101) {
 		ecmd->supported |= (SUPPORTED_100baseT_Full |
 				    SUPPORTED_1000baseT_Full);

-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.


^ permalink raw reply related

* [PATCH 18/32] sfc: Generalise link state monitoring
From: Ben Hutchings @ 2009-11-28  3:49 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, linux-net-drivers

Use the efx_nic_type::monitor operation or event handling as
appropriate.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 drivers/net/sfc/efx.c      |   16 ++++++++-
 drivers/net/sfc/selftest.c |   79 ++++++++++++++++++++++++++------------------
 2 files changed, 61 insertions(+), 34 deletions(-)

diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index c77338f..d94ec07 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -1174,10 +1174,18 @@ static void efx_start_all(struct efx_nic *efx)
 
 	falcon_enable_interrupts(efx);
 
-	/* Start the hardware monitor (if there is one) if we're in RUNNING */
-	if (efx->state == STATE_RUNNING && efx->type->monitor != NULL)
+	/* Start the hardware monitor if there is one. Otherwise (we're link
+	 * event driven), we have to poll the PHY because after an event queue
+	 * flush, we could have a missed a link state change */
+	if (efx->type->monitor != NULL) {
 		queue_delayed_work(efx->workqueue, &efx->monitor_work,
 				   efx_monitor_interval);
+	} else {
+		mutex_lock(&efx->mac_lock);
+		if (efx->phy_op->poll(efx))
+			efx_link_status_changed(efx);
+		mutex_unlock(&efx->mac_lock);
+	}
 
 	efx->type->start_stats(efx);
 }
@@ -1421,6 +1429,10 @@ static int efx_net_open(struct net_device *net_dev)
 	if (efx->phy_mode & PHY_MODE_SPECIAL)
 		return -EBUSY;
 
+	/* Notify the kernel of the link state polled during driver load,
+	 * before the monitor starts running */
+	efx_link_status_changed(efx);
+
 	efx_start_all(efx);
 	return 0;
 }
diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c
index dddeb9d..f45bf74 100644
--- a/drivers/net/sfc/selftest.c
+++ b/drivers/net/sfc/selftest.c
@@ -563,14 +563,49 @@ efx_test_loopback(struct efx_tx_queue *tx_queue,
 	return 0;
 }
 
+/* Wait for link up. On Falcon, we would prefer to rely on efx_monitor, but
+ * any contention on the mac lock (via e.g. efx_mac_mcast_work) causes it
+ * to delay and retry. Therefore, it's safer to just poll directly. Wait
+ * for link up and any faults to dissipate. */
+static int efx_wait_for_link(struct efx_nic *efx)
+{
+	struct efx_link_state *link_state = &efx->link_state;
+	int count;
+	bool link_up;
+
+	for (count = 0; count < 40; count++) {
+		schedule_timeout_uninterruptible(HZ / 10);
+
+		if (efx->type->monitor != NULL) {
+			mutex_lock(&efx->mac_lock);
+			efx->type->monitor(efx);
+			mutex_unlock(&efx->mac_lock);
+		} else {
+			struct efx_channel *channel = &efx->channel[0];
+			if (channel->work_pending)
+				efx_process_channel_now(channel);
+		}
+
+		mutex_lock(&efx->mac_lock);
+		link_up = link_state->up;
+		if (link_up)
+			link_up = !efx->mac_op->check_fault(efx);
+		mutex_unlock(&efx->mac_lock);
+
+		if (link_up)
+			return 0;
+	}
+
+	return -ETIMEDOUT;
+}
+
 static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests,
 			      unsigned int loopback_modes)
 {
 	enum efx_loopback_mode mode;
 	struct efx_loopback_state *state;
 	struct efx_tx_queue *tx_queue;
-	bool link_up;
-	int count, rc = 0;
+	int rc = 0;
 
 	/* Set the port loopback_selftest member. From this point on
 	 * all received packets will be dropped. Mark the state as
@@ -589,43 +624,23 @@ static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests,
 
 		/* Move the port into the specified loopback mode. */
 		state->flush = true;
+		mutex_lock(&efx->mac_lock);
 		efx->loopback_mode = mode;
-		efx_reconfigure_port(efx);
-
-		/* Wait for the PHY to signal the link is up. Interrupts
-		 * are enabled for PHY's using LASI, otherwise we poll()
-		 * quickly */
-		count = 0;
-		do {
-			struct efx_channel *channel = &efx->channel[0];
-
-			efx->phy_op->poll(efx);
-			schedule_timeout_uninterruptible(HZ / 10);
-			if (channel->work_pending)
-				efx_process_channel_now(channel);
-			/* Wait for PHY events to be processed */
-			flush_workqueue(efx->workqueue);
-			rmb();
-
-			/* We need both the PHY and MAC-PHY links to be OK */
-			link_up = efx->link_state.up;
-			if (link_up)
-				link_up = !efx->mac_op->check_fault(efx);
-
-		} while ((++count < 20) && !link_up);
+		rc = __efx_reconfigure_port(efx);
+		mutex_unlock(&efx->mac_lock);
+		if (rc) {
+			EFX_ERR(efx, "unable to move into %s loopback\n",
+				LOOPBACK_MODE(efx));
+			goto out;
+		}
 
-		/* The link should now be up. If it isn't, there is no point
-		 * in attempting a loopback test */
-		if (!link_up) {
+		rc = efx_wait_for_link(efx);
+		if (rc) {
 			EFX_ERR(efx, "loopback %s never came up\n",
 				LOOPBACK_MODE(efx));
-			rc = -EIO;
 			goto out;
 		}
 
-		EFX_LOG(efx, "link came up in %s loopback in %d iterations\n",
-			LOOPBACK_MODE(efx), count);
-
 		/* Test every TX queue */
 		efx_for_each_tx_queue(tx_queue, efx) {
 			state->offload_csum = (tx_queue->queue ==


-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.


^ permalink raw reply related

* [PATCH 19/32] sfc: Add power-management and wake-on-LAN support
From: Ben Hutchings @ 2009-11-28  3:50 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, linux-net-drivers

Wake-on-LAN is a stub for Falcon, but will be implemented fully for
new NICs.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 drivers/net/sfc/efx.c        |   96 ++++++++++++++++++++++++++++++++++++++++++
 drivers/net/sfc/ethtool.c    |   17 +++++++
 drivers/net/sfc/falcon.c     |   27 ++++++++++++
 drivers/net/sfc/net_driver.h |    6 +++
 4 files changed, 146 insertions(+), 0 deletions(-)

diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index d94ec07..75a2ce3 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -2243,11 +2243,107 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev,
 	return rc;
 }
 
+static int efx_pm_freeze(struct device *dev)
+{
+	struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev));
+
+	efx->state = STATE_FINI;
+
+	netif_device_detach(efx->net_dev);
+
+	efx_stop_all(efx);
+	efx_fini_channels(efx);
+
+	return 0;
+}
+
+static int efx_pm_thaw(struct device *dev)
+{
+	struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev));
+
+	efx->state = STATE_INIT;
+
+	efx_init_channels(efx);
+
+	mutex_lock(&efx->mac_lock);
+	efx->phy_op->reconfigure(efx);
+	mutex_unlock(&efx->mac_lock);
+
+	efx_start_all(efx);
+
+	netif_device_attach(efx->net_dev);
+
+	efx->state = STATE_RUNNING;
+
+	efx->type->resume_wol(efx);
+
+	return 0;
+}
+
+static int efx_pm_poweroff(struct device *dev)
+{
+	struct pci_dev *pci_dev = to_pci_dev(dev);
+	struct efx_nic *efx = pci_get_drvdata(pci_dev);
+
+	efx->type->fini(efx);
+
+	efx->reset_pending = RESET_TYPE_NONE;
+
+	pci_save_state(pci_dev);
+	return pci_set_power_state(pci_dev, PCI_D3hot);
+}
+
+/* Used for both resume and restore */
+static int efx_pm_resume(struct device *dev)
+{
+	struct pci_dev *pci_dev = to_pci_dev(dev);
+	struct efx_nic *efx = pci_get_drvdata(pci_dev);
+	int rc;
+
+	rc = pci_set_power_state(pci_dev, PCI_D0);
+	if (rc)
+		return rc;
+	pci_restore_state(pci_dev);
+	rc = pci_enable_device(pci_dev);
+	if (rc)
+		return rc;
+	pci_set_master(efx->pci_dev);
+	rc = efx->type->reset(efx, RESET_TYPE_ALL);
+	if (rc)
+		return rc;
+	rc = efx->type->init(efx);
+	if (rc)
+		return rc;
+	efx_pm_thaw(dev);
+	return 0;
+}
+
+static int efx_pm_suspend(struct device *dev)
+{
+	int rc;
+
+	efx_pm_freeze(dev);
+	rc = efx_pm_poweroff(dev);
+	if (rc)
+		efx_pm_resume(dev);
+	return rc;
+}
+
+static struct dev_pm_ops efx_pm_ops = {
+	.suspend	= efx_pm_suspend,
+	.resume		= efx_pm_resume,
+	.freeze		= efx_pm_freeze,
+	.thaw		= efx_pm_thaw,
+	.poweroff	= efx_pm_poweroff,
+	.restore	= efx_pm_resume,
+};
+
 static struct pci_driver efx_pci_driver = {
 	.name		= EFX_DRIVER_NAME,
 	.id_table	= efx_pci_table,
 	.probe		= efx_pci_probe,
 	.remove		= efx_pci_remove,
+	.driver.pm	= &efx_pm_ops,
 };
 
 /**************************************************************************
diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c
index 92c5d8d..901bad3 100644
--- a/drivers/net/sfc/ethtool.c
+++ b/drivers/net/sfc/ethtool.c
@@ -752,6 +752,21 @@ static void efx_ethtool_get_pauseparam(struct net_device *net_dev,
 }
 

+static void efx_ethtool_get_wol(struct net_device *net_dev,
+				struct ethtool_wolinfo *wol)
+{
+	struct efx_nic *efx = netdev_priv(net_dev);
+	return efx->type->get_wol(efx, wol);
+}
+
+
+static int efx_ethtool_set_wol(struct net_device *net_dev,
+			       struct ethtool_wolinfo *wol)
+{
+	struct efx_nic *efx = netdev_priv(net_dev);
+	return efx->type->set_wol(efx, wol->wolopts);
+}
+
 const struct ethtool_ops efx_ethtool_ops = {
 	.get_settings		= efx_ethtool_get_settings,
 	.set_settings		= efx_ethtool_set_settings,
@@ -781,4 +796,6 @@ const struct ethtool_ops efx_ethtool_ops = {
 	.get_strings		= efx_ethtool_get_strings,
 	.phys_id		= efx_ethtool_phys_id,
 	.get_ethtool_stats	= efx_ethtool_get_stats,
+	.get_wol                = efx_ethtool_get_wol,
+	.set_wol                = efx_ethtool_set_wol,
 };
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index 85233c8..6b89607 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -3245,6 +3245,27 @@ void falcon_stop_nic_stats(struct efx_nic *efx)
 
 /**************************************************************************
  *
+ * Wake on LAN
+ *
+ **************************************************************************
+ */
+
+static void falcon_get_wol(struct efx_nic *efx, struct ethtool_wolinfo *wol)
+{
+	wol->supported = 0;
+	wol->wolopts = 0;
+	memset(&wol->sopass, 0, sizeof(wol->sopass));
+}
+
+static int falcon_set_wol(struct efx_nic *efx, u32 type)
+{
+	if (type != 0)
+		return -EINVAL;
+	return 0;
+}
+
+/**************************************************************************
+ *
  * Revision-dependent attributes used by efx.c
  *
  **************************************************************************
@@ -3266,6 +3287,9 @@ struct efx_nic_type falcon_a1_nic_type = {
 	.push_irq_moderation = falcon_push_irq_moderation,
 	.push_multicast_hash = falcon_push_multicast_hash,
 	.reconfigure_port = falcon_reconfigure_port,
+	.get_wol = falcon_get_wol,
+	.set_wol = falcon_set_wol,
+	.resume_wol = efx_port_dummy_op_void,
 	.default_mac_ops = &falcon_xmac_operations,
 
 	.revision = EFX_REV_FALCON_A1,
@@ -3300,6 +3324,9 @@ struct efx_nic_type falcon_b0_nic_type = {
 	.push_irq_moderation = falcon_push_irq_moderation,
 	.push_multicast_hash = falcon_push_multicast_hash,
 	.reconfigure_port = falcon_reconfigure_port,
+	.get_wol = falcon_get_wol,
+	.set_wol = falcon_set_wol,
+	.resume_wol = efx_port_dummy_op_void,
 	.default_mac_ops = &falcon_xmac_operations,
 
 	.revision = EFX_REV_FALCON_B0,
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index ecb24b9..9ce5a28 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -861,6 +861,9 @@ static inline const char *efx_dev_name(struct efx_nic *efx)
  * @push_irq_moderation: Apply interrupt moderation value
  * @push_multicast_hash: Apply multicast hash table
  * @reconfigure_port: Push loopback/power/txdis changes to the MAC and PHY
+ * @get_wol: Get WoL configuration from driver state
+ * @set_wol: Push WoL configuration to the NIC
+ * @resume_wol: Synchronise WoL state between driver and MC (e.g. after resume)
  * @default_mac_ops: efx_mac_operations to set at startup
  * @revision: Hardware architecture revision
  * @mem_map_size: Memory BAR mapped size
@@ -896,6 +899,9 @@ struct efx_nic_type {
 	void (*push_irq_moderation)(struct efx_channel *channel);
 	void (*push_multicast_hash)(struct efx_nic *efx);
 	int (*reconfigure_port)(struct efx_nic *efx);
+	void (*get_wol)(struct efx_nic *efx, struct ethtool_wolinfo *wol);
+	int (*set_wol)(struct efx_nic *efx, u32 type);
+	void (*resume_wol)(struct efx_nic *efx);
 	struct efx_mac_operations *default_mac_ops;
 
 	int revision;

-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.


^ permalink raw reply related

* [PATCH 20/32] sfc: Implement ethtool reset operation
From: Ben Hutchings @ 2009-11-28  3:50 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, linux-net-drivers

Refactor efx_reset_down() and efx_reset_up() accordingly.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 drivers/net/sfc/efx.c        |   98 ++++++++++++++++++++---------------------
 drivers/net/sfc/efx.h        |    1 +
 drivers/net/sfc/ethtool.c    |   30 +++++++++++++
 drivers/net/sfc/falcon.c     |    2 +
 drivers/net/sfc/net_driver.h |    3 +
 5 files changed, 84 insertions(+), 50 deletions(-)

diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index 75a2ce3..265033b 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -1754,58 +1754,49 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok)
 	rc = efx->type->init(efx);
 	if (rc) {
 		EFX_ERR(efx, "failed to initialise NIC\n");
-		ok = false;
+		goto fail;
 	}
 
+	if (!ok)
+		goto fail;
+
 	if (efx->port_initialized && method != RESET_TYPE_INVISIBLE) {
-		if (ok) {
-			rc = efx->phy_op->init(efx);
-			if (rc)
-				ok = false;
-			if (efx->phy_op->reconfigure(efx))
-				EFX_ERR(efx, "could not restore PHY settings\n");
-		}
-		if (!ok)
-			efx->port_initialized = false;
+		rc = efx->phy_op->init(efx);
+		if (rc)
+			goto fail;
+		if (efx->phy_op->reconfigure(efx))
+			EFX_ERR(efx, "could not restore PHY settings\n");
 	}
 
-	if (ok) {
-		efx->mac_op->reconfigure(efx);
+	efx->mac_op->reconfigure(efx);
 
-		efx_init_channels(efx);
-	}
+	efx_init_channels(efx);
+
+	mutex_unlock(&efx->spi_lock);
+	mutex_unlock(&efx->mac_lock);
+
+	efx_start_all(efx);
+
+	return 0;
+
+fail:
+	efx->port_initialized = false;
 
 	mutex_unlock(&efx->spi_lock);
 	mutex_unlock(&efx->mac_lock);
 
-	if (ok)
-		efx_start_all(efx);
 	return rc;
 }
 
-/* Reset the NIC as transparently as possible. Do not reset the PHY
- * Note that the reset may fail, in which case the card will be left
- * in a most-probably-unusable state.
- *
- * This function will sleep.  You cannot reset from within an atomic
- * state; use efx_schedule_reset() instead.
+/* Reset the NIC using the specified method.  Note that the reset may
+ * fail, in which case the card will be left in an unusable state.
  *
- * Grabs the rtnl_lock.
+ * Caller must hold the rtnl_lock.
  */
-static int efx_reset(struct efx_nic *efx)
+int efx_reset(struct efx_nic *efx, enum reset_type method)
 {
-	enum reset_type method = efx->reset_pending;
-	int rc = 0;
-
-	/* Serialise with kernel interfaces */
-	rtnl_lock();
-
-	/* If we're not RUNNING then don't reset. Leave the reset_pending
-	 * flag set so that efx_pci_probe_main will be retried */
-	if (efx->state != STATE_RUNNING) {
-		EFX_INFO(efx, "scheduled reset quenched. NIC not RUNNING\n");
-		goto out_unlock;
-	}
+	int rc, rc2;
+	bool disabled;
 
 	EFX_INFO(efx, "resetting (%s)\n", RESET_TYPE(method));
 
@@ -1814,7 +1805,7 @@ static int efx_reset(struct efx_nic *efx)
 	rc = efx->type->reset(efx, method);
 	if (rc) {
 		EFX_ERR(efx, "failed to reset hardware\n");
-		goto out_disable;
+		goto out;
 	}
 
 	/* Allow resets to be rescheduled. */
@@ -1826,25 +1817,22 @@ static int efx_reset(struct efx_nic *efx)
 	 * can respond to requests. */
 	pci_set_master(efx->pci_dev);
 
+out:
 	/* Leave device stopped if necessary */
-	if (method == RESET_TYPE_DISABLE) {
-		efx_reset_up(efx, method, false);
-		rc = -EIO;
-	} else {
-		rc = efx_reset_up(efx, method, true);
+	disabled = rc || method == RESET_TYPE_DISABLE;
+	rc2 = efx_reset_up(efx, method, !disabled);
+	if (rc2) {
+		disabled = true;
+		if (!rc)
+			rc = rc2;
 	}
 
-out_disable:
-	if (rc) {
+	if (disabled) {
 		EFX_ERR(efx, "has been disabled\n");
 		efx->state = STATE_DISABLED;
-		dev_close(efx->net_dev);
 	} else {
 		EFX_LOG(efx, "reset complete\n");
 	}
-
-out_unlock:
-	rtnl_unlock();
 	return rc;
 }
 
@@ -1853,9 +1841,19 @@ out_unlock:
  */
 static void efx_reset_work(struct work_struct *data)
 {
-	struct efx_nic *nic = container_of(data, struct efx_nic, reset_work);
+	struct efx_nic *efx = container_of(data, struct efx_nic, reset_work);
 
-	efx_reset(nic);
+	/* If we're not RUNNING then don't reset. Leave the reset_pending
+	 * flag set so that efx_pci_probe_main will be retried */
+	if (efx->state != STATE_RUNNING) {
+		EFX_INFO(efx, "scheduled reset quenched. NIC not RUNNING\n");
+		return;
+	}
+
+	rtnl_lock();
+	if (efx_reset(efx, efx->reset_pending))
+		dev_close(efx->net_dev);
+	rtnl_unlock();
 }
 
 void efx_schedule_reset(struct efx_nic *efx, enum reset_type type)
diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h
index c785003..fa40c7b 100644
--- a/drivers/net/sfc/efx.h
+++ b/drivers/net/sfc/efx.h
@@ -71,6 +71,7 @@ extern int efx_ethtool_set_settings(struct net_device *net_dev,
 extern const struct ethtool_ops efx_ethtool_ops;
 
 /* Reset handling */
+extern int efx_reset(struct efx_nic *efx, enum reset_type method);
 extern void efx_reset_down(struct efx_nic *efx, enum reset_type method);
 extern int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok);
 
diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c
index 901bad3..0a2b6a4 100644
--- a/drivers/net/sfc/ethtool.c
+++ b/drivers/net/sfc/ethtool.c
@@ -767,6 +767,35 @@ static int efx_ethtool_set_wol(struct net_device *net_dev,
 	return efx->type->set_wol(efx, wol->wolopts);
 }
 
+extern int efx_ethtool_reset(struct net_device *net_dev, u32 *flags)
+{
+	struct efx_nic *efx = netdev_priv(net_dev);
+	enum reset_type method;
+	enum {
+		ETH_RESET_EFX_INVISIBLE = (ETH_RESET_DMA | ETH_RESET_FILTER |
+					   ETH_RESET_OFFLOAD | ETH_RESET_MAC)
+	};
+
+	/* Check for minimal reset flags */
+	if ((*flags & ETH_RESET_EFX_INVISIBLE) != ETH_RESET_EFX_INVISIBLE)
+		return -EINVAL;
+	*flags ^= ETH_RESET_EFX_INVISIBLE;
+	method = RESET_TYPE_INVISIBLE;
+
+	if (*flags & ETH_RESET_PHY) {
+		*flags ^= ETH_RESET_PHY;
+		method = RESET_TYPE_ALL;
+	}
+
+	if ((*flags & efx->type->reset_world_flags) ==
+	    efx->type->reset_world_flags) {
+		*flags ^= efx->type->reset_world_flags;
+		method = RESET_TYPE_WORLD;
+	}
+
+	return efx_reset(efx, method);
+}
+
 const struct ethtool_ops efx_ethtool_ops = {
 	.get_settings		= efx_ethtool_get_settings,
 	.set_settings		= efx_ethtool_set_settings,
@@ -798,4 +827,5 @@ const struct ethtool_ops efx_ethtool_ops = {
 	.get_ethtool_stats	= efx_ethtool_get_stats,
 	.get_wol                = efx_ethtool_get_wol,
 	.set_wol                = efx_ethtool_set_wol,
+	.reset			= efx_ethtool_reset,
 };
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index 6b89607..67ad54d 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -3306,6 +3306,7 @@ struct efx_nic_type falcon_a1_nic_type = {
 	.tx_dc_base = 0x130000,
 	.rx_dc_base = 0x100000,
 	.offload_features = NETIF_F_IP_CSUM,
+	.reset_world_flags = ETH_RESET_IRQ,
 };
 
 struct efx_nic_type falcon_b0_nic_type = {
@@ -3350,5 +3351,6 @@ struct efx_nic_type falcon_b0_nic_type = {
 	.tx_dc_base = 0x130000,
 	.rx_dc_base = 0x100000,
 	.offload_features = NETIF_F_IP_CSUM,
+	.reset_world_flags = ETH_RESET_IRQ,
 };
 
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index 9ce5a28..ee2b445 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -882,6 +882,8 @@ static inline const char *efx_dev_name(struct efx_nic *efx)
  * @rx_dc_base: Base address in SRAM of RX queue descriptor caches
  * @offload_features: net_device feature flags for protocol offload
  *	features implemented in hardware
+ * @reset_world_flags: Flags for additional components covered by
+ *	reset method RESET_TYPE_WORLD
  */
 struct efx_nic_type {
 	int (*probe)(struct efx_nic *efx);
@@ -918,6 +920,7 @@ struct efx_nic_type {
 	unsigned int tx_dc_base;
 	unsigned int rx_dc_base;
 	unsigned long offload_features;
+	u32 reset_world_flags;
 };
 
 /**************************************************************************

-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.


^ permalink raw reply related

* [PATCH 21/32] sfc: Add efx_nic_type operation for register self-test
From: Ben Hutchings @ 2009-11-28  3:50 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, linux-net-drivers

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 drivers/net/sfc/falcon.c     |    3 ++-
 drivers/net/sfc/falcon.h     |    1 -
 drivers/net/sfc/net_driver.h |    2 ++
 drivers/net/sfc/selftest.c   |   12 ++++++------
 4 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index 67ad54d..f0541d4 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -2458,7 +2458,7 @@ static bool efx_masked_compare_oword(const efx_oword_t *a, const efx_oword_t *b,
 		((a->u64[1] ^ b->u64[1]) & mask->u64[1]);
 }
 
-int falcon_test_registers(struct efx_nic *efx)
+static int falcon_b0_test_registers(struct efx_nic *efx)
 {
 	unsigned address = 0, i, j;
 	efx_oword_t mask, imask, original, reg, buf;
@@ -3328,6 +3328,7 @@ struct efx_nic_type falcon_b0_nic_type = {
 	.get_wol = falcon_get_wol,
 	.set_wol = falcon_set_wol,
 	.resume_wol = efx_port_dummy_op_void,
+	.test_registers = falcon_b0_test_registers,
 	.default_mac_ops = &falcon_xmac_operations,
 
 	.revision = EFX_REV_FALCON_B0,
diff --git a/drivers/net/sfc/falcon.h b/drivers/net/sfc/falcon.h
index 560a3f9..cfcc2a3 100644
--- a/drivers/net/sfc/falcon.h
+++ b/drivers/net/sfc/falcon.h
@@ -154,7 +154,6 @@ extern int falcon_reset_xaui(struct efx_nic *efx);
 struct falcon_nvconfig;
 extern int falcon_read_nvram(struct efx_nic *efx,
 			     struct falcon_nvconfig *nvconfig);
-extern int falcon_test_registers(struct efx_nic *efx);
 
 /**************************************************************************
  *
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index ee2b445..c465610 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -864,6 +864,7 @@ static inline const char *efx_dev_name(struct efx_nic *efx)
  * @get_wol: Get WoL configuration from driver state
  * @set_wol: Push WoL configuration to the NIC
  * @resume_wol: Synchronise WoL state between driver and MC (e.g. after resume)
+ * @test_registers: Test read/write functionality of control registers
  * @default_mac_ops: efx_mac_operations to set at startup
  * @revision: Hardware architecture revision
  * @mem_map_size: Memory BAR mapped size
@@ -904,6 +905,7 @@ struct efx_nic_type {
 	void (*get_wol)(struct efx_nic *efx, struct ethtool_wolinfo *wol);
 	int (*set_wol)(struct efx_nic *efx, u32 type);
 	void (*resume_wol)(struct efx_nic *efx);
+	int (*test_registers)(struct efx_nic *efx);
 	struct efx_mac_operations *default_mac_ops;
 
 	int revision;
diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c
index f45bf74..f303552 100644
--- a/drivers/net/sfc/selftest.c
+++ b/drivers/net/sfc/selftest.c
@@ -122,14 +122,14 @@ static int efx_test_nvram(struct efx_nic *efx, struct efx_self_tests *tests)
 
 static int efx_test_chip(struct efx_nic *efx, struct efx_self_tests *tests)
 {
-	int rc;
+	int rc = 0;
 
-	/* Not supported on A-series silicon */
-	if (efx_nic_rev(efx) < EFX_REV_FALCON_B0)
-		return 0;
+	/* Test register access */
+	if (efx->type->test_registers) {
+		rc = efx->type->test_registers(efx);
+		tests->registers = rc ? -1 : 1;
+	}
 
-	rc = falcon_test_registers(efx);
-	tests->registers = rc ? -1 : 1;
 	return rc;
 }
 

-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.


^ permalink raw reply related

* [PATCH 22/32] sfc: Add efx_nic_type operation for NVRAM self-test
From: Ben Hutchings @ 2009-11-28  3:50 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, linux-net-drivers

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 drivers/net/sfc/falcon.c     |   10 +++++++++-
 drivers/net/sfc/falcon.h     |    3 ---
 drivers/net/sfc/net_driver.h |    2 ++
 drivers/net/sfc/selftest.c   |    9 ++++++---
 4 files changed, 17 insertions(+), 7 deletions(-)

diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index f0541d4..c689206 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -2345,7 +2345,8 @@ static void falcon_remove_port(struct efx_nic *efx)
  *
  **************************************************************************/
 
-int falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out)
+static int
+falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out)
 {
 	struct falcon_nvconfig *nvconfig;
 	struct efx_spi_device *spi;
@@ -2408,6 +2409,11 @@ int falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out)
 	return rc;
 }
 
+static int falcon_test_nvram(struct efx_nic *efx)
+{
+	return falcon_read_nvram(efx, NULL);
+}
+
 /* Registers tested in the falcon register test */
 static struct {
 	unsigned address;
@@ -3290,6 +3296,7 @@ struct efx_nic_type falcon_a1_nic_type = {
 	.get_wol = falcon_get_wol,
 	.set_wol = falcon_set_wol,
 	.resume_wol = efx_port_dummy_op_void,
+	.test_nvram = falcon_test_nvram,
 	.default_mac_ops = &falcon_xmac_operations,
 
 	.revision = EFX_REV_FALCON_A1,
@@ -3329,6 +3336,7 @@ struct efx_nic_type falcon_b0_nic_type = {
 	.set_wol = falcon_set_wol,
 	.resume_wol = efx_port_dummy_op_void,
 	.test_registers = falcon_b0_test_registers,
+	.test_nvram = falcon_test_nvram,
 	.default_mac_ops = &falcon_xmac_operations,
 
 	.revision = EFX_REV_FALCON_B0,
diff --git a/drivers/net/sfc/falcon.h b/drivers/net/sfc/falcon.h
index cfcc2a3..464c274 100644
--- a/drivers/net/sfc/falcon.h
+++ b/drivers/net/sfc/falcon.h
@@ -151,9 +151,6 @@ extern void falcon_stop_nic_stats(struct efx_nic *efx);
 extern int falcon_reset_xaui(struct efx_nic *efx);
 
 /* Tests */
-struct falcon_nvconfig;
-extern int falcon_read_nvram(struct efx_nic *efx,
-			     struct falcon_nvconfig *nvconfig);
 
 /**************************************************************************
  *
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index c465610..e75235b 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -865,6 +865,7 @@ static inline const char *efx_dev_name(struct efx_nic *efx)
  * @set_wol: Push WoL configuration to the NIC
  * @resume_wol: Synchronise WoL state between driver and MC (e.g. after resume)
  * @test_registers: Test read/write functionality of control registers
+ * @test_nvram: Test validity of NVRAM contents
  * @default_mac_ops: efx_mac_operations to set at startup
  * @revision: Hardware architecture revision
  * @mem_map_size: Memory BAR mapped size
@@ -906,6 +907,7 @@ struct efx_nic_type {
 	int (*set_wol)(struct efx_nic *efx, u32 type);
 	void (*resume_wol)(struct efx_nic *efx);
 	int (*test_registers)(struct efx_nic *efx);
+	int (*test_nvram)(struct efx_nic *efx);
 	struct efx_mac_operations *default_mac_ops;
 
 	int revision;
diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c
index f303552..fa56e2e 100644
--- a/drivers/net/sfc/selftest.c
+++ b/drivers/net/sfc/selftest.c
@@ -113,10 +113,13 @@ out:
 
 static int efx_test_nvram(struct efx_nic *efx, struct efx_self_tests *tests)
 {
-	int rc;
+	int rc = 0;
+
+	if (efx->type->test_nvram) {
+		rc = efx->type->test_nvram(efx);
+		tests->nvram = rc ? -1 : 1;
+	}
 
-	rc = falcon_read_nvram(efx, NULL);
-	tests->nvram = rc ? -1 : 1;
 	return rc;
 }
 

-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.


^ permalink raw reply related

* [PATCH 23/32] sfc: Add efx_nic_type operation for identity LED control
From: Ben Hutchings @ 2009-11-28  3:50 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, linux-net-drivers

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 drivers/net/sfc/ethtool.c    |    6 +++---
 drivers/net/sfc/falcon.c     |    7 +++++++
 drivers/net/sfc/net_driver.h |    2 ++
 3 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c
index 0a2b6a4..4f5fda5 100644
--- a/drivers/net/sfc/ethtool.c
+++ b/drivers/net/sfc/ethtool.c
@@ -174,14 +174,14 @@ static int efx_ethtool_phys_id(struct net_device *net_dev, u32 count)
 	struct efx_nic *efx = netdev_priv(net_dev);
 
 	do {
-		falcon_board(efx)->type->set_id_led(efx, EFX_LED_ON);
+		efx->type->set_id_led(efx, EFX_LED_ON);
 		schedule_timeout_interruptible(HZ / 2);
 
-		falcon_board(efx)->type->set_id_led(efx, EFX_LED_OFF);
+		efx->type->set_id_led(efx, EFX_LED_OFF);
 		schedule_timeout_interruptible(HZ / 2);
 	} while (!signal_pending(current) && --count != 0);
 
-	falcon_board(efx)->type->set_id_led(efx, EFX_LED_DEFAULT);
+	efx->type->set_id_led(efx, EFX_LED_DEFAULT);
 	return 0;
 }
 
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index c689206..544f777 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -3249,6 +3249,11 @@ void falcon_stop_nic_stats(struct efx_nic *efx)
 	spin_unlock_bh(&efx->stats_lock);
 }
 
+static void falcon_set_id_led(struct efx_nic *efx, enum efx_led_mode mode)
+{
+	falcon_board(efx)->type->set_id_led(efx, mode);
+}
+
 /**************************************************************************
  *
  * Wake on LAN
@@ -3290,6 +3295,7 @@ struct efx_nic_type falcon_a1_nic_type = {
 	.update_stats = falcon_update_nic_stats,
 	.start_stats = falcon_start_nic_stats,
 	.stop_stats = falcon_stop_nic_stats,
+	.set_id_led = falcon_set_id_led,
 	.push_irq_moderation = falcon_push_irq_moderation,
 	.push_multicast_hash = falcon_push_multicast_hash,
 	.reconfigure_port = falcon_reconfigure_port,
@@ -3329,6 +3335,7 @@ struct efx_nic_type falcon_b0_nic_type = {
 	.update_stats = falcon_update_nic_stats,
 	.start_stats = falcon_start_nic_stats,
 	.stop_stats = falcon_stop_nic_stats,
+	.set_id_led = falcon_set_id_led,
 	.push_irq_moderation = falcon_push_irq_moderation,
 	.push_multicast_hash = falcon_push_multicast_hash,
 	.reconfigure_port = falcon_reconfigure_port,
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index e75235b..16db934 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -858,6 +858,7 @@ static inline const char *efx_dev_name(struct efx_nic *efx)
  * @update_stats: Update statistics not provided by event handling
  * @start_stats: Start the regular fetching of statistics
  * @stop_stats: Stop the regular fetching of statistics
+ * @set_id_led: Set state of identifying LED or revert to automatic function
  * @push_irq_moderation: Apply interrupt moderation value
  * @push_multicast_hash: Apply multicast hash table
  * @reconfigure_port: Push loopback/power/txdis changes to the MAC and PHY
@@ -900,6 +901,7 @@ struct efx_nic_type {
 	void (*update_stats)(struct efx_nic *efx);
 	void (*start_stats)(struct efx_nic *efx);
 	void (*stop_stats)(struct efx_nic *efx);
+	void (*set_id_led)(struct efx_nic *efx, enum efx_led_mode mode);
 	void (*push_irq_moderation)(struct efx_channel *channel);
 	void (*push_multicast_hash)(struct efx_nic *efx);
 	int (*reconfigure_port)(struct efx_nic *efx);

-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.


^ permalink raw reply related

* [PATCH 24/32] sfc: Separate shared NIC code from Falcon-specific and rename accordingly
From: Ben Hutchings @ 2009-11-28  3:51 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, linux-net-drivers

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 drivers/net/sfc/efx.c      |   30 ++--
 drivers/net/sfc/ethtool.c  |    4 +-
 drivers/net/sfc/falcon.c   |  507 ++++++++++++++++++++++---------------------
 drivers/net/sfc/falcon.h   |   80 +++++---
 drivers/net/sfc/rx.c       |   10 +-
 drivers/net/sfc/selftest.c |    4 +-
 drivers/net/sfc/tx.c       |   12 +-
 7 files changed, 341 insertions(+), 306 deletions(-)

diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index 265033b..3477408 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -213,7 +213,7 @@ static int efx_process_channel(struct efx_channel *channel, int rx_quota)
 		     !channel->enabled))
 		return 0;
 
-	rx_packets = falcon_process_eventq(channel, rx_quota);
+	rx_packets = efx_nic_process_eventq(channel, rx_quota);
 	if (rx_packets == 0)
 		return 0;
 
@@ -245,7 +245,7 @@ static inline void efx_channel_processed(struct efx_channel *channel)
 	channel->work_pending = false;
 	smp_wmb();
 
-	falcon_eventq_read_ack(channel);
+	efx_nic_eventq_read_ack(channel);
 }
 
 /* NAPI poll handler
@@ -316,7 +316,7 @@ void efx_process_channel_now(struct efx_channel *channel)
 	BUG_ON(!channel->enabled);
 
 	/* Disable interrupts and wait for ISRs to complete */
-	falcon_disable_interrupts(efx);
+	efx_nic_disable_interrupts(efx);
 	if (efx->legacy_irq)
 		synchronize_irq(efx->legacy_irq);
 	if (channel->irq)
@@ -333,7 +333,7 @@ void efx_process_channel_now(struct efx_channel *channel)
 	efx_channel_processed(channel);
 
 	napi_enable(&channel->napi_str);
-	falcon_enable_interrupts(efx);
+	efx_nic_enable_interrupts(efx);
 }
 
 /* Create event queue
@@ -345,7 +345,7 @@ static int efx_probe_eventq(struct efx_channel *channel)
 {
 	EFX_LOG(channel->efx, "chan %d create event queue\n", channel->channel);
 
-	return falcon_probe_eventq(channel);
+	return efx_nic_probe_eventq(channel);
 }
 
 /* Prepare channel's event queue */
@@ -355,21 +355,21 @@ static void efx_init_eventq(struct efx_channel *channel)
 
 	channel->eventq_read_ptr = 0;
 
-	falcon_init_eventq(channel);
+	efx_nic_init_eventq(channel);
 }
 
 static void efx_fini_eventq(struct efx_channel *channel)
 {
 	EFX_LOG(channel->efx, "chan %d fini event queue\n", channel->channel);
 
-	falcon_fini_eventq(channel);
+	efx_nic_fini_eventq(channel);
 }
 
 static void efx_remove_eventq(struct efx_channel *channel)
 {
 	EFX_LOG(channel->efx, "chan %d remove event queue\n", channel->channel);
 
-	falcon_remove_eventq(channel);
+	efx_nic_remove_eventq(channel);
 }
 
 /**************************************************************************
@@ -535,7 +535,7 @@ static void efx_fini_channels(struct efx_nic *efx)
 	EFX_ASSERT_RESET_SERIALISED(efx);
 	BUG_ON(efx->port_enabled);
 
-	rc = falcon_flush_queues(efx);
+	rc = efx_nic_flush_queues(efx);
 	if (rc)
 		EFX_ERR(efx, "failed to flush queues\n");
 	else
@@ -1172,7 +1172,7 @@ static void efx_start_all(struct efx_nic *efx)
 	efx_for_each_channel(channel, efx)
 		efx_start_channel(channel);
 
-	falcon_enable_interrupts(efx);
+	efx_nic_enable_interrupts(efx);
 
 	/* Start the hardware monitor if there is one. Otherwise (we're link
 	 * event driven), we have to poll the PHY because after an event queue
@@ -1226,7 +1226,7 @@ static void efx_stop_all(struct efx_nic *efx)
 	efx->type->stop_stats(efx);
 
 	/* Disable interrupts and wait for ISR to complete */
-	falcon_disable_interrupts(efx);
+	efx_nic_disable_interrupts(efx);
 	if (efx->legacy_irq)
 		synchronize_irq(efx->legacy_irq);
 	efx_for_each_channel(channel, efx) {
@@ -1286,8 +1286,8 @@ void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs, int rx_usecs,
 {
 	struct efx_tx_queue *tx_queue;
 	struct efx_rx_queue *rx_queue;
-	unsigned tx_ticks = irq_mod_ticks(tx_usecs, FALCON_IRQ_MOD_RESOLUTION);
-	unsigned rx_ticks = irq_mod_ticks(rx_usecs, FALCON_IRQ_MOD_RESOLUTION);
+	unsigned tx_ticks = irq_mod_ticks(tx_usecs, EFX_IRQ_MOD_RESOLUTION);
+	unsigned rx_ticks = irq_mod_ticks(rx_usecs, EFX_IRQ_MOD_RESOLUTION);
 
 	EFX_ASSERT_RESET_SERIALISED(efx);
 
@@ -2042,7 +2042,7 @@ static void efx_fini_struct(struct efx_nic *efx)
  */
 static void efx_pci_remove_main(struct efx_nic *efx)
 {
-	falcon_fini_interrupt(efx);
+	efx_nic_fini_interrupt(efx);
 	efx_fini_channels(efx);
 	efx_fini_port(efx);
 	efx->type->fini(efx);
@@ -2119,7 +2119,7 @@ static int efx_pci_probe_main(struct efx_nic *efx)
 
 	efx_init_channels(efx);
 
-	rc = falcon_init_interrupt(efx);
+	rc = efx_nic_init_interrupt(efx);
 	if (rc)
 		goto fail5;
 
diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c
index 4f5fda5..643ce49 100644
--- a/drivers/net/sfc/ethtool.c
+++ b/drivers/net/sfc/ethtool.c
@@ -624,8 +624,8 @@ static int efx_ethtool_get_coalesce(struct net_device *net_dev,
 	coalesce->use_adaptive_rx_coalesce = efx->irq_rx_adaptive;
 	coalesce->rx_coalesce_usecs_irq = efx->irq_rx_moderation;
 
-	coalesce->tx_coalesce_usecs_irq *= FALCON_IRQ_MOD_RESOLUTION;
-	coalesce->rx_coalesce_usecs_irq *= FALCON_IRQ_MOD_RESOLUTION;
+	coalesce->tx_coalesce_usecs_irq *= EFX_IRQ_MOD_RESOLUTION;
+	coalesce->rx_coalesce_usecs_irq *= EFX_IRQ_MOD_RESOLUTION;
 
 	return 0;
 }
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index 544f777..9eb3bfb 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -69,8 +69,8 @@ default_flash_type = ((17 << SPI_DEV_TYPE_SIZE_LBN)
  * watermark send XOFF. Only used if RX flow control is enabled (ethtool -A)
  * This also has an effect on RX/TX arbitration
  */
-static int rx_xoff_thresh_bytes = -1;
-module_param(rx_xoff_thresh_bytes, int, 0644);
+int efx_nic_rx_xoff_thresh = -1;
+module_param_named(rx_xoff_thresh_bytes, efx_nic_rx_xoff_thresh, int, 0644);
 MODULE_PARM_DESC(rx_xoff_thresh_bytes, "RX fifo XOFF threshold");
 
 /* RX FIFO XON watermark
@@ -79,21 +79,21 @@ MODULE_PARM_DESC(rx_xoff_thresh_bytes, "RX fifo XOFF threshold");
  * watermark send XON. Only used if TX flow control is enabled (ethtool -A)
  * This also has an effect on RX/TX arbitration
  */
-static int rx_xon_thresh_bytes = -1;
-module_param(rx_xon_thresh_bytes, int, 0644);
+int efx_nic_rx_xon_thresh = -1;
+module_param_named(rx_xon_thresh_bytes, efx_nic_rx_xon_thresh, int, 0644);
 MODULE_PARM_DESC(rx_xon_thresh_bytes, "RX fifo XON threshold");
 
-/* If FALCON_MAX_INT_ERRORS internal errors occur within
- * FALCON_INT_ERROR_EXPIRE seconds, we consider the NIC broken and
+/* If EFX_MAX_INT_ERRORS internal errors occur within
+ * EFX_INT_ERROR_EXPIRE seconds, we consider the NIC broken and
  * disable it.
  */
-#define FALCON_INT_ERROR_EXPIRE 3600
-#define FALCON_MAX_INT_ERRORS 5
+#define EFX_INT_ERROR_EXPIRE 3600
+#define EFX_MAX_INT_ERRORS 5
 
 /* We poll for events every FLUSH_INTERVAL ms, and check FLUSH_POLL_COUNT times
  */
-#define FALCON_FLUSH_INTERVAL 10
-#define FALCON_FLUSH_POLL_COUNT 100
+#define EFX_FLUSH_INTERVAL 10
+#define EFX_FLUSH_POLL_COUNT 100
 
 /**************************************************************************
  *
@@ -103,30 +103,27 @@ MODULE_PARM_DESC(rx_xon_thresh_bytes, "RX fifo XON threshold");
  */
 
 /* Size and alignment of special buffers (4KB) */
-#define FALCON_BUF_SIZE 4096
+#define EFX_BUF_SIZE 4096
 
 /* Depth of RX flush request fifo */
-#define FALCON_RX_FLUSH_COUNT 4
-
-#define FALCON_IS_DUAL_FUNC(efx)		\
-	(efx_nic_rev(efx) < EFX_REV_FALCON_B0)
+#define EFX_RX_FLUSH_COUNT 4
 
 /**************************************************************************
  *
- * Falcon hardware access
+ * Solarstorm hardware access
  *
  **************************************************************************/
 
-static inline void falcon_write_buf_tbl(struct efx_nic *efx, efx_qword_t *value,
-					unsigned int index)
+static inline void efx_write_buf_tbl(struct efx_nic *efx, efx_qword_t *value,
+				     unsigned int index)
 {
 	efx_sram_writeq(efx, efx->membase + efx->type->buf_tbl_base,
 			value, index);
 }
 
 /* Read the current event from the event queue */
-static inline efx_qword_t *falcon_event(struct efx_channel *channel,
-					unsigned int index)
+static inline efx_qword_t *efx_event(struct efx_channel *channel,
+				     unsigned int index)
 {
 	return (((efx_qword_t *) (channel->eventq.addr)) + index);
 }
@@ -141,7 +138,7 @@ static inline efx_qword_t *falcon_event(struct efx_channel *channel,
  * Note that using a single 64-bit comparison is incorrect; even
  * though the CPU read will be atomic, the DMA write may not be.
  */
-static inline int falcon_event_present(efx_qword_t *event)
+static inline int efx_event_present(efx_qword_t *event)
 {
 	return (!(EFX_DWORD_IS_ALL_ONES(event->dword[0]) |
 		  EFX_DWORD_IS_ALL_ONES(event->dword[1])));
@@ -205,22 +202,21 @@ static struct i2c_algo_bit_data falcon_i2c_bit_operations = {
 
 /**************************************************************************
  *
- * Falcon special buffer handling
+ * Special buffer handling
  * Special buffers are used for event queues and the TX and RX
  * descriptor rings.
  *
  *************************************************************************/
 
 /*
- * Initialise a Falcon special buffer
+ * Initialise a special buffer
  *
  * This will define a buffer (previously allocated via
- * falcon_alloc_special_buffer()) in Falcon's buffer table, allowing
+ * efx_alloc_special_buffer()) in the buffer table, allowing
  * it to be used for event queues, descriptor rings etc.
  */
 static void
-falcon_init_special_buffer(struct efx_nic *efx,
-			   struct efx_special_buffer *buffer)
+efx_init_special_buffer(struct efx_nic *efx, struct efx_special_buffer *buffer)
 {
 	efx_qword_t buf_desc;
 	int index;
@@ -239,14 +235,13 @@ falcon_init_special_buffer(struct efx_nic *efx,
 				     FRF_AZ_BUF_ADR_REGION, 0,
 				     FRF_AZ_BUF_ADR_FBUF, dma_addr >> 12,
 				     FRF_AZ_BUF_OWNER_ID_FBUF, 0);
-		falcon_write_buf_tbl(efx, &buf_desc, index);
+		efx_write_buf_tbl(efx, &buf_desc, index);
 	}
 }
 
-/* Unmaps a buffer from Falcon and clears the buffer table entries */
+/* Unmaps a buffer and clears the buffer table entries */
 static void
-falcon_fini_special_buffer(struct efx_nic *efx,
-			   struct efx_special_buffer *buffer)
+efx_fini_special_buffer(struct efx_nic *efx, struct efx_special_buffer *buffer)
 {
 	efx_oword_t buf_tbl_upd;
 	unsigned int start = buffer->index;
@@ -267,27 +262,27 @@ falcon_fini_special_buffer(struct efx_nic *efx,
 }
 
 /*
- * Allocate a new Falcon special buffer
+ * Allocate a new special buffer
  *
  * This allocates memory for a new buffer, clears it and allocates a
- * new buffer ID range.  It does not write into Falcon's buffer table.
+ * new buffer ID range.  It does not write into the buffer table.
  *
- * This call will allocate 4KB buffers, since Falcon can't use 8KB
- * buffers for event queues and descriptor rings.
+ * This call will allocate 4KB buffers, since 8KB buffers can't be
+ * used for event queues and descriptor rings.
  */
-static int falcon_alloc_special_buffer(struct efx_nic *efx,
-				       struct efx_special_buffer *buffer,
-				       unsigned int len)
+static int efx_alloc_special_buffer(struct efx_nic *efx,
+				    struct efx_special_buffer *buffer,
+				    unsigned int len)
 {
-	len = ALIGN(len, FALCON_BUF_SIZE);
+	len = ALIGN(len, EFX_BUF_SIZE);
 
 	buffer->addr = pci_alloc_consistent(efx->pci_dev, len,
 					    &buffer->dma_addr);
 	if (!buffer->addr)
 		return -ENOMEM;
 	buffer->len = len;
-	buffer->entries = len / FALCON_BUF_SIZE;
-	BUG_ON(buffer->dma_addr & (FALCON_BUF_SIZE - 1));
+	buffer->entries = len / EFX_BUF_SIZE;
+	BUG_ON(buffer->dma_addr & (EFX_BUF_SIZE - 1));
 
 	/* All zeros is a potentially valid event so memset to 0xff */
 	memset(buffer->addr, 0xff, len);
@@ -305,8 +300,8 @@ static int falcon_alloc_special_buffer(struct efx_nic *efx,
 	return 0;
 }
 
-static void falcon_free_special_buffer(struct efx_nic *efx,
-				       struct efx_special_buffer *buffer)
+static void
+efx_free_special_buffer(struct efx_nic *efx, struct efx_special_buffer *buffer)
 {
 	if (!buffer->addr)
 		return;
@@ -325,13 +320,13 @@ static void falcon_free_special_buffer(struct efx_nic *efx,
 
 /**************************************************************************
  *
- * Falcon generic buffer handling
+ * Generic buffer handling
  * These buffers are used for interrupt status and MAC stats
  *
  **************************************************************************/
 
-static int falcon_alloc_buffer(struct efx_nic *efx,
-			       struct efx_buffer *buffer, unsigned int len)
+int efx_nic_alloc_buffer(struct efx_nic *efx, struct efx_buffer *buffer,
+			 unsigned int len)
 {
 	buffer->addr = pci_alloc_consistent(efx->pci_dev, len,
 					    &buffer->dma_addr);
@@ -342,7 +337,7 @@ static int falcon_alloc_buffer(struct efx_nic *efx,
 	return 0;
 }
 
-static void falcon_free_buffer(struct efx_nic *efx, struct efx_buffer *buffer)
+void efx_nic_free_buffer(struct efx_nic *efx, struct efx_buffer *buffer)
 {
 	if (buffer->addr) {
 		pci_free_consistent(efx->pci_dev, buffer->len,
@@ -353,21 +348,21 @@ static void falcon_free_buffer(struct efx_nic *efx, struct efx_buffer *buffer)
 
 /**************************************************************************
  *
- * Falcon TX path
+ * TX path
  *
  **************************************************************************/
 
 /* Returns a pointer to the specified transmit descriptor in the TX
  * descriptor queue belonging to the specified channel.
  */
-static inline efx_qword_t *falcon_tx_desc(struct efx_tx_queue *tx_queue,
-					       unsigned int index)
+static inline efx_qword_t *
+efx_tx_desc(struct efx_tx_queue *tx_queue, unsigned int index)
 {
 	return (((efx_qword_t *) (tx_queue->txd.addr)) + index);
 }
 
 /* This writes to the TX_DESC_WPTR; write pointer for TX descriptor ring */
-static inline void falcon_notify_tx_desc(struct efx_tx_queue *tx_queue)
+static inline void efx_notify_tx_desc(struct efx_tx_queue *tx_queue)
 {
 	unsigned write_ptr;
 	efx_dword_t reg;
@@ -383,7 +378,7 @@ static inline void falcon_notify_tx_desc(struct efx_tx_queue *tx_queue)
  * descriptor in the hardware TX descriptor ring (in host memory), and
  * write a doorbell.
  */
-void falcon_push_buffers(struct efx_tx_queue *tx_queue)
+void efx_nic_push_buffers(struct efx_tx_queue *tx_queue)
 {
 
 	struct efx_tx_buffer *buffer;
@@ -395,7 +390,7 @@ void falcon_push_buffers(struct efx_tx_queue *tx_queue)
 	do {
 		write_ptr = tx_queue->write_count & EFX_TXQ_MASK;
 		buffer = &tx_queue->buffer[write_ptr];
-		txd = falcon_tx_desc(tx_queue, write_ptr);
+		txd = efx_tx_desc(tx_queue, write_ptr);
 		++tx_queue->write_count;
 
 		/* Create TX descriptor ring entry */
@@ -407,20 +402,20 @@ void falcon_push_buffers(struct efx_tx_queue *tx_queue)
 	} while (tx_queue->write_count != tx_queue->insert_count);
 
 	wmb(); /* Ensure descriptors are written before they are fetched */
-	falcon_notify_tx_desc(tx_queue);
+	efx_notify_tx_desc(tx_queue);
 }
 
 /* Allocate hardware resources for a TX queue */
-int falcon_probe_tx(struct efx_tx_queue *tx_queue)
+int efx_nic_probe_tx(struct efx_tx_queue *tx_queue)
 {
 	struct efx_nic *efx = tx_queue->efx;
 	BUILD_BUG_ON(EFX_TXQ_SIZE < 512 || EFX_TXQ_SIZE > 4096 ||
 		     EFX_TXQ_SIZE & EFX_TXQ_MASK);
-	return falcon_alloc_special_buffer(efx, &tx_queue->txd,
-					   EFX_TXQ_SIZE * sizeof(efx_qword_t));
+	return efx_alloc_special_buffer(efx, &tx_queue->txd,
+					EFX_TXQ_SIZE * sizeof(efx_qword_t));
 }
 
-void falcon_init_tx(struct efx_tx_queue *tx_queue)
+void efx_nic_init_tx(struct efx_tx_queue *tx_queue)
 {
 	efx_oword_t tx_desc_ptr;
 	struct efx_nic *efx = tx_queue->efx;
@@ -428,7 +423,7 @@ void falcon_init_tx(struct efx_tx_queue *tx_queue)
 	tx_queue->flushed = FLUSH_NONE;
 
 	/* Pin TX descriptor ring */
-	falcon_init_special_buffer(efx, &tx_queue->txd);
+	efx_init_special_buffer(efx, &tx_queue->txd);
 
 	/* Push TX descriptor ring to card */
 	EFX_POPULATE_OWORD_10(tx_desc_ptr,
@@ -470,7 +465,7 @@ void falcon_init_tx(struct efx_tx_queue *tx_queue)
 	}
 }
 
-static void falcon_flush_tx_queue(struct efx_tx_queue *tx_queue)
+static void efx_flush_tx_queue(struct efx_tx_queue *tx_queue)
 {
 	struct efx_nic *efx = tx_queue->efx;
 	efx_oword_t tx_flush_descq;
@@ -484,7 +479,7 @@ static void falcon_flush_tx_queue(struct efx_tx_queue *tx_queue)
 	efx_writeo(efx, &tx_flush_descq, FR_AZ_TX_FLUSH_DESCQ);
 }
 
-void falcon_fini_tx(struct efx_tx_queue *tx_queue)
+void efx_nic_fini_tx(struct efx_tx_queue *tx_queue)
 {
 	struct efx_nic *efx = tx_queue->efx;
 	efx_oword_t tx_desc_ptr;
@@ -498,36 +493,36 @@ void falcon_fini_tx(struct efx_tx_queue *tx_queue)
 			 tx_queue->queue);
 
 	/* Unpin TX descriptor ring */
-	falcon_fini_special_buffer(efx, &tx_queue->txd);
+	efx_fini_special_buffer(efx, &tx_queue->txd);
 }
 
 /* Free buffers backing TX queue */
-void falcon_remove_tx(struct efx_tx_queue *tx_queue)
+void efx_nic_remove_tx(struct efx_tx_queue *tx_queue)
 {
-	falcon_free_special_buffer(tx_queue->efx, &tx_queue->txd);
+	efx_free_special_buffer(tx_queue->efx, &tx_queue->txd);
 }
 
 /**************************************************************************
  *
- * Falcon RX path
+ * RX path
  *
  **************************************************************************/
 
 /* Returns a pointer to the specified descriptor in the RX descriptor queue */
-static inline efx_qword_t *falcon_rx_desc(struct efx_rx_queue *rx_queue,
-					       unsigned int index)
+static inline efx_qword_t *
+efx_rx_desc(struct efx_rx_queue *rx_queue, unsigned int index)
 {
 	return (((efx_qword_t *) (rx_queue->rxd.addr)) + index);
 }
 
 /* This creates an entry in the RX descriptor queue */
-static inline void falcon_build_rx_desc(struct efx_rx_queue *rx_queue,
-					unsigned index)
+static inline void
+efx_build_rx_desc(struct efx_rx_queue *rx_queue, unsigned index)
 {
 	struct efx_rx_buffer *rx_buf;
 	efx_qword_t *rxd;
 
-	rxd = falcon_rx_desc(rx_queue, index);
+	rxd = efx_rx_desc(rx_queue, index);
 	rx_buf = efx_rx_buffer(rx_queue, index);
 	EFX_POPULATE_QWORD_3(*rxd,
 			     FSF_AZ_RX_KER_BUF_SIZE,
@@ -540,15 +535,15 @@ static inline void falcon_build_rx_desc(struct efx_rx_queue *rx_queue,
 /* This writes to the RX_DESC_WPTR register for the specified receive
  * descriptor ring.
  */
-void falcon_notify_rx_desc(struct efx_rx_queue *rx_queue)
+void efx_nic_notify_rx_desc(struct efx_rx_queue *rx_queue)
 {
 	efx_dword_t reg;
 	unsigned write_ptr;
 
 	while (rx_queue->notified_count != rx_queue->added_count) {
-		falcon_build_rx_desc(rx_queue,
-				     rx_queue->notified_count &
-				     EFX_RXQ_MASK);
+		efx_build_rx_desc(rx_queue,
+				  rx_queue->notified_count &
+				  EFX_RXQ_MASK);
 		++rx_queue->notified_count;
 	}
 
@@ -559,16 +554,16 @@ void falcon_notify_rx_desc(struct efx_rx_queue *rx_queue)
 			FR_AZ_RX_DESC_UPD_DWORD_P0, rx_queue->queue);
 }
 
-int falcon_probe_rx(struct efx_rx_queue *rx_queue)
+int efx_nic_probe_rx(struct efx_rx_queue *rx_queue)
 {
 	struct efx_nic *efx = rx_queue->efx;
 	BUILD_BUG_ON(EFX_RXQ_SIZE < 512 || EFX_RXQ_SIZE > 4096 ||
 		     EFX_RXQ_SIZE & EFX_RXQ_MASK);
-	return falcon_alloc_special_buffer(efx, &rx_queue->rxd,
-					   EFX_RXQ_SIZE * sizeof(efx_qword_t));
+	return efx_alloc_special_buffer(efx, &rx_queue->rxd,
+					EFX_RXQ_SIZE * sizeof(efx_qword_t));
 }
 
-void falcon_init_rx(struct efx_rx_queue *rx_queue)
+void efx_nic_init_rx(struct efx_rx_queue *rx_queue)
 {
 	efx_oword_t rx_desc_ptr;
 	struct efx_nic *efx = rx_queue->efx;
@@ -582,7 +577,7 @@ void falcon_init_rx(struct efx_rx_queue *rx_queue)
 	rx_queue->flushed = FLUSH_NONE;
 
 	/* Pin RX descriptor ring */
-	falcon_init_special_buffer(efx, &rx_queue->rxd);
+	efx_init_special_buffer(efx, &rx_queue->rxd);
 
 	/* Push RX descriptor ring to card */
 	EFX_POPULATE_OWORD_10(rx_desc_ptr,
@@ -603,7 +598,7 @@ void falcon_init_rx(struct efx_rx_queue *rx_queue)
 			 rx_queue->queue);
 }
 
-static void falcon_flush_rx_queue(struct efx_rx_queue *rx_queue)
+static void efx_flush_rx_queue(struct efx_rx_queue *rx_queue)
 {
 	struct efx_nic *efx = rx_queue->efx;
 	efx_oword_t rx_flush_descq;
@@ -617,7 +612,7 @@ static void falcon_flush_rx_queue(struct efx_rx_queue *rx_queue)
 	efx_writeo(efx, &rx_flush_descq, FR_AZ_RX_FLUSH_DESCQ);
 }
 
-void falcon_fini_rx(struct efx_rx_queue *rx_queue)
+void efx_nic_fini_rx(struct efx_rx_queue *rx_queue)
 {
 	efx_oword_t rx_desc_ptr;
 	struct efx_nic *efx = rx_queue->efx;
@@ -631,18 +626,18 @@ void falcon_fini_rx(struct efx_rx_queue *rx_queue)
 			 rx_queue->queue);
 
 	/* Unpin RX descriptor ring */
-	falcon_fini_special_buffer(efx, &rx_queue->rxd);
+	efx_fini_special_buffer(efx, &rx_queue->rxd);
 }
 
 /* Free buffers backing RX queue */
-void falcon_remove_rx(struct efx_rx_queue *rx_queue)
+void efx_nic_remove_rx(struct efx_rx_queue *rx_queue)
 {
-	falcon_free_special_buffer(rx_queue->efx, &rx_queue->rxd);
+	efx_free_special_buffer(rx_queue->efx, &rx_queue->rxd);
 }
 
 /**************************************************************************
  *
- * Falcon event queue processing
+ * Event queue processing
  * Event queues are processed by per-channel tasklets.
  *
  **************************************************************************/
@@ -656,7 +651,7 @@ void falcon_remove_rx(struct efx_rx_queue *rx_queue)
  * whereas channel->eventq_read_ptr contains the index of the "next to
  * read" event.
  */
-void falcon_eventq_read_ack(struct efx_channel *channel)
+void efx_nic_eventq_read_ack(struct efx_channel *channel)
 {
 	efx_dword_t reg;
 	struct efx_nic *efx = channel->efx;
@@ -667,7 +662,7 @@ void falcon_eventq_read_ack(struct efx_channel *channel)
 }
 
 /* Use HW to insert a SW defined event */
-void falcon_generate_event(struct efx_channel *channel, efx_qword_t *event)
+void efx_generate_event(struct efx_channel *channel, efx_qword_t *event)
 {
 	efx_oword_t drv_ev_reg;
 
@@ -683,11 +678,11 @@ void falcon_generate_event(struct efx_channel *channel, efx_qword_t *event)
 
 /* Handle a transmit completion event
  *
- * Falcon batches TX completion events; the message we receive is of
+ * The NIC batches TX completion events; the message we receive is of
  * the form "complete all TX events up to this index".
  */
-static void falcon_handle_tx_event(struct efx_channel *channel,
-				   efx_qword_t *event)
+static void
+efx_handle_tx_event(struct efx_channel *channel, efx_qword_t *event)
 {
 	unsigned int tx_ev_desc_ptr;
 	unsigned int tx_ev_q_label;
@@ -710,7 +705,7 @@ static void falcon_handle_tx_event(struct efx_channel *channel,
 
 		if (efx_dev_registered(efx))
 			netif_tx_lock(efx->net_dev);
-		falcon_notify_tx_desc(tx_queue);
+		efx_notify_tx_desc(tx_queue);
 		if (efx_dev_registered(efx))
 			netif_tx_unlock(efx->net_dev);
 	} else if (EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_PKT_ERR) &&
@@ -724,10 +719,10 @@ static void falcon_handle_tx_event(struct efx_channel *channel,
 }
 
 /* Detect errors included in the rx_evt_pkt_ok bit. */
-static void falcon_handle_rx_not_ok(struct efx_rx_queue *rx_queue,
-				    const efx_qword_t *event,
-				    bool *rx_ev_pkt_ok,
-				    bool *discard)
+static void efx_handle_rx_not_ok(struct efx_rx_queue *rx_queue,
+				 const efx_qword_t *event,
+				 bool *rx_ev_pkt_ok,
+				 bool *discard)
 {
 	struct efx_nic *efx = rx_queue->efx;
 	bool rx_ev_buf_owner_id_err, rx_ev_ip_hdr_chksum_err;
@@ -799,8 +794,8 @@ static void falcon_handle_rx_not_ok(struct efx_rx_queue *rx_queue,
 }
 
 /* Handle receive events that are not in-order. */
-static void falcon_handle_rx_bad_index(struct efx_rx_queue *rx_queue,
-				       unsigned index)
+static void
+efx_handle_rx_bad_index(struct efx_rx_queue *rx_queue, unsigned index)
 {
 	struct efx_nic *efx = rx_queue->efx;
 	unsigned expected, dropped;
@@ -816,13 +811,13 @@ static void falcon_handle_rx_bad_index(struct efx_rx_queue *rx_queue,
 
 /* Handle a packet received event
  *
- * Falcon silicon gives a "discard" flag if it's a unicast packet with the
+ * The NIC gives a "discard" flag if it's a unicast packet with the
  * wrong destination address
  * Also "is multicast" and "matches multicast filter" flags can be used to
  * discard non-matching multicast packets.
  */
-static void falcon_handle_rx_event(struct efx_channel *channel,
-				   const efx_qword_t *event)
+static void
+efx_handle_rx_event(struct efx_channel *channel, const efx_qword_t *event)
 {
 	unsigned int rx_ev_desc_ptr, rx_ev_byte_cnt;
 	unsigned int rx_ev_hdr_type, rx_ev_mcast_pkt;
@@ -845,19 +840,18 @@ static void falcon_handle_rx_event(struct efx_channel *channel,
 	rx_ev_desc_ptr = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_DESC_PTR);
 	expected_ptr = rx_queue->removed_count & EFX_RXQ_MASK;
 	if (unlikely(rx_ev_desc_ptr != expected_ptr))
-		falcon_handle_rx_bad_index(rx_queue, rx_ev_desc_ptr);
+		efx_handle_rx_bad_index(rx_queue, rx_ev_desc_ptr);
 
 	if (likely(rx_ev_pkt_ok)) {
-		/* If packet is marked as OK and packet type is TCP/IPv4 or
-		 * UDP/IPv4, then we can rely on the hardware checksum.
+		/* If packet is marked as OK and packet type is TCP/IP or
+		 * UDP/IP, then we can rely on the hardware checksum.
 		 */
 		checksummed =
 			likely(efx->rx_checksum_enabled) &&
-			(rx_ev_hdr_type == FSE_AB_RX_EV_HDR_TYPE_IPV4_TCP ||
-			 rx_ev_hdr_type == FSE_AB_RX_EV_HDR_TYPE_IPV4_UDP);
+			(rx_ev_hdr_type == FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_TCP ||
+			 rx_ev_hdr_type == FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_UDP);
 	} else {
-		falcon_handle_rx_not_ok(rx_queue, event, &rx_ev_pkt_ok,
-					&discard);
+		efx_handle_rx_not_ok(rx_queue, event, &rx_ev_pkt_ok, &discard);
 		checksummed = false;
 	}
 
@@ -881,8 +875,8 @@ static void falcon_handle_rx_event(struct efx_channel *channel,
 }
 
 /* Global events are basically PHY events */
-static void falcon_handle_global_event(struct efx_channel *channel,
-				       efx_qword_t *event)
+static void
+efx_handle_global_event(struct efx_channel *channel, efx_qword_t *event)
 {
 	struct efx_nic *efx = channel->efx;
 	bool handled = false;
@@ -918,8 +912,8 @@ static void falcon_handle_global_event(struct efx_channel *channel,
 			EFX_QWORD_VAL(*event));
 }
 
-static void falcon_handle_driver_event(struct efx_channel *channel,
-				       efx_qword_t *event)
+static void
+efx_handle_driver_event(struct efx_channel *channel, efx_qword_t *event)
 {
 	struct efx_nic *efx = channel->efx;
 	unsigned int ev_sub_code;
@@ -980,7 +974,7 @@ static void falcon_handle_driver_event(struct efx_channel *channel,
 	}
 }
 
-int falcon_process_eventq(struct efx_channel *channel, int rx_quota)
+int efx_nic_process_eventq(struct efx_channel *channel, int rx_quota)
 {
 	unsigned int read_ptr;
 	efx_qword_t event, *p_event;
@@ -990,10 +984,10 @@ int falcon_process_eventq(struct efx_channel *channel, int rx_quota)
 	read_ptr = channel->eventq_read_ptr;
 
 	do {
-		p_event = falcon_event(channel, read_ptr);
+		p_event = efx_event(channel, read_ptr);
 		event = *p_event;
 
-		if (!falcon_event_present(&event))
+		if (!efx_event_present(&event))
 			/* End of events */
 			break;
 
@@ -1007,11 +1001,11 @@ int falcon_process_eventq(struct efx_channel *channel, int rx_quota)
 
 		switch (ev_code) {
 		case FSE_AZ_EV_CODE_RX_EV:
-			falcon_handle_rx_event(channel, &event);
+			efx_handle_rx_event(channel, &event);
 			++rx_packets;
 			break;
 		case FSE_AZ_EV_CODE_TX_EV:
-			falcon_handle_tx_event(channel, &event);
+			efx_handle_tx_event(channel, &event);
 			break;
 		case FSE_AZ_EV_CODE_DRV_GEN_EV:
 			channel->eventq_magic = EFX_QWORD_FIELD(
@@ -1021,10 +1015,10 @@ int falcon_process_eventq(struct efx_channel *channel, int rx_quota)
 				EFX_QWORD_VAL(event));
 			break;
 		case FSE_AZ_EV_CODE_GLOBAL_EV:
-			falcon_handle_global_event(channel, &event);
+			efx_handle_global_event(channel, &event);
 			break;
 		case FSE_AZ_EV_CODE_DRIVER_EV:
-			falcon_handle_driver_event(channel, &event);
+			efx_handle_driver_event(channel, &event);
 			break;
 		default:
 			EFX_ERR(channel->efx, "channel %d unknown event type %d"
@@ -1066,16 +1060,16 @@ static void falcon_push_irq_moderation(struct efx_channel *channel)
 }
 
 /* Allocate buffer table entries for event queue */
-int falcon_probe_eventq(struct efx_channel *channel)
+int efx_nic_probe_eventq(struct efx_channel *channel)
 {
 	struct efx_nic *efx = channel->efx;
 	BUILD_BUG_ON(EFX_EVQ_SIZE < 512 || EFX_EVQ_SIZE > 32768 ||
 		     EFX_EVQ_SIZE & EFX_EVQ_MASK);
-	return falcon_alloc_special_buffer(efx, &channel->eventq,
-					   EFX_EVQ_SIZE * sizeof(efx_qword_t));
+	return efx_alloc_special_buffer(efx, &channel->eventq,
+					EFX_EVQ_SIZE * sizeof(efx_qword_t));
 }
 
-void falcon_init_eventq(struct efx_channel *channel)
+void efx_nic_init_eventq(struct efx_channel *channel)
 {
 	efx_oword_t evq_ptr;
 	struct efx_nic *efx = channel->efx;
@@ -1085,7 +1079,7 @@ void falcon_init_eventq(struct efx_channel *channel)
 		channel->eventq.index + channel->eventq.entries - 1);
 
 	/* Pin event queue buffer */
-	falcon_init_special_buffer(efx, &channel->eventq);
+	efx_init_special_buffer(efx, &channel->eventq);
 
 	/* Fill event queue with all ones (i.e. empty events) */
 	memset(channel->eventq.addr, 0xff, channel->eventq.len);
@@ -1098,10 +1092,10 @@ void falcon_init_eventq(struct efx_channel *channel)
 	efx_writeo_table(efx, &evq_ptr, efx->type->evq_ptr_tbl_base,
 			 channel->channel);
 
-	falcon_push_irq_moderation(channel);
+	efx->type->push_irq_moderation(channel);
 }
 
-void falcon_fini_eventq(struct efx_channel *channel)
+void efx_nic_fini_eventq(struct efx_channel *channel)
 {
 	efx_oword_t eventq_ptr;
 	struct efx_nic *efx = channel->efx;
@@ -1112,13 +1106,13 @@ void falcon_fini_eventq(struct efx_channel *channel)
 			 channel->channel);
 
 	/* Unpin event queue */
-	falcon_fini_special_buffer(efx, &channel->eventq);
+	efx_fini_special_buffer(efx, &channel->eventq);
 }
 
 /* Free buffers backing event queue */
-void falcon_remove_eventq(struct efx_channel *channel)
+void efx_nic_remove_eventq(struct efx_channel *channel)
 {
-	falcon_free_special_buffer(channel->efx, &channel->eventq);
+	efx_free_special_buffer(channel->efx, &channel->eventq);
 }
 

@@ -1126,14 +1120,14 @@ void falcon_remove_eventq(struct efx_channel *channel)
  * process_eventq() should pick up the event and place the value of
  * "magic" into channel->eventq_magic;
  */
-void falcon_generate_test_event(struct efx_channel *channel, unsigned int magic)
+void efx_nic_generate_test_event(struct efx_channel *channel, unsigned int magic)
 {
 	efx_qword_t test_event;
 
 	EFX_POPULATE_QWORD_2(test_event, FSF_AZ_EV_CODE,
 			     FSE_AZ_EV_CODE_DRV_GEN_EV,
 			     FSF_AZ_DRV_GEN_EV_MAGIC, magic);
-	falcon_generate_event(channel, &test_event);
+	efx_generate_event(channel, &test_event);
 }
 
 /**************************************************************************
@@ -1143,7 +1137,7 @@ void falcon_generate_test_event(struct efx_channel *channel, unsigned int magic)
  **************************************************************************/
 

-static void falcon_poll_flush_events(struct efx_nic *efx)
+static void efx_poll_flush_events(struct efx_nic *efx)
 {
 	struct efx_channel *channel = &efx->channel[0];
 	struct efx_tx_queue *tx_queue;
@@ -1152,11 +1146,11 @@ static void falcon_poll_flush_events(struct efx_nic *efx)
 	unsigned int end_ptr = (read_ptr - 1) & EFX_EVQ_MASK;
 
 	do {
-		efx_qword_t *event = falcon_event(channel, read_ptr);
+		efx_qword_t *event = efx_event(channel, read_ptr);
 		int ev_code, ev_sub_code, ev_queue;
 		bool ev_failed;
 
-		if (!falcon_event_present(event))
+		if (!efx_event_present(event))
 			break;
 
 		ev_code = EFX_QWORD_FIELD(*event, FSF_AZ_EV_CODE);
@@ -1208,7 +1202,7 @@ static void falcon_prepare_flush(struct efx_nic *efx)
 /* Handle tx and rx flushes at the same time, since they run in
  * parallel in the hardware and there's no reason for us to
  * serialise them */
-int falcon_flush_queues(struct efx_nic *efx)
+int efx_nic_flush_queues(struct efx_nic *efx)
 {
 	struct efx_rx_queue *rx_queue;
 	struct efx_tx_queue *tx_queue;
@@ -1219,22 +1213,22 @@ int falcon_flush_queues(struct efx_nic *efx)
 
 	/* Flush all tx queues in parallel */
 	efx_for_each_tx_queue(tx_queue, efx)
-		falcon_flush_tx_queue(tx_queue);
+		efx_flush_tx_queue(tx_queue);
 
 	/* The hardware supports four concurrent rx flushes, each of which may
 	 * need to be retried if there is an outstanding descriptor fetch */
-	for (i = 0; i < FALCON_FLUSH_POLL_COUNT; ++i) {
+	for (i = 0; i < EFX_FLUSH_POLL_COUNT; ++i) {
 		rx_pending = tx_pending = 0;
 		efx_for_each_rx_queue(rx_queue, efx) {
 			if (rx_queue->flushed == FLUSH_PENDING)
 				++rx_pending;
 		}
 		efx_for_each_rx_queue(rx_queue, efx) {
-			if (rx_pending == FALCON_RX_FLUSH_COUNT)
+			if (rx_pending == EFX_RX_FLUSH_COUNT)
 				break;
 			if (rx_queue->flushed == FLUSH_FAILED ||
 			    rx_queue->flushed == FLUSH_NONE) {
-				falcon_flush_rx_queue(rx_queue);
+				efx_flush_rx_queue(rx_queue);
 				++rx_pending;
 			}
 		}
@@ -1246,8 +1240,8 @@ int falcon_flush_queues(struct efx_nic *efx)
 		if (rx_pending == 0 && tx_pending == 0)
 			return 0;
 
-		msleep(FALCON_FLUSH_INTERVAL);
-		falcon_poll_flush_events(efx);
+		msleep(EFX_FLUSH_INTERVAL);
+		efx_poll_flush_events(efx);
 	}
 
 	/* Mark the queues as all flushed. We're going to return failure
@@ -1273,15 +1267,15 @@ int falcon_flush_queues(struct efx_nic *efx)
 
 /**************************************************************************
  *
- * Falcon hardware interrupts
+ * Hardware interrupts
  * The hardware interrupt handler does very little work; all the event
  * queue processing is carried out by per-channel tasklets.
  *
  **************************************************************************/
 
-/* Enable/disable/generate Falcon interrupts */
-static inline void falcon_interrupts(struct efx_nic *efx, int enabled,
-				     int force)
+/* Enable/disable/generate interrupts */
+static inline void efx_nic_interrupts(struct efx_nic *efx,
+				      bool enabled, bool force)
 {
 	efx_oword_t int_en_reg_ker;
 
@@ -1291,7 +1285,7 @@ static inline void falcon_interrupts(struct efx_nic *efx, int enabled,
 	efx_writeo(efx, &int_en_reg_ker, FR_AZ_INT_EN_KER);
 }
 
-void falcon_enable_interrupts(struct efx_nic *efx)
+void efx_nic_enable_interrupts(struct efx_nic *efx)
 {
 	struct efx_channel *channel;
 
@@ -1299,7 +1293,7 @@ void falcon_enable_interrupts(struct efx_nic *efx)
 	wmb(); /* Ensure interrupt vector is clear before interrupts enabled */
 
 	/* Enable interrupts */
-	falcon_interrupts(efx, 1, 0);
+	efx_nic_interrupts(efx, true, false);
 
 	/* Force processing of all the channels to get the EVQ RPTRs up to
 	   date */
@@ -1307,19 +1301,19 @@ void falcon_enable_interrupts(struct efx_nic *efx)
 		efx_schedule_channel(channel);
 }
 
-void falcon_disable_interrupts(struct efx_nic *efx)
+void efx_nic_disable_interrupts(struct efx_nic *efx)
 {
 	/* Disable interrupts */
-	falcon_interrupts(efx, 0, 0);
+	efx_nic_interrupts(efx, false, false);
 }
 
-/* Generate a Falcon test interrupt
+/* Generate a test interrupt
  * Interrupt must already have been enabled, otherwise nasty things
  * may happen.
  */
-void falcon_generate_interrupt(struct efx_nic *efx)
+void efx_nic_generate_interrupt(struct efx_nic *efx)
 {
-	falcon_interrupts(efx, 1, 1);
+	efx_nic_interrupts(efx, true, true);
 }
 
 /* Acknowledge a legacy interrupt from Falcon
@@ -1332,7 +1326,7 @@ void falcon_generate_interrupt(struct efx_nic *efx)
  *
  * NB most hardware supports MSI interrupts
  */
-static inline void falcon_irq_ack_a1(struct efx_nic *efx)
+inline void falcon_irq_ack_a1(struct efx_nic *efx)
 {
 	efx_dword_t reg;
 
@@ -1344,7 +1338,7 @@ static inline void falcon_irq_ack_a1(struct efx_nic *efx)
 /* Process a fatal interrupt
  * Disable bus mastering ASAP and schedule a reset
  */
-static irqreturn_t falcon_fatal_interrupt(struct efx_nic *efx)
+irqreturn_t efx_nic_fatal_interrupt(struct efx_nic *efx)
 {
 	struct falcon_nic_data *nic_data = efx->nic_data;
 	efx_oword_t *int_ker = efx->irq_status.addr;
@@ -1372,18 +1366,18 @@ static irqreturn_t falcon_fatal_interrupt(struct efx_nic *efx)
 
 	/* Disable both devices */
 	pci_clear_master(efx->pci_dev);
-	if (FALCON_IS_DUAL_FUNC(efx))
+	if (efx_nic_is_dual_func(efx))
 		pci_clear_master(nic_data->pci_dev2);
-	falcon_disable_interrupts(efx);
+	efx_nic_disable_interrupts(efx);
 
 	/* Count errors and reset or disable the NIC accordingly */
 	if (efx->int_error_count == 0 ||
 	    time_after(jiffies, efx->int_error_expire)) {
 		efx->int_error_count = 0;
 		efx->int_error_expire =
-			jiffies + FALCON_INT_ERROR_EXPIRE * HZ;
+			jiffies + EFX_INT_ERROR_EXPIRE * HZ;
 	}
-	if (++efx->int_error_count < FALCON_MAX_INT_ERRORS) {
+	if (++efx->int_error_count < EFX_MAX_INT_ERRORS) {
 		EFX_ERR(efx, "SYSTEM ERROR - reset scheduled\n");
 		efx_schedule_reset(efx, RESET_TYPE_INT_ERROR);
 	} else {
@@ -1395,10 +1389,10 @@ out:
 	return IRQ_HANDLED;
 }
 
-/* Handle a legacy interrupt from Falcon
+/* Handle a legacy interrupt
  * Acknowledges the interrupt and schedule event queue processing.
  */
-static irqreturn_t falcon_legacy_interrupt_b0(int irq, void *dev_id)
+static irqreturn_t efx_legacy_interrupt(int irq, void *dev_id)
 {
 	struct efx_nic *efx = dev_id;
 	efx_oword_t *int_ker = efx->irq_status.addr;
@@ -1415,13 +1409,13 @@ static irqreturn_t falcon_legacy_interrupt_b0(int irq, void *dev_id)
 	/* Check to see if we have a serious error condition */
 	syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT);
 	if (unlikely(syserr))
-		return falcon_fatal_interrupt(efx);
+		return efx_nic_fatal_interrupt(efx);
 
 	/* Schedule processing of any interrupting queues */
 	efx_for_each_channel(channel, efx) {
 		if ((queues & 1) ||
-		    falcon_event_present(
-			    falcon_event(channel, channel->eventq_read_ptr))) {
+		    efx_event_present(
+			    efx_event(channel, channel->eventq_read_ptr))) {
 			efx_schedule_channel(channel);
 			result = IRQ_HANDLED;
 		}
@@ -1438,7 +1432,7 @@ static irqreturn_t falcon_legacy_interrupt_b0(int irq, void *dev_id)
 }
 

-static irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id)
+irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id)
 {
 	struct efx_nic *efx = dev_id;
 	efx_oword_t *int_ker = efx->irq_status.addr;
@@ -1461,7 +1455,7 @@ static irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id)
 	/* Check to see if we have a serious error condition */
 	syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT);
 	if (unlikely(syserr))
-		return falcon_fatal_interrupt(efx);
+		return efx_nic_fatal_interrupt(efx);
 
 	/* Determine interrupting queues, clear interrupt status
 	 * register and acknowledge the device interrupt.
@@ -1484,14 +1478,14 @@ static irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
-/* Handle an MSI interrupt from Falcon
+/* Handle an MSI interrupt
  *
  * Handle an MSI hardware interrupt.  This routine schedules event
  * queue processing.  No interrupt acknowledgement cycle is necessary.
  * Also, we never need to check that the interrupt is for us, since
  * MSI interrupts cannot be shared.
  */
-static irqreturn_t falcon_msi_interrupt(int irq, void *dev_id)
+static irqreturn_t efx_msi_interrupt(int irq, void *dev_id)
 {
 	struct efx_channel *channel = dev_id;
 	struct efx_nic *efx = channel->efx;
@@ -1505,7 +1499,7 @@ static irqreturn_t falcon_msi_interrupt(int irq, void *dev_id)
 	/* Check to see if we have a serious error condition */
 	syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT);
 	if (unlikely(syserr))
-		return falcon_fatal_interrupt(efx);
+		return efx_nic_fatal_interrupt(efx);
 
 	/* Schedule processing of the channel */
 	efx_schedule_channel(channel);
@@ -1517,7 +1511,7 @@ static irqreturn_t falcon_msi_interrupt(int irq, void *dev_id)
 /* Setup RSS indirection table.
  * This maps from the hash value of the packet to RXQ
  */
-static void falcon_setup_rss_indir_table(struct efx_nic *efx)
+static void efx_setup_rss_indir_table(struct efx_nic *efx)
 {
 	int i = 0;
 	unsigned long offset;
@@ -1539,7 +1533,7 @@ static void falcon_setup_rss_indir_table(struct efx_nic *efx)
 /* Hook interrupt handler(s)
  * Try MSI and then legacy interrupts.
  */
-int falcon_init_interrupt(struct efx_nic *efx)
+int efx_nic_init_interrupt(struct efx_nic *efx)
 {
 	struct efx_channel *channel;
 	int rc;
@@ -1547,7 +1541,7 @@ int falcon_init_interrupt(struct efx_nic *efx)
 	if (!EFX_INT_MODE_USE_MSI(efx)) {
 		irq_handler_t handler;
 		if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0)
-			handler = falcon_legacy_interrupt_b0;
+			handler = efx_legacy_interrupt;
 		else
 			handler = falcon_legacy_interrupt_a1;
 
@@ -1563,7 +1557,7 @@ int falcon_init_interrupt(struct efx_nic *efx)
 
 	/* Hook MSI or MSI-X interrupt */
 	efx_for_each_channel(channel, efx) {
-		rc = request_irq(channel->irq, falcon_msi_interrupt,
+		rc = request_irq(channel->irq, efx_msi_interrupt,
 				 IRQF_PROBE_SHARED, /* Not shared */
 				 channel->name, channel);
 		if (rc) {
@@ -1581,7 +1575,7 @@ int falcon_init_interrupt(struct efx_nic *efx)
 	return rc;
 }
 
-void falcon_fini_interrupt(struct efx_nic *efx)
+void efx_nic_fini_interrupt(struct efx_nic *efx)
 {
 	struct efx_channel *channel;
 	efx_oword_t reg;
@@ -2322,8 +2316,8 @@ static int falcon_probe_port(struct efx_nic *efx)
 		efx->wanted_fc = EFX_FC_RX;
 
 	/* Allocate buffer for stats */
-	rc = falcon_alloc_buffer(efx, &efx->stats_buffer,
-				 FALCON_MAC_STATS_SIZE);
+	rc = efx_nic_alloc_buffer(efx, &efx->stats_buffer,
+				  FALCON_MAC_STATS_SIZE);
 	if (rc)
 		return rc;
 	EFX_LOG(efx, "stats buffer at %llx (virt %p phys %llx)\n",
@@ -2336,7 +2330,7 @@ static int falcon_probe_port(struct efx_nic *efx)
 
 static void falcon_remove_port(struct efx_nic *efx)
 {
-	falcon_free_buffer(efx, &efx->stats_buffer);
+	efx_nic_free_buffer(efx, &efx->stats_buffer);
 }
 
 /**************************************************************************
@@ -2414,11 +2408,7 @@ static int falcon_test_nvram(struct efx_nic *efx)
 	return falcon_read_nvram(efx, NULL);
 }
 
-/* Registers tested in the falcon register test */
-static struct {
-	unsigned address;
-	efx_oword_t mask;
-} efx_test_registers[] = {
+static const struct efx_nic_register_test falcon_b0_register_tests[] = {
 	{ FR_AZ_ADR_REGION,
 	  EFX_OWORD32(0x0001FFFF, 0x0001FFFF, 0x0001FFFF, 0x0001FFFF) },
 	{ FR_AZ_RX_CFG,
@@ -2464,7 +2454,9 @@ static bool efx_masked_compare_oword(const efx_oword_t *a, const efx_oword_t *b,
 		((a->u64[1] ^ b->u64[1]) & mask->u64[1]);
 }
 
-static int falcon_b0_test_registers(struct efx_nic *efx)
+int efx_nic_test_registers(struct efx_nic *efx,
+			   const struct efx_nic_register_test *regs,
+			   size_t n_regs)
 {
 	unsigned address = 0, i, j;
 	efx_oword_t mask, imask, original, reg, buf;
@@ -2472,9 +2464,9 @@ static int falcon_b0_test_registers(struct efx_nic *efx)
 	/* Falcon should be in loopback to isolate the XMAC from the PHY */
 	WARN_ON(!LOOPBACK_INTERNAL(efx));
 
-	for (i = 0; i < ARRAY_SIZE(efx_test_registers); ++i) {
-		address = efx_test_registers[i].address;
-		mask = imask = efx_test_registers[i].mask;
+	for (i = 0; i < n_regs; ++i) {
+		address = regs[i].address;
+		mask = imask = regs[i].mask;
 		EFX_INVERT_OWORD(imask);
 
 		efx_reado(efx, &original, address);
@@ -2517,6 +2509,12 @@ fail:
 	return -EIO;
 }
 
+static int falcon_b0_test_registers(struct efx_nic *efx)
+{
+	return efx_nic_test_registers(efx, falcon_b0_register_tests,
+				      ARRAY_SIZE(falcon_b0_register_tests));
+}
+
 /**************************************************************************
  *
  * Device reset
@@ -2542,7 +2540,7 @@ static int falcon_reset_hw(struct efx_nic *efx, enum reset_type method)
 				"function prior to hardware reset\n");
 			goto fail1;
 		}
-		if (FALCON_IS_DUAL_FUNC(efx)) {
+		if (efx_nic_is_dual_func(efx)) {
 			rc = pci_save_state(nic_data->pci_dev2);
 			if (rc) {
 				EFX_ERR(efx, "failed to backup PCI state of "
@@ -2577,7 +2575,7 @@ static int falcon_reset_hw(struct efx_nic *efx, enum reset_type method)
 
 	/* Restore PCI configuration if needed */
 	if (method == RESET_TYPE_WORLD) {
-		if (FALCON_IS_DUAL_FUNC(efx)) {
+		if (efx_nic_is_dual_func(efx)) {
 			rc = pci_restore_state(nic_data->pci_dev2);
 			if (rc) {
 				EFX_ERR(efx, "failed to restore PCI config for "
@@ -2800,16 +2798,22 @@ static int falcon_probe_nvconfig(struct efx_nic *efx)
 	return rc;
 }
 
+u32 efx_nic_fpga_ver(struct efx_nic *efx)
+{
+	efx_oword_t altera_build;
+
+	efx_reado(efx, &altera_build, FR_AZ_ALTERA_BUILD);
+	return EFX_OWORD_FIELD(altera_build, FRF_AZ_ALTERA_BUILD_VER);
+}
+
 /* Probe the NIC variant (revision, ASIC vs FPGA, function count, port
  * count, port speed).  Set workaround and feature flags accordingly.
  */
 static int falcon_probe_nic_variant(struct efx_nic *efx)
 {
-	efx_oword_t altera_build;
 	efx_oword_t nic_stat;
 
-	efx_reado(efx, &altera_build, FR_AZ_ALTERA_BUILD);
-	if (EFX_OWORD_FIELD(altera_build, FRF_AZ_ALTERA_BUILD_VER)) {
+	if (efx_nic_fpga_ver(efx) != 0) {
 		EFX_ERR(efx, "Falcon FPGA not supported\n");
 		return -ENODEV;
 	}
@@ -2893,7 +2897,7 @@ static int falcon_probe_nic(struct efx_nic *efx)
 		goto fail1;
 
 	/* Probe secondary function if expected */
-	if (FALCON_IS_DUAL_FUNC(efx)) {
+	if (efx_nic_is_dual_func(efx)) {
 		struct pci_dev *dev = pci_dev_get(efx->pci_dev);
 
 		while ((dev = pci_get_device(EFX_VENDID_SFC, FALCON_A_S_DEVID,
@@ -2919,7 +2923,7 @@ static int falcon_probe_nic(struct efx_nic *efx)
 	}
 
 	/* Allocate memory for INT_KER */
-	rc = falcon_alloc_buffer(efx, &efx->irq_status, sizeof(efx_oword_t));
+	rc = efx_nic_alloc_buffer(efx, &efx->irq_status, sizeof(efx_oword_t));
 	if (rc)
 		goto fail4;
 	BUG_ON(efx->irq_status.dma_addr & 0x0f);
@@ -2965,7 +2969,7 @@ static int falcon_probe_nic(struct efx_nic *efx)
 	memset(&board->i2c_adap, 0, sizeof(board->i2c_adap));
  fail5:
 	falcon_remove_spi_devices(efx);
-	falcon_free_buffer(efx, &efx->irq_status);
+	efx_nic_free_buffer(efx, &efx->irq_status);
  fail4:
  fail3:
 	if (nic_data->pci_dev2) {
@@ -2988,8 +2992,8 @@ static void falcon_init_rx_cfg(struct efx_nic *efx)
 	const unsigned ctrl_xon_thr = 20;
 	const unsigned ctrl_xoff_thr = 25;
 	/* RX data FIFO thresholds (256-byte units; size varies) */
-	int data_xon_thr = rx_xon_thresh_bytes >> 8;
-	int data_xoff_thr = rx_xoff_thresh_bytes >> 8;
+	int data_xon_thr = efx_nic_rx_xon_thresh >> 8;
+	int data_xoff_thr = efx_nic_rx_xoff_thresh >> 8;
 	efx_oword_t reg;
 
 	efx_reado(efx, &reg, FR_AZ_RX_CFG);
@@ -3027,33 +3031,9 @@ static void falcon_init_rx_cfg(struct efx_nic *efx)
 	efx_writeo(efx, &reg, FR_AZ_RX_CFG);
 }
 
-/* This call performs hardware-specific global initialisation, such as
- * defining the descriptor cache sizes and number of RSS channels.
- * It does not set up any buffers, descriptor rings or event queues.
- */
-static int falcon_init_nic(struct efx_nic *efx)
+void efx_nic_init_common(struct efx_nic *efx)
 {
 	efx_oword_t temp;
-	int rc;
-
-	/* Use on-chip SRAM */
-	efx_reado(efx, &temp, FR_AB_NIC_STAT);
-	EFX_SET_OWORD_FIELD(temp, FRF_AB_ONCHIP_SRAM, 1);
-	efx_writeo(efx, &temp, FR_AB_NIC_STAT);
-
-	/* Set the source of the GMAC clock */
-	if (efx_nic_rev(efx) == EFX_REV_FALCON_B0) {
-		efx_reado(efx, &temp, FR_AB_GPIO_CTL);
-		EFX_SET_OWORD_FIELD(temp, FRF_AB_USE_NIC_CLK, true);
-		efx_writeo(efx, &temp, FR_AB_GPIO_CTL);
-	}
-
-	/* Select the correct MAC */
-	falcon_clock_mac(efx);
-
-	rc = falcon_reset_sram(efx);
-	if (rc)
-		return rc;
 
 	/* Set positions of descriptor caches in SRAM. */
 	EFX_POPULATE_OWORD_1(temp, FRF_AZ_SRM_TX_DC_BASE_ADR,
@@ -3084,15 +3064,6 @@ static int falcon_init_nic(struct efx_nic *efx)
 			     FRF_AZ_INT_ADR_KER, efx->irq_status.dma_addr);
 	efx_writeo(efx, &temp, FR_AZ_INT_ADR_KER);
 
-	/* Clear the parity enables on the TX data fifos as
-	 * they produce false parity errors because of timing issues
-	 */
-	if (EFX_WORKAROUND_5129(efx)) {
-		efx_reado(efx, &temp, FR_AZ_CSR_SPARE);
-		EFX_SET_OWORD_FIELD(temp, FRF_AB_MEM_PERR_EN_TX_DATA, 0);
-		efx_writeo(efx, &temp, FR_AZ_CSR_SPARE);
-	}
-
 	/* Enable all the genuinely fatal interrupts.  (They are still
 	 * masked by the overall interrupt mask, controlled by
 	 * falcon_interrupts()).
@@ -3106,6 +3077,64 @@ static int falcon_init_nic(struct efx_nic *efx)
 	EFX_INVERT_OWORD(temp);
 	efx_writeo(efx, &temp, FR_AZ_FATAL_INTR_KER);
 
+	efx_setup_rss_indir_table(efx);
+
+	/* Disable the ugly timer-based TX DMA backoff and allow TX DMA to be
+	 * controlled by the RX FIFO fill level. Set arbitration to one pkt/Q.
+	 */
+	efx_reado(efx, &temp, FR_AZ_TX_RESERVED);
+	EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_RX_SPACER, 0xfe);
+	EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_RX_SPACER_EN, 1);
+	EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_ONE_PKT_PER_Q, 1);
+	EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_PUSH_EN, 0);
+	EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_DIS_NON_IP_EV, 1);
+	/* Enable SW_EV to inherit in char driver - assume harmless here */
+	EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_SOFT_EVT_EN, 1);
+	/* Prefetch threshold 2 => fetch when descriptor cache half empty */
+	EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_PREF_THRESHOLD, 2);
+	/* Squash TX of packets of 16 bytes or less */
+	if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0)
+		EFX_SET_OWORD_FIELD(temp, FRF_BZ_TX_FLUSH_MIN_LEN_EN, 1);
+	efx_writeo(efx, &temp, FR_AZ_TX_RESERVED);
+}
+
+/* This call performs hardware-specific global initialisation, such as
+ * defining the descriptor cache sizes and number of RSS channels.
+ * It does not set up any buffers, descriptor rings or event queues.
+ */
+static int falcon_init_nic(struct efx_nic *efx)
+{
+	efx_oword_t temp;
+	int rc;
+
+	/* Use on-chip SRAM */
+	efx_reado(efx, &temp, FR_AB_NIC_STAT);
+	EFX_SET_OWORD_FIELD(temp, FRF_AB_ONCHIP_SRAM, 1);
+	efx_writeo(efx, &temp, FR_AB_NIC_STAT);
+
+	/* Set the source of the GMAC clock */
+	if (efx_nic_rev(efx) == EFX_REV_FALCON_B0) {
+		efx_reado(efx, &temp, FR_AB_GPIO_CTL);
+		EFX_SET_OWORD_FIELD(temp, FRF_AB_USE_NIC_CLK, true);
+		efx_writeo(efx, &temp, FR_AB_GPIO_CTL);
+	}
+
+	/* Select the correct MAC */
+	falcon_clock_mac(efx);
+
+	rc = falcon_reset_sram(efx);
+	if (rc)
+		return rc;
+
+	/* Clear the parity enables on the TX data fifos as
+	 * they produce false parity errors because of timing issues
+	 */
+	if (EFX_WORKAROUND_5129(efx)) {
+		efx_reado(efx, &temp, FR_AZ_CSR_SPARE);
+		EFX_SET_OWORD_FIELD(temp, FRF_AB_MEM_PERR_EN_TX_DATA, 0);
+		efx_writeo(efx, &temp, FR_AZ_CSR_SPARE);
+	}
+
 	if (EFX_WORKAROUND_7244(efx)) {
 		efx_reado(efx, &temp, FR_BZ_RX_FILTER_CTL);
 		EFX_SET_OWORD_FIELD(temp, FRF_BZ_UDP_FULL_SRCH_LIMIT, 8);
@@ -3115,8 +3144,6 @@ static int falcon_init_nic(struct efx_nic *efx)
 		efx_writeo(efx, &temp, FR_BZ_RX_FILTER_CTL);
 	}
 
-	falcon_setup_rss_indir_table(efx);
-
 	/* XXX This is documented only for Falcon A0/A1 */
 	/* Setup RX.  Wait for descriptor is broken and must
 	 * be disabled.  RXDP recovery shouldn't be needed, but is.
@@ -3128,24 +3155,6 @@ static int falcon_init_nic(struct efx_nic *efx)
 		EFX_SET_OWORD_FIELD(temp, FRF_AA_RX_ISCSI_DIS, 1);
 	efx_writeo(efx, &temp, FR_AA_RX_SELF_RST);
 
-	/* Disable the ugly timer-based TX DMA backoff and allow TX DMA to be
-	 * controlled by the RX FIFO fill level. Set arbitration to one pkt/Q.
-	 */
-	efx_reado(efx, &temp, FR_AZ_TX_RESERVED);
-	EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_RX_SPACER, 0xfe);
-	EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_RX_SPACER_EN, 1);
-	EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_ONE_PKT_PER_Q, 1);
-	EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_PUSH_EN, 0);
-	EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_DIS_NON_IP_EV, 1);
-	/* Enable SW_EV to inherit in char driver - assume harmless here */
-	EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_SOFT_EVT_EN, 1);
-	/* Prefetch threshold 2 => fetch when descriptor cache half empty */
-	EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_PREF_THRESHOLD, 2);
-	/* Squash TX of packets of 16 bytes or less */
-	if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0)
-		EFX_SET_OWORD_FIELD(temp, FRF_BZ_TX_FLUSH_MIN_LEN_EN, 1);
-	efx_writeo(efx, &temp, FR_AZ_TX_RESERVED);
-
 	/* Do not enable TX_NO_EOP_DISC_EN, since it limits packets to 16
 	 * descriptors (which is bad).
 	 */
@@ -3161,6 +3170,8 @@ static int falcon_init_nic(struct efx_nic *efx)
 		efx_writeo(efx, &temp, FR_BZ_DP_CTRL);
 	}
 
+	efx_nic_init_common(efx);
+
 	return 0;
 }
 
@@ -3178,7 +3189,7 @@ static void falcon_remove_nic(struct efx_nic *efx)
 	memset(&board->i2c_adap, 0, sizeof(board->i2c_adap));
 
 	falcon_remove_spi_devices(efx);
-	falcon_free_buffer(efx, &efx->irq_status);
+	efx_nic_free_buffer(efx, &efx->irq_status);
 
 	falcon_reset_hw(efx, RESET_TYPE_ALL);
 
diff --git a/drivers/net/sfc/falcon.h b/drivers/net/sfc/falcon.h
index 464c274..875b58e 100644
--- a/drivers/net/sfc/falcon.h
+++ b/drivers/net/sfc/falcon.h
@@ -30,6 +30,14 @@ static inline int efx_nic_rev(struct efx_nic *efx)
 	return efx->type->revision;
 }
 
+extern u32 efx_nic_fpga_ver(struct efx_nic *efx);
+
+/* NIC has two interlinked PCI functions for the same port. */
+static inline bool efx_nic_is_dual_func(struct efx_nic *efx)
+{
+	return efx_nic_rev(efx) < EFX_REV_FALCON_B0;
+}
+
 /**
  * struct falcon_board_type - board operations and type information
  * @id: Board type id, as found in NVRAM
@@ -108,49 +116,65 @@ extern struct efx_nic_type falcon_b0_nic_type;
 extern void falcon_probe_board(struct efx_nic *efx, u16 revision_info);
 
 /* TX data path */
-extern int falcon_probe_tx(struct efx_tx_queue *tx_queue);
-extern void falcon_init_tx(struct efx_tx_queue *tx_queue);
-extern void falcon_fini_tx(struct efx_tx_queue *tx_queue);
-extern void falcon_remove_tx(struct efx_tx_queue *tx_queue);
-extern void falcon_push_buffers(struct efx_tx_queue *tx_queue);
+extern int efx_nic_probe_tx(struct efx_tx_queue *tx_queue);
+extern void efx_nic_init_tx(struct efx_tx_queue *tx_queue);
+extern void efx_nic_fini_tx(struct efx_tx_queue *tx_queue);
+extern void efx_nic_remove_tx(struct efx_tx_queue *tx_queue);
+extern void efx_nic_push_buffers(struct efx_tx_queue *tx_queue);
 
 /* RX data path */
-extern int falcon_probe_rx(struct efx_rx_queue *rx_queue);
-extern void falcon_init_rx(struct efx_rx_queue *rx_queue);
-extern void falcon_fini_rx(struct efx_rx_queue *rx_queue);
-extern void falcon_remove_rx(struct efx_rx_queue *rx_queue);
-extern void falcon_notify_rx_desc(struct efx_rx_queue *rx_queue);
+extern int efx_nic_probe_rx(struct efx_rx_queue *rx_queue);
+extern void efx_nic_init_rx(struct efx_rx_queue *rx_queue);
+extern void efx_nic_fini_rx(struct efx_rx_queue *rx_queue);
+extern void efx_nic_remove_rx(struct efx_rx_queue *rx_queue);
+extern void efx_nic_notify_rx_desc(struct efx_rx_queue *rx_queue);
 
 /* Event data path */
-extern int falcon_probe_eventq(struct efx_channel *channel);
-extern void falcon_init_eventq(struct efx_channel *channel);
-extern void falcon_fini_eventq(struct efx_channel *channel);
-extern void falcon_remove_eventq(struct efx_channel *channel);
-extern int falcon_process_eventq(struct efx_channel *channel, int rx_quota);
-extern void falcon_eventq_read_ack(struct efx_channel *channel);
+extern int efx_nic_probe_eventq(struct efx_channel *channel);
+extern void efx_nic_init_eventq(struct efx_channel *channel);
+extern void efx_nic_fini_eventq(struct efx_channel *channel);
+extern void efx_nic_remove_eventq(struct efx_channel *channel);
+extern int efx_nic_process_eventq(struct efx_channel *channel, int rx_quota);
+extern void efx_nic_eventq_read_ack(struct efx_channel *channel);
 
 /* MAC/PHY */
 extern void falcon_drain_tx_fifo(struct efx_nic *efx);
 extern void falcon_reconfigure_mac_wrapper(struct efx_nic *efx);
+extern int efx_nic_rx_xoff_thresh, efx_nic_rx_xon_thresh;
 
 /* Interrupts and test events */
-extern int falcon_init_interrupt(struct efx_nic *efx);
-extern void falcon_enable_interrupts(struct efx_nic *efx);
-extern void falcon_generate_test_event(struct efx_channel *channel,
-				       unsigned int magic);
-extern void falcon_generate_interrupt(struct efx_nic *efx);
-extern void falcon_disable_interrupts(struct efx_nic *efx);
-extern void falcon_fini_interrupt(struct efx_nic *efx);
-
-#define FALCON_IRQ_MOD_RESOLUTION 5
+extern int efx_nic_init_interrupt(struct efx_nic *efx);
+extern void efx_nic_enable_interrupts(struct efx_nic *efx);
+extern void efx_nic_generate_test_event(struct efx_channel *channel,
+					unsigned int magic);
+extern void efx_nic_generate_interrupt(struct efx_nic *efx);
+extern void efx_nic_disable_interrupts(struct efx_nic *efx);
+extern void efx_nic_fini_interrupt(struct efx_nic *efx);
+extern irqreturn_t efx_nic_fatal_interrupt(struct efx_nic *efx);
+extern irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id);
+extern void falcon_irq_ack_a1(struct efx_nic *efx);
+
+#define EFX_IRQ_MOD_RESOLUTION 5
 
 /* Global Resources */
-extern int falcon_flush_queues(struct efx_nic *efx);
+extern int efx_nic_flush_queues(struct efx_nic *efx);
 extern void falcon_start_nic_stats(struct efx_nic *efx);
 extern void falcon_stop_nic_stats(struct efx_nic *efx);
 extern int falcon_reset_xaui(struct efx_nic *efx);
+extern void efx_nic_init_common(struct efx_nic *efx);
+
+int efx_nic_alloc_buffer(struct efx_nic *efx, struct efx_buffer *buffer,
+			 unsigned int len);
+void efx_nic_free_buffer(struct efx_nic *efx, struct efx_buffer *buffer);
 
 /* Tests */
+struct efx_nic_register_test {
+	unsigned address;
+	efx_oword_t mask;
+};
+extern int efx_nic_test_registers(struct efx_nic *efx,
+				  const struct efx_nic_register_test *regs,
+				  size_t n_regs);
 
 /**************************************************************************
  *
@@ -186,8 +210,8 @@ extern int falcon_reset_xaui(struct efx_nic *efx);
 #define MAC_DATA_LBN 0
 #define MAC_DATA_WIDTH 32
 
-extern void falcon_generate_event(struct efx_channel *channel,
-				  efx_qword_t *event);
+extern void efx_nic_generate_event(struct efx_channel *channel,
+				   efx_qword_t *event);
 
 extern void falcon_poll_xmac(struct efx_nic *efx);
 
diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c
index accf055..8fffd37 100644
--- a/drivers/net/sfc/rx.c
+++ b/drivers/net/sfc/rx.c
@@ -341,7 +341,7 @@ static int __efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue,
 
  out:
 	/* Send write pointer to card. */
-	falcon_notify_rx_desc(rx_queue);
+	efx_nic_notify_rx_desc(rx_queue);
 
 	/* If the fast fill is running inside from the refill tasklet, then
 	 * for SMP systems it may be running on a different CPU to
@@ -640,7 +640,7 @@ int efx_probe_rx_queue(struct efx_rx_queue *rx_queue)
 	if (!rx_queue->buffer)
 		return -ENOMEM;
 
-	rc = falcon_probe_rx(rx_queue);
+	rc = efx_nic_probe_rx(rx_queue);
 	if (rc) {
 		kfree(rx_queue->buffer);
 		rx_queue->buffer = NULL;
@@ -671,7 +671,7 @@ void efx_init_rx_queue(struct efx_rx_queue *rx_queue)
 	rx_queue->fast_fill_limit = limit;
 
 	/* Set up RX descriptor ring */
-	falcon_init_rx(rx_queue);
+	efx_nic_init_rx(rx_queue);
 }
 
 void efx_fini_rx_queue(struct efx_rx_queue *rx_queue)
@@ -681,7 +681,7 @@ void efx_fini_rx_queue(struct efx_rx_queue *rx_queue)
 
 	EFX_LOG(rx_queue->efx, "shutting down RX queue %d\n", rx_queue->queue);
 
-	falcon_fini_rx(rx_queue);
+	efx_nic_fini_rx(rx_queue);
 
 	/* Release RX buffers NB start at index 0 not current HW ptr */
 	if (rx_queue->buffer) {
@@ -706,7 +706,7 @@ void efx_remove_rx_queue(struct efx_rx_queue *rx_queue)
 {
 	EFX_LOG(rx_queue->efx, "destroying RX queue %d\n", rx_queue->queue);
 
-	falcon_remove_rx(rx_queue);
+	efx_nic_remove_rx(rx_queue);
 
 	kfree(rx_queue->buffer);
 	rx_queue->buffer = NULL;
diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c
index fa56e2e..9a24053 100644
--- a/drivers/net/sfc/selftest.c
+++ b/drivers/net/sfc/selftest.c
@@ -164,7 +164,7 @@ static int efx_test_interrupts(struct efx_nic *efx,
 			goto success;
 	}
 
-	falcon_generate_interrupt(efx);
+	efx_nic_generate_interrupt(efx);
 
 	/* Wait for arrival of test interrupt. */
 	EFX_LOG(efx, "waiting for test interrupt\n");
@@ -202,7 +202,7 @@ static int efx_test_eventq_irq(struct efx_channel *channel,
 	channel->eventq_magic = 0;
 	smp_wmb();
 
-	falcon_generate_test_event(channel, magic);
+	efx_nic_generate_test_event(channel, magic);
 
 	/* Wait for arrival of interrupt */
 	count = 0;
diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c
index c54fa30..2531d02 100644
--- a/drivers/net/sfc/tx.c
+++ b/drivers/net/sfc/tx.c
@@ -278,7 +278,7 @@ netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb)
 	buffer->continuation = false;
 
 	/* Pass off to hardware */
-	falcon_push_buffers(tx_queue);
+	efx_nic_push_buffers(tx_queue);
 
 	return NETDEV_TX_OK;
 
@@ -426,7 +426,7 @@ int efx_probe_tx_queue(struct efx_tx_queue *tx_queue)
 		tx_queue->buffer[i].continuation = true;
 
 	/* Allocate hardware ring */
-	rc = falcon_probe_tx(tx_queue);
+	rc = efx_nic_probe_tx(tx_queue);
 	if (rc)
 		goto fail;
 
@@ -449,7 +449,7 @@ void efx_init_tx_queue(struct efx_tx_queue *tx_queue)
 	BUG_ON(tx_queue->stopped);
 
 	/* Set up TX descriptor ring */
-	falcon_init_tx(tx_queue);
+	efx_nic_init_tx(tx_queue);
 }
 
 void efx_release_tx_buffers(struct efx_tx_queue *tx_queue)
@@ -475,7 +475,7 @@ void efx_fini_tx_queue(struct efx_tx_queue *tx_queue)
 	EFX_LOG(tx_queue->efx, "shutting down TX queue %d\n", tx_queue->queue);
 
 	/* Flush TX queue, remove descriptor ring */
-	falcon_fini_tx(tx_queue);
+	efx_nic_fini_tx(tx_queue);
 
 	efx_release_tx_buffers(tx_queue);
 
@@ -492,7 +492,7 @@ void efx_fini_tx_queue(struct efx_tx_queue *tx_queue)
 void efx_remove_tx_queue(struct efx_tx_queue *tx_queue)
 {
 	EFX_LOG(tx_queue->efx, "destroying TX queue %d\n", tx_queue->queue);
-	falcon_remove_tx(tx_queue);
+	efx_nic_remove_tx(tx_queue);
 
 	kfree(tx_queue->buffer);
 	tx_queue->buffer = NULL;
@@ -1078,7 +1078,7 @@ static int efx_enqueue_skb_tso(struct efx_tx_queue *tx_queue,
 	}
 
 	/* Pass off to hardware */
-	falcon_push_buffers(tx_queue);
+	efx_nic_push_buffers(tx_queue);
 
 	tx_queue->tso_bursts++;
 	return NETDEV_TX_OK;

-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.


^ permalink raw reply related

* [PATCH 25/32] sfc: Fold falcon_probe_nic_variant() into falcon_probe_nic()
From: Ben Hutchings @ 2009-11-28  3:51 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, linux-net-drivers

falcon_probe_nic_variant() does a lot less than it used to, and a
lot less than it claims to.  Fold the remainder into its caller.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 drivers/net/sfc/falcon.c |   64 +++++++++++++++++----------------------------
 1 files changed, 24 insertions(+), 40 deletions(-)

diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index 9eb3bfb..dbd0d62 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -2806,40 +2806,6 @@ u32 efx_nic_fpga_ver(struct efx_nic *efx)
 	return EFX_OWORD_FIELD(altera_build, FRF_AZ_ALTERA_BUILD_VER);
 }
 
-/* Probe the NIC variant (revision, ASIC vs FPGA, function count, port
- * count, port speed).  Set workaround and feature flags accordingly.
- */
-static int falcon_probe_nic_variant(struct efx_nic *efx)
-{
-	efx_oword_t nic_stat;
-
-	if (efx_nic_fpga_ver(efx) != 0) {
-		EFX_ERR(efx, "Falcon FPGA not supported\n");
-		return -ENODEV;
-	}
-
-	efx_reado(efx, &nic_stat, FR_AB_NIC_STAT);
-
-	if (efx_nic_rev(efx) <= EFX_REV_FALCON_A1) {
-		u8 pci_rev = efx->pci_dev->revision;
-
-		if ((pci_rev == 0xff) || (pci_rev == 0)) {
-			EFX_ERR(efx, "Falcon rev A0 not supported\n");
-			return -ENODEV;
-		}
-		if (EFX_OWORD_FIELD(nic_stat, FRF_AB_STRAP_10G) == 0) {
-			EFX_ERR(efx, "Falcon rev A1 1G not supported\n");
-			return -ENODEV;
-		}
-		if (EFX_OWORD_FIELD(nic_stat, FRF_AA_STRAP_PCIE) == 0) {
-			EFX_ERR(efx, "Falcon rev A1 PCI-X not supported\n");
-			return -ENODEV;
-		}
-	}
-
-	return 0;
-}
-
 /* Probe all SPI devices on the NIC */
 static void falcon_probe_spi_devices(struct efx_nic *efx)
 {
@@ -2891,15 +2857,33 @@ static int falcon_probe_nic(struct efx_nic *efx)
 		return -ENOMEM;
 	efx->nic_data = nic_data;
 
-	/* Determine number of ports etc. */
-	rc = falcon_probe_nic_variant(efx);
-	if (rc)
+	rc = -ENODEV;
+
+	if (efx_nic_fpga_ver(efx) != 0) {
+		EFX_ERR(efx, "Falcon FPGA not supported\n");
 		goto fail1;
+	}
+
+	if (efx_nic_rev(efx) <= EFX_REV_FALCON_A1) {
+		efx_oword_t nic_stat;
+		struct pci_dev *dev;
+		u8 pci_rev = efx->pci_dev->revision;
 
-	/* Probe secondary function if expected */
-	if (efx_nic_is_dual_func(efx)) {
-		struct pci_dev *dev = pci_dev_get(efx->pci_dev);
+		if ((pci_rev == 0xff) || (pci_rev == 0)) {
+			EFX_ERR(efx, "Falcon rev A0 not supported\n");
+			goto fail1;
+		}
+		efx_reado(efx, &nic_stat, FR_AB_NIC_STAT);
+		if (EFX_OWORD_FIELD(nic_stat, FRF_AB_STRAP_10G) == 0) {
+			EFX_ERR(efx, "Falcon rev A1 1G not supported\n");
+			goto fail1;
+		}
+		if (EFX_OWORD_FIELD(nic_stat, FRF_AA_STRAP_PCIE) == 0) {
+			EFX_ERR(efx, "Falcon rev A1 PCI-X not supported\n");
+			goto fail1;
+		}
 
+		dev = pci_dev_get(efx->pci_dev);
 		while ((dev = pci_get_device(EFX_VENDID_SFC, FALCON_A_S_DEVID,
 					     dev))) {
 			if (dev->bus == efx->pci_dev->bus &&

-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.


^ permalink raw reply related

* [PATCH 26/32] sfc: Extend loopback mode enumeration
From: Ben Hutchings @ 2009-11-28  3:51 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, linux-net-drivers

New NICs and PHYs support a wider variety of loopback modes.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 drivers/net/sfc/efx.c         |   19 +++++++-
 drivers/net/sfc/enum.h        |  106 +++++++++++++++++++++++++++++++++--------
 drivers/net/sfc/falcon_xmac.c |    2 +-
 drivers/net/sfc/mdio_10g.c    |    4 +-
 drivers/net/sfc/net_driver.h  |    2 +-
 drivers/net/sfc/qt202x_phy.c  |    2 +-
 drivers/net/sfc/tenxpress.c   |    4 +-
 7 files changed, 111 insertions(+), 28 deletions(-)

diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index 3477408..fec11d6 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -36,15 +36,32 @@
 const unsigned int efx_loopback_mode_max = LOOPBACK_MAX;
 const char *efx_loopback_mode_names[] = {
 	[LOOPBACK_NONE]		= "NONE",
+	[LOOPBACK_DATA]		= "DATAPATH",
 	[LOOPBACK_GMAC]		= "GMAC",
 	[LOOPBACK_XGMII]	= "XGMII",
 	[LOOPBACK_XGXS]		= "XGXS",
 	[LOOPBACK_XAUI]  	= "XAUI",
+	[LOOPBACK_GMII] 	= "GMII",
+	[LOOPBACK_SGMII] 	= "SGMII",
+	[LOOPBACK_XGBR]		= "XGBR",
+	[LOOPBACK_XFI]		= "XFI",
+	[LOOPBACK_XAUI_FAR]	= "XAUI_FAR",
+	[LOOPBACK_GMII_FAR]	= "GMII_FAR",
+	[LOOPBACK_SGMII_FAR]	= "SGMII_FAR",
+	[LOOPBACK_XFI_FAR]	= "XFI_FAR",
 	[LOOPBACK_GPHY]		= "GPHY",
 	[LOOPBACK_PHYXS]	= "PHYXS",
 	[LOOPBACK_PCS]	 	= "PCS",
 	[LOOPBACK_PMAPMD] 	= "PMA/PMD",
-	[LOOPBACK_NETWORK]	= "NETWORK",
+	[LOOPBACK_XPORT]	= "XPORT",
+	[LOOPBACK_XGMII_WS]	= "XGMII_WS",
+	[LOOPBACK_XAUI_WS]  	= "XAUI_WS",
+	[LOOPBACK_XAUI_WS_FAR]  = "XAUI_WS_FAR",
+	[LOOPBACK_XAUI_WS_NEAR] = "XAUI_WS_NEAR",
+	[LOOPBACK_GMII_WS] 	= "GMII_WS",
+	[LOOPBACK_XFI_WS]	= "XFI_WS",
+	[LOOPBACK_XFI_WS_FAR]	= "XFI_WS_FAR",
+	[LOOPBACK_PHYXS_WS]  	= "PHYXS_WS",
 };
 
 /* Interrupt mode names (see INT_MODE())) */
diff --git a/drivers/net/sfc/enum.h b/drivers/net/sfc/enum.h
index fcd14b7..7a9e79a 100644
--- a/drivers/net/sfc/enum.h
+++ b/drivers/net/sfc/enum.h
@@ -13,38 +13,101 @@
 /**
  * enum efx_loopback_mode - loopback modes
  * @LOOPBACK_NONE: no loopback
- * @LOOPBACK_GMAC: loopback within GMAC at unspecified level
- * @LOOPBACK_XGMII: loopback within XMAC at XGMII level
- * @LOOPBACK_XGXS: loopback within XMAC at XGXS level
- * @LOOPBACK_XAUI: loopback within XMAC at XAUI level
+ * @LOOPBACK_DATA: data path loopback
+ * @LOOPBACK_GMAC: loopback within GMAC
+ * @LOOPBACK_XGMII: loopback after XMAC
+ * @LOOPBACK_XGXS: loopback within BPX after XGXS
+ * @LOOPBACK_XAUI: loopback within BPX before XAUI serdes
+ * @LOOPBACK_GMII: loopback within BPX after GMAC
+ * @LOOPBACK_SGMII: loopback within BPX within SGMII
+ * @LOOPBACK_XGBR: loopback within BPX within XGBR
+ * @LOOPBACK_XFI: loopback within BPX before XFI serdes
+ * @LOOPBACK_XAUI_FAR: loopback within BPX after XAUI serdes
+ * @LOOPBACK_GMII_FAR: loopback within BPX before SGMII
+ * @LOOPBACK_SGMII_FAR: loopback within BPX after SGMII
+ * @LOOPBACK_XFI_FAR: loopback after XFI serdes
  * @LOOPBACK_GPHY: loopback within 1G PHY at unspecified 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_XPORT: cross port loopback
+ * @LOOPBACK_XGMII_WS: wireside loopback excluding XMAC
+ * @LOOPBACK_XAUI_WS: wireside loopback within BPX within XAUI serdes
+ * @LOOPBACK_XAUI_WS_FAR: wireside loopback within BPX including XAUI serdes
+ * @LOOPBACK_XAUI_WS_NEAR: wireside loopback within BPX excluding XAUI serdes
+ * @LOOPBACK_GMII_WS: wireside loopback excluding GMAC
+ * @LOOPBACK_XFI_WS: wireside loopback excluding XFI serdes
+ * @LOOPBACK_XFI_WS_FAR: wireside loopback including XFI serdes
+ * @LOOPBACK_PHYXS_WS: wireside loopback within 10G PHY at PHYXS level
  */
-/* Please keep in order and up-to-date w.r.t the following two #defines */
+/* Please keep up-to-date w.r.t the following two #defines */
 enum efx_loopback_mode {
 	LOOPBACK_NONE = 0,
-	LOOPBACK_GMAC = 1,
-	LOOPBACK_XGMII = 2,
-	LOOPBACK_XGXS = 3,
-	LOOPBACK_XAUI = 4,
-	LOOPBACK_GPHY = 5,
-	LOOPBACK_PHYXS = 6,
-	LOOPBACK_PCS = 7,
-	LOOPBACK_PMAPMD = 8,
-	LOOPBACK_NETWORK = 9,
+	LOOPBACK_DATA = 1,
+	LOOPBACK_GMAC = 2,
+	LOOPBACK_XGMII = 3,
+	LOOPBACK_XGXS = 4,
+	LOOPBACK_XAUI = 5,
+	LOOPBACK_GMII = 6,
+	LOOPBACK_SGMII = 7,
+	LOOPBACK_XGBR = 8,
+	LOOPBACK_XFI = 9,
+	LOOPBACK_XAUI_FAR = 10,
+	LOOPBACK_GMII_FAR = 11,
+	LOOPBACK_SGMII_FAR = 12,
+	LOOPBACK_XFI_FAR = 13,
+	LOOPBACK_GPHY = 14,
+	LOOPBACK_PHYXS = 15,
+	LOOPBACK_PCS = 16,
+	LOOPBACK_PMAPMD = 17,
+	LOOPBACK_XPORT = 18,
+	LOOPBACK_XGMII_WS = 19,
+	LOOPBACK_XAUI_WS = 20,
+	LOOPBACK_XAUI_WS_FAR = 21,
+	LOOPBACK_XAUI_WS_NEAR = 22,
+	LOOPBACK_GMII_WS = 23,
+	LOOPBACK_XFI_WS = 24,
+	LOOPBACK_XFI_WS_FAR = 25,
+	LOOPBACK_PHYXS_WS = 26,
 	LOOPBACK_MAX
 };
-
 #define LOOPBACK_TEST_MAX LOOPBACK_PMAPMD
 
 /* These loopbacks occur within the controller */
-#define LOOPBACKS_INTERNAL ((1 << LOOPBACK_GMAC) |     \
-			    (1 << LOOPBACK_XGMII)|     \
-			    (1 << LOOPBACK_XGXS) |     \
-			    (1 << LOOPBACK_XAUI))
+#define LOOPBACKS_INTERNAL ((1 << LOOPBACK_DATA) |		\
+			    (1 << LOOPBACK_GMAC) |		\
+			    (1 << LOOPBACK_XGMII)|		\
+			    (1 << LOOPBACK_XGXS) |		\
+			    (1 << LOOPBACK_XAUI) |		\
+			    (1 << LOOPBACK_GMII) |		\
+			    (1 << LOOPBACK_SGMII) |		\
+			    (1 << LOOPBACK_SGMII) |		\
+			    (1 << LOOPBACK_XGBR) |		\
+			    (1 << LOOPBACK_XFI) |		\
+			    (1 << LOOPBACK_XAUI_FAR) |		\
+			    (1 << LOOPBACK_GMII_FAR) |		\
+			    (1 << LOOPBACK_SGMII_FAR) |		\
+			    (1 << LOOPBACK_XFI_FAR) |		\
+			    (1 << LOOPBACK_XGMII_WS) |		\
+			    (1 << LOOPBACK_XAUI_WS) |		\
+			    (1 << LOOPBACK_XAUI_WS_FAR) |	\
+			    (1 << LOOPBACK_XAUI_WS_NEAR) |	\
+			    (1 << LOOPBACK_GMII_WS) |		\
+			    (1 << LOOPBACK_XFI_WS) |		\
+			    (1 << LOOPBACK_XFI_WS_FAR))
+
+#define LOOPBACKS_WS ((1 << LOOPBACK_XGMII_WS) |		\
+		      (1 << LOOPBACK_XAUI_WS) |			\
+		      (1 << LOOPBACK_XAUI_WS_FAR) |		\
+		      (1 << LOOPBACK_XAUI_WS_NEAR) |		\
+		      (1 << LOOPBACK_GMII_WS) |			\
+		      (1 << LOOPBACK_XFI_WS) |			\
+		      (1 << LOOPBACK_XFI_WS_FAR) |		\
+		      (1 << LOOPBACK_PHYXS_WS))
+
+#define LOOPBACKS_EXTERNAL(_efx)					\
+	((_efx)->loopback_modes & ~LOOPBACKS_INTERNAL &			\
+	 ~(1 << LOOPBACK_NONE))
 
 #define LOOPBACK_MASK(_efx)			\
 	(1 << (_efx)->loopback_mode)
@@ -52,6 +115,9 @@ enum efx_loopback_mode {
 #define LOOPBACK_INTERNAL(_efx)				\
 	(!!(LOOPBACKS_INTERNAL & LOOPBACK_MASK(_efx)))
 
+#define LOOPBACK_EXTERNAL(_efx)				\
+	(!!(LOOPBACK_MASK(_efx) & LOOPBACKS_EXTERNAL(_efx)))
+
 #define LOOPBACK_CHANGED(_from, _to, _mask)				\
 	(!!((LOOPBACK_MASK(_from) ^ LOOPBACK_MASK(_to)) & (_mask)))
 
diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c
index 898afc1..83da792 100644
--- a/drivers/net/sfc/falcon_xmac.c
+++ b/drivers/net/sfc/falcon_xmac.c
@@ -249,7 +249,7 @@ static bool falcon_check_xaui_link_up(struct efx_nic *efx, int tries)
 {
 	bool mac_up = falcon_xaui_link_ok(efx);
 
-	if ((efx->loopback_mode == LOOPBACK_NETWORK) ||
+	if (LOOPBACK_MASK(efx) & LOOPBACKS_EXTERNAL(efx) & LOOPBACKS_WS ||
 	    efx_phy_mode_disabled(efx->phy_mode))
 		/* XAUI link is expected to be down */
 		return mac_up;
diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c
index 1f62a5c..e6ca988 100644
--- a/drivers/net/sfc/mdio_10g.c
+++ b/drivers/net/sfc/mdio_10g.c
@@ -173,7 +173,7 @@ bool efx_mdio_links_ok(struct efx_nic *efx, unsigned int mmd_mask)
 	 * of mmd's */
 	if (LOOPBACK_INTERNAL(efx))
 		return true;
-	else if (efx->loopback_mode == LOOPBACK_NETWORK)
+	else if (LOOPBACK_MASK(efx) & LOOPBACKS_WS)
 		return false;
 	else if (efx_phy_mode_disabled(efx->phy_mode))
 		return false;
@@ -210,7 +210,7 @@ void efx_mdio_phy_reconfigure(struct efx_nic *efx)
 			  efx->loopback_mode == LOOPBACK_PCS);
 	efx_mdio_set_flag(efx, MDIO_MMD_PHYXS,
 			  MDIO_CTRL1, MDIO_PHYXS_CTRL1_LOOPBACK,
-			  efx->loopback_mode == LOOPBACK_NETWORK);
+			  efx->loopback_mode == LOOPBACK_PHYXS_WS);
 }
 
 static void efx_mdio_set_mmd_lpower(struct efx_nic *efx,
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index 16db934..28fd538 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -824,7 +824,7 @@ struct efx_nic {
 
 	atomic_t rx_reset;
 	enum efx_loopback_mode loopback_mode;
-	unsigned int loopback_modes;
+	u64 loopback_modes;
 
 	void *loopback_selftest;
 };
diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c
index 4c38516..49a5ab5 100644
--- a/drivers/net/sfc/qt202x_phy.c
+++ b/drivers/net/sfc/qt202x_phy.c
@@ -23,7 +23,7 @@
 
 #define QT202X_LOOPBACKS ((1 << LOOPBACK_PCS) |		\
 			  (1 << LOOPBACK_PMAPMD) |	\
-			  (1 << LOOPBACK_NETWORK))
+			  (1 << LOOPBACK_PHYXS_WS))
 
 /****************************************************************************/
 /* Quake-specific MDIO registers */
diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c
index c301853..0dfb227 100644
--- a/drivers/net/sfc/tenxpress.c
+++ b/drivers/net/sfc/tenxpress.c
@@ -30,13 +30,13 @@
 #define SFX7101_LOOPBACKS ((1 << LOOPBACK_PHYXS) |	\
 			   (1 << LOOPBACK_PCS) |	\
 			   (1 << LOOPBACK_PMAPMD) |	\
-			   (1 << LOOPBACK_NETWORK))
+			   (1 << LOOPBACK_PHYXS_WS))
 
 #define SFT9001_LOOPBACKS ((1 << LOOPBACK_GPHY) |	\
 			   (1 << LOOPBACK_PHYXS) |	\
 			   (1 << LOOPBACK_PCS) |	\
 			   (1 << LOOPBACK_PMAPMD) |	\
-			   (1 << LOOPBACK_NETWORK))
+			   (1 << LOOPBACK_PHYXS_WS))
 
 /* We complain if we fail to see the link partner as 10G capable this many
  * times in a row (must be > 1 as sampling the autoneg. registers is racy)

-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.


^ permalink raw reply related

* [PATCH 27/32] sfc: Remove static PHY data and enumerations
From: Ben Hutchings @ 2009-11-28  3:51 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, linux-net-drivers

New NICs have firmware managing the PHY, and we will discover the PHY
capabilities at run-time.  Replace the static data with probe() and
test_name() operations.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 drivers/net/sfc/ethtool.c     |   18 ++++++++++++--
 drivers/net/sfc/falcon.c      |   15 +++---------
 drivers/net/sfc/falcon.h      |   20 ++++++++++++++++
 drivers/net/sfc/falcon_xmac.c |    2 +-
 drivers/net/sfc/mdio_10g.c    |    4 +-
 drivers/net/sfc/net_driver.h  |   35 +++++------------------------
 drivers/net/sfc/qt202x_phy.c  |   12 +++++++--
 drivers/net/sfc/selftest.c    |    5 +---
 drivers/net/sfc/tenxpress.c   |   49 +++++++++++++++++++++++++++++++----------
 9 files changed, 95 insertions(+), 65 deletions(-)

diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c
index 643ce49..5c18ca5 100644
--- a/drivers/net/sfc/ethtool.c
+++ b/drivers/net/sfc/ethtool.c
@@ -365,9 +365,21 @@ static int efx_ethtool_fill_self_tests(struct efx_nic *efx,
 	efx_fill_test(n++, strings, data, &tests->registers,
 		      "core", 0, "registers", NULL);
 
-	for (i = 0; i < efx->phy_op->num_tests; i++)
-		efx_fill_test(n++, strings, data, &tests->phy[i],
-			      "phy", 0, efx->phy_op->test_names[i], NULL);
+	if (efx->phy_op->run_tests != NULL) {
+		EFX_BUG_ON_PARANOID(efx->phy_op->test_name == NULL);
+
+		for (i = 0; true; ++i) {
+			const char *name;
+
+			EFX_BUG_ON_PARANOID(i >= EFX_MAX_PHY_TESTS);
+			name = efx->phy_op->test_name(efx, i);
+			if (name == NULL)
+				break;
+
+			efx_fill_test(n++, strings, data, &tests->phy[i],
+				      "phy", 0, name, NULL);
+		}
+	}
 
 	/* Loopback tests */
 	for (mode = LOOPBACK_NONE; mode <= LOOPBACK_TEST_MAX; mode++) {
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index dbd0d62..0a7c3d2 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -2291,19 +2291,12 @@ static int falcon_probe_port(struct efx_nic *efx)
 		return -ENODEV;
 	}
 
-	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;
-
-	/* Set up MDIO structure for PHY */
-	efx->mdio.mmds = efx->phy_op->mmds;
-	efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22;
+	/* Fill out MDIO structure and loopback modes */
 	efx->mdio.mdio_read = falcon_mdio_read;
 	efx->mdio.mdio_write = falcon_mdio_write;
+	rc = efx->phy_op->probe(efx);
+	if (rc != 0)
+		return rc;
 
 	/* Initial assumption */
 	efx->link_state.speed = 10000;
diff --git a/drivers/net/sfc/falcon.h b/drivers/net/sfc/falcon.h
index 875b58e..3085ecf 100644
--- a/drivers/net/sfc/falcon.h
+++ b/drivers/net/sfc/falcon.h
@@ -38,6 +38,26 @@ static inline bool efx_nic_is_dual_func(struct efx_nic *efx)
 	return efx_nic_rev(efx) < EFX_REV_FALCON_B0;
 }
 
+enum {
+	PHY_TYPE_NONE = 0,
+	PHY_TYPE_TXC43128 = 1,
+	PHY_TYPE_88E1111 = 2,
+	PHY_TYPE_SFX7101 = 3,
+	PHY_TYPE_QT2022C2 = 4,
+	PHY_TYPE_PM8358 = 6,
+	PHY_TYPE_SFT9001A = 8,
+	PHY_TYPE_QT2025C = 9,
+	PHY_TYPE_SFT9001B = 10,
+};
+
+#define FALCON_XMAC_LOOPBACKS			\
+	((1 << LOOPBACK_XGMII) |		\
+	 (1 << LOOPBACK_XGXS) |			\
+	 (1 << LOOPBACK_XAUI))
+
+#define FALCON_GMAC_LOOPBACKS			\
+	(1 << LOOPBACK_GMAC)
+
 /**
  * struct falcon_board_type - board operations and type information
  * @id: Board type id, as found in NVRAM
diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c
index 83da792..643622d 100644
--- a/drivers/net/sfc/falcon_xmac.c
+++ b/drivers/net/sfc/falcon_xmac.c
@@ -137,7 +137,7 @@ static bool falcon_xaui_link_ok(struct efx_nic *efx)
 
 	/* If the link is up, then check the phy side of the xaui link */
 	if (efx->link_state.up && link_ok)
-		if (efx->phy_op->mmds & (1 << MDIO_MMD_PHYXS))
+		if (efx->mdio.mmds & (1 << MDIO_MMD_PHYXS))
 			link_ok = efx_mdio_phyxgxs_lane_sync(efx);
 
 	return link_ok;
diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c
index e6ca988..20e6274 100644
--- a/drivers/net/sfc/mdio_10g.c
+++ b/drivers/net/sfc/mdio_10g.c
@@ -15,6 +15,7 @@
 #include "net_driver.h"
 #include "mdio_10g.h"
 #include "workarounds.h"
+#include "falcon.h"
 
 unsigned efx_mdio_id_oui(u32 id)
 {
@@ -312,8 +313,7 @@ void efx_mdio_an_reconfigure(struct efx_nic *efx)
 	/* Enable and restart AN */
 	reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_CTRL1);
 	reg |= MDIO_AN_CTRL1_ENABLE;
-	if (!(EFX_WORKAROUND_15195(efx) &&
-	      LOOPBACK_MASK(efx) & efx->phy_op->loopbacks))
+	if (!(EFX_WORKAROUND_15195(efx) && LOOPBACK_EXTERNAL(efx)))
 		reg |= MDIO_AN_CTRL1_RESTART;
 	if (xnp)
 		reg |= MDIO_AN_CTRL1_XNP;
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index 28fd538..4ec6ef3 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -428,19 +428,6 @@ enum efx_int_mode {
 };
 #define EFX_INT_MODE_USE_MSI(x) (((x)->interrupt_mode) <= EFX_INT_MODE_MSI)
 
-enum phy_type {
-	PHY_TYPE_NONE = 0,
-	PHY_TYPE_TXC43128 = 1,
-	PHY_TYPE_88E1111 = 2,
-	PHY_TYPE_SFX7101 = 3,
-	PHY_TYPE_QT2022C2 = 4,
-	PHY_TYPE_PM8358 = 6,
-	PHY_TYPE_SFT9001A = 8,
-	PHY_TYPE_QT2025C = 9,
-	PHY_TYPE_SFT9001B = 10,
-	PHY_TYPE_MAX	/* Insert any new items before this */
-};
-
 #define EFX_IS10G(efx) ((efx)->link_state.speed == 10000)
 
 enum nic_state {
@@ -483,12 +470,6 @@ enum efx_fc_type {
 	EFX_FC_AUTO = 4,
 };
 
-/* Supported MAC bit-mask */
-enum efx_mac_type {
-	EFX_GMAC = 1,
-	EFX_XMAC = 2,
-};
-
 /**
  * struct efx_link_state - Current state of the link
  * @up: Link is up
@@ -524,6 +505,8 @@ struct efx_mac_operations {
 
 /**
  * struct efx_phy_operations - Efx PHY operations table
+ * @probe: Probe PHY and initialise efx->mdio.mode_support, efx->mdio.mmds,
+ *	efx->loopback_modes.
  * @init: Initialise PHY
  * @fini: Shut down PHY
  * @reconfigure: Reconfigure PHY (e.g. for new link parameters)
@@ -533,15 +516,12 @@ struct efx_mac_operations {
  * @set_settings: Set ethtool settings. Serialised by the mac_lock.
  * @set_npage_adv: Set abilities advertised in (Extended) Next Page
  *	(only needed where AN bit is set in mmds)
- * @num_tests: Number of PHY-specific tests/results
- * @test_names: Names of the tests/results
+ * @test_name: Get the name of a PHY-specific test/result
  * @run_tests: Run tests and record results as appropriate.
  *	Flags are the ethtool tests flags.
- * @mmds: MMD presence mask
- * @loopbacks: Supported loopback modes mask
  */
 struct efx_phy_operations {
-	enum efx_mac_type macs;
+	int (*probe) (struct efx_nic *efx);
 	int (*init) (struct efx_nic *efx);
 	void (*fini) (struct efx_nic *efx);
 	int (*reconfigure) (struct efx_nic *efx);
@@ -551,11 +531,8 @@ struct efx_phy_operations {
 	int (*set_settings) (struct efx_nic *efx,
 			     struct ethtool_cmd *ecmd);
 	void (*set_npage_adv) (struct efx_nic *efx, u32);
-	u32 num_tests;
-	const char *const *test_names;
+	const char *(*test_name) (struct efx_nic *efx, unsigned int index);
 	int (*run_tests) (struct efx_nic *efx, int *results, unsigned flags);
-	int mmds;
-	unsigned loopbacks;
 };
 
 /**
@@ -806,7 +783,7 @@ struct efx_nic {
 	struct efx_mac_operations *mac_op;
 	unsigned char mac_address[ETH_ALEN];
 
-	enum phy_type phy_type;
+	unsigned int phy_type;
 	struct mutex mdio_lock;
 	struct efx_phy_operations *phy_op;
 	void *phy_data;
diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c
index 49a5ab5..22b0e89 100644
--- a/drivers/net/sfc/qt202x_phy.c
+++ b/drivers/net/sfc/qt202x_phy.c
@@ -135,6 +135,14 @@ static int qt202x_reset_phy(struct efx_nic *efx)
 	return rc;
 }
 
+static int qt202x_phy_probe(struct efx_nic *efx)
+{
+	efx->mdio.mmds = QT202X_REQUIRED_DEVS;
+	efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22;
+	efx->loopback_modes = QT202X_LOOPBACKS | FALCON_XMAC_LOOPBACKS;
+	return 0;
+}
+
 static int qt202x_phy_init(struct efx_nic *efx)
 {
 	struct qt202x_phy_data *phy_data;
@@ -224,13 +232,11 @@ static void qt202x_phy_fini(struct efx_nic *efx)
 }
 
 struct efx_phy_operations falcon_qt202x_phy_ops = {
-	.macs		 = EFX_XMAC,
+	.probe		 = qt202x_phy_probe,
 	.init		 = qt202x_phy_init,
 	.reconfigure	 = qt202x_phy_reconfigure,
 	.poll	     	 = qt202x_phy_poll,
 	.fini	  	 = qt202x_phy_fini,
 	.get_settings	 = qt202x_phy_get_settings,
 	.set_settings	 = efx_mdio_set_settings,
-	.mmds            = QT202X_REQUIRED_DEVS,
-	.loopbacks       = QT202X_LOOPBACKS,
 };
diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c
index 9a24053..16258d8 100644
--- a/drivers/net/sfc/selftest.c
+++ b/drivers/net/sfc/selftest.c
@@ -100,7 +100,7 @@ static int efx_test_mdio(struct efx_nic *efx, struct efx_self_tests *tests)
 	}
 
 	if (EFX_IS10G(efx)) {
-		rc = efx_mdio_check_mmds(efx, efx->phy_op->mmds, 0);
+		rc = efx_mdio_check_mmds(efx, efx->mdio.mmds, 0);
 		if (rc)
 			goto out;
 	}
@@ -253,9 +253,6 @@ static int efx_test_phy(struct efx_nic *efx, struct efx_self_tests *tests,
 	if (!efx->phy_op->run_tests)
 		return 0;
 
-	EFX_BUG_ON_PARANOID(efx->phy_op->num_tests == 0 ||
-			    efx->phy_op->num_tests > EFX_MAX_PHY_TESTS);
-
 	mutex_lock(&efx->mac_lock);
 	rc = efx->phy_op->run_tests(efx, tests->phy, flags);
 	mutex_unlock(&efx->mac_lock);
diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c
index 0dfb227..8de97a9 100644
--- a/drivers/net/sfc/tenxpress.c
+++ b/drivers/net/sfc/tenxpress.c
@@ -298,6 +298,23 @@ static int tenxpress_init(struct efx_nic *efx)
 	return 0;
 }
 
+static int sfx7101_phy_probe(struct efx_nic *efx)
+{
+	efx->mdio.mmds = TENXPRESS_REQUIRED_DEVS;
+	efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22;
+	efx->loopback_modes = SFX7101_LOOPBACKS | FALCON_XMAC_LOOPBACKS;
+	return 0;
+}
+
+static int sft9001_phy_probe(struct efx_nic *efx)
+{
+	efx->mdio.mmds = TENXPRESS_REQUIRED_DEVS;
+	efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22;
+	efx->loopback_modes = (SFT9001_LOOPBACKS | FALCON_XMAC_LOOPBACKS |
+			       FALCON_GMAC_LOOPBACKS);
+	return 0;
+}
+
 static int tenxpress_phy_init(struct efx_nic *efx)
 {
 	struct tenxpress_phy_data *phy_data;
@@ -512,7 +529,7 @@ static int tenxpress_phy_reconfigure(struct efx_nic *efx)
 
 	phy_mode_change = (efx->phy_mode == PHY_MODE_NORMAL &&
 			   phy_data->phy_mode != PHY_MODE_NORMAL);
-	loop_reset = (LOOPBACK_OUT_OF(phy_data, efx, efx->phy_op->loopbacks) ||
+	loop_reset = (LOOPBACK_OUT_OF(phy_data, efx, LOOPBACKS_EXTERNAL(efx)) ||
 		      LOOPBACK_CHANGED(phy_data, efx, 1 << LOOPBACK_GPHY));
 
 	if (loop_reset || phy_mode_change) {
@@ -627,6 +644,13 @@ static const char *const sfx7101_test_names[] = {
 	"bist"
 };
 
+static const char *sfx7101_test_name(struct efx_nic *efx, unsigned int index)
+{
+	if (index < ARRAY_SIZE(sfx7101_test_names))
+		return sfx7101_test_names[index];
+	return NULL;
+}
+
 static int
 sfx7101_run_tests(struct efx_nic *efx, int *results, unsigned flags)
 {
@@ -656,6 +680,13 @@ static const char *const sft9001_test_names[] = {
 	"cable.pairD.length",
 };
 
+static const char *sft9001_test_name(struct efx_nic *efx, unsigned int index)
+{
+	if (index < ARRAY_SIZE(sft9001_test_names))
+		return sft9001_test_names[index];
+	return NULL;
+}
+
 static int sft9001_run_tests(struct efx_nic *efx, int *results, unsigned flags)
 {
 	int rc = 0, rc2, i, ctrl_reg, res_reg;
@@ -758,7 +789,7 @@ tenxpress_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
 	 * but doesn't advertise the correct speed. So override it */
 	if (efx->loopback_mode == LOOPBACK_GPHY)
 		ecmd->speed = SPEED_1000;
-	else if (LOOPBACK_MASK(efx) & efx->phy_op->loopbacks)
+	else if (LOOPBACK_EXTERNAL(efx))
 		ecmd->speed = SPEED_10000;
 }
 
@@ -788,7 +819,7 @@ static void sft9001_set_npage_adv(struct efx_nic *efx, u32 advertising)
 }
 
 struct efx_phy_operations falcon_sfx7101_phy_ops = {
-	.macs		  = EFX_XMAC,
+	.probe		  = sfx7101_phy_probe,
 	.init             = tenxpress_phy_init,
 	.reconfigure      = tenxpress_phy_reconfigure,
 	.poll             = tenxpress_phy_poll,
@@ -796,15 +827,12 @@ struct efx_phy_operations falcon_sfx7101_phy_ops = {
 	.get_settings	  = tenxpress_get_settings,
 	.set_settings	  = tenxpress_set_settings,
 	.set_npage_adv    = sfx7101_set_npage_adv,
-	.num_tests	  = ARRAY_SIZE(sfx7101_test_names),
-	.test_names	  = sfx7101_test_names,
+	.test_name	  = sfx7101_test_name,
 	.run_tests	  = sfx7101_run_tests,
-	.mmds             = TENXPRESS_REQUIRED_DEVS,
-	.loopbacks        = SFX7101_LOOPBACKS,
 };
 
 struct efx_phy_operations falcon_sft9001_phy_ops = {
-	.macs		  = EFX_GMAC | EFX_XMAC,
+	.probe		  = sft9001_phy_probe,
 	.init             = tenxpress_phy_init,
 	.reconfigure      = tenxpress_phy_reconfigure,
 	.poll             = tenxpress_phy_poll,
@@ -812,9 +840,6 @@ struct efx_phy_operations falcon_sft9001_phy_ops = {
 	.get_settings	  = tenxpress_get_settings,
 	.set_settings	  = tenxpress_set_settings,
 	.set_npage_adv    = sft9001_set_npage_adv,
-	.num_tests	  = ARRAY_SIZE(sft9001_test_names),
-	.test_names	  = sft9001_test_names,
+	.test_name	  = sft9001_test_name,
 	.run_tests	  = sft9001_run_tests,
-	.mmds             = TENXPRESS_REQUIRED_DEVS,
-	.loopbacks        = SFT9001_LOOPBACKS,
 };

-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.


^ permalink raw reply related

* [PATCH 28/32] sfc: Extend MTD driver for use with new NICs
From: Ben Hutchings @ 2009-11-28  3:51 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, linux-net-drivers

In new NICs flash is managed by firmware and we will use high-level
operations on partitions rather than direct SPI commands.  Add support
for multiple MTD partitions per flash device and remove the direct
link between MTD and SPI devices.  Maintain a list of MTD partitions
in struct efx_nic.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 drivers/net/sfc/efx.c        |    3 +
 drivers/net/sfc/ethtool.c    |    6 +-
 drivers/net/sfc/falcon.c     |   32 ++---
 drivers/net/sfc/mtd.c        |  312 +++++++++++++++++++++++++++++-------------
 drivers/net/sfc/net_driver.h |    8 +-
 drivers/net/sfc/spi.h        |   18 +--
 6 files changed, 255 insertions(+), 124 deletions(-)

diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index fec11d6..c49d364 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -1977,6 +1977,9 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type,
 	spin_lock_init(&efx->biu_lock);
 	mutex_init(&efx->mdio_lock);
 	mutex_init(&efx->spi_lock);
+#ifdef CONFIG_SFC_MTD
+	INIT_LIST_HEAD(&efx->mtd_list);
+#endif
 	INIT_WORK(&efx->reset_work, efx_reset_work);
 	INIT_DELAYED_WORK(&efx->monitor_work, efx_monitor);
 	efx->pci_dev = pci_dev;
diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c
index 5c18ca5..0a79ec7 100644
--- a/drivers/net/sfc/ethtool.c
+++ b/drivers/net/sfc/ethtool.c
@@ -580,7 +580,8 @@ static int efx_ethtool_get_eeprom(struct net_device *net_dev,
 	rc = mutex_lock_interruptible(&efx->spi_lock);
 	if (rc)
 		return rc;
-	rc = falcon_spi_read(spi, eeprom->offset + EFX_EEPROM_BOOTCONFIG_START,
+	rc = falcon_spi_read(efx, spi,
+			     eeprom->offset + EFX_EEPROM_BOOTCONFIG_START,
 			     eeprom->len, &len, buf);
 	mutex_unlock(&efx->spi_lock);
 
@@ -603,7 +604,8 @@ static int efx_ethtool_set_eeprom(struct net_device *net_dev,
 	rc = mutex_lock_interruptible(&efx->spi_lock);
 	if (rc)
 		return rc;
-	rc = falcon_spi_write(spi, eeprom->offset + EFX_EEPROM_BOOTCONFIG_START,
+	rc = falcon_spi_write(efx, spi,
+			      eeprom->offset + EFX_EEPROM_BOOTCONFIG_START,
 			      eeprom->len, &len, buf);
 	mutex_unlock(&efx->spi_lock);
 
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index 0a7c3d2..f77bbbe 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -1640,11 +1640,10 @@ static int falcon_spi_wait(struct efx_nic *efx)
 	}
 }
 
-int falcon_spi_cmd(const struct efx_spi_device *spi,
+int falcon_spi_cmd(struct efx_nic *efx, const struct efx_spi_device *spi,
 		   unsigned int command, int address,
 		   const void *in, void *out, size_t len)
 {
-	struct efx_nic *efx = spi->efx;
 	bool addressed = (address >= 0);
 	bool reading = (out != NULL);
 	efx_oword_t reg;
@@ -1713,15 +1712,15 @@ efx_spi_munge_command(const struct efx_spi_device *spi,
 }
 
 /* Wait up to 10 ms for buffered write completion */
-int falcon_spi_wait_write(const struct efx_spi_device *spi)
+int
+falcon_spi_wait_write(struct efx_nic *efx, const struct efx_spi_device *spi)
 {
-	struct efx_nic *efx = spi->efx;
 	unsigned long timeout = jiffies + 1 + DIV_ROUND_UP(HZ, 100);
 	u8 status;
 	int rc;
 
 	for (;;) {
-		rc = falcon_spi_cmd(spi, SPI_RDSR, -1, NULL,
+		rc = falcon_spi_cmd(efx, spi, SPI_RDSR, -1, NULL,
 				    &status, sizeof(status));
 		if (rc)
 			return rc;
@@ -1737,8 +1736,8 @@ int falcon_spi_wait_write(const struct efx_spi_device *spi)
 	}
 }
 
-int falcon_spi_read(const struct efx_spi_device *spi, loff_t start,
-		    size_t len, size_t *retlen, u8 *buffer)
+int falcon_spi_read(struct efx_nic *efx, const struct efx_spi_device *spi,
+		    loff_t start, size_t len, size_t *retlen, u8 *buffer)
 {
 	size_t block_len, pos = 0;
 	unsigned int command;
@@ -1748,7 +1747,7 @@ int falcon_spi_read(const struct efx_spi_device *spi, loff_t start,
 		block_len = min(len - pos, FALCON_SPI_MAX_LEN);
 
 		command = efx_spi_munge_command(spi, SPI_READ, start + pos);
-		rc = falcon_spi_cmd(spi, command, start + pos, NULL,
+		rc = falcon_spi_cmd(efx, spi, command, start + pos, NULL,
 				    buffer + pos, block_len);
 		if (rc)
 			break;
@@ -1767,8 +1766,9 @@ int falcon_spi_read(const struct efx_spi_device *spi, loff_t start,
 	return rc;
 }
 
-int falcon_spi_write(const struct efx_spi_device *spi, loff_t start,
-		     size_t len, size_t *retlen, const u8 *buffer)
+int
+falcon_spi_write(struct efx_nic *efx, const struct efx_spi_device *spi,
+		 loff_t start, size_t len, size_t *retlen, const u8 *buffer)
 {
 	u8 verify_buffer[FALCON_SPI_MAX_LEN];
 	size_t block_len, pos = 0;
@@ -1776,24 +1776,24 @@ int falcon_spi_write(const struct efx_spi_device *spi, loff_t start,
 	int rc = 0;
 
 	while (pos < len) {
-		rc = falcon_spi_cmd(spi, SPI_WREN, -1, NULL, NULL, 0);
+		rc = falcon_spi_cmd(efx, spi, SPI_WREN, -1, NULL, NULL, 0);
 		if (rc)
 			break;
 
 		block_len = min(len - pos,
 				falcon_spi_write_limit(spi, start + pos));
 		command = efx_spi_munge_command(spi, SPI_WRITE, start + pos);
-		rc = falcon_spi_cmd(spi, command, start + pos,
+		rc = falcon_spi_cmd(efx, spi, command, start + pos,
 				    buffer + pos, NULL, block_len);
 		if (rc)
 			break;
 
-		rc = falcon_spi_wait_write(spi);
+		rc = falcon_spi_wait_write(efx, spi);
 		if (rc)
 			break;
 
 		command = efx_spi_munge_command(spi, SPI_READ, start + pos);
-		rc = falcon_spi_cmd(spi, command, start + pos,
+		rc = falcon_spi_cmd(efx, spi, command, start + pos,
 				    NULL, verify_buffer, block_len);
 		if (memcmp(verify_buffer, buffer + pos, block_len)) {
 			rc = -EIO;
@@ -2352,7 +2352,7 @@ falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out)
 	nvconfig = region + FALCON_NVCONFIG_OFFSET;
 
 	mutex_lock(&efx->spi_lock);
-	rc = falcon_spi_read(spi, 0, FALCON_NVCONFIG_END, NULL, region);
+	rc = falcon_spi_read(efx, spi, 0, FALCON_NVCONFIG_END, NULL, region);
 	mutex_unlock(&efx->spi_lock);
 	if (rc) {
 		EFX_ERR(efx, "Failed to read %s\n",
@@ -2710,8 +2710,6 @@ static int falcon_spi_device_init(struct efx_nic *efx,
 		spi_device->block_size =
 			1 << SPI_DEV_TYPE_FIELD(device_type,
 						SPI_DEV_TYPE_BLOCK_SIZE);
-
-		spi_device->efx = efx;
 	} else {
 		spi_device = NULL;
 	}
diff --git a/drivers/net/sfc/mtd.c b/drivers/net/sfc/mtd.c
index 820c233..3121e24 100644
--- a/drivers/net/sfc/mtd.c
+++ b/drivers/net/sfc/mtd.c
@@ -11,26 +11,58 @@
 #include <linux/module.h>
 #include <linux/mtd/mtd.h>
 #include <linux/delay.h>
+#include <linux/rtnetlink.h>
 
 #define EFX_DRIVER_NAME "sfc_mtd"
 #include "net_driver.h"
 #include "spi.h"
 #include "efx.h"
+#include "falcon.h"
 
 #define EFX_SPI_VERIFY_BUF_LEN 16
 
-struct efx_mtd {
-	const struct efx_spi_device *spi;
+struct efx_mtd_partition {
 	struct mtd_info mtd;
+	size_t offset;
+	const char *type_name;
 	char name[IFNAMSIZ + 20];
 };
 
+struct efx_mtd_ops {
+	int (*read)(struct mtd_info *mtd, loff_t start, size_t len,
+		    size_t *retlen, u8 *buffer);
+	int (*erase)(struct mtd_info *mtd, loff_t start, size_t len);
+	int (*write)(struct mtd_info *mtd, loff_t start, size_t len,
+		     size_t *retlen, const u8 *buffer);
+	int (*sync)(struct mtd_info *mtd);
+};
+
+struct efx_mtd {
+	struct list_head node;
+	struct efx_nic *efx;
+	const struct efx_spi_device *spi;
+	const char *name;
+	const struct efx_mtd_ops *ops;
+	size_t n_parts;
+	struct efx_mtd_partition part[0];
+};
+
+#define efx_for_each_partition(part, efx_mtd)			\
+	for ((part) = &(efx_mtd)->part[0];			\
+	     (part) != &(efx_mtd)->part[(efx_mtd)->n_parts];	\
+	     (part)++)
+
+#define to_efx_mtd_partition(mtd)				\
+	container_of(mtd, struct efx_mtd_partition, mtd)
+
+static int falcon_mtd_probe(struct efx_nic *efx);
+
 /* SPI utilities */
 
 static int efx_spi_slow_wait(struct efx_mtd *efx_mtd, bool uninterruptible)
 {
 	const struct efx_spi_device *spi = efx_mtd->spi;
-	struct efx_nic *efx = spi->efx;
+	struct efx_nic *efx = efx_mtd->efx;
 	u8 status;
 	int rc, i;
 
@@ -39,7 +71,7 @@ static int efx_spi_slow_wait(struct efx_mtd *efx_mtd, bool uninterruptible)
 		__set_current_state(uninterruptible ?
 				    TASK_UNINTERRUPTIBLE : TASK_INTERRUPTIBLE);
 		schedule_timeout(HZ / 10);
-		rc = falcon_spi_cmd(spi, SPI_RDSR, -1, NULL,
+		rc = falcon_spi_cmd(efx, spi, SPI_RDSR, -1, NULL,
 				    &status, sizeof(status));
 		if (rc)
 			return rc;
@@ -52,32 +84,35 @@ static int efx_spi_slow_wait(struct efx_mtd *efx_mtd, bool uninterruptible)
 	return -ETIMEDOUT;
 }
 
-static int efx_spi_unlock(const struct efx_spi_device *spi)
+static int
+efx_spi_unlock(struct efx_nic *efx, const struct efx_spi_device *spi)
 {
 	const u8 unlock_mask = (SPI_STATUS_BP2 | SPI_STATUS_BP1 |
 				SPI_STATUS_BP0);
 	u8 status;
 	int rc;
 
-	rc = falcon_spi_cmd(spi, SPI_RDSR, -1, NULL, &status, sizeof(status));
+	rc = falcon_spi_cmd(efx, spi, SPI_RDSR, -1, NULL,
+			    &status, sizeof(status));
 	if (rc)
 		return rc;
 
 	if (!(status & unlock_mask))
 		return 0; /* already unlocked */
 
-	rc = falcon_spi_cmd(spi, SPI_WREN, -1, NULL, NULL, 0);
+	rc = falcon_spi_cmd(efx, spi, SPI_WREN, -1, NULL, NULL, 0);
 	if (rc)
 		return rc;
-	rc = falcon_spi_cmd(spi, SPI_SST_EWSR, -1, NULL, NULL, 0);
+	rc = falcon_spi_cmd(efx, spi, SPI_SST_EWSR, -1, NULL, NULL, 0);
 	if (rc)
 		return rc;
 
 	status &= ~unlock_mask;
-	rc = falcon_spi_cmd(spi, SPI_WRSR, -1, &status, NULL, sizeof(status));
+	rc = falcon_spi_cmd(efx, spi, SPI_WRSR, -1, &status,
+			    NULL, sizeof(status));
 	if (rc)
 		return rc;
-	rc = falcon_spi_wait_write(spi);
+	rc = falcon_spi_wait_write(efx, spi);
 	if (rc)
 		return rc;
 
@@ -87,6 +122,7 @@ static int efx_spi_unlock(const struct efx_spi_device *spi)
 static int efx_spi_erase(struct efx_mtd *efx_mtd, loff_t start, size_t len)
 {
 	const struct efx_spi_device *spi = efx_mtd->spi;
+	struct efx_nic *efx = efx_mtd->efx;
 	unsigned pos, block_len;
 	u8 empty[EFX_SPI_VERIFY_BUF_LEN];
 	u8 buffer[EFX_SPI_VERIFY_BUF_LEN];
@@ -98,13 +134,14 @@ static int efx_spi_erase(struct efx_mtd *efx_mtd, loff_t start, size_t len)
 	if (spi->erase_command == 0)
 		return -EOPNOTSUPP;
 
-	rc = efx_spi_unlock(spi);
+	rc = efx_spi_unlock(efx, spi);
 	if (rc)
 		return rc;
-	rc = falcon_spi_cmd(spi, SPI_WREN, -1, NULL, NULL, 0);
+	rc = falcon_spi_cmd(efx, spi, SPI_WREN, -1, NULL, NULL, 0);
 	if (rc)
 		return rc;
-	rc = falcon_spi_cmd(spi, spi->erase_command, start, NULL, NULL, 0);
+	rc = falcon_spi_cmd(efx, spi, spi->erase_command, start, NULL,
+			    NULL, 0);
 	if (rc)
 		return rc;
 	rc = efx_spi_slow_wait(efx_mtd, false);
@@ -113,7 +150,8 @@ static int efx_spi_erase(struct efx_mtd *efx_mtd, loff_t start, size_t len)
 	memset(empty, 0xff, sizeof(empty));
 	for (pos = 0; pos < len; pos += block_len) {
 		block_len = min(len - pos, sizeof(buffer));
-		rc = falcon_spi_read(spi, start + pos, block_len, NULL, buffer);
+		rc = falcon_spi_read(efx, spi, start + pos, block_len,
+				     NULL, buffer);
 		if (rc)
 			return rc;
 		if (memcmp(empty, buffer, block_len))
@@ -130,140 +168,228 @@ static int efx_spi_erase(struct efx_mtd *efx_mtd, loff_t start, size_t len)
 
 /* MTD interface */
 
-static int efx_mtd_read(struct mtd_info *mtd, loff_t start, size_t len,
-			size_t *retlen, u8 *buffer)
+static int efx_mtd_erase(struct mtd_info *mtd, struct erase_info *erase)
+{
+	struct efx_mtd *efx_mtd = mtd->priv;
+	int rc;
+
+	rc = efx_mtd->ops->erase(mtd, erase->addr, erase->len);
+	if (rc == 0) {
+		erase->state = MTD_ERASE_DONE;
+	} else {
+		erase->state = MTD_ERASE_FAILED;
+		erase->fail_addr = 0xffffffff;
+	}
+	mtd_erase_callback(erase);
+	return rc;
+}
+
+static void efx_mtd_sync(struct mtd_info *mtd)
+{
+	struct efx_mtd *efx_mtd = mtd->priv;
+	struct efx_nic *efx = efx_mtd->efx;
+	int rc;
+
+	rc = efx_mtd->ops->sync(mtd);
+	if (rc)
+		EFX_ERR(efx, "%s sync failed (%d)\n", efx_mtd->name, rc);
+}
+
+static void efx_mtd_remove_partition(struct efx_mtd_partition *part)
+{
+	int rc;
+
+	for (;;) {
+		rc = del_mtd_device(&part->mtd);
+		if (rc != -EBUSY)
+			break;
+		ssleep(1);
+	}
+	WARN_ON(rc);
+}
+
+static void efx_mtd_remove_device(struct efx_mtd *efx_mtd)
+{
+	struct efx_mtd_partition *part;
+
+	efx_for_each_partition(part, efx_mtd)
+		efx_mtd_remove_partition(part);
+	list_del(&efx_mtd->node);
+	kfree(efx_mtd);
+}
+
+static void efx_mtd_rename_device(struct efx_mtd *efx_mtd)
+{
+	struct efx_mtd_partition *part;
+
+	efx_for_each_partition(part, efx_mtd)
+		snprintf(part->name, sizeof(part->name),
+			 "%s %s", efx_mtd->efx->name,
+			 part->type_name);
+}
+
+static int efx_mtd_probe_device(struct efx_nic *efx, struct efx_mtd *efx_mtd)
+{
+	struct efx_mtd_partition *part;
+
+	efx_mtd->efx = efx;
+
+	efx_mtd_rename_device(efx_mtd);
+
+	efx_for_each_partition(part, efx_mtd) {
+		part->mtd.writesize = 1;
+
+		part->mtd.owner = THIS_MODULE;
+		part->mtd.priv = efx_mtd;
+		part->mtd.name = part->name;
+		part->mtd.erase = efx_mtd_erase;
+		part->mtd.read = efx_mtd->ops->read;
+		part->mtd.write = efx_mtd->ops->write;
+		part->mtd.sync = efx_mtd_sync;
+
+		if (add_mtd_device(&part->mtd))
+			goto fail;
+	}
+
+	list_add(&efx_mtd->node, &efx->mtd_list);
+	return 0;
+
+fail:
+	while (part != &efx_mtd->part[0]) {
+		--part;
+		efx_mtd_remove_partition(part);
+	}
+	/* add_mtd_device() returns 1 if the MTD table is full */
+	return -ENOMEM;
+}
+
+void efx_mtd_remove(struct efx_nic *efx)
 {
+	struct efx_mtd *efx_mtd, *next;
+
+	WARN_ON(efx_dev_registered(efx));
+
+	list_for_each_entry_safe(efx_mtd, next, &efx->mtd_list, node)
+		efx_mtd_remove_device(efx_mtd);
+}
+
+void efx_mtd_rename(struct efx_nic *efx)
+{
+	struct efx_mtd *efx_mtd;
+
+	ASSERT_RTNL();
+
+	list_for_each_entry(efx_mtd, &efx->mtd_list, node)
+		efx_mtd_rename_device(efx_mtd);
+}
+
+int efx_mtd_probe(struct efx_nic *efx)
+{
+	return falcon_mtd_probe(efx);
+}
+
+/* Implementation of MTD operations for Falcon */
+
+static int falcon_mtd_read(struct mtd_info *mtd, loff_t start,
+			   size_t len, size_t *retlen, u8 *buffer)
+{
+	struct efx_mtd_partition *part = to_efx_mtd_partition(mtd);
 	struct efx_mtd *efx_mtd = mtd->priv;
 	const struct efx_spi_device *spi = efx_mtd->spi;
-	struct efx_nic *efx = spi->efx;
+	struct efx_nic *efx = efx_mtd->efx;
 	int rc;
 
 	rc = mutex_lock_interruptible(&efx->spi_lock);
 	if (rc)
 		return rc;
-	rc = falcon_spi_read(spi, FALCON_FLASH_BOOTCODE_START + start,
-			     len, retlen, buffer);
+	rc = falcon_spi_read(efx, spi, part->offset + start, len,
+			     retlen, buffer);
 	mutex_unlock(&efx->spi_lock);
 	return rc;
 }
 
-static int efx_mtd_erase(struct mtd_info *mtd, struct erase_info *erase)
+static int falcon_mtd_erase(struct mtd_info *mtd, loff_t start, size_t len)
 {
+	struct efx_mtd_partition *part = to_efx_mtd_partition(mtd);
 	struct efx_mtd *efx_mtd = mtd->priv;
-	struct efx_nic *efx = efx_mtd->spi->efx;
+	struct efx_nic *efx = efx_mtd->efx;
 	int rc;
 
 	rc = mutex_lock_interruptible(&efx->spi_lock);
 	if (rc)
 		return rc;
-	rc = efx_spi_erase(efx_mtd, FALCON_FLASH_BOOTCODE_START + erase->addr,
-			   erase->len);
+	rc = efx_spi_erase(efx_mtd, part->offset + start, len);
 	mutex_unlock(&efx->spi_lock);
-
-	if (rc == 0) {
-		erase->state = MTD_ERASE_DONE;
-	} else {
-		erase->state = MTD_ERASE_FAILED;
-		erase->fail_addr = 0xffffffff;
-	}
-	mtd_erase_callback(erase);
 	return rc;
 }
 
-static int efx_mtd_write(struct mtd_info *mtd, loff_t start,
-			 size_t len, size_t *retlen, const u8 *buffer)
+static int falcon_mtd_write(struct mtd_info *mtd, loff_t start,
+			    size_t len, size_t *retlen, const u8 *buffer)
 {
+	struct efx_mtd_partition *part = to_efx_mtd_partition(mtd);
 	struct efx_mtd *efx_mtd = mtd->priv;
 	const struct efx_spi_device *spi = efx_mtd->spi;
-	struct efx_nic *efx = spi->efx;
+	struct efx_nic *efx = efx_mtd->efx;
 	int rc;
 
 	rc = mutex_lock_interruptible(&efx->spi_lock);
 	if (rc)
 		return rc;
-	rc = falcon_spi_write(spi, FALCON_FLASH_BOOTCODE_START + start,
-			      len, retlen, buffer);
+	rc = falcon_spi_write(efx, spi, part->offset + start, len,
+			      retlen, buffer);
 	mutex_unlock(&efx->spi_lock);
 	return rc;
 }
 
-static void efx_mtd_sync(struct mtd_info *mtd)
+static int falcon_mtd_sync(struct mtd_info *mtd)
 {
 	struct efx_mtd *efx_mtd = mtd->priv;
-	struct efx_nic *efx = efx_mtd->spi->efx;
+	struct efx_nic *efx = efx_mtd->efx;
 	int rc;
 
 	mutex_lock(&efx->spi_lock);
 	rc = efx_spi_slow_wait(efx_mtd, true);
 	mutex_unlock(&efx->spi_lock);
-
-	if (rc)
-		EFX_ERR(efx, "%s sync failed (%d)\n", efx_mtd->name, rc);
-	return;
-}
-
-void efx_mtd_remove(struct efx_nic *efx)
-{
-	if (efx->spi_flash && efx->spi_flash->mtd) {
-		struct efx_mtd *efx_mtd = efx->spi_flash->mtd;
-		int rc;
-
-		for (;;) {
-			rc = del_mtd_device(&efx_mtd->mtd);
-			if (rc != -EBUSY)
-				break;
-			ssleep(1);
-		}
-		WARN_ON(rc);
-		kfree(efx_mtd);
-	}
+	return rc;
 }
 
-void efx_mtd_rename(struct efx_nic *efx)
-{
-	if (efx->spi_flash && efx->spi_flash->mtd) {
-		struct efx_mtd *efx_mtd = efx->spi_flash->mtd;
-		snprintf(efx_mtd->name, sizeof(efx_mtd->name),
-			 "%s sfc_flash_bootrom", efx->name);
-	}
-}
+static struct efx_mtd_ops falcon_mtd_ops = {
+	.read	= falcon_mtd_read,
+	.erase	= falcon_mtd_erase,
+	.write	= falcon_mtd_write,
+	.sync	= falcon_mtd_sync,
+};
 
-int efx_mtd_probe(struct efx_nic *efx)
+static int falcon_mtd_probe(struct efx_nic *efx)
 {
 	struct efx_spi_device *spi = efx->spi_flash;
 	struct efx_mtd *efx_mtd;
+	int rc;
+
+	ASSERT_RTNL();
 
 	if (!spi || spi->size <= FALCON_FLASH_BOOTCODE_START)
 		return -ENODEV;
 
-	efx_mtd = kzalloc(sizeof(*efx_mtd), GFP_KERNEL);
+	efx_mtd = kzalloc(sizeof(*efx_mtd) + sizeof(efx_mtd->part[0]),
+			  GFP_KERNEL);
 	if (!efx_mtd)
 		return -ENOMEM;
 
 	efx_mtd->spi = spi;
-	spi->mtd = efx_mtd;
-
-	efx_mtd->mtd.type = MTD_NORFLASH;
-	efx_mtd->mtd.flags = MTD_CAP_NORFLASH;
-	efx_mtd->mtd.size = spi->size - FALCON_FLASH_BOOTCODE_START;
-	efx_mtd->mtd.erasesize = spi->erase_size;
-	efx_mtd->mtd.writesize = 1;
-	efx_mtd_rename(efx);
-
-	efx_mtd->mtd.owner = THIS_MODULE;
-	efx_mtd->mtd.priv = efx_mtd;
-	efx_mtd->mtd.name = efx_mtd->name;
-	efx_mtd->mtd.erase = efx_mtd_erase;
-	efx_mtd->mtd.read = efx_mtd_read;
-	efx_mtd->mtd.write = efx_mtd_write;
-	efx_mtd->mtd.sync = efx_mtd_sync;
-
-	if (add_mtd_device(&efx_mtd->mtd)) {
+	efx_mtd->name = "flash";
+	efx_mtd->ops = &falcon_mtd_ops;
+
+	efx_mtd->n_parts = 1;
+	efx_mtd->part[0].mtd.type = MTD_NORFLASH;
+	efx_mtd->part[0].mtd.flags = MTD_CAP_NORFLASH;
+	efx_mtd->part[0].mtd.size = spi->size - FALCON_FLASH_BOOTCODE_START;
+	efx_mtd->part[0].mtd.erasesize = spi->erase_size;
+	efx_mtd->part[0].offset = FALCON_FLASH_BOOTCODE_START;
+	efx_mtd->part[0].type_name = "sfc_flash_bootrom";
+
+	rc = efx_mtd_probe_device(efx, efx_mtd);
+	if (rc)
 		kfree(efx_mtd);
-		spi->mtd = NULL;
-		/* add_mtd_device() returns 1 if the MTD table is full */
-		return -ENOMEM;
-	}
-
-	return 0;
+	return rc;
 }
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index 4ec6ef3..96d3f00 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -674,10 +674,11 @@ union efx_multicast_hash {
  *	interrupt is handled.  It is used by falcon_test_interrupt()
  *	to verify that an interrupt has occurred.
  * @spi_flash: SPI flash device
- *	This field will be %NULL if no flash device is present.
+ *	This field will be %NULL if no flash device is present (or for Siena).
  * @spi_eeprom: SPI EEPROM device
- *	This field will be %NULL if no EEPROM device is present.
+ *	This field will be %NULL if no EEPROM device is present (or for Siena).
  * @spi_lock: SPI bus lock
+ * @mtd_list: List of MTDs attached to the NIC
  * @n_rx_nodesc_drop_cnt: RX no descriptor drop count
  * @nic_data: Hardware dependant state
  * @mac_lock: MAC access lock. Protects @port_enabled, @phy_mode,
@@ -759,6 +760,9 @@ struct efx_nic {
 	struct efx_spi_device *spi_flash;
 	struct efx_spi_device *spi_eeprom;
 	struct mutex spi_lock;
+#ifdef CONFIG_SFC_MTD
+	struct list_head mtd_list;
+#endif
 
 	unsigned n_rx_nodesc_drop_cnt;
 
diff --git a/drivers/net/sfc/spi.h b/drivers/net/sfc/spi.h
index 1b1ceb4..8bf4fce 100644
--- a/drivers/net/sfc/spi.h
+++ b/drivers/net/sfc/spi.h
@@ -36,8 +36,6 @@
 
 /**
  * struct efx_spi_device - an Efx SPI (Serial Peripheral Interface) device
- * @efx:		The Efx controller that owns this device
- * @mtd:		MTD state
  * @device_id:		Controller's id for the device
  * @size:		Size (in bytes)
  * @addr_len:		Number of address bytes in read/write commands
@@ -54,10 +52,6 @@
  *	Write commands are limited to blocks with this size and alignment.
  */
 struct efx_spi_device {
-	struct efx_nic *efx;
-#ifdef CONFIG_SFC_MTD
-	void *mtd;
-#endif
 	int device_id;
 	unsigned int size;
 	unsigned int addr_len;
@@ -67,12 +61,16 @@ struct efx_spi_device {
 	unsigned int block_size;
 };
 
-int falcon_spi_cmd(const struct efx_spi_device *spi, unsigned int command,
+int falcon_spi_cmd(struct efx_nic *efx,
+		   const struct efx_spi_device *spi, unsigned int command,
 		   int address, const void* in, void *out, size_t len);
-int falcon_spi_wait_write(const struct efx_spi_device *spi);
-int falcon_spi_read(const struct efx_spi_device *spi, loff_t start,
+int falcon_spi_wait_write(struct efx_nic *efx,
+			  const struct efx_spi_device *spi);
+int falcon_spi_read(struct efx_nic *efx,
+		    const struct efx_spi_device *spi, loff_t start,
 		    size_t len, size_t *retlen, u8 *buffer);
-int falcon_spi_write(const struct efx_spi_device *spi, loff_t start,
+int falcon_spi_write(struct efx_nic *efx,
+		     const struct efx_spi_device *spi, loff_t start,
 		     size_t len, size_t *retlen, const u8 *buffer);
 
 /*


-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox