diff options
author | Igor Russkikh <igor.russkikh@aquantia.com> | 2017-12-14 04:34:42 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-12-15 12:46:41 -0500 |
commit | be08d839d9ef1c9b0e4ed809ec852ff100f9970d (patch) | |
tree | ab61e7bccdf588746c705c85e79119c6d4944de9 | |
parent | 1e366161510f266516107a69db91f1f2edaea11c (diff) |
net: aquantia: Extend stat counters to 64bit values
Device hardware provides only 32bit counters. Using these directly
causes byte counters to overflow soon. A separate nic level structure
with 64 bit counters is now used to collect incrementally all the stats
and report these counters to ethtool stats and ndev stats.
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
4 files changed, 79 insertions, 67 deletions
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h index 4ebd53b3c7da..b3825de6cdfb 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h | |||
@@ -46,6 +46,28 @@ struct aq_hw_link_status_s { | |||
46 | unsigned int mbps; | 46 | unsigned int mbps; |
47 | }; | 47 | }; |
48 | 48 | ||
49 | struct aq_stats_s { | ||
50 | u64 uprc; | ||
51 | u64 mprc; | ||
52 | u64 bprc; | ||
53 | u64 erpt; | ||
54 | u64 uptc; | ||
55 | u64 mptc; | ||
56 | u64 bptc; | ||
57 | u64 erpr; | ||
58 | u64 mbtc; | ||
59 | u64 bbtc; | ||
60 | u64 mbrc; | ||
61 | u64 bbrc; | ||
62 | u64 ubrc; | ||
63 | u64 ubtc; | ||
64 | u64 dpc; | ||
65 | u64 dma_pkt_rc; | ||
66 | u64 dma_pkt_tc; | ||
67 | u64 dma_oct_rc; | ||
68 | u64 dma_oct_tc; | ||
69 | }; | ||
70 | |||
49 | #define AQ_HW_IRQ_INVALID 0U | 71 | #define AQ_HW_IRQ_INVALID 0U |
50 | #define AQ_HW_IRQ_LEGACY 1U | 72 | #define AQ_HW_IRQ_LEGACY 1U |
51 | #define AQ_HW_IRQ_MSI 2U | 73 | #define AQ_HW_IRQ_MSI 2U |
@@ -166,8 +188,7 @@ struct aq_hw_ops { | |||
166 | 188 | ||
167 | int (*hw_update_stats)(struct aq_hw_s *self); | 189 | int (*hw_update_stats)(struct aq_hw_s *self); |
168 | 190 | ||
169 | int (*hw_get_hw_stats)(struct aq_hw_s *self, u64 *data, | 191 | struct aq_stats_s *(*hw_get_hw_stats)(struct aq_hw_s *self); |
170 | unsigned int *p_count); | ||
171 | 192 | ||
172 | int (*hw_get_fw_version)(struct aq_hw_s *self, u32 *fw_version); | 193 | int (*hw_get_fw_version)(struct aq_hw_s *self, u32 *fw_version); |
173 | 194 | ||
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c index a360ccc298b9..28cbe9d43df6 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c | |||
@@ -750,16 +750,40 @@ int aq_nic_get_regs_count(struct aq_nic_s *self) | |||
750 | 750 | ||
751 | void aq_nic_get_stats(struct aq_nic_s *self, u64 *data) | 751 | void aq_nic_get_stats(struct aq_nic_s *self, u64 *data) |
752 | { | 752 | { |
753 | struct aq_vec_s *aq_vec = NULL; | ||
754 | unsigned int i = 0U; | 753 | unsigned int i = 0U; |
755 | unsigned int count = 0U; | 754 | unsigned int count = 0U; |
756 | int err = 0; | 755 | struct aq_vec_s *aq_vec = NULL; |
756 | struct aq_stats_s *stats = self->aq_hw_ops.hw_get_hw_stats(self->aq_hw); | ||
757 | 757 | ||
758 | err = self->aq_hw_ops.hw_get_hw_stats(self->aq_hw, data, &count); | 758 | if (!stats) |
759 | if (err < 0) | ||
760 | goto err_exit; | 759 | goto err_exit; |
761 | 760 | ||
762 | data += count; | 761 | data[i] = stats->uprc + stats->mprc + stats->bprc; |
762 | data[++i] = stats->uprc; | ||
763 | data[++i] = stats->mprc; | ||
764 | data[++i] = stats->bprc; | ||
765 | data[++i] = stats->erpt; | ||
766 | data[++i] = stats->uptc + stats->mptc + stats->bptc; | ||
767 | data[++i] = stats->uptc; | ||
768 | data[++i] = stats->mptc; | ||
769 | data[++i] = stats->bptc; | ||
770 | data[++i] = stats->ubrc; | ||
771 | data[++i] = stats->ubtc; | ||
772 | data[++i] = stats->mbrc; | ||
773 | data[++i] = stats->mbtc; | ||
774 | data[++i] = stats->bbrc; | ||
775 | data[++i] = stats->bbtc; | ||
776 | data[++i] = stats->ubrc + stats->mbrc + stats->bbrc; | ||
777 | data[++i] = stats->ubtc + stats->mbtc + stats->bbtc; | ||
778 | data[++i] = stats->dma_pkt_rc; | ||
779 | data[++i] = stats->dma_pkt_tc; | ||
780 | data[++i] = stats->dma_oct_rc; | ||
781 | data[++i] = stats->dma_oct_tc; | ||
782 | data[++i] = stats->dpc; | ||
783 | |||
784 | i++; | ||
785 | |||
786 | data += i; | ||
763 | count = 0U; | 787 | count = 0U; |
764 | 788 | ||
765 | for (i = 0U, aq_vec = self->aq_vec[0]; | 789 | for (i = 0U, aq_vec = self->aq_vec[0]; |
@@ -769,7 +793,6 @@ void aq_nic_get_stats(struct aq_nic_s *self, u64 *data) | |||
769 | } | 793 | } |
770 | 794 | ||
771 | err_exit:; | 795 | err_exit:; |
772 | (void)err; | ||
773 | } | 796 | } |
774 | 797 | ||
775 | void aq_nic_get_link_ksettings(struct aq_nic_s *self, | 798 | void aq_nic_get_link_ksettings(struct aq_nic_s *self, |
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c index 1fe016fc4bc7..f2ce12ed4218 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c | |||
@@ -503,73 +503,43 @@ int hw_atl_utils_update_stats(struct aq_hw_s *self) | |||
503 | struct hw_atl_s *hw_self = PHAL_ATLANTIC; | 503 | struct hw_atl_s *hw_self = PHAL_ATLANTIC; |
504 | struct hw_aq_atl_utils_mbox mbox; | 504 | struct hw_aq_atl_utils_mbox mbox; |
505 | 505 | ||
506 | if (!self->aq_link_status.mbps) | ||
507 | return 0; | ||
508 | |||
509 | hw_atl_utils_mpi_read_stats(self, &mbox); | 506 | hw_atl_utils_mpi_read_stats(self, &mbox); |
510 | 507 | ||
511 | #define AQ_SDELTA(_N_) (hw_self->curr_stats._N_ += \ | 508 | #define AQ_SDELTA(_N_) (hw_self->curr_stats._N_ += \ |
512 | mbox.stats._N_ - hw_self->last_stats._N_) | 509 | mbox.stats._N_ - hw_self->last_stats._N_) |
513 | 510 | if (self->aq_link_status.mbps) { | |
514 | AQ_SDELTA(uprc); | 511 | AQ_SDELTA(uprc); |
515 | AQ_SDELTA(mprc); | 512 | AQ_SDELTA(mprc); |
516 | AQ_SDELTA(bprc); | 513 | AQ_SDELTA(bprc); |
517 | AQ_SDELTA(erpt); | 514 | AQ_SDELTA(erpt); |
518 | 515 | ||
519 | AQ_SDELTA(uptc); | 516 | AQ_SDELTA(uptc); |
520 | AQ_SDELTA(mptc); | 517 | AQ_SDELTA(mptc); |
521 | AQ_SDELTA(bptc); | 518 | AQ_SDELTA(bptc); |
522 | AQ_SDELTA(erpr); | 519 | AQ_SDELTA(erpr); |
523 | 520 | ||
524 | AQ_SDELTA(ubrc); | 521 | AQ_SDELTA(ubrc); |
525 | AQ_SDELTA(ubtc); | 522 | AQ_SDELTA(ubtc); |
526 | AQ_SDELTA(mbrc); | 523 | AQ_SDELTA(mbrc); |
527 | AQ_SDELTA(mbtc); | 524 | AQ_SDELTA(mbtc); |
528 | AQ_SDELTA(bbrc); | 525 | AQ_SDELTA(bbrc); |
529 | AQ_SDELTA(bbtc); | 526 | AQ_SDELTA(bbtc); |
530 | AQ_SDELTA(dpc); | 527 | AQ_SDELTA(dpc); |
531 | 528 | } | |
532 | #undef AQ_SDELTA | 529 | #undef AQ_SDELTA |
530 | hw_self->curr_stats.dma_pkt_rc = stats_rx_dma_good_pkt_counterlsw_get(self); | ||
531 | hw_self->curr_stats.dma_pkt_tc = stats_tx_dma_good_pkt_counterlsw_get(self); | ||
532 | hw_self->curr_stats.dma_oct_rc = stats_rx_dma_good_octet_counterlsw_get(self); | ||
533 | hw_self->curr_stats.dma_oct_tc = stats_tx_dma_good_octet_counterlsw_get(self); | ||
533 | 534 | ||
534 | memcpy(&hw_self->last_stats, &mbox.stats, sizeof(mbox.stats)); | 535 | memcpy(&hw_self->last_stats, &mbox.stats, sizeof(mbox.stats)); |
535 | 536 | ||
536 | return 0; | 537 | return 0; |
537 | } | 538 | } |
538 | 539 | ||
539 | int hw_atl_utils_get_hw_stats(struct aq_hw_s *self, | 540 | struct aq_stats_s *hw_atl_utils_get_hw_stats(struct aq_hw_s *self) |
540 | u64 *data, unsigned int *p_count) | ||
541 | { | 541 | { |
542 | struct hw_atl_s *hw_self = PHAL_ATLANTIC; | 542 | return &PHAL_ATLANTIC->curr_stats; |
543 | struct hw_atl_stats_s *stats = &hw_self->curr_stats; | ||
544 | int i = 0; | ||
545 | |||
546 | data[i] = stats->uprc + stats->mprc + stats->bprc; | ||
547 | data[++i] = stats->uprc; | ||
548 | data[++i] = stats->mprc; | ||
549 | data[++i] = stats->bprc; | ||
550 | data[++i] = stats->erpt; | ||
551 | data[++i] = stats->uptc + stats->mptc + stats->bptc; | ||
552 | data[++i] = stats->uptc; | ||
553 | data[++i] = stats->mptc; | ||
554 | data[++i] = stats->bptc; | ||
555 | data[++i] = stats->ubrc; | ||
556 | data[++i] = stats->ubtc; | ||
557 | data[++i] = stats->mbrc; | ||
558 | data[++i] = stats->mbtc; | ||
559 | data[++i] = stats->bbrc; | ||
560 | data[++i] = stats->bbtc; | ||
561 | data[++i] = stats->ubrc + stats->mbrc + stats->bbrc; | ||
562 | data[++i] = stats->ubtc + stats->mbtc + stats->bbtc; | ||
563 | data[++i] = stats_rx_dma_good_pkt_counterlsw_get(self); | ||
564 | data[++i] = stats_tx_dma_good_pkt_counterlsw_get(self); | ||
565 | data[++i] = stats_rx_dma_good_octet_counterlsw_get(self); | ||
566 | data[++i] = stats_tx_dma_good_octet_counterlsw_get(self); | ||
567 | data[++i] = stats->dpc; | ||
568 | |||
569 | if (p_count) | ||
570 | *p_count = ++i; | ||
571 | |||
572 | return 0; | ||
573 | } | 543 | } |
574 | 544 | ||
575 | static const u32 hw_atl_utils_hw_mac_regs[] = { | 545 | static const u32 hw_atl_utils_hw_mac_regs[] = { |
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h index c99cc690e425..21aeca6908d3 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h | |||
@@ -129,7 +129,7 @@ struct __packed hw_aq_atl_utils_mbox { | |||
129 | struct __packed hw_atl_s { | 129 | struct __packed hw_atl_s { |
130 | struct aq_hw_s base; | 130 | struct aq_hw_s base; |
131 | struct hw_atl_stats_s last_stats; | 131 | struct hw_atl_stats_s last_stats; |
132 | struct hw_atl_stats_s curr_stats; | 132 | struct aq_stats_s curr_stats; |
133 | u64 speed; | 133 | u64 speed; |
134 | unsigned int chip_features; | 134 | unsigned int chip_features; |
135 | u32 fw_ver_actual; | 135 | u32 fw_ver_actual; |
@@ -207,8 +207,6 @@ int hw_atl_utils_get_fw_version(struct aq_hw_s *self, u32 *fw_version); | |||
207 | 207 | ||
208 | int hw_atl_utils_update_stats(struct aq_hw_s *self); | 208 | int hw_atl_utils_update_stats(struct aq_hw_s *self); |
209 | 209 | ||
210 | int hw_atl_utils_get_hw_stats(struct aq_hw_s *self, | 210 | struct aq_stats_s *hw_atl_utils_get_hw_stats(struct aq_hw_s *self); |
211 | u64 *data, | ||
212 | unsigned int *p_count); | ||
213 | 211 | ||
214 | #endif /* HW_ATL_UTILS_H */ | 212 | #endif /* HW_ATL_UTILS_H */ |