]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/net/ethernet/qlogic/qed/qed_l2.c
qed: Move statistics to L2 code
[linux.git] / drivers / net / ethernet / qlogic / qed / qed_l2.c
index bba59c51f72c9b057cc1f9b194584ec0890d404b..102ddc73b8410600f6ed86f4026b634f40bdfd8f 100644 (file)
@@ -31,6 +31,7 @@
 #include "qed_hsi.h"
 #include "qed_hw.h"
 #include "qed_int.h"
+#include "qed_mcp.h"
 #include "qed_reg_addr.h"
 #include "qed_sp.h"
 
@@ -1231,6 +1232,328 @@ static int qed_filter_ucast_cmd(struct qed_dev *cdev,
        return rc;
 }
 
+/* Statistics related code */
+static void __qed_get_vport_pstats_addrlen(struct qed_hwfn *p_hwfn,
+                                          u32 *p_addr,
+                                          u32 *p_len,
+                                          u16 statistics_bin)
+{
+       *p_addr = BAR0_MAP_REG_PSDM_RAM +
+                 PSTORM_QUEUE_STAT_OFFSET(statistics_bin);
+       *p_len = sizeof(struct eth_pstorm_per_queue_stat);
+}
+
+static void __qed_get_vport_pstats(struct qed_hwfn *p_hwfn,
+                                  struct qed_ptt *p_ptt,
+                                  struct qed_eth_stats *p_stats,
+                                  u16 statistics_bin)
+{
+       struct eth_pstorm_per_queue_stat pstats;
+       u32 pstats_addr = 0, pstats_len = 0;
+
+       __qed_get_vport_pstats_addrlen(p_hwfn, &pstats_addr, &pstats_len,
+                                      statistics_bin);
+
+       memset(&pstats, 0, sizeof(pstats));
+       qed_memcpy_from(p_hwfn, p_ptt, &pstats,
+                       pstats_addr, pstats_len);
+
+       p_stats->tx_ucast_bytes +=
+               HILO_64_REGPAIR(pstats.sent_ucast_bytes);
+       p_stats->tx_mcast_bytes +=
+               HILO_64_REGPAIR(pstats.sent_mcast_bytes);
+       p_stats->tx_bcast_bytes +=
+               HILO_64_REGPAIR(pstats.sent_bcast_bytes);
+       p_stats->tx_ucast_pkts +=
+               HILO_64_REGPAIR(pstats.sent_ucast_pkts);
+       p_stats->tx_mcast_pkts +=
+               HILO_64_REGPAIR(pstats.sent_mcast_pkts);
+       p_stats->tx_bcast_pkts +=
+               HILO_64_REGPAIR(pstats.sent_bcast_pkts);
+       p_stats->tx_err_drop_pkts +=
+               HILO_64_REGPAIR(pstats.error_drop_pkts);
+}
+
+static void __qed_get_vport_tstats_addrlen(struct qed_hwfn *p_hwfn,
+                                          u32 *p_addr,
+                                          u32 *p_len)
+{
+       *p_addr = BAR0_MAP_REG_TSDM_RAM +
+                 TSTORM_PORT_STAT_OFFSET(MFW_PORT(p_hwfn));
+       *p_len = sizeof(struct tstorm_per_port_stat);
+}
+
+static void __qed_get_vport_tstats(struct qed_hwfn *p_hwfn,
+                                  struct qed_ptt *p_ptt,
+                                  struct qed_eth_stats *p_stats,
+                                  u16 statistics_bin)
+{
+       u32 tstats_addr = 0, tstats_len = 0;
+       struct tstorm_per_port_stat tstats;
+
+       __qed_get_vport_tstats_addrlen(p_hwfn, &tstats_addr, &tstats_len);
+
+       memset(&tstats, 0, sizeof(tstats));
+       qed_memcpy_from(p_hwfn, p_ptt, &tstats,
+                       tstats_addr, tstats_len);
+
+       p_stats->mftag_filter_discards +=
+               HILO_64_REGPAIR(tstats.mftag_filter_discard);
+       p_stats->mac_filter_discards +=
+               HILO_64_REGPAIR(tstats.eth_mac_filter_discard);
+}
+
+static void __qed_get_vport_ustats_addrlen(struct qed_hwfn *p_hwfn,
+                                          u32 *p_addr,
+                                          u32 *p_len,
+                                          u16 statistics_bin)
+{
+       *p_addr = BAR0_MAP_REG_USDM_RAM +
+                 USTORM_QUEUE_STAT_OFFSET(statistics_bin);
+       *p_len = sizeof(struct eth_ustorm_per_queue_stat);
+}
+
+static void __qed_get_vport_ustats(struct qed_hwfn *p_hwfn,
+                                  struct qed_ptt *p_ptt,
+                                  struct qed_eth_stats *p_stats,
+                                  u16 statistics_bin)
+{
+       struct eth_ustorm_per_queue_stat ustats;
+       u32 ustats_addr = 0, ustats_len = 0;
+
+       __qed_get_vport_ustats_addrlen(p_hwfn, &ustats_addr, &ustats_len,
+                                      statistics_bin);
+
+       memset(&ustats, 0, sizeof(ustats));
+       qed_memcpy_from(p_hwfn, p_ptt, &ustats,
+                       ustats_addr, ustats_len);
+
+       p_stats->rx_ucast_bytes +=
+               HILO_64_REGPAIR(ustats.rcv_ucast_bytes);
+       p_stats->rx_mcast_bytes +=
+               HILO_64_REGPAIR(ustats.rcv_mcast_bytes);
+       p_stats->rx_bcast_bytes +=
+               HILO_64_REGPAIR(ustats.rcv_bcast_bytes);
+       p_stats->rx_ucast_pkts +=
+               HILO_64_REGPAIR(ustats.rcv_ucast_pkts);
+       p_stats->rx_mcast_pkts +=
+               HILO_64_REGPAIR(ustats.rcv_mcast_pkts);
+       p_stats->rx_bcast_pkts +=
+               HILO_64_REGPAIR(ustats.rcv_bcast_pkts);
+}
+
+static void __qed_get_vport_mstats_addrlen(struct qed_hwfn *p_hwfn,
+                                          u32 *p_addr,
+                                          u32 *p_len,
+                                          u16 statistics_bin)
+{
+       *p_addr = BAR0_MAP_REG_MSDM_RAM +
+                 MSTORM_QUEUE_STAT_OFFSET(statistics_bin);
+       *p_len = sizeof(struct eth_mstorm_per_queue_stat);
+}
+
+static void __qed_get_vport_mstats(struct qed_hwfn *p_hwfn,
+                                  struct qed_ptt *p_ptt,
+                                  struct qed_eth_stats *p_stats,
+                                  u16 statistics_bin)
+{
+       struct eth_mstorm_per_queue_stat mstats;
+       u32 mstats_addr = 0, mstats_len = 0;
+
+       __qed_get_vport_mstats_addrlen(p_hwfn, &mstats_addr, &mstats_len,
+                                      statistics_bin);
+
+       memset(&mstats, 0, sizeof(mstats));
+       qed_memcpy_from(p_hwfn, p_ptt, &mstats,
+                       mstats_addr, mstats_len);
+
+       p_stats->no_buff_discards +=
+               HILO_64_REGPAIR(mstats.no_buff_discard);
+       p_stats->packet_too_big_discard +=
+               HILO_64_REGPAIR(mstats.packet_too_big_discard);
+       p_stats->ttl0_discard +=
+               HILO_64_REGPAIR(mstats.ttl0_discard);
+       p_stats->tpa_coalesced_pkts +=
+               HILO_64_REGPAIR(mstats.tpa_coalesced_pkts);
+       p_stats->tpa_coalesced_events +=
+               HILO_64_REGPAIR(mstats.tpa_coalesced_events);
+       p_stats->tpa_aborts_num +=
+               HILO_64_REGPAIR(mstats.tpa_aborts_num);
+       p_stats->tpa_coalesced_bytes +=
+               HILO_64_REGPAIR(mstats.tpa_coalesced_bytes);
+}
+
+static void __qed_get_vport_port_stats(struct qed_hwfn *p_hwfn,
+                                      struct qed_ptt *p_ptt,
+                                      struct qed_eth_stats *p_stats)
+{
+       struct port_stats port_stats;
+       int j;
+
+       memset(&port_stats, 0, sizeof(port_stats));
+
+       qed_memcpy_from(p_hwfn, p_ptt, &port_stats,
+                       p_hwfn->mcp_info->port_addr +
+                       offsetof(struct public_port, stats),
+                       sizeof(port_stats));
+
+       p_stats->rx_64_byte_packets             += port_stats.pmm.r64;
+       p_stats->rx_127_byte_packets            += port_stats.pmm.r127;
+       p_stats->rx_255_byte_packets            += port_stats.pmm.r255;
+       p_stats->rx_511_byte_packets            += port_stats.pmm.r511;
+       p_stats->rx_1023_byte_packets           += port_stats.pmm.r1023;
+       p_stats->rx_1518_byte_packets           += port_stats.pmm.r1518;
+       p_stats->rx_1522_byte_packets           += port_stats.pmm.r1522;
+       p_stats->rx_2047_byte_packets           += port_stats.pmm.r2047;
+       p_stats->rx_4095_byte_packets           += port_stats.pmm.r4095;
+       p_stats->rx_9216_byte_packets           += port_stats.pmm.r9216;
+       p_stats->rx_16383_byte_packets          += port_stats.pmm.r16383;
+       p_stats->rx_crc_errors                  += port_stats.pmm.rfcs;
+       p_stats->rx_mac_crtl_frames             += port_stats.pmm.rxcf;
+       p_stats->rx_pause_frames                += port_stats.pmm.rxpf;
+       p_stats->rx_pfc_frames                  += port_stats.pmm.rxpp;
+       p_stats->rx_align_errors                += port_stats.pmm.raln;
+       p_stats->rx_carrier_errors              += port_stats.pmm.rfcr;
+       p_stats->rx_oversize_packets            += port_stats.pmm.rovr;
+       p_stats->rx_jabbers                     += port_stats.pmm.rjbr;
+       p_stats->rx_undersize_packets           += port_stats.pmm.rund;
+       p_stats->rx_fragments                   += port_stats.pmm.rfrg;
+       p_stats->tx_64_byte_packets             += port_stats.pmm.t64;
+       p_stats->tx_65_to_127_byte_packets      += port_stats.pmm.t127;
+       p_stats->tx_128_to_255_byte_packets     += port_stats.pmm.t255;
+       p_stats->tx_256_to_511_byte_packets     += port_stats.pmm.t511;
+       p_stats->tx_512_to_1023_byte_packets    += port_stats.pmm.t1023;
+       p_stats->tx_1024_to_1518_byte_packets   += port_stats.pmm.t1518;
+       p_stats->tx_1519_to_2047_byte_packets   += port_stats.pmm.t2047;
+       p_stats->tx_2048_to_4095_byte_packets   += port_stats.pmm.t4095;
+       p_stats->tx_4096_to_9216_byte_packets   += port_stats.pmm.t9216;
+       p_stats->tx_9217_to_16383_byte_packets  += port_stats.pmm.t16383;
+       p_stats->tx_pause_frames                += port_stats.pmm.txpf;
+       p_stats->tx_pfc_frames                  += port_stats.pmm.txpp;
+       p_stats->tx_lpi_entry_count             += port_stats.pmm.tlpiec;
+       p_stats->tx_total_collisions            += port_stats.pmm.tncl;
+       p_stats->rx_mac_bytes                   += port_stats.pmm.rbyte;
+       p_stats->rx_mac_uc_packets              += port_stats.pmm.rxuca;
+       p_stats->rx_mac_mc_packets              += port_stats.pmm.rxmca;
+       p_stats->rx_mac_bc_packets              += port_stats.pmm.rxbca;
+       p_stats->rx_mac_frames_ok               += port_stats.pmm.rxpok;
+       p_stats->tx_mac_bytes                   += port_stats.pmm.tbyte;
+       p_stats->tx_mac_uc_packets              += port_stats.pmm.txuca;
+       p_stats->tx_mac_mc_packets              += port_stats.pmm.txmca;
+       p_stats->tx_mac_bc_packets              += port_stats.pmm.txbca;
+       p_stats->tx_mac_ctrl_frames             += port_stats.pmm.txcf;
+       for (j = 0; j < 8; j++) {
+               p_stats->brb_truncates  += port_stats.brb.brb_truncate[j];
+               p_stats->brb_discards   += port_stats.brb.brb_discard[j];
+       }
+}
+
+static void __qed_get_vport_stats(struct qed_hwfn *p_hwfn,
+                                 struct qed_ptt *p_ptt,
+                                 struct qed_eth_stats *stats,
+                                 u16 statistics_bin)
+{
+       __qed_get_vport_mstats(p_hwfn, p_ptt, stats, statistics_bin);
+       __qed_get_vport_ustats(p_hwfn, p_ptt, stats, statistics_bin);
+       __qed_get_vport_tstats(p_hwfn, p_ptt, stats, statistics_bin);
+       __qed_get_vport_pstats(p_hwfn, p_ptt, stats, statistics_bin);
+
+       if (p_hwfn->mcp_info)
+               __qed_get_vport_port_stats(p_hwfn, p_ptt, stats);
+}
+
+static void _qed_get_vport_stats(struct qed_dev *cdev,
+                                struct qed_eth_stats *stats)
+{
+       u8      fw_vport = 0;
+       int     i;
+
+       memset(stats, 0, sizeof(*stats));
+
+       for_each_hwfn(cdev, i) {
+               struct qed_hwfn *p_hwfn = &cdev->hwfns[i];
+               struct qed_ptt *p_ptt;
+
+               /* The main vport index is relative first */
+               if (qed_fw_vport(p_hwfn, 0, &fw_vport)) {
+                       DP_ERR(p_hwfn, "No vport available!\n");
+                       continue;
+               }
+
+               p_ptt = qed_ptt_acquire(p_hwfn);
+               if (!p_ptt) {
+                       DP_ERR(p_hwfn, "Failed to acquire ptt\n");
+                       continue;
+               }
+
+               __qed_get_vport_stats(p_hwfn, p_ptt, stats, fw_vport);
+
+               qed_ptt_release(p_hwfn, p_ptt);
+       }
+}
+
+void qed_get_vport_stats(struct qed_dev *cdev,
+                        struct qed_eth_stats *stats)
+{
+       u32 i;
+
+       if (!cdev) {
+               memset(stats, 0, sizeof(*stats));
+               return;
+       }
+
+       _qed_get_vport_stats(cdev, stats);
+
+       if (!cdev->reset_stats)
+               return;
+
+       /* Reduce the statistics baseline */
+       for (i = 0; i < sizeof(struct qed_eth_stats) / sizeof(u64); i++)
+               ((u64 *)stats)[i] -= ((u64 *)cdev->reset_stats)[i];
+}
+
+/* zeroes V-PORT specific portion of stats (Port stats remains untouched) */
+void qed_reset_vport_stats(struct qed_dev *cdev)
+{
+       int i;
+
+       for_each_hwfn(cdev, i) {
+               struct qed_hwfn *p_hwfn = &cdev->hwfns[i];
+               struct eth_mstorm_per_queue_stat mstats;
+               struct eth_ustorm_per_queue_stat ustats;
+               struct eth_pstorm_per_queue_stat pstats;
+               struct qed_ptt *p_ptt = qed_ptt_acquire(p_hwfn);
+               u32 addr = 0, len = 0;
+
+               if (!p_ptt) {
+                       DP_ERR(p_hwfn, "Failed to acquire ptt\n");
+                       continue;
+               }
+
+               memset(&mstats, 0, sizeof(mstats));
+               __qed_get_vport_mstats_addrlen(p_hwfn, &addr, &len, 0);
+               qed_memcpy_to(p_hwfn, p_ptt, addr, &mstats, len);
+
+               memset(&ustats, 0, sizeof(ustats));
+               __qed_get_vport_ustats_addrlen(p_hwfn, &addr, &len, 0);
+               qed_memcpy_to(p_hwfn, p_ptt, addr, &ustats, len);
+
+               memset(&pstats, 0, sizeof(pstats));
+               __qed_get_vport_pstats_addrlen(p_hwfn, &addr, &len, 0);
+               qed_memcpy_to(p_hwfn, p_ptt, addr, &pstats, len);
+
+               qed_ptt_release(p_hwfn, p_ptt);
+       }
+
+       /* PORT statistics are not necessarily reset, so we need to
+        * read and create a baseline for future statistics.
+        */
+       if (!cdev->reset_stats)
+               DP_INFO(cdev, "Reset stats not allocated\n");
+       else
+               _qed_get_vport_stats(cdev, cdev->reset_stats);
+}
+
 static int qed_fill_eth_dev_info(struct qed_dev *cdev,
                                 struct qed_dev_eth_info *info)
 {