aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/niu.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/niu.c')
-rw-r--r--drivers/net/niu.c51
1 files changed, 51 insertions, 0 deletions
diff --git a/drivers/net/niu.c b/drivers/net/niu.c
index 022866dc0915..7b6cdd07c85f 100644
--- a/drivers/net/niu.c
+++ b/drivers/net/niu.c
@@ -3527,6 +3527,51 @@ out:
3527 } 3527 }
3528} 3528}
3529 3529
3530static inline void niu_sync_rx_discard_stats(struct niu *np,
3531 struct rx_ring_info *rp,
3532 const int limit)
3533{
3534 /* This elaborate scheme is needed for reading the RX discard
3535 * counters, as they are only 16-bit and can overflow quickly,
3536 * and because the overflow indication bit is not usable as
3537 * the counter value does not wrap, but remains at max value
3538 * 0xFFFF.
3539 *
3540 * In theory and in practice counters can be lost in between
3541 * reading nr64() and clearing the counter nw64(). For this
3542 * reason, the number of counter clearings nw64() is
3543 * limited/reduced though the limit parameter.
3544 */
3545 int rx_channel = rp->rx_channel;
3546 u32 misc, wred;
3547
3548 /* RXMISC (Receive Miscellaneous Discard Count), covers the
3549 * following discard events: IPP (Input Port Process),
3550 * FFLP/TCAM, Full RCR (Receive Completion Ring) RBR (Receive
3551 * Block Ring) prefetch buffer is empty.
3552 */
3553 misc = nr64(RXMISC(rx_channel));
3554 if (unlikely((misc & RXMISC_COUNT) > limit)) {
3555 nw64(RXMISC(rx_channel), 0);
3556 rp->rx_errors += misc & RXMISC_COUNT;
3557
3558 if (unlikely(misc & RXMISC_OFLOW))
3559 dev_err(np->device, "rx-%d: Counter overflow "
3560 "RXMISC discard\n", rx_channel);
3561 }
3562
3563 /* WRED (Weighted Random Early Discard) by hardware */
3564 wred = nr64(RED_DIS_CNT(rx_channel));
3565 if (unlikely((wred & RED_DIS_CNT_COUNT) > limit)) {
3566 nw64(RED_DIS_CNT(rx_channel), 0);
3567 rp->rx_dropped += wred & RED_DIS_CNT_COUNT;
3568
3569 if (unlikely(wred & RED_DIS_CNT_OFLOW))
3570 dev_err(np->device, "rx-%d: Counter overflow "
3571 "WRED discard\n", rx_channel);
3572 }
3573}
3574
3530static int niu_rx_work(struct niu *np, struct rx_ring_info *rp, int budget) 3575static int niu_rx_work(struct niu *np, struct rx_ring_info *rp, int budget)
3531{ 3576{
3532 int qlen, rcr_done = 0, work_done = 0; 3577 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)
3567 3612
3568 nw64(RX_DMA_CTL_STAT(rp->rx_channel), stat); 3613 nw64(RX_DMA_CTL_STAT(rp->rx_channel), stat);
3569 3614
3615 niu_sync_rx_discard_stats(np, rp, 0x7FFF);
3616
3570 return work_done; 3617 return work_done;
3571} 3618}
3572 3619
@@ -6073,6 +6120,8 @@ static void niu_get_rx_stats(struct niu *np)
6073 for (i = 0; i < np->num_rx_rings; i++) { 6120 for (i = 0; i < np->num_rx_rings; i++) {
6074 struct rx_ring_info *rp = &np->rx_rings[i]; 6121 struct rx_ring_info *rp = &np->rx_rings[i];
6075 6122
6123 niu_sync_rx_discard_stats(np, rp, 0);
6124
6076 pkts += rp->rx_packets; 6125 pkts += rp->rx_packets;
6077 bytes += rp->rx_bytes; 6126 bytes += rp->rx_bytes;
6078 dropped += rp->rx_dropped; 6127 dropped += rp->rx_dropped;
@@ -7014,6 +7063,8 @@ static void niu_get_ethtool_stats(struct net_device *dev,
7014 for (i = 0; i < np->num_rx_rings; i++) { 7063 for (i = 0; i < np->num_rx_rings; i++) {
7015 struct rx_ring_info *rp = &np->rx_rings[i]; 7064 struct rx_ring_info *rp = &np->rx_rings[i];
7016 7065
7066 niu_sync_rx_discard_stats(np, rp, 0);
7067
7017 data[0] = rp->rx_channel; 7068 data[0] = rp->rx_channel;
7018 data[1] = rp->rx_packets; 7069 data[1] = rp->rx_packets;
7019 data[2] = rp->rx_bytes; 7070 data[2] = rp->rx_bytes;