Commit ab1594e9 authored by Sathya Perla's avatar Sathya Perla Committed by David S. Miller
Browse files

be2net: use stats-sync to read/write 64-bit stats



64-bit stats in be2net are written/read as follows using the stats-sync
interface for safe access in 32-bit archs:

64-bit 		sync			writer			reader
stats
------------------------------------------------------------------------------
tx_stats	tx_stats->sync		be_xmit			be_get_stats64,
								ethtool
tx-compl	tx_stats->sync_compl	tx-compl-processing	ethtool
rx-stats	rx_stats->sync		rx-compl-processing	be_get_stats64,
								ethtool,
								eqd-update

This patch is based on Stephen Hemminger's earlier patch on the same issue...
Signed-off-by: default avatarSathya Perla <sathya.perla@emulex.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ac124ff9
......@@ -29,6 +29,7 @@
#include <linux/interrupt.h>
#include <linux/firmware.h>
#include <linux/slab.h>
#include <linux/u64_stats_sync.h>
#include "be_hw.h"
......@@ -174,6 +175,8 @@ struct be_tx_stats {
u64 tx_compl;
ulong tx_jiffies;
u32 tx_stops;
struct u64_stats_sync sync;
struct u64_stats_sync sync_compl;
};
struct be_tx_obj {
......@@ -206,6 +209,7 @@ struct be_rx_stats {
u32 rx_mcast_pkts;
u32 rx_compl_err; /* completions with err set */
u32 rx_pps; /* pkts per second */
struct u64_stats_sync sync;
};
struct be_rx_compl_info {
......@@ -518,7 +522,6 @@ static inline bool be_multi_rxq(const struct be_adapter *adapter)
extern void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm,
u16 num_popped);
extern void be_link_status_update(struct be_adapter *adapter, bool link_up);
extern void netdev_stats_update(struct be_adapter *adapter);
extern void be_parse_stats(struct be_adapter *adapter);
extern int be_load_fw(struct be_adapter *adapter, u8 *func);
#endif /* BE_H */
......@@ -83,7 +83,6 @@ static int be_mcc_compl_process(struct be_adapter *adapter,
(compl->tag0 == OPCODE_ETH_GET_PPORT_STATS)) &&
(compl->tag1 == CMD_SUBSYSTEM_ETH)) {
be_parse_stats(adapter);
netdev_stats_update(adapter);
adapter->stats_cmd_sent = false;
}
} else {
......
......@@ -74,10 +74,12 @@ static const struct be_ethtool_stat et_stats[] = {
};
#define ETHTOOL_STATS_NUM ARRAY_SIZE(et_stats)
/* Stats related to multi RX queues */
/* Stats related to multi RX queues: get_stats routine assumes bytes, pkts
* are first and second members respectively.
*/
static const struct be_ethtool_stat et_rx_stats[] = {
{DRVSTAT_RX_INFO(rx_bytes)},
{DRVSTAT_RX_INFO(rx_pkts)},
{DRVSTAT_RX_INFO(rx_bytes)},/* If moving this member see above note */
{DRVSTAT_RX_INFO(rx_pkts)}, /* If moving this member see above note */
{DRVSTAT_RX_INFO(rx_polls)},
{DRVSTAT_RX_INFO(rx_events)},
{DRVSTAT_RX_INFO(rx_compl)},
......@@ -88,8 +90,11 @@ static const struct be_ethtool_stat et_rx_stats[] = {
};
#define ETHTOOL_RXSTATS_NUM (ARRAY_SIZE(et_rx_stats))
/* Stats related to multi TX queues */
/* Stats related to multi TX queues: get_stats routine assumes compl is the
* first member
*/
static const struct be_ethtool_stat et_tx_stats[] = {
{DRVSTAT_TX_INFO(tx_compl)}, /* If moving this member see above note */
{DRVSTAT_TX_INFO(tx_bytes)},
{DRVSTAT_TX_INFO(tx_pkts)},
{DRVSTAT_TX_INFO(tx_reqs)},
......@@ -243,32 +248,48 @@ be_get_ethtool_stats(struct net_device *netdev,
struct be_rx_obj *rxo;
struct be_tx_obj *txo;
void *p;
int i, j, base;
unsigned int i, j, base = 0, start;
for (i = 0; i < ETHTOOL_STATS_NUM; i++) {
p = (u8 *)&adapter->drv_stats + et_stats[i].offset;
data[i] = (et_stats[i].size == sizeof(u64)) ?
*(u64 *)p: *(u32 *)p;
data[i] = *(u32 *)p;
}
base += ETHTOOL_STATS_NUM;
base = ETHTOOL_STATS_NUM;
for_all_rx_queues(adapter, rxo, j) {
for (i = 0; i < ETHTOOL_RXSTATS_NUM; i++) {
p = (u8 *)rx_stats(rxo) + et_rx_stats[i].offset;
data[base + j * ETHTOOL_RXSTATS_NUM + i] =
(et_rx_stats[i].size == sizeof(u64)) ?
*(u64 *)p: *(u32 *)p;
struct be_rx_stats *stats = rx_stats(rxo);
do {
start = u64_stats_fetch_begin_bh(&stats->sync);
data[base] = stats->rx_bytes;
data[base + 1] = stats->rx_pkts;
} while (u64_stats_fetch_retry_bh(&stats->sync, start));
for (i = 2; i < ETHTOOL_RXSTATS_NUM; i++) {
p = (u8 *)stats + et_rx_stats[i].offset;
data[base + i] = *(u32 *)p;
}
base += ETHTOOL_RXSTATS_NUM;
}
base = ETHTOOL_STATS_NUM + adapter->num_rx_qs * ETHTOOL_RXSTATS_NUM;
for_all_tx_queues(adapter, txo, j) {
for (i = 0; i < ETHTOOL_TXSTATS_NUM; i++) {
p = (u8 *)tx_stats(txo) + et_tx_stats[i].offset;
data[base + j * ETHTOOL_TXSTATS_NUM + i] =
(et_tx_stats[i].size == sizeof(u64)) ?
*(u64 *)p: *(u32 *)p;
}
struct be_tx_stats *stats = tx_stats(txo);
do {
start = u64_stats_fetch_begin_bh(&stats->sync_compl);
data[base] = stats->tx_compl;
} while (u64_stats_fetch_retry_bh(&stats->sync_compl, start));
do {
start = u64_stats_fetch_begin_bh(&stats->sync);
for (i = 1; i < ETHTOOL_TXSTATS_NUM; i++) {
p = (u8 *)stats + et_tx_stats[i].offset;
data[base + i] =
(et_tx_stats[i].size == sizeof(u64)) ?
*(u64 *)p : *(u32 *)p;
}
} while (u64_stats_fetch_retry_bh(&stats->sync, start));
base += ETHTOOL_TXSTATS_NUM;
}
}
......
......@@ -396,36 +396,44 @@ void be_parse_stats(struct be_adapter *adapter)
erx->rx_drops_no_fragments[rxo->q.id];
}
void netdev_stats_update(struct be_adapter *adapter)
static struct rtnl_link_stats64 *be_get_stats64(struct net_device *netdev,
struct rtnl_link_stats64 *stats)
{
struct be_adapter *adapter = netdev_priv(netdev);
struct be_drv_stats *drvs = &adapter->drv_stats;
struct net_device_stats *dev_stats = &adapter->netdev->stats;
struct be_rx_obj *rxo;
struct be_tx_obj *txo;
unsigned long pkts = 0, bytes = 0, mcast = 0, drops = 0;
u64 pkts, bytes;
unsigned int start;
int i;
for_all_rx_queues(adapter, rxo, i) {
pkts += rx_stats(rxo)->rx_pkts;
bytes += rx_stats(rxo)->rx_bytes;
mcast += rx_stats(rxo)->rx_mcast_pkts;
drops += rx_stats(rxo)->rx_drops_no_skbs;
const struct be_rx_stats *rx_stats = rx_stats(rxo);
do {
start = u64_stats_fetch_begin_bh(&rx_stats->sync);
pkts = rx_stats(rxo)->rx_pkts;
bytes = rx_stats(rxo)->rx_bytes;
} while (u64_stats_fetch_retry_bh(&rx_stats->sync, start));
stats->rx_packets += pkts;
stats->rx_bytes += bytes;
stats->multicast += rx_stats(rxo)->rx_mcast_pkts;
stats->rx_dropped += rx_stats(rxo)->rx_drops_no_skbs +
rx_stats(rxo)->rx_drops_no_frags;
}
dev_stats->rx_packets = pkts;
dev_stats->rx_bytes = bytes;
dev_stats->multicast = mcast;
dev_stats->rx_dropped = drops;
pkts = bytes = 0;
for_all_tx_queues(adapter, txo, i) {
pkts += tx_stats(txo)->tx_pkts;
bytes += tx_stats(txo)->tx_bytes;
const struct be_tx_stats *tx_stats = tx_stats(txo);
do {
start = u64_stats_fetch_begin_bh(&tx_stats->sync);
pkts = tx_stats(txo)->tx_pkts;
bytes = tx_stats(txo)->tx_bytes;
} while (u64_stats_fetch_retry_bh(&tx_stats->sync, start));
stats->tx_packets += pkts;
stats->tx_bytes += bytes;
}
dev_stats->tx_packets = pkts;
dev_stats->tx_bytes = bytes;
/* bad pkts received */
dev_stats->rx_errors = drvs->rx_crc_errors +
stats->rx_errors = drvs->rx_crc_errors +
drvs->rx_alignment_symbol_errors +
drvs->rx_in_range_errors +
drvs->rx_out_range_errors +
......@@ -434,26 +442,24 @@ void netdev_stats_update(struct be_adapter *adapter)
drvs->rx_dropped_too_short +
drvs->rx_dropped_header_too_small +
drvs->rx_dropped_tcp_length +
drvs->rx_dropped_runt +
drvs->rx_tcp_checksum_errs +
drvs->rx_ip_checksum_errs +
drvs->rx_udp_checksum_errs;
drvs->rx_dropped_runt;
/* detailed rx errors */
dev_stats->rx_length_errors = drvs->rx_in_range_errors +
stats->rx_length_errors = drvs->rx_in_range_errors +
drvs->rx_out_range_errors +
drvs->rx_frame_too_long;
dev_stats->rx_crc_errors = drvs->rx_crc_errors;
stats->rx_crc_errors = drvs->rx_crc_errors;
/* frame alignment errors */
dev_stats->rx_frame_errors = drvs->rx_alignment_symbol_errors;
stats->rx_frame_errors = drvs->rx_alignment_symbol_errors;
/* receiver fifo overrun */
/* drops_no_pbuf is no per i/f, it's per BE card */
dev_stats->rx_fifo_errors = drvs->rxpp_fifo_overflow_drop +
stats->rx_fifo_errors = drvs->rxpp_fifo_overflow_drop +
drvs->rx_input_fifo_overflow_drop +
drvs->rx_drops_no_pbuf;
return stats;
}
void be_link_status_update(struct be_adapter *adapter, bool link_up)
......@@ -479,12 +485,14 @@ static void be_tx_stats_update(struct be_tx_obj *txo,
{
struct be_tx_stats *stats = tx_stats(txo);
u64_stats_update_begin(&stats->sync);
stats->tx_reqs++;
stats->tx_wrbs += wrb_cnt;
stats->tx_bytes += copied;
stats->tx_pkts += (gso_segs ? gso_segs : 1);
if (stopped)
stats->tx_stops++;
u64_stats_update_end(&stats->sync);
}
/* Determine number of WRB entries needed to xmit data in an skb */
......@@ -905,7 +913,8 @@ static void be_rx_eqd_update(struct be_adapter *adapter, struct be_rx_obj *rxo)
struct be_rx_stats *stats = rx_stats(rxo);
ulong now = jiffies;
ulong delta = now - stats->rx_jiffies;
u32 eqd;
u64 pkts;
unsigned int start, eqd;
if (!rx_eq->enable_aic)
return;
......@@ -920,8 +929,13 @@ static void be_rx_eqd_update(struct be_adapter *adapter, struct be_rx_obj *rxo)
if (delta < HZ)
return;
stats->rx_pps = (stats->rx_pkts - stats->rx_pkts_prev) / (delta / HZ);
stats->rx_pkts_prev = stats->rx_pkts;
do {
start = u64_stats_fetch_begin_bh(&stats->sync);
pkts = stats->rx_pkts;
} while (u64_stats_fetch_retry_bh(&stats->sync, start));
stats->rx_pps = (pkts - stats->rx_pkts_prev) / (delta / HZ);
stats->rx_pkts_prev = pkts;
stats->rx_jiffies = now;
eqd = stats->rx_pps / 110000;
eqd = eqd << 3;
......@@ -942,6 +956,7 @@ static void be_rx_stats_update(struct be_rx_obj *rxo,
{
struct be_rx_stats *stats = rx_stats(rxo);
u64_stats_update_begin(&stats->sync);
stats->rx_compl++;
stats->rx_bytes += rxcp->pkt_size;
stats->rx_pkts++;
......@@ -949,6 +964,7 @@ static void be_rx_stats_update(struct be_rx_obj *rxo,
stats->rx_mcast_pkts++;
if (rxcp->err)
stats->rx_compl_err++;
u64_stats_update_end(&stats->sync);
}
static inline bool csum_passed(struct be_rx_compl_info *rxcp)
......@@ -1878,8 +1894,9 @@ static int be_poll_tx_mcc(struct napi_struct *napi, int budget)
netif_wake_subqueue(adapter->netdev, i);
}
adapter->drv_stats.tx_events++;
u64_stats_update_begin(&tx_stats(txo)->sync_compl);
tx_stats(txo)->tx_compl += tx_compl;
u64_stats_update_end(&tx_stats(txo)->sync_compl);
}
}
......@@ -1893,6 +1910,7 @@ static int be_poll_tx_mcc(struct napi_struct *napi, int budget)
napi_complete(napi);
be_eq_notify(adapter, tx_eq->q.id, true, false, 0);
adapter->drv_stats.tx_events++;
return 1;
}
......@@ -2843,6 +2861,7 @@ static struct net_device_ops be_netdev_ops = {
.ndo_set_rx_mode = be_set_multicast_list,
.ndo_set_mac_address = be_mac_addr_set,
.ndo_change_mtu = be_change_mtu,
.ndo_get_stats64 = be_get_stats64,
.ndo_validate_addr = eth_validate_addr,
.ndo_vlan_rx_add_vid = be_vlan_add_vid,
.ndo_vlan_rx_kill_vid = be_vlan_rem_vid,
......
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