Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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
Loading
Loading
Loading
Loading
+4 −1
Original line number Original line Diff line number Diff line
@@ -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 {
	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 {
	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)
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 */
+0 −1
Original line number Original line Diff line number Diff line
@@ -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 {
+41 −20
Original line number Original line Diff line number Diff line
@@ -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[] = {
};
};
#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,
	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 {
			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)) ?
					(et_tx_stats[i].size == sizeof(u64)) ?
						*(u64 *)p : *(u32 *)p;
						*(u64 *)p : *(u32 *)p;
			}
			}
		} while (u64_stats_fetch_retry_bh(&stats->sync, start));
		base += ETHTOOL_TXSTATS_NUM;
	}
	}
}
}


+48 −29
Original line number Original line Diff line number Diff line
@@ -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)
		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,
{
{
	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)
	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)
	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,
{
{
	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,
		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)
				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)
	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 = {
	.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,