forked from Minki/linux
ixgbevf: Fix VF Stats accounting after reset
The counters in the 82599 Virtual Function are not clear on read. They accumulate to the maximum value and then roll over. They are also not cleared when the VF executes a soft reset, so it is possible they are non-zero when the driver loads and starts. This has all been accounted for in the code that keeps the stats up to date but there is one case that is not. When the PF driver is reset the counters in the VF are all reset to zero. This adds an additional accounting overhead into the VF driver when the PF is reset under its feet. This patch adds additional counters that are used by the VF driver to accumulate and save stats after a PF reset has been detected. Prior to this patch displaying the stats in the VF after the PF has reset would show bogus data. Signed-off-by: Greg Rose <gregory.v.rose@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
fd3686a842
commit
33bd9f601e
@ -46,22 +46,32 @@ struct ixgbe_stats {
|
|||||||
int sizeof_stat;
|
int sizeof_stat;
|
||||||
int stat_offset;
|
int stat_offset;
|
||||||
int base_stat_offset;
|
int base_stat_offset;
|
||||||
|
int saved_reset_offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define IXGBEVF_STAT(m, b) sizeof(((struct ixgbevf_adapter *)0)->m), \
|
#define IXGBEVF_STAT(m, b, r) sizeof(((struct ixgbevf_adapter *)0)->m), \
|
||||||
offsetof(struct ixgbevf_adapter, m), \
|
offsetof(struct ixgbevf_adapter, m), \
|
||||||
offsetof(struct ixgbevf_adapter, b)
|
offsetof(struct ixgbevf_adapter, b), \
|
||||||
|
offsetof(struct ixgbevf_adapter, r)
|
||||||
static struct ixgbe_stats ixgbe_gstrings_stats[] = {
|
static struct ixgbe_stats ixgbe_gstrings_stats[] = {
|
||||||
{"rx_packets", IXGBEVF_STAT(stats.vfgprc, stats.base_vfgprc)},
|
{"rx_packets", IXGBEVF_STAT(stats.vfgprc, stats.base_vfgprc,
|
||||||
{"tx_packets", IXGBEVF_STAT(stats.vfgptc, stats.base_vfgptc)},
|
stats.saved_reset_vfgprc)},
|
||||||
{"rx_bytes", IXGBEVF_STAT(stats.vfgorc, stats.base_vfgorc)},
|
{"tx_packets", IXGBEVF_STAT(stats.vfgptc, stats.base_vfgptc,
|
||||||
{"tx_bytes", IXGBEVF_STAT(stats.vfgotc, stats.base_vfgotc)},
|
stats.saved_reset_vfgptc)},
|
||||||
{"tx_busy", IXGBEVF_STAT(tx_busy, zero_base)},
|
{"rx_bytes", IXGBEVF_STAT(stats.vfgorc, stats.base_vfgorc,
|
||||||
{"multicast", IXGBEVF_STAT(stats.vfmprc, stats.base_vfmprc)},
|
stats.saved_reset_vfgorc)},
|
||||||
{"rx_csum_offload_good", IXGBEVF_STAT(hw_csum_rx_good, zero_base)},
|
{"tx_bytes", IXGBEVF_STAT(stats.vfgotc, stats.base_vfgotc,
|
||||||
{"rx_csum_offload_errors", IXGBEVF_STAT(hw_csum_rx_error, zero_base)},
|
stats.saved_reset_vfgotc)},
|
||||||
{"tx_csum_offload_ctxt", IXGBEVF_STAT(hw_csum_tx_good, zero_base)},
|
{"tx_busy", IXGBEVF_STAT(tx_busy, zero_base, zero_base)},
|
||||||
{"rx_header_split", IXGBEVF_STAT(rx_hdr_split, zero_base)},
|
{"multicast", IXGBEVF_STAT(stats.vfmprc, stats.base_vfmprc,
|
||||||
|
stats.saved_reset_vfmprc)},
|
||||||
|
{"rx_csum_offload_good", IXGBEVF_STAT(hw_csum_rx_good, zero_base,
|
||||||
|
zero_base)},
|
||||||
|
{"rx_csum_offload_errors", IXGBEVF_STAT(hw_csum_rx_error, zero_base,
|
||||||
|
zero_base)},
|
||||||
|
{"tx_csum_offload_ctxt", IXGBEVF_STAT(hw_csum_tx_good, zero_base,
|
||||||
|
zero_base)},
|
||||||
|
{"rx_header_split", IXGBEVF_STAT(rx_hdr_split, zero_base, zero_base)},
|
||||||
};
|
};
|
||||||
|
|
||||||
#define IXGBE_QUEUE_STATS_LEN 0
|
#define IXGBE_QUEUE_STATS_LEN 0
|
||||||
@ -455,10 +465,14 @@ static void ixgbevf_get_ethtool_stats(struct net_device *netdev,
|
|||||||
ixgbe_gstrings_stats[i].stat_offset;
|
ixgbe_gstrings_stats[i].stat_offset;
|
||||||
char *b = (char *)adapter +
|
char *b = (char *)adapter +
|
||||||
ixgbe_gstrings_stats[i].base_stat_offset;
|
ixgbe_gstrings_stats[i].base_stat_offset;
|
||||||
|
char *r = (char *)adapter +
|
||||||
|
ixgbe_gstrings_stats[i].saved_reset_offset;
|
||||||
data[i] = ((ixgbe_gstrings_stats[i].sizeof_stat ==
|
data[i] = ((ixgbe_gstrings_stats[i].sizeof_stat ==
|
||||||
sizeof(u64)) ? *(u64 *)p : *(u32 *)p) -
|
sizeof(u64)) ? *(u64 *)p : *(u32 *)p) -
|
||||||
((ixgbe_gstrings_stats[i].sizeof_stat ==
|
((ixgbe_gstrings_stats[i].sizeof_stat ==
|
||||||
sizeof(u64)) ? *(u64 *)b : *(u32 *)b);
|
sizeof(u64)) ? *(u64 *)b : *(u32 *)b) +
|
||||||
|
((ixgbe_gstrings_stats[i].sizeof_stat ==
|
||||||
|
sizeof(u64)) ? *(u64 *)r : *(u32 *)r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1610,6 +1610,44 @@ static inline void ixgbevf_rx_desc_queue_enable(struct ixgbevf_adapter *adapter,
|
|||||||
(adapter->rx_ring[rxr].count - 1));
|
(adapter->rx_ring[rxr].count - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ixgbevf_save_reset_stats(struct ixgbevf_adapter *adapter)
|
||||||
|
{
|
||||||
|
/* Only save pre-reset stats if there are some */
|
||||||
|
if (adapter->stats.vfgprc || adapter->stats.vfgptc) {
|
||||||
|
adapter->stats.saved_reset_vfgprc += adapter->stats.vfgprc -
|
||||||
|
adapter->stats.base_vfgprc;
|
||||||
|
adapter->stats.saved_reset_vfgptc += adapter->stats.vfgptc -
|
||||||
|
adapter->stats.base_vfgptc;
|
||||||
|
adapter->stats.saved_reset_vfgorc += adapter->stats.vfgorc -
|
||||||
|
adapter->stats.base_vfgorc;
|
||||||
|
adapter->stats.saved_reset_vfgotc += adapter->stats.vfgotc -
|
||||||
|
adapter->stats.base_vfgotc;
|
||||||
|
adapter->stats.saved_reset_vfmprc += adapter->stats.vfmprc -
|
||||||
|
adapter->stats.base_vfmprc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ixgbevf_init_last_counter_stats(struct ixgbevf_adapter *adapter)
|
||||||
|
{
|
||||||
|
struct ixgbe_hw *hw = &adapter->hw;
|
||||||
|
|
||||||
|
adapter->stats.last_vfgprc = IXGBE_READ_REG(hw, IXGBE_VFGPRC);
|
||||||
|
adapter->stats.last_vfgorc = IXGBE_READ_REG(hw, IXGBE_VFGORC_LSB);
|
||||||
|
adapter->stats.last_vfgorc |=
|
||||||
|
(((u64)(IXGBE_READ_REG(hw, IXGBE_VFGORC_MSB))) << 32);
|
||||||
|
adapter->stats.last_vfgptc = IXGBE_READ_REG(hw, IXGBE_VFGPTC);
|
||||||
|
adapter->stats.last_vfgotc = IXGBE_READ_REG(hw, IXGBE_VFGOTC_LSB);
|
||||||
|
adapter->stats.last_vfgotc |=
|
||||||
|
(((u64)(IXGBE_READ_REG(hw, IXGBE_VFGOTC_MSB))) << 32);
|
||||||
|
adapter->stats.last_vfmprc = IXGBE_READ_REG(hw, IXGBE_VFMPRC);
|
||||||
|
|
||||||
|
adapter->stats.base_vfgprc = adapter->stats.last_vfgprc;
|
||||||
|
adapter->stats.base_vfgorc = adapter->stats.last_vfgorc;
|
||||||
|
adapter->stats.base_vfgptc = adapter->stats.last_vfgptc;
|
||||||
|
adapter->stats.base_vfgotc = adapter->stats.last_vfgotc;
|
||||||
|
adapter->stats.base_vfmprc = adapter->stats.last_vfmprc;
|
||||||
|
}
|
||||||
|
|
||||||
static int ixgbevf_up_complete(struct ixgbevf_adapter *adapter)
|
static int ixgbevf_up_complete(struct ixgbevf_adapter *adapter)
|
||||||
{
|
{
|
||||||
struct net_device *netdev = adapter->netdev;
|
struct net_device *netdev = adapter->netdev;
|
||||||
@ -1656,6 +1694,9 @@ static int ixgbevf_up_complete(struct ixgbevf_adapter *adapter)
|
|||||||
/* enable transmits */
|
/* enable transmits */
|
||||||
netif_tx_start_all_queues(netdev);
|
netif_tx_start_all_queues(netdev);
|
||||||
|
|
||||||
|
ixgbevf_save_reset_stats(adapter);
|
||||||
|
ixgbevf_init_last_counter_stats(adapter);
|
||||||
|
|
||||||
/* bring the link up in the watchdog, this could race with our first
|
/* bring the link up in the watchdog, this could race with our first
|
||||||
* link up interrupt but shouldn't be a problem */
|
* link up interrupt but shouldn't be a problem */
|
||||||
adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
|
adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
|
||||||
@ -2228,27 +2269,6 @@ out:
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ixgbevf_init_last_counter_stats(struct ixgbevf_adapter *adapter)
|
|
||||||
{
|
|
||||||
struct ixgbe_hw *hw = &adapter->hw;
|
|
||||||
|
|
||||||
adapter->stats.last_vfgprc = IXGBE_READ_REG(hw, IXGBE_VFGPRC);
|
|
||||||
adapter->stats.last_vfgorc = IXGBE_READ_REG(hw, IXGBE_VFGORC_LSB);
|
|
||||||
adapter->stats.last_vfgorc |=
|
|
||||||
(((u64)(IXGBE_READ_REG(hw, IXGBE_VFGORC_MSB))) << 32);
|
|
||||||
adapter->stats.last_vfgptc = IXGBE_READ_REG(hw, IXGBE_VFGPTC);
|
|
||||||
adapter->stats.last_vfgotc = IXGBE_READ_REG(hw, IXGBE_VFGOTC_LSB);
|
|
||||||
adapter->stats.last_vfgotc |=
|
|
||||||
(((u64)(IXGBE_READ_REG(hw, IXGBE_VFGOTC_MSB))) << 32);
|
|
||||||
adapter->stats.last_vfmprc = IXGBE_READ_REG(hw, IXGBE_VFMPRC);
|
|
||||||
|
|
||||||
adapter->stats.base_vfgprc = adapter->stats.last_vfgprc;
|
|
||||||
adapter->stats.base_vfgorc = adapter->stats.last_vfgorc;
|
|
||||||
adapter->stats.base_vfgptc = adapter->stats.last_vfgptc;
|
|
||||||
adapter->stats.base_vfgotc = adapter->stats.last_vfgotc;
|
|
||||||
adapter->stats.base_vfmprc = adapter->stats.last_vfmprc;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define UPDATE_VF_COUNTER_32bit(reg, last_counter, counter) \
|
#define UPDATE_VF_COUNTER_32bit(reg, last_counter, counter) \
|
||||||
{ \
|
{ \
|
||||||
u32 current_counter = IXGBE_READ_REG(hw, reg); \
|
u32 current_counter = IXGBE_READ_REG(hw, reg); \
|
||||||
@ -2416,9 +2436,9 @@ static void ixgbevf_watchdog_task(struct work_struct *work)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pf_has_reset:
|
|
||||||
ixgbevf_update_stats(adapter);
|
ixgbevf_update_stats(adapter);
|
||||||
|
|
||||||
|
pf_has_reset:
|
||||||
/* Force detection of hung controller every watchdog period */
|
/* Force detection of hung controller every watchdog period */
|
||||||
adapter->detect_tx_hung = true;
|
adapter->detect_tx_hung = true;
|
||||||
|
|
||||||
@ -3390,8 +3410,6 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
|
|||||||
/* setup the private structure */
|
/* setup the private structure */
|
||||||
err = ixgbevf_sw_init(adapter);
|
err = ixgbevf_sw_init(adapter);
|
||||||
|
|
||||||
ixgbevf_init_last_counter_stats(adapter);
|
|
||||||
|
|
||||||
#ifdef MAX_SKB_FRAGS
|
#ifdef MAX_SKB_FRAGS
|
||||||
netdev->features = NETIF_F_SG |
|
netdev->features = NETIF_F_SG |
|
||||||
NETIF_F_IP_CSUM |
|
NETIF_F_IP_CSUM |
|
||||||
@ -3449,6 +3467,8 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
|
|||||||
|
|
||||||
adapter->netdev_registered = true;
|
adapter->netdev_registered = true;
|
||||||
|
|
||||||
|
ixgbevf_init_last_counter_stats(adapter);
|
||||||
|
|
||||||
/* print the MAC address */
|
/* print the MAC address */
|
||||||
hw_dbg(hw, "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
|
hw_dbg(hw, "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
|
||||||
netdev->dev_addr[0],
|
netdev->dev_addr[0],
|
||||||
|
@ -157,6 +157,12 @@ struct ixgbevf_hw_stats {
|
|||||||
u64 vfgorc;
|
u64 vfgorc;
|
||||||
u64 vfgotc;
|
u64 vfgotc;
|
||||||
u64 vfmprc;
|
u64 vfmprc;
|
||||||
|
|
||||||
|
u64 saved_reset_vfgprc;
|
||||||
|
u64 saved_reset_vfgptc;
|
||||||
|
u64 saved_reset_vfgorc;
|
||||||
|
u64 saved_reset_vfgotc;
|
||||||
|
u64 saved_reset_vfmprc;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ixgbevf_info {
|
struct ixgbevf_info {
|
||||||
|
Loading…
Reference in New Issue
Block a user