Commit 4a490432 authored by Jon Mason's avatar Jon Mason Committed by David S. Miller

s2io: resolve statistics issues

This patch resolves a number of issues in the statistics gathering of
the s2io driver.

On Xframe adapters, the received multicast statistics counter includes
pause frames which are not indicated to the driver.  This can cause
issues where the multicast packet count is higher than what has actually
been received, possibly higher than the number of packets received.

The driver software counters are replaced with the adapter hardware
statistics for rx_packets, rx_bytes, and tx_bytes.  It also uses the
overflow registers to determine if the statistics wrapped the 32bit
register (removing the window of having a statistic value less than the
previous call).  rx_length_errors statistic now includes undersized
packets in addition to oversized packets in its counting.  Finally,
rx_crc_errors are now being counted.
Signed-off-by: default avatarJon Mason <jon.mason@exar.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 94e6721d
...@@ -3130,7 +3130,6 @@ static void tx_intr_handler(struct fifo_info *fifo_data) ...@@ -3130,7 +3130,6 @@ static void tx_intr_handler(struct fifo_info *fifo_data)
pkt_cnt++; pkt_cnt++;
/* Updating the statistics block */ /* Updating the statistics block */
nic->dev->stats.tx_bytes += skb->len;
swstats->mem_freed += skb->truesize; swstats->mem_freed += skb->truesize;
dev_kfree_skb_irq(skb); dev_kfree_skb_irq(skb);
...@@ -4901,48 +4900,81 @@ static void s2io_updt_stats(struct s2io_nic *sp) ...@@ -4901,48 +4900,81 @@ static void s2io_updt_stats(struct s2io_nic *sp)
* Return value: * Return value:
* pointer to the updated net_device_stats structure. * pointer to the updated net_device_stats structure.
*/ */
static struct net_device_stats *s2io_get_stats(struct net_device *dev) static struct net_device_stats *s2io_get_stats(struct net_device *dev)
{ {
struct s2io_nic *sp = netdev_priv(dev); struct s2io_nic *sp = netdev_priv(dev);
struct config_param *config = &sp->config;
struct mac_info *mac_control = &sp->mac_control; struct mac_info *mac_control = &sp->mac_control;
struct stat_block *stats = mac_control->stats_info; struct stat_block *stats = mac_control->stats_info;
int i; u64 delta;
/* Configure Stats for immediate updt */ /* Configure Stats for immediate updt */
s2io_updt_stats(sp); s2io_updt_stats(sp);
/* Using sp->stats as a staging area, because reset (due to mtu /* A device reset will cause the on-adapter statistics to be zero'ed.
change, for example) will clear some hardware counters */ * This can be done while running by changing the MTU. To prevent the
dev->stats.tx_packets += le32_to_cpu(stats->tmac_frms) - * system from having the stats zero'ed, the driver keeps a copy of the
sp->stats.tx_packets; * last update to the system (which is also zero'ed on reset). This
sp->stats.tx_packets = le32_to_cpu(stats->tmac_frms); * enables the driver to accurately know the delta between the last
* update and the current update.
dev->stats.tx_errors += le32_to_cpu(stats->tmac_any_err_frms) - */
sp->stats.tx_errors; delta = ((u64) le32_to_cpu(stats->rmac_vld_frms_oflow) << 32 |
sp->stats.tx_errors = le32_to_cpu(stats->tmac_any_err_frms); le32_to_cpu(stats->rmac_vld_frms)) - sp->stats.rx_packets;
sp->stats.rx_packets += delta;
dev->stats.rx_errors += le64_to_cpu(stats->rmac_drop_frms) - dev->stats.rx_packets += delta;
sp->stats.rx_errors;
sp->stats.rx_errors = le64_to_cpu(stats->rmac_drop_frms); delta = ((u64) le32_to_cpu(stats->tmac_frms_oflow) << 32 |
le32_to_cpu(stats->tmac_frms)) - sp->stats.tx_packets;
dev->stats.multicast = le32_to_cpu(stats->rmac_vld_mcst_frms) - sp->stats.tx_packets += delta;
sp->stats.multicast; dev->stats.tx_packets += delta;
sp->stats.multicast = le32_to_cpu(stats->rmac_vld_mcst_frms);
delta = ((u64) le32_to_cpu(stats->rmac_data_octets_oflow) << 32 |
dev->stats.rx_length_errors = le64_to_cpu(stats->rmac_long_frms) - le32_to_cpu(stats->rmac_data_octets)) - sp->stats.rx_bytes;
sp->stats.rx_length_errors; sp->stats.rx_bytes += delta;
sp->stats.rx_length_errors = le64_to_cpu(stats->rmac_long_frms); dev->stats.rx_bytes += delta;
delta = ((u64) le32_to_cpu(stats->tmac_data_octets_oflow) << 32 |
le32_to_cpu(stats->tmac_data_octets)) - sp->stats.tx_bytes;
sp->stats.tx_bytes += delta;
dev->stats.tx_bytes += delta;
delta = le64_to_cpu(stats->rmac_drop_frms) - sp->stats.rx_errors;
sp->stats.rx_errors += delta;
dev->stats.rx_errors += delta;
delta = ((u64) le32_to_cpu(stats->tmac_any_err_frms_oflow) << 32 |
le32_to_cpu(stats->tmac_any_err_frms)) - sp->stats.tx_errors;
sp->stats.tx_errors += delta;
dev->stats.tx_errors += delta;
delta = le64_to_cpu(stats->rmac_drop_frms) - sp->stats.rx_dropped;
sp->stats.rx_dropped += delta;
dev->stats.rx_dropped += delta;
delta = le64_to_cpu(stats->tmac_drop_frms) - sp->stats.tx_dropped;
sp->stats.tx_dropped += delta;
dev->stats.tx_dropped += delta;
/* The adapter MAC interprets pause frames as multicast packets, but
* does not pass them up. This erroneously increases the multicast
* packet count and needs to be deducted when the multicast frame count
* is queried.
*/
delta = (u64) le32_to_cpu(stats->rmac_vld_mcst_frms_oflow) << 32 |
le32_to_cpu(stats->rmac_vld_mcst_frms);
delta -= le64_to_cpu(stats->rmac_pause_ctrl_frms);
delta -= sp->stats.multicast;
sp->stats.multicast += delta;
dev->stats.multicast += delta;
/* collect per-ring rx_packets and rx_bytes */ delta = ((u64) le32_to_cpu(stats->rmac_usized_frms_oflow) << 32 |
dev->stats.rx_packets = dev->stats.rx_bytes = 0; le32_to_cpu(stats->rmac_usized_frms)) +
for (i = 0; i < config->rx_ring_num; i++) { le64_to_cpu(stats->rmac_long_frms) - sp->stats.rx_length_errors;
struct ring_info *ring = &mac_control->rings[i]; sp->stats.rx_length_errors += delta;
dev->stats.rx_length_errors += delta;
dev->stats.rx_packets += ring->rx_packets; delta = le64_to_cpu(stats->rmac_fcs_err_frms) - sp->stats.rx_crc_errors;
dev->stats.rx_bytes += ring->rx_bytes; sp->stats.rx_crc_errors += delta;
} dev->stats.rx_crc_errors += delta;
return &dev->stats; return &dev->stats;
} }
...@@ -7455,15 +7487,11 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) ...@@ -7455,15 +7487,11 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)
} }
} }
/* Updating statistics */
ring_data->rx_packets++;
rxdp->Host_Control = 0; rxdp->Host_Control = 0;
if (sp->rxd_mode == RXD_MODE_1) { if (sp->rxd_mode == RXD_MODE_1) {
int len = RXD_GET_BUFFER0_SIZE_1(rxdp->Control_2); int len = RXD_GET_BUFFER0_SIZE_1(rxdp->Control_2);
ring_data->rx_bytes += len;
skb_put(skb, len); skb_put(skb, len);
} else if (sp->rxd_mode == RXD_MODE_3B) { } else if (sp->rxd_mode == RXD_MODE_3B) {
int get_block = ring_data->rx_curr_get_info.block_index; int get_block = ring_data->rx_curr_get_info.block_index;
int get_off = ring_data->rx_curr_get_info.offset; int get_off = ring_data->rx_curr_get_info.offset;
...@@ -7472,7 +7500,6 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) ...@@ -7472,7 +7500,6 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)
unsigned char *buff = skb_push(skb, buf0_len); unsigned char *buff = skb_push(skb, buf0_len);
struct buffAdd *ba = &ring_data->ba[get_block][get_off]; struct buffAdd *ba = &ring_data->ba[get_block][get_off];
ring_data->rx_bytes += buf0_len + buf2_len;
memcpy(buff, ba->ba_0, buf0_len); memcpy(buff, ba->ba_0, buf0_len);
skb_put(skb, buf2_len); skb_put(skb, buf2_len);
} }
......
...@@ -745,10 +745,6 @@ struct ring_info { ...@@ -745,10 +745,6 @@ struct ring_info {
/* Buffer Address store. */ /* Buffer Address store. */
struct buffAdd **ba; struct buffAdd **ba;
/* per-Ring statistics */
unsigned long rx_packets;
unsigned long rx_bytes;
} ____cacheline_aligned; } ____cacheline_aligned;
/* Fifo specific structure */ /* Fifo specific structure */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment