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: sta...@dpdk.org

Signed-off-by: Junyu Jiang <junyux.ji...@intel.com>
Reviewed-by: Ferruh Yigit <ferruh.yi...@intel.com>
---
V5: move this known issue next to related to the stats
v4: put reading stats and extending in same function.
v3: create a function to hide the extension inside it.
v2: modify the error code
---
---
 doc/guides/nics/i40e.rst       |  9 +++++
 drivers/net/i40e/i40e_ethdev.c | 66 +++++++++++++++++++++-------------
 drivers/net/i40e/i40e_ethdev.h |  9 +++++
 3 files changed, 59 insertions(+), 25 deletions(-)

diff --git a/doc/guides/nics/i40e.rst b/doc/guides/nics/i40e.rst
index b7430f6c4..a0b81e669 100644
--- a/doc/guides/nics/i40e.rst
+++ b/doc/guides/nics/i40e.rst
@@ -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
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c
index 563f21d9d..6439baf2f 100644
--- a/drivers/net/i40e/i40e_ethdev.c
+++ b/drivers/net/i40e/i40e_ethdev.c
@@ -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,
diff --git a/drivers/net/i40e/i40e_ethdev.h b/drivers/net/i40e/i40e_ethdev.h
index 19f821829..1466998aa 100644
--- a/drivers/net/i40e/i40e_ethdev.h
+++ b/drivers/net/i40e/i40e_ethdev.h
@@ -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 {
-- 
2.17.1

Reply via email to