From 13011694b715e51074daf735e295741f0c389531 Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Thu, 18 Dec 2008 19:50:49 -0800 Subject: [PATCH] --- yaml --- r: 122777 b: refs/heads/master c: b8a606b871d37e03b92be1bd3deedeee97ea4f13 h: refs/heads/master i: 122775: 627b0a00c5e8fc64562d43209996be069286da50 v: v3 --- [refs] | 2 +- trunk/drivers/net/niu.c | 51 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/[refs] b/[refs] index 74eea7121182..01d95f5a2f28 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 5664dd5561850df580414783cf3c8e0aa834c62e +refs/heads/master: b8a606b871d37e03b92be1bd3deedeee97ea4f13 diff --git a/trunk/drivers/net/niu.c b/trunk/drivers/net/niu.c index 022866dc0915..7b6cdd07c85f 100644 --- a/trunk/drivers/net/niu.c +++ b/trunk/drivers/net/niu.c @@ -3527,6 +3527,51 @@ static void niu_tx_work(struct niu *np, struct tx_ring_info *rp) } } +static inline void niu_sync_rx_discard_stats(struct niu *np, + struct rx_ring_info *rp, + const int limit) +{ + /* This elaborate scheme is needed for reading the RX discard + * counters, as they are only 16-bit and can overflow quickly, + * and because the overflow indication bit is not usable as + * the counter value does not wrap, but remains at max value + * 0xFFFF. + * + * In theory and in practice counters can be lost in between + * reading nr64() and clearing the counter nw64(). For this + * reason, the number of counter clearings nw64() is + * limited/reduced though the limit parameter. + */ + int rx_channel = rp->rx_channel; + u32 misc, wred; + + /* RXMISC (Receive Miscellaneous Discard Count), covers the + * following discard events: IPP (Input Port Process), + * FFLP/TCAM, Full RCR (Receive Completion Ring) RBR (Receive + * Block Ring) prefetch buffer is empty. + */ + misc = nr64(RXMISC(rx_channel)); + if (unlikely((misc & RXMISC_COUNT) > limit)) { + nw64(RXMISC(rx_channel), 0); + rp->rx_errors += misc & RXMISC_COUNT; + + if (unlikely(misc & RXMISC_OFLOW)) + dev_err(np->device, "rx-%d: Counter overflow " + "RXMISC discard\n", rx_channel); + } + + /* WRED (Weighted Random Early Discard) by hardware */ + wred = nr64(RED_DIS_CNT(rx_channel)); + if (unlikely((wred & RED_DIS_CNT_COUNT) > limit)) { + nw64(RED_DIS_CNT(rx_channel), 0); + rp->rx_dropped += wred & RED_DIS_CNT_COUNT; + + if (unlikely(wred & RED_DIS_CNT_OFLOW)) + dev_err(np->device, "rx-%d: Counter overflow " + "WRED discard\n", rx_channel); + } +} + static int niu_rx_work(struct niu *np, struct rx_ring_info *rp, int budget) { int qlen, rcr_done = 0, work_done = 0; @@ -3567,6 +3612,8 @@ static int niu_rx_work(struct niu *np, struct rx_ring_info *rp, int budget) nw64(RX_DMA_CTL_STAT(rp->rx_channel), stat); + niu_sync_rx_discard_stats(np, rp, 0x7FFF); + return work_done; } @@ -6073,6 +6120,8 @@ static void niu_get_rx_stats(struct niu *np) for (i = 0; i < np->num_rx_rings; i++) { struct rx_ring_info *rp = &np->rx_rings[i]; + niu_sync_rx_discard_stats(np, rp, 0); + pkts += rp->rx_packets; bytes += rp->rx_bytes; dropped += rp->rx_dropped; @@ -7014,6 +7063,8 @@ static void niu_get_ethtool_stats(struct net_device *dev, for (i = 0; i < np->num_rx_rings; i++) { struct rx_ring_info *rp = &np->rx_rings[i]; + niu_sync_rx_discard_stats(np, rp, 0); + data[0] = rp->rx_channel; data[1] = rp->rx_packets; data[2] = rp->rx_bytes;