sfc: Split MAC stats DMA initiation and completion

From: Steve Hodgson <shodgson@solarflare.com>

Currently we initiate MAC stats DMA and busy-wait for completion when
stats are requested.  We can improve on this with a periodic timer to
initiate and poll for stats, and opportunistically poll when stats are
requested.

Since efx_nic::stats_disable_count and efx_stats_{disable,enable}()
are Falcon-specific, rename them and move them accordingly.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index 155aa1c..41ca5db 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -637,6 +637,7 @@
 		netif_addr_unlock_bh(efx->net_dev);
 	}
 
+	falcon_stop_nic_stats(efx);
 	falcon_deconfigure_mac_wrapper(efx);
 
 	/* Reconfigure the PHY, disabling transmit in mac level loopback. */
@@ -651,6 +652,8 @@
 
 	efx->mac_op->reconfigure(efx);
 
+	falcon_start_nic_stats(efx);
+
 	/* Inform kernel of loss/gain of carrier */
 	efx_link_status_changed(efx);
 	return;
@@ -749,7 +752,6 @@
 	efx->mac_op->reconfigure(efx);
 
 	efx->port_initialized = true;
-	efx_stats_enable(efx);
 
 	mutex_unlock(&efx->mac_lock);
 	return 0;
@@ -802,7 +804,6 @@
 	if (!efx->port_initialized)
 		return;
 
-	efx_stats_disable(efx);
 	efx->phy_op->fini(efx);
 	efx->port_initialized = false;
 
@@ -1158,6 +1159,8 @@
 	if (efx->state == STATE_RUNNING)
 		queue_delayed_work(efx->workqueue, &efx->monitor_work,
 				   efx_monitor_interval);
+
+	falcon_start_nic_stats(efx);
 }
 
 /* Flush all delayed work. Should only be called when no more delayed work
@@ -1195,6 +1198,8 @@
 	if (!efx->port_enabled)
 		return;
 
+	falcon_stop_nic_stats(efx);
+
 	/* Disable interrupts and wait for ISR to complete */
 	falcon_disable_interrupts(efx);
 	if (efx->legacy_irq)
@@ -1438,20 +1443,6 @@
 	return 0;
 }
 
-void efx_stats_disable(struct efx_nic *efx)
-{
-	spin_lock(&efx->stats_lock);
-	++efx->stats_disable_count;
-	spin_unlock(&efx->stats_lock);
-}
-
-void efx_stats_enable(struct efx_nic *efx)
-{
-	spin_lock(&efx->stats_lock);
-	--efx->stats_disable_count;
-	spin_unlock(&efx->stats_lock);
-}
-
 /* Context: process, dev_base_lock or RTNL held, non-blocking. */
 static struct net_device_stats *efx_net_stats(struct net_device *net_dev)
 {
@@ -1459,17 +1450,9 @@
 	struct efx_mac_stats *mac_stats = &efx->mac_stats;
 	struct net_device_stats *stats = &net_dev->stats;
 
-	/* Update stats if possible, but do not wait if another thread
-	 * is updating them or if MAC stats fetches are temporarily
-	 * disabled; slightly stale stats are acceptable.
-	 */
-	if (!spin_trylock(&efx->stats_lock))
-		return stats;
-	if (!efx->stats_disable_count) {
-		efx->mac_op->update_stats(efx);
-		falcon_update_nic_stats(efx);
-	}
-	spin_unlock(&efx->stats_lock);
+	spin_lock_bh(&efx->stats_lock);
+	falcon_update_nic_stats(efx);
+	spin_unlock_bh(&efx->stats_lock);
 
 	stats->rx_packets = mac_stats->rx_packets;
 	stats->tx_packets = mac_stats->tx_packets;
@@ -1726,7 +1709,6 @@
 {
 	EFX_ASSERT_RESET_SERIALISED(efx);
 
-	efx_stats_disable(efx);
 	efx_stop_all(efx);
 	mutex_lock(&efx->mac_lock);
 	mutex_lock(&efx->spi_lock);
@@ -1776,10 +1758,8 @@
 	mutex_unlock(&efx->spi_lock);
 	mutex_unlock(&efx->mac_lock);
 
-	if (ok) {
+	if (ok)
 		efx_start_all(efx);
-		efx_stats_enable(efx);
-	}
 	return rc;
 }
 
@@ -1977,7 +1957,6 @@
 	efx->rx_checksum_enabled = true;
 	spin_lock_init(&efx->netif_stop_lock);
 	spin_lock_init(&efx->stats_lock);
-	efx->stats_disable_count = 1;
 	mutex_init(&efx->mac_lock);
 	efx->mac_op = &efx_dummy_mac_operations;
 	efx->phy_op = &efx_dummy_phy_operations;
@@ -2219,9 +2198,8 @@
 		goto fail4;
 	}
 
-	/* Switch to the running state before we expose the device to
-	 * the OS.  This is to ensure that the initial gathering of
-	 * MAC stats succeeds. */
+	/* Switch to the running state before we expose the device to the OS,
+	 * so that dev_open()|efx_start_all() will actually start the device */
 	efx->state = STATE_RUNNING;
 
 	rc = efx_register_netdev(efx);