Commit 4de77251 authored by David S. Miller's avatar David S. Miller

Merge branch 'gianfar-64-bit-stats'

Esben Haabendal says:

====================
net: gianfar: 64-bit statistics and rx_missed_errors counter

This series replaces the legacy 32-bit statistics to proper 64-bit ditto,
and implements rx_missed_errors counter on top of that.

The device supports a 16-bit RDRP counter, and a related carry bit and
interrupt, which allows implementation of a robust 64-bit counter.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 55d96f72 14870b75
......@@ -274,32 +274,44 @@ static void gfar_configure_coalescing_all(struct gfar_private *priv)
gfar_configure_coalescing(priv, 0xFF, 0xFF);
}
static struct net_device_stats *gfar_get_stats(struct net_device *dev)
static void gfar_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
{
struct gfar_private *priv = netdev_priv(dev);
unsigned long rx_packets = 0, rx_bytes = 0, rx_dropped = 0;
unsigned long tx_packets = 0, tx_bytes = 0;
int i;
for (i = 0; i < priv->num_rx_queues; i++) {
rx_packets += priv->rx_queue[i]->stats.rx_packets;
rx_bytes += priv->rx_queue[i]->stats.rx_bytes;
rx_dropped += priv->rx_queue[i]->stats.rx_dropped;
stats->rx_packets += priv->rx_queue[i]->stats.rx_packets;
stats->rx_bytes += priv->rx_queue[i]->stats.rx_bytes;
stats->rx_dropped += priv->rx_queue[i]->stats.rx_dropped;
}
dev->stats.rx_packets = rx_packets;
dev->stats.rx_bytes = rx_bytes;
dev->stats.rx_dropped = rx_dropped;
for (i = 0; i < priv->num_tx_queues; i++) {
tx_bytes += priv->tx_queue[i]->stats.tx_bytes;
tx_packets += priv->tx_queue[i]->stats.tx_packets;
stats->tx_bytes += priv->tx_queue[i]->stats.tx_bytes;
stats->tx_packets += priv->tx_queue[i]->stats.tx_packets;
}
dev->stats.tx_bytes = tx_bytes;
dev->stats.tx_packets = tx_packets;
if (priv->device_flags & FSL_GIANFAR_DEV_HAS_RMON) {
struct rmon_mib __iomem *rmon = &priv->gfargrp[0].regs->rmon;
unsigned long flags;
u32 rdrp, car, car_before;
u64 rdrp_offset;
spin_lock_irqsave(&priv->rmon_overflow.lock, flags);
car = gfar_read(&rmon->car1) & CAR1_C1RDR;
do {
car_before = car;
rdrp = gfar_read(&rmon->rdrp);
car = gfar_read(&rmon->car1) & CAR1_C1RDR;
} while (car != car_before);
if (car) {
priv->rmon_overflow.rdrp++;
gfar_write(&rmon->car1, car);
}
rdrp_offset = priv->rmon_overflow.rdrp;
spin_unlock_irqrestore(&priv->rmon_overflow.lock, flags);
return &dev->stats;
stats->rx_missed_errors = rdrp + (rdrp_offset << 16);
}
}
/* Set the appropriate hash bit for the given addr */
......@@ -390,7 +402,8 @@ static void gfar_ints_enable(struct gfar_private *priv)
for (i = 0; i < priv->num_grps; i++) {
struct gfar __iomem *regs = priv->gfargrp[i].regs;
/* Unmask the interrupts we look for */
gfar_write(&regs->imask, IMASK_DEFAULT);
gfar_write(&regs->imask,
IMASK_DEFAULT | priv->rmon_overflow.imask);
}
}
......@@ -2298,7 +2311,7 @@ static irqreturn_t gfar_receive(int irq, void *grp_id)
if (likely(napi_schedule_prep(&grp->napi_rx))) {
spin_lock_irqsave(&grp->grplock, flags);
imask = gfar_read(&grp->regs->imask);
imask &= IMASK_RX_DISABLED;
imask &= IMASK_RX_DISABLED | grp->priv->rmon_overflow.imask;
gfar_write(&grp->regs->imask, imask);
spin_unlock_irqrestore(&grp->grplock, flags);
__napi_schedule(&grp->napi_rx);
......@@ -2322,7 +2335,7 @@ static irqreturn_t gfar_transmit(int irq, void *grp_id)
if (likely(napi_schedule_prep(&grp->napi_tx))) {
spin_lock_irqsave(&grp->grplock, flags);
imask = gfar_read(&grp->regs->imask);
imask &= IMASK_TX_DISABLED;
imask &= IMASK_TX_DISABLED | grp->priv->rmon_overflow.imask;
gfar_write(&grp->regs->imask, imask);
spin_unlock_irqrestore(&grp->grplock, flags);
__napi_schedule(&grp->napi_tx);
......@@ -2693,6 +2706,18 @@ static irqreturn_t gfar_error(int irq, void *grp_id)
}
netif_dbg(priv, tx_err, dev, "Transmit Error\n");
}
if (events & IEVENT_MSRO) {
struct rmon_mib __iomem *rmon = &regs->rmon;
u32 car;
spin_lock(&priv->rmon_overflow.lock);
car = gfar_read(&rmon->car1) & CAR1_C1RDR;
if (car) {
priv->rmon_overflow.rdrp++;
gfar_write(&rmon->car1, car);
}
spin_unlock(&priv->rmon_overflow.lock);
}
if (events & IEVENT_BSY) {
dev->stats.rx_over_errors++;
atomic64_inc(&priv->extra_stats.rx_bsy);
......@@ -3109,11 +3134,14 @@ static void gfar_hw_init(struct gfar_private *priv)
/* Zero out the rmon mib registers if it has them */
if (priv->device_flags & FSL_GIANFAR_DEV_HAS_RMON) {
memset_io(&(regs->rmon), 0, sizeof(struct rmon_mib));
memset_io(&regs->rmon, 0, offsetof(struct rmon_mib, car1));
/* Mask off the CAM interrupts */
gfar_write(&regs->rmon.cam1, 0xffffffff);
gfar_write(&regs->rmon.cam2, 0xffffffff);
/* Clear the CAR registers (w1c style) */
gfar_write(&regs->rmon.car1, 0xffffffff);
gfar_write(&regs->rmon.car2, 0xffffffff);
}
/* Initialize ECNTRL */
......@@ -3157,7 +3185,7 @@ static const struct net_device_ops gfar_netdev_ops = {
.ndo_set_rx_mode = gfar_set_multi,
.ndo_tx_timeout = gfar_timeout,
.ndo_do_ioctl = gfar_ioctl,
.ndo_get_stats = gfar_get_stats,
.ndo_get_stats64 = gfar_get_stats64,
.ndo_change_carrier = fixed_phy_change_carrier,
.ndo_set_mac_address = gfar_set_mac_addr,
.ndo_validate_addr = eth_validate_addr,
......@@ -3267,6 +3295,14 @@ static int gfar_probe(struct platform_device *ofdev)
gfar_hw_init(priv);
if (priv->device_flags & FSL_GIANFAR_DEV_HAS_RMON) {
struct rmon_mib __iomem *rmon = &priv->gfargrp[0].regs->rmon;
spin_lock_init(&priv->rmon_overflow.lock);
priv->rmon_overflow.imask = IMASK_MSRO;
gfar_write(&rmon->cam1, gfar_read(&rmon->cam1) & ~CAM1_M1RDR);
}
/* Carrier starts down, phylib will bring it up */
netif_carrier_off(dev);
......
......@@ -445,6 +445,60 @@ struct ethtool_rx_list {
#define RQFPR_PER 0x00000002
#define RQFPR_EER 0x00000001
/* CAR1 bits */
#define CAR1_C164 0x80000000
#define CAR1_C1127 0x40000000
#define CAR1_C1255 0x20000000
#define CAR1_C1511 0x10000000
#define CAR1_C11K 0x08000000
#define CAR1_C1MAX 0x04000000
#define CAR1_C1MGV 0x02000000
#define CAR1_C1REJ 0x00020000
#define CAR1_C1RBY 0x00010000
#define CAR1_C1RPK 0x00008000
#define CAR1_C1RFC 0x00004000
#define CAR1_C1RMC 0x00002000
#define CAR1_C1RBC 0x00001000
#define CAR1_C1RXC 0x00000800
#define CAR1_C1RXP 0x00000400
#define CAR1_C1RXU 0x00000200
#define CAR1_C1RAL 0x00000100
#define CAR1_C1RFL 0x00000080
#define CAR1_C1RCD 0x00000040
#define CAR1_C1RCS 0x00000020
#define CAR1_C1RUN 0x00000010
#define CAR1_C1ROV 0x00000008
#define CAR1_C1RFR 0x00000004
#define CAR1_C1RJB 0x00000002
#define CAR1_C1RDR 0x00000001
/* CAM1 bits */
#define CAM1_M164 0x80000000
#define CAM1_M1127 0x40000000
#define CAM1_M1255 0x20000000
#define CAM1_M1511 0x10000000
#define CAM1_M11K 0x08000000
#define CAM1_M1MAX 0x04000000
#define CAM1_M1MGV 0x02000000
#define CAM1_M1REJ 0x00020000
#define CAM1_M1RBY 0x00010000
#define CAM1_M1RPK 0x00008000
#define CAM1_M1RFC 0x00004000
#define CAM1_M1RMC 0x00002000
#define CAM1_M1RBC 0x00001000
#define CAM1_M1RXC 0x00000800
#define CAM1_M1RXP 0x00000400
#define CAM1_M1RXU 0x00000200
#define CAM1_M1RAL 0x00000100
#define CAM1_M1RFL 0x00000080
#define CAM1_M1RCD 0x00000040
#define CAM1_M1RCS 0x00000020
#define CAM1_M1RUN 0x00000010
#define CAM1_M1ROV 0x00000008
#define CAM1_M1RFR 0x00000004
#define CAM1_M1RJB 0x00000002
#define CAM1_M1RDR 0x00000001
/* TxBD status field bits */
#define TXBD_READY 0x8000
#define TXBD_PADCRC 0x4000
......@@ -609,6 +663,15 @@ struct rmon_mib
u32 cam2; /* 0x.73c - Carry Mask Register Two */
};
struct rmon_overflow {
/* lock for synchronization of the rdrp field of this struct, and
* CAR1/CAR2 registers
*/
spinlock_t lock;
u32 imask;
u64 rdrp;
};
struct gfar_extra_stats {
atomic64_t rx_alloc_err;
atomic64_t rx_large;
......@@ -913,8 +976,8 @@ enum {
* Per TX queue stats
*/
struct tx_q_stats {
unsigned long tx_packets;
unsigned long tx_bytes;
u64 tx_packets;
u64 tx_bytes;
};
/**
......@@ -963,9 +1026,9 @@ struct gfar_priv_tx_q {
* Per RX queue stats
*/
struct rx_q_stats {
unsigned long rx_packets;
unsigned long rx_bytes;
unsigned long rx_dropped;
u64 rx_packets;
u64 rx_bytes;
u64 rx_dropped;
};
struct gfar_rx_buff {
......@@ -1096,6 +1159,7 @@ struct gfar_private {
/* Network Statistics */
struct gfar_extra_stats extra_stats;
struct rmon_overflow rmon_overflow;
/* PHY stuff */
phy_interface_t interface;
......
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