diff options
author | Denis Kirjanov <dkirjanov@kernel.org> | 2010-10-12 20:56:09 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-10-16 14:13:21 -0400 |
commit | 725a4a465c943ab0f91fcffc3846acbcdb704aac (patch) | |
tree | 0b2a49221b57efb26c4d519d17fac6caa949d583 /drivers/net/sundance.c | |
parent | 89980827c7a1e3c2b36895c22c6ef0e92aea6b0c (diff) |
sundance: Add initial ethtool stats support
Add ethtool stats support.
Signed-off-by: Denis Kirjanov <dkirjanov@kernel.org>
Acked-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/sundance.c')
-rw-r--r-- | drivers/net/sundance.c | 94 |
1 files changed, 87 insertions, 7 deletions
diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index 4283cc52a8c9..3ed2a67bd6d3 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c | |||
@@ -363,6 +363,19 @@ struct netdev_private { | |||
363 | dma_addr_t tx_ring_dma; | 363 | dma_addr_t tx_ring_dma; |
364 | dma_addr_t rx_ring_dma; | 364 | dma_addr_t rx_ring_dma; |
365 | struct timer_list timer; /* Media monitoring timer. */ | 365 | struct timer_list timer; /* Media monitoring timer. */ |
366 | /* ethtool extra stats */ | ||
367 | struct { | ||
368 | u64 tx_multiple_collisions; | ||
369 | u64 tx_single_collisions; | ||
370 | u64 tx_late_collisions; | ||
371 | u64 tx_deferred; | ||
372 | u64 tx_deferred_excessive; | ||
373 | u64 tx_aborted; | ||
374 | u64 tx_bcasts; | ||
375 | u64 rx_bcasts; | ||
376 | u64 tx_mcasts; | ||
377 | u64 rx_mcasts; | ||
378 | } xstats; | ||
366 | /* Frequently used values: keep some adjacent for cache effect. */ | 379 | /* Frequently used values: keep some adjacent for cache effect. */ |
367 | spinlock_t lock; | 380 | spinlock_t lock; |
368 | int msg_enable; | 381 | int msg_enable; |
@@ -1486,21 +1499,34 @@ static struct net_device_stats *get_stats(struct net_device *dev) | |||
1486 | { | 1499 | { |
1487 | struct netdev_private *np = netdev_priv(dev); | 1500 | struct netdev_private *np = netdev_priv(dev); |
1488 | void __iomem *ioaddr = np->base; | 1501 | void __iomem *ioaddr = np->base; |
1489 | int i; | ||
1490 | unsigned long flags; | 1502 | unsigned long flags; |
1503 | u8 late_coll, single_coll, mult_coll; | ||
1491 | 1504 | ||
1492 | spin_lock_irqsave(&np->statlock, flags); | 1505 | spin_lock_irqsave(&np->statlock, flags); |
1493 | /* The chip only need report frame silently dropped. */ | 1506 | /* The chip only need report frame silently dropped. */ |
1494 | dev->stats.rx_missed_errors += ioread8(ioaddr + RxMissed); | 1507 | dev->stats.rx_missed_errors += ioread8(ioaddr + RxMissed); |
1495 | dev->stats.tx_packets += ioread16(ioaddr + TxFramesOK); | 1508 | dev->stats.tx_packets += ioread16(ioaddr + TxFramesOK); |
1496 | dev->stats.rx_packets += ioread16(ioaddr + RxFramesOK); | 1509 | dev->stats.rx_packets += ioread16(ioaddr + RxFramesOK); |
1497 | dev->stats.collisions += ioread8(ioaddr + StatsLateColl); | ||
1498 | dev->stats.collisions += ioread8(ioaddr + StatsMultiColl); | ||
1499 | dev->stats.collisions += ioread8(ioaddr + StatsOneColl); | ||
1500 | dev->stats.tx_carrier_errors += ioread8(ioaddr + StatsCarrierError); | 1510 | dev->stats.tx_carrier_errors += ioread8(ioaddr + StatsCarrierError); |
1501 | ioread8(ioaddr + StatsTxDefer); | 1511 | |
1502 | for (i = StatsTxDefer; i <= StatsMcastRx; i++) | 1512 | mult_coll = ioread8(ioaddr + StatsMultiColl); |
1503 | ioread8(ioaddr + i); | 1513 | np->xstats.tx_multiple_collisions += mult_coll; |
1514 | single_coll = ioread8(ioaddr + StatsOneColl); | ||
1515 | np->xstats.tx_single_collisions += single_coll; | ||
1516 | late_coll = ioread8(ioaddr + StatsLateColl); | ||
1517 | np->xstats.tx_late_collisions += late_coll; | ||
1518 | dev->stats.collisions += mult_coll | ||
1519 | + single_coll | ||
1520 | + late_coll; | ||
1521 | |||
1522 | np->xstats.tx_deferred += ioread8(ioaddr + StatsTxDefer); | ||
1523 | np->xstats.tx_deferred_excessive += ioread8(ioaddr + StatsTxXSDefer); | ||
1524 | np->xstats.tx_aborted += ioread8(ioaddr + StatsTxAbort); | ||
1525 | np->xstats.tx_bcasts += ioread8(ioaddr + StatsBcastTx); | ||
1526 | np->xstats.rx_bcasts += ioread8(ioaddr + StatsBcastRx); | ||
1527 | np->xstats.tx_mcasts += ioread8(ioaddr + StatsMcastTx); | ||
1528 | np->xstats.rx_mcasts += ioread8(ioaddr + StatsMcastRx); | ||
1529 | |||
1504 | dev->stats.tx_bytes += ioread16(ioaddr + TxOctetsLow); | 1530 | dev->stats.tx_bytes += ioread16(ioaddr + TxOctetsLow); |
1505 | dev->stats.tx_bytes += ioread16(ioaddr + TxOctetsHigh) << 16; | 1531 | dev->stats.tx_bytes += ioread16(ioaddr + TxOctetsHigh) << 16; |
1506 | dev->stats.rx_bytes += ioread16(ioaddr + RxOctetsLow); | 1532 | dev->stats.rx_bytes += ioread16(ioaddr + RxOctetsLow); |
@@ -1566,6 +1592,21 @@ static int __set_mac_addr(struct net_device *dev) | |||
1566 | return 0; | 1592 | return 0; |
1567 | } | 1593 | } |
1568 | 1594 | ||
1595 | static const struct { | ||
1596 | const char name[ETH_GSTRING_LEN]; | ||
1597 | } sundance_stats[] = { | ||
1598 | { "tx_multiple_collisions" }, | ||
1599 | { "tx_single_collisions" }, | ||
1600 | { "tx_late_collisions" }, | ||
1601 | { "tx_deferred" }, | ||
1602 | { "tx_deferred_excessive" }, | ||
1603 | { "tx_aborted" }, | ||
1604 | { "tx_bcasts" }, | ||
1605 | { "rx_bcasts" }, | ||
1606 | { "tx_mcasts" }, | ||
1607 | { "rx_mcasts" }, | ||
1608 | }; | ||
1609 | |||
1569 | static int check_if_running(struct net_device *dev) | 1610 | static int check_if_running(struct net_device *dev) |
1570 | { | 1611 | { |
1571 | if (!netif_running(dev)) | 1612 | if (!netif_running(dev)) |
@@ -1624,6 +1665,42 @@ static void set_msglevel(struct net_device *dev, u32 val) | |||
1624 | np->msg_enable = val; | 1665 | np->msg_enable = val; |
1625 | } | 1666 | } |
1626 | 1667 | ||
1668 | static void get_strings(struct net_device *dev, u32 stringset, | ||
1669 | u8 *data) | ||
1670 | { | ||
1671 | if (stringset == ETH_SS_STATS) | ||
1672 | memcpy(data, sundance_stats, sizeof(sundance_stats)); | ||
1673 | } | ||
1674 | |||
1675 | static int get_sset_count(struct net_device *dev, int sset) | ||
1676 | { | ||
1677 | switch (sset) { | ||
1678 | case ETH_SS_STATS: | ||
1679 | return ARRAY_SIZE(sundance_stats); | ||
1680 | default: | ||
1681 | return -EOPNOTSUPP; | ||
1682 | } | ||
1683 | } | ||
1684 | |||
1685 | static void get_ethtool_stats(struct net_device *dev, | ||
1686 | struct ethtool_stats *stats, u64 *data) | ||
1687 | { | ||
1688 | struct netdev_private *np = netdev_priv(dev); | ||
1689 | int i = 0; | ||
1690 | |||
1691 | get_stats(dev); | ||
1692 | data[i++] = np->xstats.tx_multiple_collisions; | ||
1693 | data[i++] = np->xstats.tx_single_collisions; | ||
1694 | data[i++] = np->xstats.tx_late_collisions; | ||
1695 | data[i++] = np->xstats.tx_deferred; | ||
1696 | data[i++] = np->xstats.tx_deferred_excessive; | ||
1697 | data[i++] = np->xstats.tx_aborted; | ||
1698 | data[i++] = np->xstats.tx_bcasts; | ||
1699 | data[i++] = np->xstats.rx_bcasts; | ||
1700 | data[i++] = np->xstats.tx_mcasts; | ||
1701 | data[i++] = np->xstats.rx_mcasts; | ||
1702 | } | ||
1703 | |||
1627 | static const struct ethtool_ops ethtool_ops = { | 1704 | static const struct ethtool_ops ethtool_ops = { |
1628 | .begin = check_if_running, | 1705 | .begin = check_if_running, |
1629 | .get_drvinfo = get_drvinfo, | 1706 | .get_drvinfo = get_drvinfo, |
@@ -1633,6 +1710,9 @@ static const struct ethtool_ops ethtool_ops = { | |||
1633 | .get_link = get_link, | 1710 | .get_link = get_link, |
1634 | .get_msglevel = get_msglevel, | 1711 | .get_msglevel = get_msglevel, |
1635 | .set_msglevel = set_msglevel, | 1712 | .set_msglevel = set_msglevel, |
1713 | .get_strings = get_strings, | ||
1714 | .get_sset_count = get_sset_count, | ||
1715 | .get_ethtool_stats = get_ethtool_stats, | ||
1636 | }; | 1716 | }; |
1637 | 1717 | ||
1638 | static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | 1718 | static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) |