net/i40e: fix byte counters
authorJunyu Jiang <junyux.jiang@intel.com>
Tue, 22 Sep 2020 09:19:31 +0000 (09:19 +0000)
committerFerruh Yigit <ferruh.yigit@intel.com>
Wed, 30 Sep 2020 17:19:09 +0000 (19:19 +0200)
This patch fixed the issue that rx/tx bytes statistics counters
overflowed on 48 bit limitation by enlarging the limitation.

Fixes: 4861cde46116 ("i40e: new poll mode driver")
Cc: stable@dpdk.org
Signed-off-by: Junyu Jiang <junyux.jiang@intel.com>
Reviewed-by: Ferruh Yigit <ferruh.yigit@intel.com>
doc/guides/nics/i40e.rst
drivers/net/i40e/i40e_ethdev.c
drivers/net/i40e/i40e_ethdev.h

index b7430f6..a0b81e6 100644 (file)
@@ -670,6 +670,15 @@ When a packet is over maximum frame size, the packet is dropped.
 However, the Rx statistics, when calling `rte_eth_stats_get` incorrectly
 shows it as received.
 
+RX/TX statistics may be incorrect when register overflowed
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The rx_bytes/tx_bytes statistics register is 48 bit length.
+Although this limitation is enlarged to 64 bit length on the software side,
+but there is no way to detect if the overflow occurred more than once.
+So rx_bytes/tx_bytes statistics data is correct when statistics are
+updated at least once between two overflows.
+
 VF & TC max bandwidth setting
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
index 563f21d..6439baf 100644 (file)
@@ -3052,6 +3052,21 @@ i40e_dev_link_update(struct rte_eth_dev *dev,
        return ret;
 }
 
+static void
+i40e_stat_update_48_in_64(struct i40e_hw *hw, uint32_t hireg,
+                         uint32_t loreg, bool offset_loaded, uint64_t *offset,
+                         uint64_t *stat, uint64_t *prev_stat)
+{
+       i40e_stat_update_48(hw, hireg, loreg, offset_loaded, offset, stat);
+       /* enlarge the limitation when statistics counters overflowed */
+       if (offset_loaded) {
+               if (I40E_RXTX_BYTES_L_48_BIT(*prev_stat) > *stat)
+                       *stat += (uint64_t)1 << I40E_48_BIT_WIDTH;
+               *stat += I40E_RXTX_BYTES_H_16_BIT(*prev_stat);
+       }
+       *prev_stat = *stat;
+}
+
 /* Get all the statistics of a VSI */
 void
 i40e_update_vsi_stats(struct i40e_vsi *vsi)
@@ -3061,9 +3076,9 @@ i40e_update_vsi_stats(struct i40e_vsi *vsi)
        struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
        int idx = rte_le_to_cpu_16(vsi->info.stat_counter_idx);
 
-       i40e_stat_update_48(hw, I40E_GLV_GORCH(idx), I40E_GLV_GORCL(idx),
-                           vsi->offset_loaded, &oes->rx_bytes,
-                           &nes->rx_bytes);
+       i40e_stat_update_48_in_64(hw, I40E_GLV_GORCH(idx), I40E_GLV_GORCL(idx),
+                                 vsi->offset_loaded, &oes->rx_bytes,
+                                 &nes->rx_bytes, &vsi->prev_rx_bytes);
        i40e_stat_update_48(hw, I40E_GLV_UPRCH(idx), I40E_GLV_UPRCL(idx),
                            vsi->offset_loaded, &oes->rx_unicast,
                            &nes->rx_unicast);
@@ -3084,9 +3099,9 @@ i40e_update_vsi_stats(struct i40e_vsi *vsi)
        i40e_stat_update_32(hw, I40E_GLV_RUPP(idx), vsi->offset_loaded,
                            &oes->rx_unknown_protocol,
                            &nes->rx_unknown_protocol);
-       i40e_stat_update_48(hw, I40E_GLV_GOTCH(idx), I40E_GLV_GOTCL(idx),
-                           vsi->offset_loaded, &oes->tx_bytes,
-                           &nes->tx_bytes);
+       i40e_stat_update_48_in_64(hw, I40E_GLV_GOTCH(idx), I40E_GLV_GOTCL(idx),
+                                 vsi->offset_loaded, &oes->tx_bytes,
+                                 &nes->tx_bytes, &vsi->prev_tx_bytes);
        i40e_stat_update_48(hw, I40E_GLV_UPTCH(idx), I40E_GLV_UPTCL(idx),
                            vsi->offset_loaded, &oes->tx_unicast,
                            &nes->tx_unicast);
@@ -3128,17 +3143,18 @@ i40e_read_stats_registers(struct i40e_pf *pf, struct i40e_hw *hw)
        struct i40e_hw_port_stats *os = &pf->stats_offset; /* old stats */
 
        /* Get rx/tx bytes of internal transfer packets */
-       i40e_stat_update_48(hw, I40E_GLV_GORCH(hw->port),
-                       I40E_GLV_GORCL(hw->port),
-                       pf->offset_loaded,
-                       &pf->internal_stats_offset.rx_bytes,
-                       &pf->internal_stats.rx_bytes);
-
-       i40e_stat_update_48(hw, I40E_GLV_GOTCH(hw->port),
-                       I40E_GLV_GOTCL(hw->port),
-                       pf->offset_loaded,
-                       &pf->internal_stats_offset.tx_bytes,
-                       &pf->internal_stats.tx_bytes);
+       i40e_stat_update_48_in_64(hw, I40E_GLV_GORCH(hw->port),
+                                 I40E_GLV_GORCL(hw->port),
+                                 pf->offset_loaded,
+                                 &pf->internal_stats_offset.rx_bytes,
+                                 &pf->internal_stats.rx_bytes,
+                                 &pf->internal_prev_rx_bytes);
+       i40e_stat_update_48_in_64(hw, I40E_GLV_GOTCH(hw->port),
+                                 I40E_GLV_GOTCL(hw->port),
+                                 pf->offset_loaded,
+                                 &pf->internal_stats_offset.tx_bytes,
+                                 &pf->internal_stats.tx_bytes,
+                                 &pf->internal_prev_tx_bytes);
        /* Get total internal rx packet count */
        i40e_stat_update_48(hw, I40E_GLV_UPRCH(hw->port),
                            I40E_GLV_UPRCL(hw->port),
@@ -3178,10 +3194,10 @@ i40e_read_stats_registers(struct i40e_pf *pf, struct i40e_hw *hw)
                pf->internal_stats.rx_broadcast) * RTE_ETHER_CRC_LEN;
 
        /* Get statistics of struct i40e_eth_stats */
-       i40e_stat_update_48(hw, I40E_GLPRT_GORCH(hw->port),
-                           I40E_GLPRT_GORCL(hw->port),
-                           pf->offset_loaded, &os->eth.rx_bytes,
-                           &ns->eth.rx_bytes);
+       i40e_stat_update_48_in_64(hw, I40E_GLPRT_GORCH(hw->port),
+                                 I40E_GLPRT_GORCL(hw->port),
+                                 pf->offset_loaded, &os->eth.rx_bytes,
+                                 &ns->eth.rx_bytes, &pf->prev_rx_bytes);
        i40e_stat_update_48(hw, I40E_GLPRT_UPRCH(hw->port),
                            I40E_GLPRT_UPRCL(hw->port),
                            pf->offset_loaded, &os->eth.rx_unicast,
@@ -3236,10 +3252,10 @@ i40e_read_stats_registers(struct i40e_pf *pf, struct i40e_hw *hw)
                            pf->offset_loaded,
                            &os->eth.rx_unknown_protocol,
                            &ns->eth.rx_unknown_protocol);
-       i40e_stat_update_48(hw, I40E_GLPRT_GOTCH(hw->port),
-                           I40E_GLPRT_GOTCL(hw->port),
-                           pf->offset_loaded, &os->eth.tx_bytes,
-                           &ns->eth.tx_bytes);
+       i40e_stat_update_48_in_64(hw, I40E_GLPRT_GOTCH(hw->port),
+                                 I40E_GLPRT_GOTCL(hw->port),
+                                 pf->offset_loaded, &os->eth.tx_bytes,
+                                 &ns->eth.tx_bytes, &pf->prev_tx_bytes);
        i40e_stat_update_48(hw, I40E_GLPRT_UPTCH(hw->port),
                            I40E_GLPRT_UPTCL(hw->port),
                            pf->offset_loaded, &os->eth.tx_unicast,
index 19f8218..1466998 100644 (file)
@@ -282,6 +282,9 @@ struct rte_flow {
 #define I40E_ETH_OVERHEAD \
        (RTE_ETHER_HDR_LEN + RTE_ETHER_CRC_LEN + I40E_VLAN_TAG_SIZE * 2)
 
+#define I40E_RXTX_BYTES_H_16_BIT(bytes) ((bytes) & ~I40E_48_BIT_MASK)
+#define I40E_RXTX_BYTES_L_48_BIT(bytes) ((bytes) & I40E_48_BIT_MASK)
+
 struct i40e_adapter;
 struct rte_pci_driver;
 
@@ -399,6 +402,8 @@ struct i40e_vsi {
        uint8_t vlan_anti_spoof_on; /* The VLAN anti-spoofing enabled */
        uint8_t vlan_filter_on; /* The VLAN filter enabled */
        struct i40e_bw_info bw_info; /* VSI bandwidth information */
+       uint64_t prev_rx_bytes;
+       uint64_t prev_tx_bytes;
 };
 
 struct pool_entry {
@@ -1156,6 +1161,10 @@ struct i40e_pf {
        uint16_t switch_domain_id;
 
        struct i40e_vf_msg_cfg vf_msg_cfg;
+       uint64_t prev_rx_bytes;
+       uint64_t prev_tx_bytes;
+       uint64_t internal_prev_rx_bytes;
+       uint64_t internal_prev_tx_bytes;
 };
 
 enum pending_msg {