diff options
Diffstat (limited to 'drivers/net/niu.c')
-rw-r--r-- | drivers/net/niu.c | 51 |
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 | ||
3530 | static 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 | |||
3530 | static int niu_rx_work(struct niu *np, struct rx_ring_info *rp, int budget) | 3575 | static 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; |