Skip to content

Commit

Permalink
sfc: Fix interface statistics running backward
Browse files Browse the repository at this point in the history
Some interface statistics are computed in such a way that they can
sometimes decrease (and even underflow).  Since the computed value
will never be greater than the true value, we fix this by only storing
the computed value when it increases.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
  • Loading branch information
Ben Hutchings committed Jul 17, 2012
1 parent d4f2cec commit b7f514a
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 10 deletions.
12 changes: 6 additions & 6 deletions drivers/net/ethernet/sfc/falcon_xmac.c
Original file line number Diff line number Diff line change
Expand Up @@ -341,12 +341,12 @@ void falcon_update_stats_xmac(struct efx_nic *efx)
FALCON_STAT(efx, XgTxIpSrcErrPkt, tx_ip_src_error);

/* Update derived statistics */
mac_stats->tx_good_bytes =
(mac_stats->tx_bytes - mac_stats->tx_bad_bytes -
mac_stats->tx_control * 64);
mac_stats->rx_bad_bytes =
(mac_stats->rx_bytes - mac_stats->rx_good_bytes -
mac_stats->rx_control * 64);
efx_update_diff_stat(&mac_stats->tx_good_bytes,
mac_stats->tx_bytes - mac_stats->tx_bad_bytes -
mac_stats->tx_control * 64);
efx_update_diff_stat(&mac_stats->rx_bad_bytes,
mac_stats->rx_bytes - mac_stats->rx_good_bytes -
mac_stats->rx_control * 64);
}

void falcon_poll_xmac(struct efx_nic *efx)
Expand Down
18 changes: 18 additions & 0 deletions drivers/net/ethernet/sfc/nic.h
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,24 @@ extern bool falcon_xmac_check_fault(struct efx_nic *efx);
extern int falcon_reconfigure_xmac(struct efx_nic *efx);
extern void falcon_update_stats_xmac(struct efx_nic *efx);

/* Some statistics are computed as A - B where A and B each increase
* linearly with some hardware counter(s) and the counters are read
* asynchronously. If the counters contributing to B are always read
* after those contributing to A, the computed value may be lower than
* the true value by some variable amount, and may decrease between
* subsequent computations.
*
* We should never allow statistics to decrease or to exceed the true
* value. Since the computed value will never be greater than the
* true value, we can achieve this by only storing the computed value
* when it increases.
*/
static inline void efx_update_diff_stat(u64 *stat, u64 diff)
{
if ((s64)(diff - *stat) > 0)
*stat = diff;
}

/* Interrupts and test events */
extern int efx_nic_init_interrupt(struct efx_nic *efx);
extern void efx_nic_enable_interrupts(struct efx_nic *efx);
Expand Down
8 changes: 4 additions & 4 deletions drivers/net/ethernet/sfc/siena.c
Original file line number Diff line number Diff line change
Expand Up @@ -458,8 +458,8 @@ static int siena_try_update_nic_stats(struct efx_nic *efx)

MAC_STAT(tx_bytes, TX_BYTES);
MAC_STAT(tx_bad_bytes, TX_BAD_BYTES);
mac_stats->tx_good_bytes = (mac_stats->tx_bytes -
mac_stats->tx_bad_bytes);
efx_update_diff_stat(&mac_stats->tx_good_bytes,
mac_stats->tx_bytes - mac_stats->tx_bad_bytes);
MAC_STAT(tx_packets, TX_PKTS);
MAC_STAT(tx_bad, TX_BAD_FCS_PKTS);
MAC_STAT(tx_pause, TX_PAUSE_PKTS);
Expand Down Expand Up @@ -492,8 +492,8 @@ static int siena_try_update_nic_stats(struct efx_nic *efx)
MAC_STAT(tx_ip_src_error, TX_IP_SRC_ERR_PKTS);
MAC_STAT(rx_bytes, RX_BYTES);
MAC_STAT(rx_bad_bytes, RX_BAD_BYTES);
mac_stats->rx_good_bytes = (mac_stats->rx_bytes -
mac_stats->rx_bad_bytes);
efx_update_diff_stat(&mac_stats->rx_good_bytes,
mac_stats->rx_bytes - mac_stats->rx_bad_bytes);
MAC_STAT(rx_packets, RX_PKTS);
MAC_STAT(rx_good, RX_GOOD_PKTS);
MAC_STAT(rx_bad, RX_BAD_FCS_PKTS);
Expand Down

0 comments on commit b7f514a

Please sign in to comment.