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

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
Loading
Loading
Loading
Loading
+56 −20
Original line number Diff line number Diff line
@@ -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;

	return &dev->stats;
		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);

		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);

+69 −5
Original line number Diff line number Diff line
@@ -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;