Skip to content

Commit

Permalink
net/i40e: fix stats counters
Browse files Browse the repository at this point in the history
[ upstream commit d8d652e ]

When low and high registers are read separately, this opens the door to
a race condition:
- low register is read
- NIC updates the registers
- high register is read

Because of this, we may end up with an incorrect counter value.
Let's read the registers in one shot, as it is done in Linux kernel
since the introduction of the i40e driver.

Fixes: 4861cde ("i40e: new poll mode driver")

Signed-off-by: Igor Ryzhov <iryzhov@nfware.com>
Acked-by: Qi Zhang <qi.z.zhang@intel.com>
  • Loading branch information
idryzhov authored and bluca committed Feb 2, 2021
1 parent a58c0cc commit 935edd8
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 3 deletions.
10 changes: 10 additions & 0 deletions drivers/net/i40e/base/i40e_osdep.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,14 @@ static inline uint32_t i40e_read_addr(volatile void *addr)
return rte_le_to_cpu_32(I40E_PCI_REG(addr));
}

#define I40E_PCI_REG64(reg) rte_read64(reg)
#define I40E_PCI_REG64_ADDR(a, reg) \
((volatile uint64_t *)((char *)(a)->hw_addr + (reg)))
static inline uint64_t i40e_read64_addr(volatile void *addr)
{
return rte_le_to_cpu_64(I40E_PCI_REG64(addr));
}

#define I40E_PCI_REG_WRITE(reg, value) \
rte_write32((rte_cpu_to_le_32(value)), reg)
#define I40E_PCI_REG_WRITE_RELAXED(reg, value) \
Expand All @@ -150,6 +158,8 @@ static inline uint32_t i40e_read_addr(volatile void *addr)
#define I40E_WRITE_REG(hw, reg, value) \
I40E_PCI_REG_WRITE(I40E_PCI_REG_ADDR((hw), (reg)), (value))

#define I40E_READ_REG64(hw, reg) i40e_read64_addr(I40E_PCI_REG64_ADDR((hw), (reg)))

#define rd32(a, reg) i40e_read_addr(I40E_PCI_REG_ADDR((a), (reg)))
#define wr32(a, reg, value) \
I40E_PCI_REG_WRITE(I40E_PCI_REG_ADDR((a), (reg)), (value))
Expand Down
10 changes: 7 additions & 3 deletions drivers/net/i40e/i40e_ethdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -6620,9 +6620,13 @@ i40e_stat_update_48(struct i40e_hw *hw,
{
uint64_t new_data;

new_data = (uint64_t)I40E_READ_REG(hw, loreg);
new_data |= ((uint64_t)(I40E_READ_REG(hw, hireg) &
I40E_16_BIT_MASK)) << I40E_32_BIT_WIDTH;
if (hw->device_id == I40E_DEV_ID_QEMU) {
new_data = (uint64_t)I40E_READ_REG(hw, loreg);
new_data |= ((uint64_t)(I40E_READ_REG(hw, hireg) &
I40E_16_BIT_MASK)) << I40E_32_BIT_WIDTH;
} else {
new_data = I40E_READ_REG64(hw, loreg);
}

if (!offset_loaded)
*offset = new_data;
Expand Down

0 comments on commit 935edd8

Please sign in to comment.