Commit 31ab1506 authored by Jeff Garzik's avatar Jeff Garzik Committed by David S. Miller

[TG3]: Dump NIC-specific statistics via ethtool.

Contributed by Tony Cureington @ HP, updated (from pre-ethtool_ops)
and modified by me.
parent 986afeb3
...@@ -126,6 +126,8 @@ ...@@ -126,6 +126,8 @@
/* minimum number of free TX descriptors required to wake up TX process */ /* minimum number of free TX descriptors required to wake up TX process */
#define TG3_TX_WAKEUP_THRESH (TG3_TX_RING_SIZE / 4) #define TG3_TX_WAKEUP_THRESH (TG3_TX_RING_SIZE / 4)
#define TG3_NUM_STATS 25 /* number of ETHTOOL_GSTATS u64's */
static char version[] __devinitdata = static char version[] __devinitdata =
DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
...@@ -199,6 +201,37 @@ static struct pci_device_id tg3_pci_tbl[] = { ...@@ -199,6 +201,37 @@ static struct pci_device_id tg3_pci_tbl[] = {
MODULE_DEVICE_TABLE(pci, tg3_pci_tbl); MODULE_DEVICE_TABLE(pci, tg3_pci_tbl);
struct {
char string[ETH_GSTRING_LEN];
} ethtool_stats_keys[TG3_NUM_STATS] = {
{ "rx_fragments" },
{ "rx_ucast_packets" },
{ "rx_bcast_packets" },
{ "rx_fcs_errors" },
{ "rx_xon_pause_rcvd" },
{ "rx_xoff_pause_rcvd" },
{ "rx_mac_ctrl_rcvd" },
{ "rx_xoff_entered" },
{ "rx_frame_too_long_errors" },
{ "rx_jabbers" },
{ "rx_undersize_packets" },
{ "rx_in_length_errors" },
{ "rx_out_length_errors" },
{ "tx_xon_sent" },
{ "tx_xoff_sent" },
{ "tx_flow_control" },
{ "tx_mac_errors" },
{ "tx_single_collisions" },
{ "tx_mult_collisions" },
{ "tx_deferred" },
{ "tx_excessive_collisions" },
{ "tx_late_collisions" },
{ "tx_ucast_packets" },
{ "tx_mcast_packets" },
{ "tx_bcast_packets" }
};
static void tg3_write_indirect_reg32(struct tg3 *tp, u32 off, u32 val) static void tg3_write_indirect_reg32(struct tg3 *tp, u32 off, u32 val)
{ {
if ((tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) != 0) { if ((tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) != 0) {
...@@ -5587,6 +5620,7 @@ static int tg3_open(struct net_device *dev) ...@@ -5587,6 +5620,7 @@ static int tg3_open(struct net_device *dev)
#endif #endif
static struct net_device_stats *tg3_get_stats(struct net_device *); static struct net_device_stats *tg3_get_stats(struct net_device *);
static struct tg3_ethtool_stats *tg3_get_estats(struct tg3 *);
static int tg3_close(struct net_device *dev) static int tg3_close(struct net_device *dev)
{ {
...@@ -5618,6 +5652,8 @@ static int tg3_close(struct net_device *dev) ...@@ -5618,6 +5652,8 @@ static int tg3_close(struct net_device *dev)
memcpy(&tp->net_stats_prev, tg3_get_stats(tp->dev), memcpy(&tp->net_stats_prev, tg3_get_stats(tp->dev),
sizeof(tp->net_stats_prev)); sizeof(tp->net_stats_prev));
memcpy(&tp->estats_prev, tg3_get_estats(tp),
sizeof(tp->estats_prev));
tg3_free_consistent(tp); tg3_free_consistent(tp);
...@@ -5660,6 +5696,49 @@ static unsigned long calc_crc_errors(struct tg3 *tp) ...@@ -5660,6 +5696,49 @@ static unsigned long calc_crc_errors(struct tg3 *tp)
return get_stat64(&hw_stats->rx_fcs_errors); return get_stat64(&hw_stats->rx_fcs_errors);
} }
#define ESTAT_ADD(member) \
estats->member = old_estats->member + \
get_stat64(&hw_stats->member)
static struct tg3_ethtool_stats *tg3_get_estats(struct tg3 *tp)
{
struct tg3_ethtool_stats *estats = &tp->estats;
struct tg3_ethtool_stats *old_estats = &tp->estats_prev;
struct tg3_hw_stats *hw_stats = tp->hw_stats;
if (!hw_stats)
return old_estats;
ESTAT_ADD(rx_fragments);
ESTAT_ADD(rx_ucast_packets);
ESTAT_ADD(rx_bcast_packets);
ESTAT_ADD(rx_fcs_errors);
ESTAT_ADD(rx_xon_pause_rcvd);
ESTAT_ADD(rx_xoff_pause_rcvd);
ESTAT_ADD(rx_mac_ctrl_rcvd);
ESTAT_ADD(rx_xoff_entered);
ESTAT_ADD(rx_frame_too_long_errors);
ESTAT_ADD(rx_jabbers);
ESTAT_ADD(rx_undersize_packets);
ESTAT_ADD(rx_in_length_errors);
ESTAT_ADD(rx_out_length_errors);
ESTAT_ADD(tx_xon_sent);
ESTAT_ADD(tx_xoff_sent);
ESTAT_ADD(tx_flow_control);
ESTAT_ADD(tx_mac_errors);
ESTAT_ADD(tx_single_collisions);
ESTAT_ADD(tx_mult_collisions);
ESTAT_ADD(tx_deferred);
ESTAT_ADD(tx_excessive_collisions);
ESTAT_ADD(tx_late_collisions);
ESTAT_ADD(tx_ucast_packets);
ESTAT_ADD(tx_mcast_packets);
ESTAT_ADD(tx_bcast_packets);
return estats;
}
static struct net_device_stats *tg3_get_stats(struct net_device *dev) static struct net_device_stats *tg3_get_stats(struct net_device *dev)
{ {
struct tg3 *tp = dev->priv; struct tg3 *tp = dev->priv;
...@@ -6183,7 +6262,31 @@ static int tg3_set_tx_csum(struct net_device *dev, u32 data) ...@@ -6183,7 +6262,31 @@ static int tg3_set_tx_csum(struct net_device *dev, u32 data)
return 0; return 0;
} }
static int tg3_get_stats_count (struct net_device *dev)
{
return TG3_NUM_STATS;
}
static void tg3_get_strings (struct net_device *dev, u32 stringset, u8 *buf)
{
switch (stringset) {
case ETH_SS_STATS:
memcpy(buf, &ethtool_stats_keys, sizeof(ethtool_stats_keys));
break;
default:
WARN_ON(1); /* we need a WARN() */
break;
}
}
static void tg3_get_ethtool_stats (struct net_device *dev,
struct ethtool_stats *estats, u64 *tmp_stats)
{
struct tg3 *tp = dev->priv;
memcpy(tmp_stats, &tp->estats, sizeof(tp->estats));
}
static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{ {
struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data; struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data;
...@@ -6280,6 +6383,9 @@ static struct ethtool_ops tg3_ethtool_ops = { ...@@ -6280,6 +6383,9 @@ static struct ethtool_ops tg3_ethtool_ops = {
.get_tso = ethtool_op_get_tso, .get_tso = ethtool_op_get_tso,
.set_tso = tg3_set_tso, .set_tso = tg3_set_tso,
#endif #endif
.get_strings = tg3_get_strings,
.get_stats_count = tg3_get_stats_count,
.get_ethtool_stats = tg3_get_ethtool_stats,
}; };
/* Chips other than 5700/5701 use the NVRAM for fetching info. */ /* Chips other than 5700/5701 use the NVRAM for fetching info. */
......
...@@ -1817,6 +1817,37 @@ struct tg3_bufmgr_config { ...@@ -1817,6 +1817,37 @@ struct tg3_bufmgr_config {
u32 dma_high_water; u32 dma_high_water;
}; };
struct tg3_ethtool_stats {
/* Statistics maintained by Receive MAC. */
u64 rx_fragments;
u64 rx_ucast_packets;
u64 rx_bcast_packets;
u64 rx_fcs_errors;
u64 rx_xon_pause_rcvd;
u64 rx_xoff_pause_rcvd;
u64 rx_mac_ctrl_rcvd;
u64 rx_xoff_entered;
u64 rx_frame_too_long_errors;
u64 rx_jabbers;
u64 rx_undersize_packets;
u64 rx_in_length_errors;
u64 rx_out_length_errors;
/* Statistics maintained by Transmit MAC. */
u64 tx_xon_sent;
u64 tx_xoff_sent;
u64 tx_flow_control;
u64 tx_mac_errors;
u64 tx_single_collisions;
u64 tx_mult_collisions;
u64 tx_deferred;
u64 tx_excessive_collisions;
u64 tx_late_collisions;
u64 tx_ucast_packets;
u64 tx_mcast_packets;
u64 tx_bcast_packets;
};
struct tg3 { struct tg3 {
/* begin "general, frequently-used members" cacheline section */ /* begin "general, frequently-used members" cacheline section */
...@@ -1880,6 +1911,9 @@ struct tg3 { ...@@ -1880,6 +1911,9 @@ struct tg3 {
/* begin "everything else" cacheline(s) section */ /* begin "everything else" cacheline(s) section */
struct net_device_stats net_stats; struct net_device_stats net_stats;
struct net_device_stats net_stats_prev; struct net_device_stats net_stats_prev;
struct tg3_ethtool_stats estats;
struct tg3_ethtool_stats estats_prev;
unsigned long phy_crc_errors; unsigned long phy_crc_errors;
u32 rx_offset; u32 rx_offset;
......
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