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

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 @@ ...@@ -29,6 +29,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/firmware.h> #include <linux/firmware.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/u64_stats_sync.h>
#include "be_hw.h" #include "be_hw.h"
...@@ -174,6 +175,8 @@ struct be_tx_stats { ...@@ -174,6 +175,8 @@ struct be_tx_stats {
u64 tx_compl; u64 tx_compl;
ulong tx_jiffies; ulong tx_jiffies;
u32 tx_stops; u32 tx_stops;
struct u64_stats_sync sync;
struct u64_stats_sync sync_compl;
}; };
struct be_tx_obj { struct be_tx_obj {
...@@ -206,6 +209,7 @@ struct be_rx_stats { ...@@ -206,6 +209,7 @@ struct be_rx_stats {
u32 rx_mcast_pkts; u32 rx_mcast_pkts;
u32 rx_compl_err; /* completions with err set */ u32 rx_compl_err; /* completions with err set */
u32 rx_pps; /* pkts per second */ u32 rx_pps; /* pkts per second */
struct u64_stats_sync sync;
}; };
struct be_rx_compl_info { struct be_rx_compl_info {
...@@ -518,7 +522,6 @@ static inline bool be_multi_rxq(const struct be_adapter *adapter) ...@@ -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, extern void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm,
u16 num_popped); u16 num_popped);
extern void be_link_status_update(struct be_adapter *adapter, bool link_up); 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 void be_parse_stats(struct be_adapter *adapter);
extern int be_load_fw(struct be_adapter *adapter, u8 *func); extern int be_load_fw(struct be_adapter *adapter, u8 *func);
#endif /* BE_H */ #endif /* BE_H */
...@@ -83,7 +83,6 @@ static int be_mcc_compl_process(struct be_adapter *adapter, ...@@ -83,7 +83,6 @@ static int be_mcc_compl_process(struct be_adapter *adapter,
(compl->tag0 == OPCODE_ETH_GET_PPORT_STATS)) && (compl->tag0 == OPCODE_ETH_GET_PPORT_STATS)) &&
(compl->tag1 == CMD_SUBSYSTEM_ETH)) { (compl->tag1 == CMD_SUBSYSTEM_ETH)) {
be_parse_stats(adapter); be_parse_stats(adapter);
netdev_stats_update(adapter);
adapter->stats_cmd_sent = false; adapter->stats_cmd_sent = false;
} }
} else { } else {
......
...@@ -74,10 +74,12 @@ static const struct be_ethtool_stat et_stats[] = { ...@@ -74,10 +74,12 @@ static const struct be_ethtool_stat et_stats[] = {
}; };
#define ETHTOOL_STATS_NUM ARRAY_SIZE(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[] = { static const struct be_ethtool_stat et_rx_stats[] = {
{DRVSTAT_RX_INFO(rx_bytes)}, {DRVSTAT_RX_INFO(rx_bytes)},/* If moving this member see above note */
{DRVSTAT_RX_INFO(rx_pkts)}, {DRVSTAT_RX_INFO(rx_pkts)}, /* If moving this member see above note */
{DRVSTAT_RX_INFO(rx_polls)}, {DRVSTAT_RX_INFO(rx_polls)},
{DRVSTAT_RX_INFO(rx_events)}, {DRVSTAT_RX_INFO(rx_events)},
{DRVSTAT_RX_INFO(rx_compl)}, {DRVSTAT_RX_INFO(rx_compl)},
...@@ -88,8 +90,11 @@ static const struct be_ethtool_stat et_rx_stats[] = { ...@@ -88,8 +90,11 @@ static const struct be_ethtool_stat et_rx_stats[] = {
}; };
#define ETHTOOL_RXSTATS_NUM (ARRAY_SIZE(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[] = { 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_bytes)},
{DRVSTAT_TX_INFO(tx_pkts)}, {DRVSTAT_TX_INFO(tx_pkts)},
{DRVSTAT_TX_INFO(tx_reqs)}, {DRVSTAT_TX_INFO(tx_reqs)},
...@@ -243,32 +248,48 @@ be_get_ethtool_stats(struct net_device *netdev, ...@@ -243,32 +248,48 @@ be_get_ethtool_stats(struct net_device *netdev,
struct be_rx_obj *rxo; struct be_rx_obj *rxo;
struct be_tx_obj *txo; struct be_tx_obj *txo;
void *p; void *p;
int i, j, base; unsigned int i, j, base = 0, start;
for (i = 0; i < ETHTOOL_STATS_NUM; i++) { for (i = 0; i < ETHTOOL_STATS_NUM; i++) {
p = (u8 *)&adapter->drv_stats + et_stats[i].offset; p = (u8 *)&adapter->drv_stats + et_stats[i].offset;
data[i] = (et_stats[i].size == sizeof(u64)) ? data[i] = *(u32 *)p;
*(u64 *)p: *(u32 *)p;
} }
base += ETHTOOL_STATS_NUM;
base = ETHTOOL_STATS_NUM;
for_all_rx_queues(adapter, rxo, j) { for_all_rx_queues(adapter, rxo, j) {
for (i = 0; i < ETHTOOL_RXSTATS_NUM; i++) { struct be_rx_stats *stats = rx_stats(rxo);
p = (u8 *)rx_stats(rxo) + et_rx_stats[i].offset;
data[base + j * ETHTOOL_RXSTATS_NUM + i] = do {
(et_rx_stats[i].size == sizeof(u64)) ? start = u64_stats_fetch_begin_bh(&stats->sync);
*(u64 *)p: *(u32 *)p; 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_all_tx_queues(adapter, txo, j) {
for (i = 0; i < ETHTOOL_TXSTATS_NUM; i++) { struct be_tx_stats *stats = tx_stats(txo);
p = (u8 *)tx_stats(txo) + et_tx_stats[i].offset;
data[base + j * ETHTOOL_TXSTATS_NUM + i] = do {
(et_tx_stats[i].size == sizeof(u64)) ? start = u64_stats_fetch_begin_bh(&stats->sync_compl);
*(u64 *)p: *(u32 *)p; 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) ...@@ -396,36 +396,44 @@ void be_parse_stats(struct be_adapter *adapter)
erx->rx_drops_no_fragments[rxo->q.id]; 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 be_drv_stats *drvs = &adapter->drv_stats;
struct net_device_stats *dev_stats = &adapter->netdev->stats;
struct be_rx_obj *rxo; struct be_rx_obj *rxo;
struct be_tx_obj *txo; struct be_tx_obj *txo;
unsigned long pkts = 0, bytes = 0, mcast = 0, drops = 0; u64 pkts, bytes;
unsigned int start;
int i; int i;
for_all_rx_queues(adapter, rxo, i) { for_all_rx_queues(adapter, rxo, i) {
pkts += rx_stats(rxo)->rx_pkts; const struct be_rx_stats *rx_stats = rx_stats(rxo);
bytes += rx_stats(rxo)->rx_bytes; do {
mcast += rx_stats(rxo)->rx_mcast_pkts; start = u64_stats_fetch_begin_bh(&rx_stats->sync);
drops += rx_stats(rxo)->rx_drops_no_skbs; 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) { for_all_tx_queues(adapter, txo, i) {
pkts += tx_stats(txo)->tx_pkts; const struct be_tx_stats *tx_stats = tx_stats(txo);
bytes += tx_stats(txo)->tx_bytes; 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 */ /* 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_alignment_symbol_errors +
drvs->rx_in_range_errors + drvs->rx_in_range_errors +
drvs->rx_out_range_errors + drvs->rx_out_range_errors +
...@@ -434,26 +442,24 @@ void netdev_stats_update(struct be_adapter *adapter) ...@@ -434,26 +442,24 @@ void netdev_stats_update(struct be_adapter *adapter)
drvs->rx_dropped_too_short + drvs->rx_dropped_too_short +
drvs->rx_dropped_header_too_small + drvs->rx_dropped_header_too_small +
drvs->rx_dropped_tcp_length + drvs->rx_dropped_tcp_length +
drvs->rx_dropped_runt + drvs->rx_dropped_runt;
drvs->rx_tcp_checksum_errs +
drvs->rx_ip_checksum_errs +
drvs->rx_udp_checksum_errs;
/* detailed rx errors */ /* 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_out_range_errors +
drvs->rx_frame_too_long; 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 */ /* 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 */ /* receiver fifo overrun */
/* drops_no_pbuf is no per i/f, it's per BE card */ /* 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_input_fifo_overflow_drop +
drvs->rx_drops_no_pbuf; drvs->rx_drops_no_pbuf;
return stats;
} }
void be_link_status_update(struct be_adapter *adapter, bool link_up) 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, ...@@ -479,12 +485,14 @@ static void be_tx_stats_update(struct be_tx_obj *txo,
{ {
struct be_tx_stats *stats = tx_stats(txo); struct be_tx_stats *stats = tx_stats(txo);
u64_stats_update_begin(&stats->sync);
stats->tx_reqs++; stats->tx_reqs++;
stats->tx_wrbs += wrb_cnt; stats->tx_wrbs += wrb_cnt;
stats->tx_bytes += copied; stats->tx_bytes += copied;
stats->tx_pkts += (gso_segs ? gso_segs : 1); stats->tx_pkts += (gso_segs ? gso_segs : 1);
if (stopped) if (stopped)
stats->tx_stops++; stats->tx_stops++;
u64_stats_update_end(&stats->sync);
} }
/* Determine number of WRB entries needed to xmit data in an skb */ /* 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) ...@@ -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); struct be_rx_stats *stats = rx_stats(rxo);
ulong now = jiffies; ulong now = jiffies;
ulong delta = now - stats->rx_jiffies; ulong delta = now - stats->rx_jiffies;
u32 eqd; u64 pkts;
unsigned int start, eqd;
if (!rx_eq->enable_aic) if (!rx_eq->enable_aic)
return; return;
...@@ -920,8 +929,13 @@ static void be_rx_eqd_update(struct be_adapter *adapter, struct be_rx_obj *rxo) ...@@ -920,8 +929,13 @@ static void be_rx_eqd_update(struct be_adapter *adapter, struct be_rx_obj *rxo)
if (delta < HZ) if (delta < HZ)
return; return;
stats->rx_pps = (stats->rx_pkts - stats->rx_pkts_prev) / (delta / HZ); do {
stats->rx_pkts_prev = stats->rx_pkts; 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; stats->rx_jiffies = now;
eqd = stats->rx_pps / 110000; eqd = stats->rx_pps / 110000;
eqd = eqd << 3; eqd = eqd << 3;
...@@ -942,6 +956,7 @@ static void be_rx_stats_update(struct be_rx_obj *rxo, ...@@ -942,6 +956,7 @@ static void be_rx_stats_update(struct be_rx_obj *rxo,
{ {
struct be_rx_stats *stats = rx_stats(rxo); struct be_rx_stats *stats = rx_stats(rxo);
u64_stats_update_begin(&stats->sync);
stats->rx_compl++; stats->rx_compl++;
stats->rx_bytes += rxcp->pkt_size; stats->rx_bytes += rxcp->pkt_size;
stats->rx_pkts++; stats->rx_pkts++;
...@@ -949,6 +964,7 @@ static void be_rx_stats_update(struct be_rx_obj *rxo, ...@@ -949,6 +964,7 @@ static void be_rx_stats_update(struct be_rx_obj *rxo,
stats->rx_mcast_pkts++; stats->rx_mcast_pkts++;
if (rxcp->err) if (rxcp->err)
stats->rx_compl_err++; stats->rx_compl_err++;
u64_stats_update_end(&stats->sync);
} }
static inline bool csum_passed(struct be_rx_compl_info *rxcp) 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) ...@@ -1878,8 +1894,9 @@ static int be_poll_tx_mcc(struct napi_struct *napi, int budget)
netif_wake_subqueue(adapter->netdev, i); 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; 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) ...@@ -1893,6 +1910,7 @@ static int be_poll_tx_mcc(struct napi_struct *napi, int budget)
napi_complete(napi); napi_complete(napi);
be_eq_notify(adapter, tx_eq->q.id, true, false, 0); be_eq_notify(adapter, tx_eq->q.id, true, false, 0);
adapter->drv_stats.tx_events++;
return 1; return 1;
} }
...@@ -2843,6 +2861,7 @@ static struct net_device_ops be_netdev_ops = { ...@@ -2843,6 +2861,7 @@ static struct net_device_ops be_netdev_ops = {
.ndo_set_rx_mode = be_set_multicast_list, .ndo_set_rx_mode = be_set_multicast_list,
.ndo_set_mac_address = be_mac_addr_set, .ndo_set_mac_address = be_mac_addr_set,
.ndo_change_mtu = be_change_mtu, .ndo_change_mtu = be_change_mtu,
.ndo_get_stats64 = be_get_stats64,
.ndo_validate_addr = eth_validate_addr, .ndo_validate_addr = eth_validate_addr,
.ndo_vlan_rx_add_vid = be_vlan_add_vid, .ndo_vlan_rx_add_vid = be_vlan_add_vid,
.ndo_vlan_rx_kill_vid = be_vlan_rem_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