aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJon Cooper <jcooper@solarflare.com>2013-09-30 12:36:50 -0400
committerBen Hutchings <bhutchings@solarflare.com>2013-12-12 17:06:51 -0500
commitf8f3b5ae3ea45ef6b00b471fed0fc90552a3c4af (patch)
treee65cedae54bb32528176a2d31890ee86cd6db62d
parentcce28794bc99c15f0d4c98936a473ac6e21be0ad (diff)
sfc: Correct RX dropped count for drops while interface is down
We don't directly control RX ingress on Siena or any later controllers, and so we cannot prevent packets from entering the RX datapath while the RX queues are not set up. This results in the hardware incrementing RX_NODESC_DROP_CNT, but it's not an error and we should not include it in error stats. When bringing an interface up or down, pull (or wait for) stats and count the number of packets that were dropped while the interface was down. Subtract this from the reported RX dropped count. Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
-rw-r--r--drivers/net/ethernet/sfc/ef10.c2
-rw-r--r--drivers/net/ethernet/sfc/efx.c11
-rw-r--r--drivers/net/ethernet/sfc/falcon.c10
-rw-r--r--drivers/net/ethernet/sfc/mcdi.h1
-rw-r--r--drivers/net/ethernet/sfc/mcdi_port.c49
-rw-r--r--drivers/net/ethernet/sfc/net_driver.h5
-rw-r--r--drivers/net/ethernet/sfc/nic.c12
-rw-r--r--drivers/net/ethernet/sfc/nic.h1
-rw-r--r--drivers/net/ethernet/sfc/siena.c3
9 files changed, 83 insertions, 11 deletions
diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c
index e9c546bdbdfe..c1b85edcb204 100644
--- a/drivers/net/ethernet/sfc/ef10.c
+++ b/drivers/net/ethernet/sfc/ef10.c
@@ -902,6 +902,7 @@ static int efx_ef10_try_update_nic_stats(struct efx_nic *efx)
902 return -EAGAIN; 902 return -EAGAIN;
903 903
904 /* Update derived statistics */ 904 /* Update derived statistics */
905 efx_nic_fix_nodesc_drop_stat(efx, &stats[EF10_STAT_rx_nodesc_drops]);
905 stats[EF10_STAT_rx_good_bytes] = 906 stats[EF10_STAT_rx_good_bytes] =
906 stats[EF10_STAT_rx_bytes] - 907 stats[EF10_STAT_rx_bytes] -
907 stats[EF10_STAT_rx_bytes_minus_good_bytes]; 908 stats[EF10_STAT_rx_bytes_minus_good_bytes];
@@ -3423,6 +3424,7 @@ const struct efx_nic_type efx_hunt_a0_nic_type = {
3423 .describe_stats = efx_ef10_describe_stats, 3424 .describe_stats = efx_ef10_describe_stats,
3424 .update_stats = efx_ef10_update_stats, 3425 .update_stats = efx_ef10_update_stats,
3425 .start_stats = efx_mcdi_mac_start_stats, 3426 .start_stats = efx_mcdi_mac_start_stats,
3427 .pull_stats = efx_mcdi_mac_pull_stats,
3426 .stop_stats = efx_mcdi_mac_stop_stats, 3428 .stop_stats = efx_mcdi_mac_stop_stats,
3427 .set_id_led = efx_mcdi_set_id_led, 3429 .set_id_led = efx_mcdi_set_id_led,
3428 .push_irq_moderation = efx_ef10_push_irq_moderation, 3430 .push_irq_moderation = efx_ef10_push_irq_moderation,
diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c
index 5e2454d07137..c734fba8c99c 100644
--- a/drivers/net/ethernet/sfc/efx.c
+++ b/drivers/net/ethernet/sfc/efx.c
@@ -1684,6 +1684,10 @@ static void efx_start_all(struct efx_nic *efx)
1684 } 1684 }
1685 1685
1686 efx->type->start_stats(efx); 1686 efx->type->start_stats(efx);
1687 efx->type->pull_stats(efx);
1688 spin_lock_bh(&efx->stats_lock);
1689 efx->type->update_stats(efx, NULL, NULL);
1690 spin_unlock_bh(&efx->stats_lock);
1687} 1691}
1688 1692
1689/* Flush all delayed work. Should only be called when no more delayed work 1693/* Flush all delayed work. Should only be called when no more delayed work
@@ -1711,6 +1715,13 @@ static void efx_stop_all(struct efx_nic *efx)
1711 if (!efx->port_enabled) 1715 if (!efx->port_enabled)
1712 return; 1716 return;
1713 1717
1718 /* update stats before we go down so we can accurately count
1719 * rx_nodesc_drops
1720 */
1721 efx->type->pull_stats(efx);
1722 spin_lock_bh(&efx->stats_lock);
1723 efx->type->update_stats(efx, NULL, NULL);
1724 spin_unlock_bh(&efx->stats_lock);
1714 efx->type->stop_stats(efx); 1725 efx->type->stop_stats(efx);
1715 efx_stop_port(efx); 1726 efx_stop_port(efx);
1716 1727
diff --git a/drivers/net/ethernet/sfc/falcon.c b/drivers/net/ethernet/sfc/falcon.c
index ff5d322b9b49..4a9e05c82e2a 100644
--- a/drivers/net/ethernet/sfc/falcon.c
+++ b/drivers/net/ethernet/sfc/falcon.c
@@ -2593,6 +2593,14 @@ void falcon_start_nic_stats(struct efx_nic *efx)
2593 spin_unlock_bh(&efx->stats_lock); 2593 spin_unlock_bh(&efx->stats_lock);
2594} 2594}
2595 2595
2596/* We don't acutally pull stats on falcon. Wait 10ms so that
2597 * they arrive when we call this just after start_stats
2598 */
2599void falcon_pull_nic_stats(struct efx_nic *efx)
2600{
2601 msleep(10);
2602}
2603
2596void falcon_stop_nic_stats(struct efx_nic *efx) 2604void falcon_stop_nic_stats(struct efx_nic *efx)
2597{ 2605{
2598 struct falcon_nic_data *nic_data = efx->nic_data; 2606 struct falcon_nic_data *nic_data = efx->nic_data;
@@ -2672,6 +2680,7 @@ const struct efx_nic_type falcon_a1_nic_type = {
2672 .describe_stats = falcon_describe_nic_stats, 2680 .describe_stats = falcon_describe_nic_stats,
2673 .update_stats = falcon_update_nic_stats, 2681 .update_stats = falcon_update_nic_stats,
2674 .start_stats = falcon_start_nic_stats, 2682 .start_stats = falcon_start_nic_stats,
2683 .pull_stats = falcon_pull_nic_stats,
2675 .stop_stats = falcon_stop_nic_stats, 2684 .stop_stats = falcon_stop_nic_stats,
2676 .set_id_led = falcon_set_id_led, 2685 .set_id_led = falcon_set_id_led,
2677 .push_irq_moderation = falcon_push_irq_moderation, 2686 .push_irq_moderation = falcon_push_irq_moderation,
@@ -2765,6 +2774,7 @@ const struct efx_nic_type falcon_b0_nic_type = {
2765 .describe_stats = falcon_describe_nic_stats, 2774 .describe_stats = falcon_describe_nic_stats,
2766 .update_stats = falcon_update_nic_stats, 2775 .update_stats = falcon_update_nic_stats,
2767 .start_stats = falcon_start_nic_stats, 2776 .start_stats = falcon_start_nic_stats,
2777 .pull_stats = falcon_pull_nic_stats,
2768 .stop_stats = falcon_stop_nic_stats, 2778 .stop_stats = falcon_stop_nic_stats,
2769 .set_id_led = falcon_set_id_led, 2779 .set_id_led = falcon_set_id_led,
2770 .push_irq_moderation = falcon_push_irq_moderation, 2780 .push_irq_moderation = falcon_push_irq_moderation,
diff --git a/drivers/net/ethernet/sfc/mcdi.h b/drivers/net/ethernet/sfc/mcdi.h
index 15816cacb548..d861628b7ee6 100644
--- a/drivers/net/ethernet/sfc/mcdi.h
+++ b/drivers/net/ethernet/sfc/mcdi.h
@@ -301,6 +301,7 @@ int efx_mcdi_set_mac(struct efx_nic *efx);
301#define EFX_MC_STATS_GENERATION_INVALID ((__force __le64)(-1)) 301#define EFX_MC_STATS_GENERATION_INVALID ((__force __le64)(-1))
302void efx_mcdi_mac_start_stats(struct efx_nic *efx); 302void efx_mcdi_mac_start_stats(struct efx_nic *efx);
303void efx_mcdi_mac_stop_stats(struct efx_nic *efx); 303void efx_mcdi_mac_stop_stats(struct efx_nic *efx);
304void efx_mcdi_mac_pull_stats(struct efx_nic *efx);
304bool efx_mcdi_mac_check_fault(struct efx_nic *efx); 305bool efx_mcdi_mac_check_fault(struct efx_nic *efx);
305enum reset_type efx_mcdi_map_reset_reason(enum reset_type reason); 306enum reset_type efx_mcdi_map_reset_reason(enum reset_type reason);
306int efx_mcdi_reset(struct efx_nic *efx, enum reset_type method); 307int efx_mcdi_reset(struct efx_nic *efx, enum reset_type method);
diff --git a/drivers/net/ethernet/sfc/mcdi_port.c b/drivers/net/ethernet/sfc/mcdi_port.c
index 7b6be61d549f..7288aefc2877 100644
--- a/drivers/net/ethernet/sfc/mcdi_port.c
+++ b/drivers/net/ethernet/sfc/mcdi_port.c
@@ -927,12 +927,23 @@ bool efx_mcdi_mac_check_fault(struct efx_nic *efx)
927 return MCDI_DWORD(outbuf, GET_LINK_OUT_MAC_FAULT) != 0; 927 return MCDI_DWORD(outbuf, GET_LINK_OUT_MAC_FAULT) != 0;
928} 928}
929 929
930static int efx_mcdi_mac_stats(struct efx_nic *efx, dma_addr_t dma_addr, 930enum efx_stats_action {
931 u32 dma_len, int enable, int clear) 931 EFX_STATS_ENABLE,
932 EFX_STATS_DISABLE,
933 EFX_STATS_PULL,
934};
935
936static int efx_mcdi_mac_stats(struct efx_nic *efx,
937 enum efx_stats_action action, int clear)
932{ 938{
933 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAC_STATS_IN_LEN); 939 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAC_STATS_IN_LEN);
934 int rc; 940 int rc;
935 int period = enable ? 1000 : 0; 941 int change = action == EFX_STATS_PULL ? 0 : 1;
942 int enable = action == EFX_STATS_ENABLE ? 1 : 0;
943 int period = action == EFX_STATS_ENABLE ? 1000 : 0;
944 dma_addr_t dma_addr = efx->stats_buffer.dma_addr;
945 u32 dma_len = action != EFX_STATS_DISABLE ?
946 MC_CMD_MAC_NSTATS * sizeof(u64) : 0;
936 947
937 BUILD_BUG_ON(MC_CMD_MAC_STATS_OUT_DMA_LEN != 0); 948 BUILD_BUG_ON(MC_CMD_MAC_STATS_OUT_DMA_LEN != 0);
938 949
@@ -940,8 +951,8 @@ static int efx_mcdi_mac_stats(struct efx_nic *efx, dma_addr_t dma_addr,
940 MCDI_POPULATE_DWORD_7(inbuf, MAC_STATS_IN_CMD, 951 MCDI_POPULATE_DWORD_7(inbuf, MAC_STATS_IN_CMD,
941 MAC_STATS_IN_DMA, !!enable, 952 MAC_STATS_IN_DMA, !!enable,
942 MAC_STATS_IN_CLEAR, clear, 953 MAC_STATS_IN_CLEAR, clear,
943 MAC_STATS_IN_PERIODIC_CHANGE, 1, 954 MAC_STATS_IN_PERIODIC_CHANGE, change,
944 MAC_STATS_IN_PERIODIC_ENABLE, !!enable, 955 MAC_STATS_IN_PERIODIC_ENABLE, enable,
945 MAC_STATS_IN_PERIODIC_CLEAR, 0, 956 MAC_STATS_IN_PERIODIC_CLEAR, 0,
946 MAC_STATS_IN_PERIODIC_NOEVENT, 1, 957 MAC_STATS_IN_PERIODIC_NOEVENT, 1,
947 MAC_STATS_IN_PERIOD_MS, period); 958 MAC_STATS_IN_PERIOD_MS, period);
@@ -955,8 +966,8 @@ static int efx_mcdi_mac_stats(struct efx_nic *efx, dma_addr_t dma_addr,
955 return 0; 966 return 0;
956 967
957fail: 968fail:
958 netif_err(efx, hw, efx->net_dev, "%s: %s failed rc=%d\n", 969 netif_err(efx, hw, efx->net_dev, "%s: action %d failed rc=%d\n",
959 __func__, enable ? "enable" : "disable", rc); 970 __func__, action, rc);
960 return rc; 971 return rc;
961} 972}
962 973
@@ -966,13 +977,29 @@ void efx_mcdi_mac_start_stats(struct efx_nic *efx)
966 977
967 dma_stats[MC_CMD_MAC_GENERATION_END] = EFX_MC_STATS_GENERATION_INVALID; 978 dma_stats[MC_CMD_MAC_GENERATION_END] = EFX_MC_STATS_GENERATION_INVALID;
968 979
969 efx_mcdi_mac_stats(efx, efx->stats_buffer.dma_addr, 980 efx_mcdi_mac_stats(efx, EFX_STATS_ENABLE, 0);
970 MC_CMD_MAC_NSTATS * sizeof(u64), 1, 0);
971} 981}
972 982
973void efx_mcdi_mac_stop_stats(struct efx_nic *efx) 983void efx_mcdi_mac_stop_stats(struct efx_nic *efx)
974{ 984{
975 efx_mcdi_mac_stats(efx, efx->stats_buffer.dma_addr, 0, 0, 0); 985 efx_mcdi_mac_stats(efx, EFX_STATS_DISABLE, 0);
986}
987
988#define EFX_MAC_STATS_WAIT_US 100
989#define EFX_MAC_STATS_WAIT_ATTEMPTS 10
990
991void efx_mcdi_mac_pull_stats(struct efx_nic *efx)
992{
993 __le64 *dma_stats = efx->stats_buffer.addr;
994 int attempts = EFX_MAC_STATS_WAIT_ATTEMPTS;
995
996 dma_stats[MC_CMD_MAC_GENERATION_END] = EFX_MC_STATS_GENERATION_INVALID;
997 efx_mcdi_mac_stats(efx, EFX_STATS_PULL, 0);
998
999 while (dma_stats[MC_CMD_MAC_GENERATION_END] ==
1000 EFX_MC_STATS_GENERATION_INVALID &&
1001 attempts-- != 0)
1002 udelay(EFX_MAC_STATS_WAIT_US);
976} 1003}
977 1004
978int efx_mcdi_port_probe(struct efx_nic *efx) 1005int efx_mcdi_port_probe(struct efx_nic *efx)
@@ -1003,7 +1030,7 @@ int efx_mcdi_port_probe(struct efx_nic *efx)
1003 efx->stats_buffer.addr, 1030 efx->stats_buffer.addr,
1004 (u64)virt_to_phys(efx->stats_buffer.addr)); 1031 (u64)virt_to_phys(efx->stats_buffer.addr));
1005 1032
1006 efx_mcdi_mac_stats(efx, efx->stats_buffer.dma_addr, 0, 0, 1); 1033 efx_mcdi_mac_stats(efx, EFX_STATS_DISABLE, 1);
1007 1034
1008 return 0; 1035 return 0;
1009} 1036}
diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h
index d98b3f031ab5..f47bac78b92c 100644
--- a/drivers/net/ethernet/sfc/net_driver.h
+++ b/drivers/net/ethernet/sfc/net_driver.h
@@ -857,6 +857,9 @@ struct efx_nic {
857 struct net_device *net_dev; 857 struct net_device *net_dev;
858 858
859 struct efx_buffer stats_buffer; 859 struct efx_buffer stats_buffer;
860 u64 rx_nodesc_drops_total;
861 u64 rx_nodesc_drops_while_down;
862 bool rx_nodesc_drops_prev_state;
860 863
861 unsigned int phy_type; 864 unsigned int phy_type;
862 const struct efx_phy_operations *phy_op; 865 const struct efx_phy_operations *phy_op;
@@ -960,6 +963,7 @@ struct efx_mtd_partition {
960 * @update_stats: Update statistics not provided by event handling. 963 * @update_stats: Update statistics not provided by event handling.
961 * Either argument may be %NULL. 964 * Either argument may be %NULL.
962 * @start_stats: Start the regular fetching of statistics 965 * @start_stats: Start the regular fetching of statistics
966 * @pull_stats: Pull stats from the NIC and wait until they arrive.
963 * @stop_stats: Stop the regular fetching of statistics 967 * @stop_stats: Stop the regular fetching of statistics
964 * @set_id_led: Set state of identifying LED or revert to automatic function 968 * @set_id_led: Set state of identifying LED or revert to automatic function
965 * @push_irq_moderation: Apply interrupt moderation value 969 * @push_irq_moderation: Apply interrupt moderation value
@@ -1078,6 +1082,7 @@ struct efx_nic_type {
1078 size_t (*update_stats)(struct efx_nic *efx, u64 *full_stats, 1082 size_t (*update_stats)(struct efx_nic *efx, u64 *full_stats,
1079 struct rtnl_link_stats64 *core_stats); 1083 struct rtnl_link_stats64 *core_stats);
1080 void (*start_stats)(struct efx_nic *efx); 1084 void (*start_stats)(struct efx_nic *efx);
1085 void (*pull_stats)(struct efx_nic *efx);
1081 void (*stop_stats)(struct efx_nic *efx); 1086 void (*stop_stats)(struct efx_nic *efx);
1082 void (*set_id_led)(struct efx_nic *efx, enum efx_led_mode mode); 1087 void (*set_id_led)(struct efx_nic *efx, enum efx_led_mode mode);
1083 void (*push_irq_moderation)(struct efx_channel *channel); 1088 void (*push_irq_moderation)(struct efx_channel *channel);
diff --git a/drivers/net/ethernet/sfc/nic.c b/drivers/net/ethernet/sfc/nic.c
index 9c90bf56090f..79226b19e3c4 100644
--- a/drivers/net/ethernet/sfc/nic.c
+++ b/drivers/net/ethernet/sfc/nic.c
@@ -519,3 +519,15 @@ void efx_nic_update_stats(const struct efx_hw_stat_desc *desc, size_t count,
519 } 519 }
520 } 520 }
521} 521}
522
523void efx_nic_fix_nodesc_drop_stat(struct efx_nic *efx, u64 *rx_nodesc_drops)
524{
525 /* if down, or this is the first update after coming up */
526 if (!(efx->net_dev->flags & IFF_UP) || !efx->rx_nodesc_drops_prev_state)
527 efx->rx_nodesc_drops_while_down +=
528 *rx_nodesc_drops - efx->rx_nodesc_drops_total;
529 efx->rx_nodesc_drops_total = *rx_nodesc_drops;
530 efx->rx_nodesc_drops_prev_state = !!(efx->net_dev->flags & IFF_UP);
531 *rx_nodesc_drops -= efx->rx_nodesc_drops_while_down;
532}
533
diff --git a/drivers/net/ethernet/sfc/nic.h b/drivers/net/ethernet/sfc/nic.h
index fe71e81ee8bf..7ac9c000696f 100644
--- a/drivers/net/ethernet/sfc/nic.h
+++ b/drivers/net/ethernet/sfc/nic.h
@@ -775,6 +775,7 @@ size_t efx_nic_describe_stats(const struct efx_hw_stat_desc *desc, size_t count,
775void efx_nic_update_stats(const struct efx_hw_stat_desc *desc, size_t count, 775void efx_nic_update_stats(const struct efx_hw_stat_desc *desc, size_t count,
776 const unsigned long *mask, u64 *stats, 776 const unsigned long *mask, u64 *stats,
777 const void *dma_buf, bool accumulate); 777 const void *dma_buf, bool accumulate);
778void efx_nic_fix_nodesc_drop_stat(struct efx_nic *efx, u64 *stat);
778 779
779#define EFX_MAX_FLUSH_TIME 5000 780#define EFX_MAX_FLUSH_TIME 5000
780 781
diff --git a/drivers/net/ethernet/sfc/siena.c b/drivers/net/ethernet/sfc/siena.c
index d034bcd124ef..f2a7ad4c76aa 100644
--- a/drivers/net/ethernet/sfc/siena.c
+++ b/drivers/net/ethernet/sfc/siena.c
@@ -458,6 +458,8 @@ static int siena_try_update_nic_stats(struct efx_nic *efx)
458 return -EAGAIN; 458 return -EAGAIN;
459 459
460 /* Update derived statistics */ 460 /* Update derived statistics */
461 efx_nic_fix_nodesc_drop_stat(efx,
462 &stats[SIENA_STAT_rx_nodesc_drop_cnt]);
461 efx_update_diff_stat(&stats[SIENA_STAT_tx_good_bytes], 463 efx_update_diff_stat(&stats[SIENA_STAT_tx_good_bytes],
462 stats[SIENA_STAT_tx_bytes] - 464 stats[SIENA_STAT_tx_bytes] -
463 stats[SIENA_STAT_tx_bad_bytes]); 465 stats[SIENA_STAT_tx_bad_bytes]);
@@ -878,6 +880,7 @@ const struct efx_nic_type siena_a0_nic_type = {
878 .describe_stats = siena_describe_nic_stats, 880 .describe_stats = siena_describe_nic_stats,
879 .update_stats = siena_update_nic_stats, 881 .update_stats = siena_update_nic_stats,
880 .start_stats = efx_mcdi_mac_start_stats, 882 .start_stats = efx_mcdi_mac_start_stats,
883 .pull_stats = efx_mcdi_mac_pull_stats,
881 .stop_stats = efx_mcdi_mac_stop_stats, 884 .stop_stats = efx_mcdi_mac_stop_stats,
882 .set_id_led = efx_mcdi_set_id_led, 885 .set_id_led = efx_mcdi_set_id_led,
883 .push_irq_moderation = siena_push_irq_moderation, 886 .push_irq_moderation = siena_push_irq_moderation,