diff options
-rw-r--r-- | drivers/net/ethernet/sfc/ef10.c | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/efx.c | 11 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/falcon.c | 10 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/mcdi.h | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/mcdi_port.c | 49 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/net_driver.h | 5 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/nic.c | 12 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/nic.h | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/siena.c | 3 |
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 | */ | ||
2599 | void falcon_pull_nic_stats(struct efx_nic *efx) | ||
2600 | { | ||
2601 | msleep(10); | ||
2602 | } | ||
2603 | |||
2596 | void falcon_stop_nic_stats(struct efx_nic *efx) | 2604 | void 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)) |
302 | void efx_mcdi_mac_start_stats(struct efx_nic *efx); | 302 | void efx_mcdi_mac_start_stats(struct efx_nic *efx); |
303 | void efx_mcdi_mac_stop_stats(struct efx_nic *efx); | 303 | void efx_mcdi_mac_stop_stats(struct efx_nic *efx); |
304 | void efx_mcdi_mac_pull_stats(struct efx_nic *efx); | ||
304 | bool efx_mcdi_mac_check_fault(struct efx_nic *efx); | 305 | bool efx_mcdi_mac_check_fault(struct efx_nic *efx); |
305 | enum reset_type efx_mcdi_map_reset_reason(enum reset_type reason); | 306 | enum reset_type efx_mcdi_map_reset_reason(enum reset_type reason); |
306 | int efx_mcdi_reset(struct efx_nic *efx, enum reset_type method); | 307 | int 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 | ||
930 | static int efx_mcdi_mac_stats(struct efx_nic *efx, dma_addr_t dma_addr, | 930 | enum 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 | |||
936 | static 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 | ||
957 | fail: | 968 | fail: |
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 | ||
973 | void efx_mcdi_mac_stop_stats(struct efx_nic *efx) | 983 | void 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 | |||
991 | void 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 | ||
978 | int efx_mcdi_port_probe(struct efx_nic *efx) | 1005 | int 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 | |||
523 | void 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, | |||
775 | void efx_nic_update_stats(const struct efx_hw_stat_desc *desc, size_t count, | 775 | void 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); |
778 | void 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, |