diff options
-rw-r--r-- | drivers/net/ethernet/freescale/gianfar.c | 76 | ||||
-rw-r--r-- | drivers/net/ethernet/freescale/gianfar.h | 74 |
2 files changed, 125 insertions, 25 deletions
diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index f2945abdb041..9646483137c4 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -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(®s->imask, IMASK_DEFAULT); + gfar_write(®s->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 = ®s->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(®s->rmon, 0, offsetof(struct rmon_mib, car1)); /* Mask off the CAM interrupts */ gfar_write(®s->rmon.cam1, 0xffffffff); gfar_write(®s->rmon.cam2, 0xffffffff); + /* Clear the CAR registers (w1c style) */ + gfar_write(®s->rmon.car1, 0xffffffff); + gfar_write(®s->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); diff --git a/drivers/net/ethernet/freescale/gianfar.h b/drivers/net/ethernet/freescale/gianfar.h index 5ea47df93e5e..ca5e14f908fe 100644 --- a/drivers/net/ethernet/freescale/gianfar.h +++ b/drivers/net/ethernet/freescale/gianfar.h @@ -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; |