Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  en_stats.c   Sprache: C

 
/*
 * Copyright (c) 2017, Mellanox Technologies, Ltd.  All rights reserved.
 *
 * This software is available to you under a choice of one of two
 * licenses.  You may choose to be licensed under the terms of the GNU
 * General Public License (GPL) Version 2, available from the file
 * COPYING in the main directory of this source tree, or the
 * OpenIB.org BSD license below:
 *
 *     Redistribution and use in source and binary forms, with or
 *     without modification, are permitted provided that the following
 *     conditions are met:
 *
 *      - Redistributions of source code must retain the above
 *        copyright notice, this list of conditions and the following
 *        disclaimer.
 *
 *      - Redistributions in binary form must reproduce the above
 *        copyright notice, this list of conditions and the following
 *        disclaimer in the documentation and/or other materials
 *        provided with the distribution.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */


#include "lib/events.h"
#include "en.h"
#include "en_accel/ktls.h"
#include "en_accel/en_accel.h"
#include "en/ptp.h"
#include "en/port.h"

#include <net/page_pool/helpers.h>

void mlx5e_ethtool_put_stat(u64 **data, u64 val)
{
 *(*data)++ = val;
}

static unsigned int stats_grps_num(struct mlx5e_priv *priv)
{
 return !priv->profile->stats_grps_num ? 0 :
  priv->profile->stats_grps_num(priv);
}

unsigned int mlx5e_stats_total_num(struct mlx5e_priv *priv)
{
 mlx5e_stats_grp_t *stats_grps = priv->profile->stats_grps;
 const unsigned int num_stats_grps = stats_grps_num(priv);
 unsigned int total = 0;
 int i;

 for (i = 0; i < num_stats_grps; i++)
  total += stats_grps[i]->get_num_stats(priv);

 return total;
}

void mlx5e_stats_update_ndo_stats(struct mlx5e_priv *priv)
{
 mlx5e_stats_grp_t *stats_grps = priv->profile->stats_grps;
 const unsigned int num_stats_grps = stats_grps_num(priv);
 int i;

 for (i = num_stats_grps - 1; i >= 0; i--)
  if (stats_grps[i]->update_stats &&
      stats_grps[i]->update_stats_mask & MLX5E_NDO_UPDATE_STATS)
   stats_grps[i]->update_stats(priv);
}

void mlx5e_stats_update(struct mlx5e_priv *priv)
{
 mlx5e_stats_grp_t *stats_grps = priv->profile->stats_grps;
 const unsigned int num_stats_grps = stats_grps_num(priv);
 int i;

 for (i = num_stats_grps - 1; i >= 0; i--)
  if (stats_grps[i]->update_stats)
   stats_grps[i]->update_stats(priv);
}

void mlx5e_stats_fill(struct mlx5e_priv *priv, u64 *data, int idx)
{
 mlx5e_stats_grp_t *stats_grps = priv->profile->stats_grps;
 const unsigned int num_stats_grps = stats_grps_num(priv);
 int i;

 for (i = 0; i < num_stats_grps; i++)
  stats_grps[i]->fill_stats(priv, &data);
}

void mlx5e_stats_fill_strings(struct mlx5e_priv *priv, u8 *data)
{
 mlx5e_stats_grp_t *stats_grps = priv->profile->stats_grps;
 const unsigned int num_stats_grps = stats_grps_num(priv);
 int i;

 for (i = 0; i < num_stats_grps; i++)
  stats_grps[i]->fill_strings(priv, &data);
}

/* Concrete NIC Stats */

static const struct counter_desc sw_stats_desc[] = {
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_packets) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_bytes) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_packets) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_bytes) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_tso_packets) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_tso_bytes) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_tso_inner_packets) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_tso_inner_bytes) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_added_vlan_packets) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_nop) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_mpwqe_blks) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_mpwqe_pkts) },

#ifdef CONFIG_MLX5_EN_TLS
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_tls_encrypted_packets) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_tls_encrypted_bytes) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_tls_ooo) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_tls_dump_packets) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_tls_dump_bytes) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_tls_resync_bytes) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_tls_skip_no_sync_data) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_tls_drop_no_sync_data) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_tls_drop_bypass_req) },
#endif

 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_lro_packets) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_lro_bytes) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_gro_packets) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_gro_bytes) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_gro_skbs) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_gro_large_hds) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_hds_nodata_packets) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_hds_nodata_bytes) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_hds_nosplit_packets) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_hds_nosplit_bytes) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_ecn_mark) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_removed_vlan_packets) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_csum_unnecessary) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_csum_none) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_csum_complete) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_csum_complete_tail) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_csum_complete_tail_slow) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_csum_unnecessary_inner) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xdp_drop) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xdp_redirect) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xdp_tx_xmit) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xdp_tx_mpwqe) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xdp_tx_inlnw) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xdp_tx_nops) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xdp_tx_full) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xdp_tx_err) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xdp_tx_cqe) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_csum_none) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_csum_partial) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_csum_partial_inner) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_queue_stopped) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_queue_dropped) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_xmit_more) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_recover) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_cqes) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_queue_wake) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_cqe_err) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_xdp_xmit) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_xdp_mpwqe) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_xdp_inlnw) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_xdp_nops) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_xdp_full) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_xdp_err) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_xdp_cqes) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_wqe_err) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_mpwqe_filler_cqes) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_mpwqe_filler_strides) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_oversize_pkts_sw_drop) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_buff_alloc_err) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_cqe_compress_blks) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_cqe_compress_pkts) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_congst_umr) },
#ifdef CONFIG_MLX5_EN_ARFS
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_arfs_add) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_arfs_request_in) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_arfs_request_out) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_arfs_expired) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_arfs_err) },
#endif
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_recover) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_pp_alloc_fast) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_pp_alloc_slow) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_pp_alloc_slow_high_order) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_pp_alloc_empty) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_pp_alloc_refill) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_pp_alloc_waive) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_pp_recycle_cached) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_pp_recycle_cache_full) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_pp_recycle_ring) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_pp_recycle_ring_full) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_pp_recycle_released_ref) },
#ifdef CONFIG_MLX5_EN_TLS
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_tls_decrypted_packets) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_tls_decrypted_bytes) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_tls_resync_req_pkt) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_tls_resync_req_start) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_tls_resync_req_end) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_tls_resync_req_skip) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_tls_resync_res_ok) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_tls_resync_res_retry) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_tls_resync_res_skip) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_tls_err) },
#endif
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, ch_events) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, ch_poll) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, ch_arm) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, ch_aff_change) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, ch_force_irq) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, ch_eq_rearm) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xsk_packets) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xsk_bytes) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xsk_csum_complete) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xsk_csum_unnecessary) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xsk_csum_unnecessary_inner) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xsk_csum_none) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xsk_ecn_mark) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xsk_removed_vlan_packets) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xsk_xdp_drop) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xsk_xdp_redirect) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xsk_wqe_err) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xsk_mpwqe_filler_cqes) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xsk_mpwqe_filler_strides) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xsk_oversize_pkts_sw_drop) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xsk_buff_alloc_err) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xsk_cqe_compress_blks) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xsk_cqe_compress_pkts) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xsk_congst_umr) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_xsk_xmit) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_xsk_mpwqe) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_xsk_inlnw) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_xsk_full) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_xsk_err) },
 { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_xsk_cqes) },
};

#define NUM_SW_COUNTERS   ARRAY_SIZE(sw_stats_desc)

static MLX5E_DECLARE_STATS_GRP_OP_NUM_STATS(sw)
{
 return NUM_SW_COUNTERS;
}

static MLX5E_DECLARE_STATS_GRP_OP_FILL_STRS(sw)
{
 int i;

 for (i = 0; i < NUM_SW_COUNTERS; i++)
  ethtool_puts(data, sw_stats_desc[i].format);
}

static MLX5E_DECLARE_STATS_GRP_OP_FILL_STATS(sw)
{
 int i;

 for (i = 0; i < NUM_SW_COUNTERS; i++)
  mlx5e_ethtool_put_stat(data,
           MLX5E_READ_CTR64_CPU(&priv->stats.sw,
           sw_stats_desc, i));
}

static void mlx5e_stats_grp_sw_update_stats_xdp_red(struct mlx5e_sw_stats *s,
          struct mlx5e_xdpsq_stats *xdpsq_red_stats)
{
 s->tx_xdp_xmit  += xdpsq_red_stats->xmit;
 s->tx_xdp_mpwqe += xdpsq_red_stats->mpwqe;
 s->tx_xdp_inlnw += xdpsq_red_stats->inlnw;
 s->tx_xdp_nops  += xdpsq_red_stats->nops;
 s->tx_xdp_full  += xdpsq_red_stats->full;
 s->tx_xdp_err   += xdpsq_red_stats->err;
 s->tx_xdp_cqes  += xdpsq_red_stats->cqes;
}

static void mlx5e_stats_grp_sw_update_stats_xdpsq(struct mlx5e_sw_stats *s,
        struct mlx5e_xdpsq_stats *xdpsq_stats)
{
 s->rx_xdp_tx_xmit  += xdpsq_stats->xmit;
 s->rx_xdp_tx_mpwqe += xdpsq_stats->mpwqe;
 s->rx_xdp_tx_inlnw += xdpsq_stats->inlnw;
 s->rx_xdp_tx_nops  += xdpsq_stats->nops;
 s->rx_xdp_tx_full  += xdpsq_stats->full;
 s->rx_xdp_tx_err   += xdpsq_stats->err;
 s->rx_xdp_tx_cqe   += xdpsq_stats->cqes;
}

static void mlx5e_stats_grp_sw_update_stats_xsksq(struct mlx5e_sw_stats *s,
        struct mlx5e_xdpsq_stats *xsksq_stats)
{
 s->tx_xsk_xmit  += xsksq_stats->xmit;
 s->tx_xsk_mpwqe += xsksq_stats->mpwqe;
 s->tx_xsk_inlnw += xsksq_stats->inlnw;
 s->tx_xsk_full  += xsksq_stats->full;
 s->tx_xsk_err   += xsksq_stats->err;
 s->tx_xsk_cqes  += xsksq_stats->cqes;
}

static void mlx5e_stats_grp_sw_update_stats_xskrq(struct mlx5e_sw_stats *s,
        struct mlx5e_rq_stats *xskrq_stats)
{
 s->rx_xsk_packets                += xskrq_stats->packets;
 s->rx_xsk_bytes                  += xskrq_stats->bytes;
 s->rx_xsk_csum_complete          += xskrq_stats->csum_complete;
 s->rx_xsk_csum_unnecessary       += xskrq_stats->csum_unnecessary;
 s->rx_xsk_csum_unnecessary_inner += xskrq_stats->csum_unnecessary_inner;
 s->rx_xsk_csum_none              += xskrq_stats->csum_none;
 s->rx_xsk_ecn_mark               += xskrq_stats->ecn_mark;
 s->rx_xsk_removed_vlan_packets   += xskrq_stats->removed_vlan_packets;
 s->rx_xsk_xdp_drop               += xskrq_stats->xdp_drop;
 s->rx_xsk_xdp_redirect           += xskrq_stats->xdp_redirect;
 s->rx_xsk_wqe_err                += xskrq_stats->wqe_err;
 s->rx_xsk_mpwqe_filler_cqes      += xskrq_stats->mpwqe_filler_cqes;
 s->rx_xsk_mpwqe_filler_strides   += xskrq_stats->mpwqe_filler_strides;
 s->rx_xsk_oversize_pkts_sw_drop  += xskrq_stats->oversize_pkts_sw_drop;
 s->rx_xsk_buff_alloc_err         += xskrq_stats->buff_alloc_err;
 s->rx_xsk_cqe_compress_blks      += xskrq_stats->cqe_compress_blks;
 s->rx_xsk_cqe_compress_pkts      += xskrq_stats->cqe_compress_pkts;
 s->rx_xsk_congst_umr             += xskrq_stats->congst_umr;
}

static void mlx5e_stats_grp_sw_update_stats_rq_stats(struct mlx5e_sw_stats *s,
           struct mlx5e_rq_stats *rq_stats)
{
 s->rx_packets                 += rq_stats->packets;
 s->rx_bytes                   += rq_stats->bytes;
 s->rx_lro_packets             += rq_stats->lro_packets;
 s->rx_lro_bytes               += rq_stats->lro_bytes;
 s->rx_gro_packets             += rq_stats->gro_packets;
 s->rx_gro_bytes               += rq_stats->gro_bytes;
 s->rx_gro_skbs                += rq_stats->gro_skbs;
 s->rx_gro_large_hds           += rq_stats->gro_large_hds;
 s->rx_hds_nodata_packets      += rq_stats->hds_nodata_packets;
 s->rx_hds_nodata_bytes        += rq_stats->hds_nodata_bytes;
 s->rx_hds_nosplit_packets     += rq_stats->hds_nosplit_packets;
 s->rx_hds_nosplit_bytes       += rq_stats->hds_nosplit_bytes;
 s->rx_ecn_mark                += rq_stats->ecn_mark;
 s->rx_removed_vlan_packets    += rq_stats->removed_vlan_packets;
 s->rx_csum_none               += rq_stats->csum_none;
 s->rx_csum_complete           += rq_stats->csum_complete;
 s->rx_csum_complete_tail      += rq_stats->csum_complete_tail;
 s->rx_csum_complete_tail_slow += rq_stats->csum_complete_tail_slow;
 s->rx_csum_unnecessary        += rq_stats->csum_unnecessary;
 s->rx_csum_unnecessary_inner  += rq_stats->csum_unnecessary_inner;
 s->rx_xdp_drop                += rq_stats->xdp_drop;
 s->rx_xdp_redirect            += rq_stats->xdp_redirect;
 s->rx_wqe_err                 += rq_stats->wqe_err;
 s->rx_mpwqe_filler_cqes       += rq_stats->mpwqe_filler_cqes;
 s->rx_mpwqe_filler_strides    += rq_stats->mpwqe_filler_strides;
 s->rx_oversize_pkts_sw_drop   += rq_stats->oversize_pkts_sw_drop;
 s->rx_buff_alloc_err          += rq_stats->buff_alloc_err;
 s->rx_cqe_compress_blks       += rq_stats->cqe_compress_blks;
 s->rx_cqe_compress_pkts       += rq_stats->cqe_compress_pkts;
 s->rx_congst_umr              += rq_stats->congst_umr;
#ifdef CONFIG_MLX5_EN_ARFS
 s->rx_arfs_add                += rq_stats->arfs_add;
 s->rx_arfs_request_in         += rq_stats->arfs_request_in;
 s->rx_arfs_request_out        += rq_stats->arfs_request_out;
 s->rx_arfs_expired            += rq_stats->arfs_expired;
 s->rx_arfs_err                += rq_stats->arfs_err;
#endif
 s->rx_recover                 += rq_stats->recover;
 s->rx_pp_alloc_fast          += rq_stats->pp_alloc_fast;
 s->rx_pp_alloc_slow          += rq_stats->pp_alloc_slow;
 s->rx_pp_alloc_empty         += rq_stats->pp_alloc_empty;
 s->rx_pp_alloc_refill        += rq_stats->pp_alloc_refill;
 s->rx_pp_alloc_waive         += rq_stats->pp_alloc_waive;
 s->rx_pp_alloc_slow_high_order  += rq_stats->pp_alloc_slow_high_order;
 s->rx_pp_recycle_cached   += rq_stats->pp_recycle_cached;
 s->rx_pp_recycle_cache_full  += rq_stats->pp_recycle_cache_full;
 s->rx_pp_recycle_ring   += rq_stats->pp_recycle_ring;
 s->rx_pp_recycle_ring_full  += rq_stats->pp_recycle_ring_full;
 s->rx_pp_recycle_released_ref  += rq_stats->pp_recycle_released_ref;
#ifdef CONFIG_MLX5_EN_TLS
 s->rx_tls_decrypted_packets   += rq_stats->tls_decrypted_packets;
 s->rx_tls_decrypted_bytes     += rq_stats->tls_decrypted_bytes;
 s->rx_tls_resync_req_pkt      += rq_stats->tls_resync_req_pkt;
 s->rx_tls_resync_req_start    += rq_stats->tls_resync_req_start;
 s->rx_tls_resync_req_end      += rq_stats->tls_resync_req_end;
 s->rx_tls_resync_req_skip     += rq_stats->tls_resync_req_skip;
 s->rx_tls_resync_res_ok       += rq_stats->tls_resync_res_ok;
 s->rx_tls_resync_res_retry    += rq_stats->tls_resync_res_retry;
 s->rx_tls_resync_res_skip     += rq_stats->tls_resync_res_skip;
 s->rx_tls_err                 += rq_stats->tls_err;
#endif
}

static void mlx5e_stats_grp_sw_update_stats_ch_stats(struct mlx5e_sw_stats *s,
           struct mlx5e_ch_stats *ch_stats)
{
 s->ch_events      += ch_stats->events;
 s->ch_poll        += ch_stats->poll;
 s->ch_arm         += ch_stats->arm;
 s->ch_aff_change  += ch_stats->aff_change;
 s->ch_force_irq   += ch_stats->force_irq;
 s->ch_eq_rearm    += ch_stats->eq_rearm;
}

static void mlx5e_stats_grp_sw_update_stats_sq(struct mlx5e_sw_stats *s,
            struct mlx5e_sq_stats *sq_stats)
{
 s->tx_packets               += sq_stats->packets;
 s->tx_bytes                 += sq_stats->bytes;
 s->tx_tso_packets           += sq_stats->tso_packets;
 s->tx_tso_bytes             += sq_stats->tso_bytes;
 s->tx_tso_inner_packets     += sq_stats->tso_inner_packets;
 s->tx_tso_inner_bytes       += sq_stats->tso_inner_bytes;
 s->tx_added_vlan_packets    += sq_stats->added_vlan_packets;
 s->tx_nop                   += sq_stats->nop;
 s->tx_mpwqe_blks            += sq_stats->mpwqe_blks;
 s->tx_mpwqe_pkts            += sq_stats->mpwqe_pkts;
 s->tx_queue_stopped         += sq_stats->stopped;
 s->tx_queue_wake            += sq_stats->wake;
 s->tx_queue_dropped         += sq_stats->dropped;
 s->tx_cqe_err               += sq_stats->cqe_err;
 s->tx_recover               += sq_stats->recover;
 s->tx_xmit_more             += sq_stats->xmit_more;
 s->tx_csum_partial_inner    += sq_stats->csum_partial_inner;
 s->tx_csum_none             += sq_stats->csum_none;
 s->tx_csum_partial          += sq_stats->csum_partial;
#ifdef CONFIG_MLX5_EN_TLS
 s->tx_tls_encrypted_packets += sq_stats->tls_encrypted_packets;
 s->tx_tls_encrypted_bytes   += sq_stats->tls_encrypted_bytes;
 s->tx_tls_ooo               += sq_stats->tls_ooo;
 s->tx_tls_dump_bytes        += sq_stats->tls_dump_bytes;
 s->tx_tls_dump_packets      += sq_stats->tls_dump_packets;
 s->tx_tls_resync_bytes      += sq_stats->tls_resync_bytes;
 s->tx_tls_skip_no_sync_data += sq_stats->tls_skip_no_sync_data;
 s->tx_tls_drop_no_sync_data += sq_stats->tls_drop_no_sync_data;
 s->tx_tls_drop_bypass_req   += sq_stats->tls_drop_bypass_req;
#endif
 s->tx_cqes                  += sq_stats->cqes;
}

static void mlx5e_stats_grp_sw_update_stats_ptp(struct mlx5e_priv *priv,
      struct mlx5e_sw_stats *s)
{
 int i;

 if (!priv->tx_ptp_opened && !priv->rx_ptp_opened)
  return;

 mlx5e_stats_grp_sw_update_stats_ch_stats(s, &priv->ptp_stats.ch);

 if (priv->tx_ptp_opened) {
  for (i = 0; i < priv->max_opened_tc; i++) {
   mlx5e_stats_grp_sw_update_stats_sq(s, &priv->ptp_stats.sq[i]);

   /* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92657 */
   barrier();
  }
 }
 if (priv->rx_ptp_opened) {
  mlx5e_stats_grp_sw_update_stats_rq_stats(s, &priv->ptp_stats.rq);

  /* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92657 */
  barrier();
 }
}

static void mlx5e_stats_grp_sw_update_stats_qos(struct mlx5e_priv *priv,
      struct mlx5e_sw_stats *s)
{
 struct mlx5e_sq_stats **stats;
 u16 max_qos_sqs;
 int i;

 /* Pairs with smp_store_release in mlx5e_open_qos_sq. */
 max_qos_sqs = smp_load_acquire(&priv->htb_max_qos_sqs);
 stats = READ_ONCE(priv->htb_qos_sq_stats);

 for (i = 0; i < max_qos_sqs; i++) {
  mlx5e_stats_grp_sw_update_stats_sq(s, READ_ONCE(stats[i]));

  /* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92657 */
  barrier();
 }
}

static void mlx5e_stats_update_stats_rq_page_pool(struct mlx5e_channel *c)
{
 struct mlx5e_rq_stats *rq_stats = c->rq.stats;
 struct page_pool *pool = c->rq.page_pool;
 struct page_pool_stats stats = { 0 };

 if (!page_pool_get_stats(pool, &stats))
  return;

 rq_stats->pp_alloc_fast = stats.alloc_stats.fast;
 rq_stats->pp_alloc_slow = stats.alloc_stats.slow;
 rq_stats->pp_alloc_slow_high_order = stats.alloc_stats.slow_high_order;
 rq_stats->pp_alloc_empty = stats.alloc_stats.empty;
 rq_stats->pp_alloc_waive = stats.alloc_stats.waive;
 rq_stats->pp_alloc_refill = stats.alloc_stats.refill;

 rq_stats->pp_recycle_cached = stats.recycle_stats.cached;
 rq_stats->pp_recycle_cache_full = stats.recycle_stats.cache_full;
 rq_stats->pp_recycle_ring = stats.recycle_stats.ring;
 rq_stats->pp_recycle_ring_full = stats.recycle_stats.ring_full;
 rq_stats->pp_recycle_released_ref = stats.recycle_stats.released_refcnt;
}

static MLX5E_DECLARE_STATS_GRP_OP_UPDATE_STATS(sw)
{
 struct mlx5e_sw_stats *s = &priv->stats.sw;
 int i;

 memset(s, 0, sizeof(*s));

 for (i = 0; i < priv->channels.num; i++) /* for active channels only */
  mlx5e_stats_update_stats_rq_page_pool(priv->channels.c[i]);

 for (i = 0; i < priv->stats_nch; i++) {
  struct mlx5e_channel_stats *channel_stats =
   priv->channel_stats[i];

  int j;

  mlx5e_stats_grp_sw_update_stats_rq_stats(s, &channel_stats->rq);
  mlx5e_stats_grp_sw_update_stats_xdpsq(s, &channel_stats->rq_xdpsq);
  mlx5e_stats_grp_sw_update_stats_ch_stats(s, &channel_stats->ch);
  /* xdp redirect */
  mlx5e_stats_grp_sw_update_stats_xdp_red(s, &channel_stats->xdpsq);
  /* AF_XDP zero-copy */
  mlx5e_stats_grp_sw_update_stats_xskrq(s, &channel_stats->xskrq);
  mlx5e_stats_grp_sw_update_stats_xsksq(s, &channel_stats->xsksq);

  for (j = 0; j < priv->max_opened_tc; j++) {
   mlx5e_stats_grp_sw_update_stats_sq(s, &channel_stats->sq[j]);

   /* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92657 */
   barrier();
  }
 }
 mlx5e_stats_grp_sw_update_stats_ptp(priv, s);
 mlx5e_stats_grp_sw_update_stats_qos(priv, s);
}

static const struct counter_desc q_stats_desc[] = {
 { MLX5E_DECLARE_STAT(struct mlx5e_qcounter_stats, rx_out_of_buffer) },
};

static const struct counter_desc drop_rq_stats_desc[] = {
 { MLX5E_DECLARE_STAT(struct mlx5e_qcounter_stats, rx_if_down_packets) },
};

#define NUM_Q_COUNTERS   ARRAY_SIZE(q_stats_desc)
#define NUM_DROP_RQ_COUNTERS  ARRAY_SIZE(drop_rq_stats_desc)

static bool q_counter_any(struct mlx5e_priv *priv)
{
 struct mlx5_core_dev *pos;
 int i;

 mlx5_sd_for_each_dev(i, priv->mdev, pos)
  if (priv->q_counter[i++])
   return true;

 return false;
}

static MLX5E_DECLARE_STATS_GRP_OP_NUM_STATS(qcnt)
{
 int num_stats = 0;

 if (q_counter_any(priv))
  num_stats += NUM_Q_COUNTERS;

 if (priv->drop_rq_q_counter)
  num_stats += NUM_DROP_RQ_COUNTERS;

 return num_stats;
}

static MLX5E_DECLARE_STATS_GRP_OP_FILL_STRS(qcnt)
{
 int i;

 for (i = 0; i < NUM_Q_COUNTERS && q_counter_any(priv); i++)
  ethtool_puts(data, q_stats_desc[i].format);

 for (i = 0; i < NUM_DROP_RQ_COUNTERS && priv->drop_rq_q_counter; i++)
  ethtool_puts(data, drop_rq_stats_desc[i].format);
}

static MLX5E_DECLARE_STATS_GRP_OP_FILL_STATS(qcnt)
{
 int i;

 for (i = 0; i < NUM_Q_COUNTERS && q_counter_any(priv); i++)
  mlx5e_ethtool_put_stat(data,
           MLX5E_READ_CTR32_CPU(&priv->stats.qcnt,
           q_stats_desc, i));
 for (i = 0; i < NUM_DROP_RQ_COUNTERS && priv->drop_rq_q_counter; i++)
  mlx5e_ethtool_put_stat(
   data, MLX5E_READ_CTR32_CPU(&priv->stats.qcnt,
         drop_rq_stats_desc, i));
}

static MLX5E_DECLARE_STATS_GRP_OP_UPDATE_STATS(qcnt)
{
 struct mlx5e_qcounter_stats *qcnt = &priv->stats.qcnt;
 u32 out[MLX5_ST_SZ_DW(query_q_counter_out)] = {};
 u32 in[MLX5_ST_SZ_DW(query_q_counter_in)] = {};
 struct mlx5_core_dev *pos;
 u32 rx_out_of_buffer = 0;
 int ret, i;

 MLX5_SET(query_q_counter_in, in, opcode, MLX5_CMD_OP_QUERY_Q_COUNTER);

 mlx5_sd_for_each_dev(i, priv->mdev, pos) {
  if (priv->q_counter[i]) {
   MLX5_SET(query_q_counter_in, in, counter_set_id,
     priv->q_counter[i]);
   ret = mlx5_cmd_exec_inout(pos, query_q_counter, in, out);
   if (!ret)
    rx_out_of_buffer += MLX5_GET(query_q_counter_out,
            out, out_of_buffer);
  }
 }
 qcnt->rx_out_of_buffer = rx_out_of_buffer;

 if (priv->drop_rq_q_counter) {
  MLX5_SET(query_q_counter_in, in, counter_set_id,
    priv->drop_rq_q_counter);
  ret = mlx5_cmd_exec_inout(priv->mdev, query_q_counter, in, out);
  if (!ret)
   qcnt->rx_if_down_packets = MLX5_GET(query_q_counter_out,
           out, out_of_buffer);
 }
}

#define VNIC_ENV_OFF(c) MLX5_BYTE_OFF(query_vnic_env_out, c)
static const struct counter_desc vnic_env_stats_steer_desc[] = {
 { "rx_steer_missed_packets",
  VNIC_ENV_OFF(vport_env.nic_receive_steering_discard) },
};

static const struct counter_desc vnic_env_stats_dev_oob_desc[] = {
 { "dev_internal_queue_oob",
  VNIC_ENV_OFF(vport_env.internal_rq_out_of_buffer) },
};

static const struct counter_desc vnic_env_stats_drop_desc[] = {
 { "rx_oversize_pkts_buffer",
  VNIC_ENV_OFF(vport_env.eth_wqe_too_small) },
};

#define NUM_VNIC_ENV_STEER_COUNTERS(dev) \
 (MLX5_CAP_GEN(dev, nic_receive_steering_discard) ? \
  ARRAY_SIZE(vnic_env_stats_steer_desc) : 0)
#define NUM_VNIC_ENV_DEV_OOB_COUNTERS(dev) \
 (MLX5_CAP_GEN(dev, vnic_env_int_rq_oob) ? \
  ARRAY_SIZE(vnic_env_stats_dev_oob_desc) : 0)
#define NUM_VNIC_ENV_DROP_COUNTERS(dev) \
 (MLX5_CAP_GEN(dev, eth_wqe_too_small) ? \
  ARRAY_SIZE(vnic_env_stats_drop_desc) : 0)

static MLX5E_DECLARE_STATS_GRP_OP_NUM_STATS(vnic_env)
{
 return NUM_VNIC_ENV_STEER_COUNTERS(priv->mdev) +
        NUM_VNIC_ENV_DEV_OOB_COUNTERS(priv->mdev) +
        NUM_VNIC_ENV_DROP_COUNTERS(priv->mdev);
}

static MLX5E_DECLARE_STATS_GRP_OP_FILL_STRS(vnic_env)
{
 int i;

 for (i = 0; i < NUM_VNIC_ENV_STEER_COUNTERS(priv->mdev); i++)
  ethtool_puts(data, vnic_env_stats_steer_desc[i].format);

 for (i = 0; i < NUM_VNIC_ENV_DEV_OOB_COUNTERS(priv->mdev); i++)
  ethtool_puts(data, vnic_env_stats_dev_oob_desc[i].format);

 for (i = 0; i < NUM_VNIC_ENV_DROP_COUNTERS(priv->mdev); i++)
  ethtool_puts(data, vnic_env_stats_drop_desc[i].format);
}

static MLX5E_DECLARE_STATS_GRP_OP_FILL_STATS(vnic_env)
{
 int i;

 for (i = 0; i < NUM_VNIC_ENV_STEER_COUNTERS(priv->mdev); i++)
  mlx5e_ethtool_put_stat(
   data,
   MLX5E_READ_CTR64_BE(priv->stats.vnic.query_vnic_env_out,
         vnic_env_stats_steer_desc, i));

 for (i = 0; i < NUM_VNIC_ENV_DEV_OOB_COUNTERS(priv->mdev); i++)
  mlx5e_ethtool_put_stat(
   data,
   MLX5E_READ_CTR32_BE(priv->stats.vnic.query_vnic_env_out,
         vnic_env_stats_dev_oob_desc, i));

 for (i = 0; i < NUM_VNIC_ENV_DROP_COUNTERS(priv->mdev); i++)
  mlx5e_ethtool_put_stat(
   data,
   MLX5E_READ_CTR32_BE(priv->stats.vnic.query_vnic_env_out,
         vnic_env_stats_drop_desc, i));
}

static MLX5E_DECLARE_STATS_GRP_OP_UPDATE_STATS(vnic_env)
{
 u32 *out = (u32 *)priv->stats.vnic.query_vnic_env_out;
 u32 in[MLX5_ST_SZ_DW(query_vnic_env_in)] = {};
 struct mlx5_core_dev *mdev = priv->mdev;

 if (!mlx5e_stats_grp_vnic_env_num_stats(priv))
  return;

 MLX5_SET(query_vnic_env_in, in, opcode, MLX5_CMD_OP_QUERY_VNIC_ENV);
 mlx5_cmd_exec_inout(mdev, query_vnic_env, in, out);
}

#define VPORT_COUNTER_OFF(c) MLX5_BYTE_OFF(query_vport_counter_out, c)
static const struct counter_desc vport_stats_desc[] = {
 { "rx_vport_unicast_packets",
  VPORT_COUNTER_OFF(received_eth_unicast.packets) },
 { "rx_vport_unicast_bytes",
  VPORT_COUNTER_OFF(received_eth_unicast.octets) },
 { "tx_vport_unicast_packets",
  VPORT_COUNTER_OFF(transmitted_eth_unicast.packets) },
 { "tx_vport_unicast_bytes",
  VPORT_COUNTER_OFF(transmitted_eth_unicast.octets) },
 { "rx_vport_multicast_packets",
  VPORT_COUNTER_OFF(received_eth_multicast.packets) },
 { "rx_vport_multicast_bytes",
  VPORT_COUNTER_OFF(received_eth_multicast.octets) },
 { "tx_vport_multicast_packets",
  VPORT_COUNTER_OFF(transmitted_eth_multicast.packets) },
 { "tx_vport_multicast_bytes",
  VPORT_COUNTER_OFF(transmitted_eth_multicast.octets) },
 { "rx_vport_broadcast_packets",
  VPORT_COUNTER_OFF(received_eth_broadcast.packets) },
 { "rx_vport_broadcast_bytes",
  VPORT_COUNTER_OFF(received_eth_broadcast.octets) },
 { "tx_vport_broadcast_packets",
  VPORT_COUNTER_OFF(transmitted_eth_broadcast.packets) },
 { "tx_vport_broadcast_bytes",
  VPORT_COUNTER_OFF(transmitted_eth_broadcast.octets) },
 { "rx_vport_rdma_unicast_packets",
  VPORT_COUNTER_OFF(received_ib_unicast.packets) },
 { "rx_vport_rdma_unicast_bytes",
  VPORT_COUNTER_OFF(received_ib_unicast.octets) },
 { "tx_vport_rdma_unicast_packets",
  VPORT_COUNTER_OFF(transmitted_ib_unicast.packets) },
 { "tx_vport_rdma_unicast_bytes",
  VPORT_COUNTER_OFF(transmitted_ib_unicast.octets) },
 { "rx_vport_rdma_multicast_packets",
  VPORT_COUNTER_OFF(received_ib_multicast.packets) },
 { "rx_vport_rdma_multicast_bytes",
  VPORT_COUNTER_OFF(received_ib_multicast.octets) },
 { "tx_vport_rdma_multicast_packets",
  VPORT_COUNTER_OFF(transmitted_ib_multicast.packets) },
 { "tx_vport_rdma_multicast_bytes",
  VPORT_COUNTER_OFF(transmitted_ib_multicast.octets) },
};

static const struct counter_desc vport_loopback_stats_desc[] = {
 { "vport_loopback_packets",
  VPORT_COUNTER_OFF(local_loopback.packets) },
 { "vport_loopback_bytes",
  VPORT_COUNTER_OFF(local_loopback.octets) },
};

#define NUM_VPORT_COUNTERS  ARRAY_SIZE(vport_stats_desc)
#define NUM_VPORT_LOOPBACK_COUNTERS(dev) \
 (MLX5_CAP_GEN(dev, vport_counter_local_loopback) ? \
  ARRAY_SIZE(vport_loopback_stats_desc) : 0)

static MLX5E_DECLARE_STATS_GRP_OP_NUM_STATS(vport)
{
 return NUM_VPORT_COUNTERS +
  NUM_VPORT_LOOPBACK_COUNTERS(priv->mdev);
}

static MLX5E_DECLARE_STATS_GRP_OP_FILL_STRS(vport)
{
 int i;

 for (i = 0; i < NUM_VPORT_COUNTERS; i++)
  ethtool_puts(data, vport_stats_desc[i].format);

 for (i = 0; i < NUM_VPORT_LOOPBACK_COUNTERS(priv->mdev); i++)
  ethtool_puts(data, vport_loopback_stats_desc[i].format);
}

static MLX5E_DECLARE_STATS_GRP_OP_FILL_STATS(vport)
{
 int i;

 for (i = 0; i < NUM_VPORT_COUNTERS; i++)
  mlx5e_ethtool_put_stat(
   data,
   MLX5E_READ_CTR64_BE(priv->stats.vport.query_vport_out,
         vport_stats_desc, i));

 for (i = 0; i < NUM_VPORT_LOOPBACK_COUNTERS(priv->mdev); i++)
  mlx5e_ethtool_put_stat(
   data,
   MLX5E_READ_CTR64_BE(priv->stats.vport.query_vport_out,
         vport_loopback_stats_desc, i));
}

static MLX5E_DECLARE_STATS_GRP_OP_UPDATE_STATS(vport)
{
 u32 *out = (u32 *)priv->stats.vport.query_vport_out;
 u32 in[MLX5_ST_SZ_DW(query_vport_counter_in)] = {};
 struct mlx5_core_dev *mdev = priv->mdev;

 MLX5_SET(query_vport_counter_in, in, opcode, MLX5_CMD_OP_QUERY_VPORT_COUNTER);
 mlx5_cmd_exec_inout(mdev, query_vport_counter, in, out);
}

#define PPORT_802_3_OFF(c) \
 MLX5_BYTE_OFF(ppcnt_reg, \
        counter_set.eth_802_3_cntrs_grp_data_layout.c##_high)
static const struct counter_desc pport_802_3_stats_desc[] = {
 { "tx_packets_phy", PPORT_802_3_OFF(a_frames_transmitted_ok) },
 { "rx_packets_phy", PPORT_802_3_OFF(a_frames_received_ok) },
 { "rx_crc_errors_phy", PPORT_802_3_OFF(a_frame_check_sequence_errors) },
 { "tx_bytes_phy", PPORT_802_3_OFF(a_octets_transmitted_ok) },
 { "rx_bytes_phy", PPORT_802_3_OFF(a_octets_received_ok) },
 { "tx_multicast_phy", PPORT_802_3_OFF(a_multicast_frames_xmitted_ok) },
 { "tx_broadcast_phy", PPORT_802_3_OFF(a_broadcast_frames_xmitted_ok) },
 { "rx_multicast_phy", PPORT_802_3_OFF(a_multicast_frames_received_ok) },
 { "rx_broadcast_phy", PPORT_802_3_OFF(a_broadcast_frames_received_ok) },
 { "rx_in_range_len_errors_phy", PPORT_802_3_OFF(a_in_range_length_errors) },
 { "rx_out_of_range_len_phy", PPORT_802_3_OFF(a_out_of_range_length_field) },
 { "rx_oversize_pkts_phy", PPORT_802_3_OFF(a_frame_too_long_errors) },
 { "rx_symbol_err_phy", PPORT_802_3_OFF(a_symbol_error_during_carrier) },
 { "tx_mac_control_phy", PPORT_802_3_OFF(a_mac_control_frames_transmitted) },
 { "rx_mac_control_phy", PPORT_802_3_OFF(a_mac_control_frames_received) },
 { "rx_unsupported_op_phy", PPORT_802_3_OFF(a_unsupported_opcodes_received) },
 { "rx_pause_ctrl_phy", PPORT_802_3_OFF(a_pause_mac_ctrl_frames_received) },
 { "tx_pause_ctrl_phy", PPORT_802_3_OFF(a_pause_mac_ctrl_frames_transmitted) },
};

#define NUM_PPORT_802_3_COUNTERS ARRAY_SIZE(pport_802_3_stats_desc)

static MLX5E_DECLARE_STATS_GRP_OP_NUM_STATS(802_3)
{
 return NUM_PPORT_802_3_COUNTERS;
}

static MLX5E_DECLARE_STATS_GRP_OP_FILL_STRS(802_3)
{
 int i;

 for (i = 0; i < NUM_PPORT_802_3_COUNTERS; i++)
  ethtool_puts(data, pport_802_3_stats_desc[i].format);
}

static MLX5E_DECLARE_STATS_GRP_OP_FILL_STATS(802_3)
{
 int i;

 for (i = 0; i < NUM_PPORT_802_3_COUNTERS; i++)
  mlx5e_ethtool_put_stat(
   data, MLX5E_READ_CTR64_BE(
          &priv->stats.pport.IEEE_802_3_counters,
          pport_802_3_stats_desc, i));
}

#define MLX5_BASIC_PPCNT_SUPPORTED(mdev) \
 (MLX5_CAP_GEN(mdev, pcam_reg) ? MLX5_CAP_PCAM_REG(mdev, ppcnt) : 1)

static MLX5E_DECLARE_STATS_GRP_OP_UPDATE_STATS(802_3)
{
 struct mlx5e_pport_stats *pstats = &priv->stats.pport;
 struct mlx5_core_dev *mdev = priv->mdev;
 u32 in[MLX5_ST_SZ_DW(ppcnt_reg)] = {0};
 int sz = MLX5_ST_SZ_BYTES(ppcnt_reg);
 void *out;

 if (!MLX5_BASIC_PPCNT_SUPPORTED(mdev))
  return;

 MLX5_SET(ppcnt_reg, in, local_port, 1);
 out = pstats->IEEE_802_3_counters;
 MLX5_SET(ppcnt_reg, in, grp, MLX5_IEEE_802_3_COUNTERS_GROUP);
 mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPCNT, 0, 0);
}

#define MLX5E_READ_CTR64_BE_F(ptr, set, c)  \
 be64_to_cpu(*(__be64 *)((char *)ptr +  \
  MLX5_BYTE_OFF(ppcnt_reg,  \
         counter_set.set.c##_high)))

static int mlx5e_stats_get_ieee(struct mlx5_core_dev *mdev,
    u32 *ppcnt_ieee_802_3)
{
 u32 in[MLX5_ST_SZ_DW(ppcnt_reg)] = {};
 int sz = MLX5_ST_SZ_BYTES(ppcnt_reg);

 if (!MLX5_BASIC_PPCNT_SUPPORTED(mdev))
  return -EOPNOTSUPP;

 MLX5_SET(ppcnt_reg, in, local_port, 1);
 MLX5_SET(ppcnt_reg, in, grp, MLX5_IEEE_802_3_COUNTERS_GROUP);
 return mlx5_core_access_reg(mdev, in, sz, ppcnt_ieee_802_3,
        sz, MLX5_REG_PPCNT, 0, 0);
}

void mlx5e_stats_pause_get(struct mlx5e_priv *priv,
      struct ethtool_pause_stats *pause_stats)
{
 u32 ppcnt_ieee_802_3[MLX5_ST_SZ_DW(ppcnt_reg)];
 struct mlx5_core_dev *mdev = priv->mdev;

 if (mlx5e_stats_get_ieee(mdev, ppcnt_ieee_802_3))
  return;

 pause_stats->tx_pause_frames =
  MLX5E_READ_CTR64_BE_F(ppcnt_ieee_802_3,
          eth_802_3_cntrs_grp_data_layout,
          a_pause_mac_ctrl_frames_transmitted);
 pause_stats->rx_pause_frames =
  MLX5E_READ_CTR64_BE_F(ppcnt_ieee_802_3,
          eth_802_3_cntrs_grp_data_layout,
          a_pause_mac_ctrl_frames_received);
}

void mlx5e_stats_eth_phy_get(struct mlx5e_priv *priv,
        struct ethtool_eth_phy_stats *phy_stats)
{
 u32 ppcnt_ieee_802_3[MLX5_ST_SZ_DW(ppcnt_reg)];
 struct mlx5_core_dev *mdev = priv->mdev;

 if (mlx5e_stats_get_ieee(mdev, ppcnt_ieee_802_3))
  return;

 phy_stats->SymbolErrorDuringCarrier =
  MLX5E_READ_CTR64_BE_F(ppcnt_ieee_802_3,
          eth_802_3_cntrs_grp_data_layout,
          a_symbol_error_during_carrier);
}

void mlx5e_stats_eth_mac_get(struct mlx5e_priv *priv,
        struct ethtool_eth_mac_stats *mac_stats)
{
 u32 ppcnt_ieee_802_3[MLX5_ST_SZ_DW(ppcnt_reg)];
 struct mlx5_core_dev *mdev = priv->mdev;

 if (mlx5e_stats_get_ieee(mdev, ppcnt_ieee_802_3))
  return;

#define RD(name)       \
 MLX5E_READ_CTR64_BE_F(ppcnt_ieee_802_3,    \
         eth_802_3_cntrs_grp_data_layout,  \
         name)

 mac_stats->FramesTransmittedOK = RD(a_frames_transmitted_ok);
 mac_stats->FramesReceivedOK = RD(a_frames_received_ok);
 mac_stats->FrameCheckSequenceErrors = RD(a_frame_check_sequence_errors);
 mac_stats->OctetsTransmittedOK = RD(a_octets_transmitted_ok);
 mac_stats->OctetsReceivedOK = RD(a_octets_received_ok);
 mac_stats->MulticastFramesXmittedOK = RD(a_multicast_frames_xmitted_ok);
 mac_stats->BroadcastFramesXmittedOK = RD(a_broadcast_frames_xmitted_ok);
 mac_stats->MulticastFramesReceivedOK = RD(a_multicast_frames_received_ok);
 mac_stats->BroadcastFramesReceivedOK = RD(a_broadcast_frames_received_ok);
 mac_stats->InRangeLengthErrors = RD(a_in_range_length_errors);
 mac_stats->OutOfRangeLengthField = RD(a_out_of_range_length_field);
 mac_stats->FrameTooLongErrors = RD(a_frame_too_long_errors);
#undef RD
}

void mlx5e_stats_eth_ctrl_get(struct mlx5e_priv *priv,
         struct ethtool_eth_ctrl_stats *ctrl_stats)
{
 u32 ppcnt_ieee_802_3[MLX5_ST_SZ_DW(ppcnt_reg)];
 struct mlx5_core_dev *mdev = priv->mdev;

 if (mlx5e_stats_get_ieee(mdev, ppcnt_ieee_802_3))
  return;

 ctrl_stats->MACControlFramesTransmitted =
  MLX5E_READ_CTR64_BE_F(ppcnt_ieee_802_3,
          eth_802_3_cntrs_grp_data_layout,
          a_mac_control_frames_transmitted);
 ctrl_stats->MACControlFramesReceived =
  MLX5E_READ_CTR64_BE_F(ppcnt_ieee_802_3,
          eth_802_3_cntrs_grp_data_layout,
          a_mac_control_frames_received);
 ctrl_stats->UnsupportedOpcodesReceived =
  MLX5E_READ_CTR64_BE_F(ppcnt_ieee_802_3,
          eth_802_3_cntrs_grp_data_layout,
          a_unsupported_opcodes_received);
}

#define PPORT_2863_OFF(c) \
 MLX5_BYTE_OFF(ppcnt_reg, \
        counter_set.eth_2863_cntrs_grp_data_layout.c##_high)
static const struct counter_desc pport_2863_stats_desc[] = {
 { "rx_discards_phy", PPORT_2863_OFF(if_in_discards) },
 { "tx_discards_phy", PPORT_2863_OFF(if_out_discards) },
 { "tx_errors_phy", PPORT_2863_OFF(if_out_errors) },
};

#define NUM_PPORT_2863_COUNTERS  ARRAY_SIZE(pport_2863_stats_desc)

static MLX5E_DECLARE_STATS_GRP_OP_NUM_STATS(2863)
{
 return NUM_PPORT_2863_COUNTERS;
}

static MLX5E_DECLARE_STATS_GRP_OP_FILL_STRS(2863)
{
 int i;

 for (i = 0; i < NUM_PPORT_2863_COUNTERS; i++)
  ethtool_puts(data, pport_2863_stats_desc[i].format);
}

static MLX5E_DECLARE_STATS_GRP_OP_FILL_STATS(2863)
{
 int i;

 for (i = 0; i < NUM_PPORT_2863_COUNTERS; i++)
  mlx5e_ethtool_put_stat(
   data, MLX5E_READ_CTR64_BE(
          &priv->stats.pport.RFC_2863_counters,
          pport_2863_stats_desc, i));
}

static MLX5E_DECLARE_STATS_GRP_OP_UPDATE_STATS(2863)
{
 struct mlx5e_pport_stats *pstats = &priv->stats.pport;
 struct mlx5_core_dev *mdev = priv->mdev;
 u32 in[MLX5_ST_SZ_DW(ppcnt_reg)] = {0};
 int sz = MLX5_ST_SZ_BYTES(ppcnt_reg);
 void *out;

 MLX5_SET(ppcnt_reg, in, local_port, 1);
 out = pstats->RFC_2863_counters;
 MLX5_SET(ppcnt_reg, in, grp, MLX5_RFC_2863_COUNTERS_GROUP);
 mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPCNT, 0, 0);
}

#define PPORT_2819_OFF(c) \
 MLX5_BYTE_OFF(ppcnt_reg, \
        counter_set.eth_2819_cntrs_grp_data_layout.c##_high)
static const struct counter_desc pport_2819_stats_desc[] = {
 { "rx_undersize_pkts_phy", PPORT_2819_OFF(ether_stats_undersize_pkts) },
 { "rx_fragments_phy", PPORT_2819_OFF(ether_stats_fragments) },
 { "rx_jabbers_phy", PPORT_2819_OFF(ether_stats_jabbers) },
 { "rx_64_bytes_phy", PPORT_2819_OFF(ether_stats_pkts64octets) },
 { "rx_65_to_127_bytes_phy", PPORT_2819_OFF(ether_stats_pkts65to127octets) },
 { "rx_128_to_255_bytes_phy", PPORT_2819_OFF(ether_stats_pkts128to255octets) },
 { "rx_256_to_511_bytes_phy", PPORT_2819_OFF(ether_stats_pkts256to511octets) },
 { "rx_512_to_1023_bytes_phy", PPORT_2819_OFF(ether_stats_pkts512to1023octets) },
 { "rx_1024_to_1518_bytes_phy", PPORT_2819_OFF(ether_stats_pkts1024to1518octets) },
 { "rx_1519_to_2047_bytes_phy", PPORT_2819_OFF(ether_stats_pkts1519to2047octets) },
 { "rx_2048_to_4095_bytes_phy", PPORT_2819_OFF(ether_stats_pkts2048to4095octets) },
 { "rx_4096_to_8191_bytes_phy", PPORT_2819_OFF(ether_stats_pkts4096to8191octets) },
 { "rx_8192_to_10239_bytes_phy", PPORT_2819_OFF(ether_stats_pkts8192to10239octets) },
};

#define NUM_PPORT_2819_COUNTERS  ARRAY_SIZE(pport_2819_stats_desc)

static MLX5E_DECLARE_STATS_GRP_OP_NUM_STATS(2819)
{
 return NUM_PPORT_2819_COUNTERS;
}

static MLX5E_DECLARE_STATS_GRP_OP_FILL_STRS(2819)
{
 int i;

 for (i = 0; i < NUM_PPORT_2819_COUNTERS; i++)
  ethtool_puts(data, pport_2819_stats_desc[i].format);
}

static MLX5E_DECLARE_STATS_GRP_OP_FILL_STATS(2819)
{
 int i;

 for (i = 0; i < NUM_PPORT_2819_COUNTERS; i++)
  mlx5e_ethtool_put_stat(
   data, MLX5E_READ_CTR64_BE(
          &priv->stats.pport.RFC_2819_counters,
          pport_2819_stats_desc, i));
}

static MLX5E_DECLARE_STATS_GRP_OP_UPDATE_STATS(2819)
{
 struct mlx5e_pport_stats *pstats = &priv->stats.pport;
 struct mlx5_core_dev *mdev = priv->mdev;
 u32 in[MLX5_ST_SZ_DW(ppcnt_reg)] = {0};
 int sz = MLX5_ST_SZ_BYTES(ppcnt_reg);
 void *out;

 if (!MLX5_BASIC_PPCNT_SUPPORTED(mdev))
  return;

 MLX5_SET(ppcnt_reg, in, local_port, 1);
 out = pstats->RFC_2819_counters;
 MLX5_SET(ppcnt_reg, in, grp, MLX5_RFC_2819_COUNTERS_GROUP);
 mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPCNT, 0, 0);
}

static const struct ethtool_rmon_hist_range mlx5e_rmon_ranges[] = {
 {    0,    64 },
 {   65,   127 },
 {  128,   255 },
 {  256,   511 },
 {  512,  1023 },
 { 1024,  1518 },
 { 1519,  2047 },
 { 2048,  4095 },
 { 4096,  8191 },
 { 8192, 10239 },
 {}
};

void mlx5e_stats_rmon_get(struct mlx5e_priv *priv,
     struct ethtool_rmon_stats *rmon,
     const struct ethtool_rmon_hist_range **ranges)
{
 u32 ppcnt_RFC_2819_counters[MLX5_ST_SZ_DW(ppcnt_reg)];
 struct mlx5_core_dev *mdev = priv->mdev;
 u32 in[MLX5_ST_SZ_DW(ppcnt_reg)] = {0};
 int sz = MLX5_ST_SZ_BYTES(ppcnt_reg);

 MLX5_SET(ppcnt_reg, in, local_port, 1);
 MLX5_SET(ppcnt_reg, in, grp, MLX5_RFC_2819_COUNTERS_GROUP);
 if (mlx5_core_access_reg(mdev, in, sz, ppcnt_RFC_2819_counters,
     sz, MLX5_REG_PPCNT, 0, 0))
  return;

#define RD(name)      \
 MLX5E_READ_CTR64_BE_F(ppcnt_RFC_2819_counters,  \
         eth_2819_cntrs_grp_data_layout, \
         name)

 rmon->undersize_pkts = RD(ether_stats_undersize_pkts);
 rmon->fragments  = RD(ether_stats_fragments);
 rmon->jabbers  = RD(ether_stats_jabbers);

 rmon->hist[0]  = RD(ether_stats_pkts64octets);
 rmon->hist[1]  = RD(ether_stats_pkts65to127octets);
 rmon->hist[2]  = RD(ether_stats_pkts128to255octets);
 rmon->hist[3]  = RD(ether_stats_pkts256to511octets);
 rmon->hist[4]  = RD(ether_stats_pkts512to1023octets);
 rmon->hist[5]  = RD(ether_stats_pkts1024to1518octets);
 rmon->hist[6]  = RD(ether_stats_pkts1519to2047octets);
 rmon->hist[7]  = RD(ether_stats_pkts2048to4095octets);
 rmon->hist[8]  = RD(ether_stats_pkts4096to8191octets);
 rmon->hist[9]  = RD(ether_stats_pkts8192to10239octets);
#undef RD

 *ranges = mlx5e_rmon_ranges;
}

void mlx5e_stats_ts_get(struct mlx5e_priv *priv,
   struct ethtool_ts_stats *ts_stats)
{
 int i, j;

 mutex_lock(&priv->state_lock);

 if (priv->tx_ptp_opened) {
  struct mlx5e_ptp *ptp = priv->channels.ptp;

  ts_stats->pkts = 0;
  ts_stats->err = 0;
  ts_stats->lost = 0;

  if (!ptp)
   goto out;

  /* Aggregate stats across all TCs */
  for (i = 0; i < ptp->num_tc; i++) {
   struct mlx5e_ptp_cq_stats *stats =
    ptp->ptpsq[i].cq_stats;

   ts_stats->pkts += stats->cqe;
   ts_stats->err += stats->abort + stats->err_cqe +
    stats->late_cqe;
   ts_stats->lost += stats->lost_cqe;
  }
 } else {
  /* DMA layer will always successfully timestamp packets. Other
 * counters do not make sense for this layer.
 */

  ts_stats->pkts = 0;

  /* Aggregate stats across all SQs */
  for (j = 0; j < priv->channels.num; j++) {
   struct mlx5e_channel *c = priv->channels.c[j];

   for (i = 0; i < c->num_tc; i++) {
    struct mlx5e_sq_stats *stats = c->sq[i].stats;

    ts_stats->pkts += stats->timestamps;
   }
  }
 }

out:
 mutex_unlock(&priv->state_lock);
}

#define PPORT_PHY_LAYER_OFF(c) \
 MLX5_BYTE_OFF(ppcnt_reg, \
        counter_set.phys_layer_cntrs.c)
static const struct counter_desc pport_phy_layer_cntrs_stats_desc[] = {
 { "link_down_events_phy", PPORT_PHY_LAYER_OFF(link_down_events) }
};

#define PPORT_PHY_STATISTICAL_OFF(c) \
 MLX5_BYTE_OFF(ppcnt_reg, \
        counter_set.phys_layer_statistical_cntrs.c##_high)
static const struct counter_desc pport_phy_statistical_stats_desc[] = {
 { "rx_pcs_symbol_err_phy", PPORT_PHY_STATISTICAL_OFF(phy_symbol_errors) },
 { "rx_corrected_bits_phy", PPORT_PHY_STATISTICAL_OFF(phy_corrected_bits) },
};

static const struct counter_desc
pport_phy_statistical_err_lanes_stats_desc[] = {
 { "rx_err_lane_0_phy", PPORT_PHY_STATISTICAL_OFF(phy_corrected_bits_lane0) },
 { "rx_err_lane_1_phy", PPORT_PHY_STATISTICAL_OFF(phy_corrected_bits_lane1) },
 { "rx_err_lane_2_phy", PPORT_PHY_STATISTICAL_OFF(phy_corrected_bits_lane2) },
 { "rx_err_lane_3_phy", PPORT_PHY_STATISTICAL_OFF(phy_corrected_bits_lane3) },
};

#define PPORT_PHY_RECOVERY_OFF(c) \
 MLX5_BYTE_OFF(ppcnt_reg, counter_set.phys_layer_recovery_cntrs.c)
static const struct counter_desc
pport_phy_recovery_cntrs_stats_desc[] = {
 { "total_success_recovery_phy",
   PPORT_PHY_RECOVERY_OFF(total_successful_recovery_events) }
};

#define NUM_PPORT_PHY_LAYER_COUNTERS \
 ARRAY_SIZE(pport_phy_layer_cntrs_stats_desc)
#define NUM_PPORT_PHY_STATISTICAL_COUNTERS \
 ARRAY_SIZE(pport_phy_statistical_stats_desc)
#define NUM_PPORT_PHY_STATISTICAL_PER_LANE_COUNTERS \
 ARRAY_SIZE(pport_phy_statistical_err_lanes_stats_desc)
#define NUM_PPORT_PHY_RECOVERY_COUNTERS \
 ARRAY_SIZE(pport_phy_recovery_cntrs_stats_desc)

#define NUM_PPORT_PHY_STATISTICAL_LOOPBACK_COUNTERS(dev) \
 (MLX5_CAP_PCAM_FEATURE(dev, ppcnt_statistical_group) ? \
 NUM_PPORT_PHY_STATISTICAL_COUNTERS : 0)
#define NUM_PPORT_PHY_STATISTICAL_PER_LANE_LOOPBACK_COUNTERS(dev) \
 (MLX5_CAP_PCAM_FEATURE(dev, per_lane_error_counters) ? \
 NUM_PPORT_PHY_STATISTICAL_PER_LANE_COUNTERS : 0)
#define NUM_PPORT_PHY_RECOVERY_LOOPBACK_COUNTERS(dev) \
 (MLX5_CAP_PCAM_FEATURE(dev, ppcnt_recovery_counters) ? \
 NUM_PPORT_PHY_RECOVERY_COUNTERS : 0)

static MLX5E_DECLARE_STATS_GRP_OP_NUM_STATS(phy)
{
 struct mlx5_core_dev *mdev = priv->mdev;
 int num_stats;

 num_stats = NUM_PPORT_PHY_LAYER_COUNTERS;

 num_stats += NUM_PPORT_PHY_STATISTICAL_LOOPBACK_COUNTERS(mdev);

 num_stats += NUM_PPORT_PHY_STATISTICAL_PER_LANE_LOOPBACK_COUNTERS(mdev);

 num_stats += NUM_PPORT_PHY_RECOVERY_LOOPBACK_COUNTERS(mdev);
 return num_stats;
}

static MLX5E_DECLARE_STATS_GRP_OP_FILL_STRS(phy)
{
 struct mlx5_core_dev *mdev = priv->mdev;
 int i;

 for (i = 0; i < NUM_PPORT_PHY_LAYER_COUNTERS; i++)
  ethtool_puts(data, pport_phy_layer_cntrs_stats_desc[i].format);

 for (i = 0; i < NUM_PPORT_PHY_STATISTICAL_LOOPBACK_COUNTERS(mdev); i++)
  ethtool_puts(data, pport_phy_statistical_stats_desc[i].format);

 for (i = 0;
      i < NUM_PPORT_PHY_STATISTICAL_PER_LANE_LOOPBACK_COUNTERS(mdev);
      i++)
  ethtool_puts(data,
        pport_phy_statistical_err_lanes_stats_desc[i]
        .format);

 for (i = 0; i < NUM_PPORT_PHY_RECOVERY_LOOPBACK_COUNTERS(mdev); i++)
  ethtool_puts(data,
        pport_phy_recovery_cntrs_stats_desc[i].format);
}

static MLX5E_DECLARE_STATS_GRP_OP_FILL_STATS(phy)
{
 struct mlx5_core_dev *mdev = priv->mdev;
 int i;

 for (i = 0; i < NUM_PPORT_PHY_LAYER_COUNTERS; i++)
  mlx5e_ethtool_put_stat(
    data,
    MLX5E_READ_CTR32_BE(&priv->stats.pport
     .phy_counters,
     pport_phy_layer_cntrs_stats_desc, i));

 for (i = 0; i < NUM_PPORT_PHY_STATISTICAL_LOOPBACK_COUNTERS(mdev); i++)
  mlx5e_ethtool_put_stat(
   data,
   MLX5E_READ_CTR64_BE(
    &priv->stats.pport.phy_statistical_counters,
    pport_phy_statistical_stats_desc, i));

 for (i = 0;
      i < NUM_PPORT_PHY_STATISTICAL_PER_LANE_LOOPBACK_COUNTERS(mdev);
      i++)
  mlx5e_ethtool_put_stat(
   data,
   MLX5E_READ_CTR64_BE(
    &priv->stats.pport.phy_statistical_counters,
    pport_phy_statistical_err_lanes_stats_desc, i));

 for (i = 0; i < NUM_PPORT_PHY_RECOVERY_LOOPBACK_COUNTERS(mdev); i++)
  mlx5e_ethtool_put_stat(
   data,
   MLX5E_READ_CTR32_BE(
    &priv->stats.pport.phy_recovery_counters,
    pport_phy_recovery_cntrs_stats_desc, i));
}

static MLX5E_DECLARE_STATS_GRP_OP_UPDATE_STATS(phy)
{
 struct mlx5e_pport_stats *pstats = &priv->stats.pport;
 struct mlx5_core_dev *mdev = priv->mdev;
 u32 in[MLX5_ST_SZ_DW(ppcnt_reg)] = {0};
 int sz = MLX5_ST_SZ_BYTES(ppcnt_reg);
 void *out;

 MLX5_SET(ppcnt_reg, in, local_port, 1);
 out = pstats->phy_counters;
 MLX5_SET(ppcnt_reg, in, grp, MLX5_PHYSICAL_LAYER_COUNTERS_GROUP);
 mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPCNT, 0, 0);

 if (MLX5_CAP_PCAM_FEATURE(mdev, ppcnt_statistical_group)) {
  out = pstats->phy_statistical_counters;
  MLX5_SET(ppcnt_reg, in, grp,
    MLX5_PHYSICAL_LAYER_STATISTICAL_GROUP);
  mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPCNT, 0,
         0);
 }

 if (MLX5_CAP_PCAM_FEATURE(mdev, ppcnt_recovery_counters)) {
  out = pstats->phy_recovery_counters;
  MLX5_SET(ppcnt_reg, in, grp,
    MLX5_PHYSICAL_LAYER_RECOVERY_GROUP);
  mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPCNT, 0,
         0);
 }
}

void mlx5e_get_link_ext_stats(struct net_device *dev,
         struct ethtool_link_ext_stats *stats)
{
 struct mlx5e_priv *priv = netdev_priv(dev);
 u32 out[MLX5_ST_SZ_DW(ppcnt_reg)] = {};
 u32 in[MLX5_ST_SZ_DW(ppcnt_reg)] = {};
 int sz = MLX5_ST_SZ_BYTES(ppcnt_reg);

 MLX5_SET(ppcnt_reg, in, local_port, 1);
 MLX5_SET(ppcnt_reg, in, grp, MLX5_PHYSICAL_LAYER_COUNTERS_GROUP);
 mlx5_core_access_reg(priv->mdev, in, sz, out,
        MLX5_ST_SZ_BYTES(ppcnt_reg), MLX5_REG_PPCNT, 0, 0);

 stats->link_down_events = MLX5_GET(ppcnt_reg, out,
        counter_set.phys_layer_cntrs.link_down_events);
}

static int fec_num_lanes(struct mlx5_core_dev *dev)
{
 u32 out[MLX5_ST_SZ_DW(pmlp_reg)] = {};
 u32 in[MLX5_ST_SZ_DW(pmlp_reg)] = {};
 int err;

 MLX5_SET(pmlp_reg, in, local_port, 1);
 err = mlx5_core_access_reg(dev, in, sizeof(in), out, sizeof(out),
       MLX5_REG_PMLP, 0, 0);
 if (err)
  return 0;

 return MLX5_GET(pmlp_reg, out, width);
}

static int fec_active_mode(struct mlx5_core_dev *mdev)
{
 unsigned long fec_active_long;
 u32 fec_active;

 if (mlx5e_get_fec_mode(mdev, &fec_active, NULL))
  return MLX5E_FEC_NOFEC;

 fec_active_long = fec_active;
 return find_first_bit(&fec_active_long, sizeof(unsigned long) * BITS_PER_BYTE);
}

#define MLX5E_STATS_SET_FEC_BLOCK(idx) ({ \
 fec_stats->corrected_blocks.lanes[(idx)] = \
  MLX5E_READ_CTR64_BE_F(ppcnt, phys_layer_cntrs, \
          fc_fec_corrected_blocks_lane##idx); \
 fec_stats->uncorrectable_blocks.lanes[(idx)] = \
  MLX5E_READ_CTR64_BE_F(ppcnt, phys_layer_cntrs, \
          fc_fec_uncorrectable_blocks_lane##idx); \
})

static void fec_set_fc_stats(struct ethtool_fec_stats *fec_stats,
        u32 *ppcnt, u8 lanes)
{
 if (lanes > 3) { /* 4 lanes */
  MLX5E_STATS_SET_FEC_BLOCK(3);
  MLX5E_STATS_SET_FEC_BLOCK(2);
 }
 if (lanes > 1) /* 2 lanes */
  MLX5E_STATS_SET_FEC_BLOCK(1);
 if (lanes > 0) /* 1 lane */
  MLX5E_STATS_SET_FEC_BLOCK(0);
}

static void fec_set_rs_stats(struct ethtool_fec_stats *fec_stats, u32 *ppcnt)
{
 fec_stats->corrected_blocks.total =
  MLX5E_READ_CTR64_BE_F(ppcnt, phys_layer_cntrs,
          rs_fec_corrected_blocks);
 fec_stats->uncorrectable_blocks.total =
  MLX5E_READ_CTR64_BE_F(ppcnt, phys_layer_cntrs,
          rs_fec_uncorrectable_blocks);
}

static void fec_set_block_stats(struct mlx5e_priv *priv,
    int mode,
    struct ethtool_fec_stats *fec_stats)
{
 struct mlx5_core_dev *mdev = priv->mdev;
 u32 out[MLX5_ST_SZ_DW(ppcnt_reg)] = {};
 u32 in[MLX5_ST_SZ_DW(ppcnt_reg)] = {};
 int sz = MLX5_ST_SZ_BYTES(ppcnt_reg);

 MLX5_SET(ppcnt_reg, in, local_port, 1);
 MLX5_SET(ppcnt_reg, in, grp, MLX5_PHYSICAL_LAYER_COUNTERS_GROUP);
 if (mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPCNT, 0, 0))
  return;

 switch (mode) {
 case MLX5E_FEC_RS_528_514:
 case MLX5E_FEC_RS_544_514:
 case MLX5E_FEC_LLRS_272_257_1:
 case MLX5E_FEC_RS_544_514_INTERLEAVED_QUAD:
  fec_set_rs_stats(fec_stats, out);
  return;
 case MLX5E_FEC_FIRECODE:
  fec_set_fc_stats(fec_stats, out, fec_num_lanes(mdev));
 }
}

static void fec_set_corrected_bits_total(struct mlx5e_priv *priv,
      struct ethtool_fec_stats *fec_stats)
{
 u32 ppcnt_phy_statistical[MLX5_ST_SZ_DW(ppcnt_reg)];
 struct mlx5_core_dev *mdev = priv->mdev;
 u32 in[MLX5_ST_SZ_DW(ppcnt_reg)] = {};
 int sz = MLX5_ST_SZ_BYTES(ppcnt_reg);

 MLX5_SET(ppcnt_reg, in, local_port, 1);
 MLX5_SET(ppcnt_reg, in, grp, MLX5_PHYSICAL_LAYER_STATISTICAL_GROUP);
 if (mlx5_core_access_reg(mdev, in, sz, ppcnt_phy_statistical,
     sz, MLX5_REG_PPCNT, 0, 0))
  return;

 fec_stats->corrected_bits.total =
  MLX5E_READ_CTR64_BE_F(ppcnt_phy_statistical,
          phys_layer_statistical_cntrs,
          phy_corrected_bits);
}

void mlx5e_stats_fec_get(struct mlx5e_priv *priv,
    struct ethtool_fec_stats *fec_stats)
{
 int mode = fec_active_mode(priv->mdev);

 if (mode == MLX5E_FEC_NOFEC ||
     !MLX5_CAP_PCAM_FEATURE(priv->mdev, ppcnt_statistical_group))
  return;

 fec_set_corrected_bits_total(priv, fec_stats);
 fec_set_block_stats(priv, mode, fec_stats);
}

#define PPORT_ETH_EXT_OFF(c) \
 MLX5_BYTE_OFF(ppcnt_reg, \
        counter_set.eth_extended_cntrs_grp_data_layout.c##_high)
static const struct counter_desc pport_eth_ext_stats_desc[] = {
 { "rx_buffer_passed_thres_phy", PPORT_ETH_EXT_OFF(rx_buffer_almost_full) },
};

#define NUM_PPORT_ETH_EXT_COUNTERS ARRAY_SIZE(pport_eth_ext_stats_desc)

static MLX5E_DECLARE_STATS_GRP_OP_NUM_STATS(eth_ext)
{
 if (MLX5_CAP_PCAM_FEATURE((priv)->mdev, rx_buffer_fullness_counters))
  return NUM_PPORT_ETH_EXT_COUNTERS;

 return 0;
}

static MLX5E_DECLARE_STATS_GRP_OP_FILL_STRS(eth_ext)
{
 int i;

 if (MLX5_CAP_PCAM_FEATURE((priv)->mdev, rx_buffer_fullness_counters))
  for (i = 0; i < NUM_PPORT_ETH_EXT_COUNTERS; i++)
   ethtool_puts(data, pport_eth_ext_stats_desc[i].format);
}

static MLX5E_DECLARE_STATS_GRP_OP_FILL_STATS(eth_ext)
{
 int i;

 if (MLX5_CAP_PCAM_FEATURE((priv)->mdev, rx_buffer_fullness_counters))
  for (i = 0; i < NUM_PPORT_ETH_EXT_COUNTERS; i++)
   mlx5e_ethtool_put_stat(
    data,
    MLX5E_READ_CTR64_BE(
     &priv->stats.pport.eth_ext_counters,
     pport_eth_ext_stats_desc, i));
}

static MLX5E_DECLARE_STATS_GRP_OP_UPDATE_STATS(eth_ext)
{
 struct mlx5e_pport_stats *pstats = &priv->stats.pport;
 struct mlx5_core_dev *mdev = priv->mdev;
 u32 in[MLX5_ST_SZ_DW(ppcnt_reg)] = {0};
 int sz = MLX5_ST_SZ_BYTES(ppcnt_reg);
 void *out;

 if (!MLX5_CAP_PCAM_FEATURE(mdev, rx_buffer_fullness_counters))
  return;

 MLX5_SET(ppcnt_reg, in, local_port, 1);
 out = pstats->eth_ext_counters;
 MLX5_SET(ppcnt_reg, in, grp, MLX5_ETHERNET_EXTENDED_COUNTERS_GROUP);
 mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPCNT, 0, 0);
}

#define PCIE_PERF_OFF(c) \
 MLX5_BYTE_OFF(mpcnt_reg, counter_set.pcie_perf_cntrs_grp_data_layout.c)
static const struct counter_desc pcie_perf_stats_desc[] = {
 { "rx_pci_signal_integrity", PCIE_PERF_OFF(rx_errors) },
 { "tx_pci_signal_integrity", PCIE_PERF_OFF(tx_errors) },
};

#define PCIE_PERF_OFF64(c) \
 MLX5_BYTE_OFF(mpcnt_reg, counter_set.pcie_perf_cntrs_grp_data_layout.c##_high)
static const struct counter_desc pcie_perf_stats_desc64[] = {
 { "outbound_pci_buffer_overflow", PCIE_PERF_OFF64(tx_overflow_buffer_pkt) },
};

static const struct counter_desc pcie_perf_stall_stats_desc[] = {
 { "outbound_pci_stalled_rd", PCIE_PERF_OFF(outbound_stalled_reads) },
 { "outbound_pci_stalled_wr", PCIE_PERF_OFF(outbound_stalled_writes) },
 { "outbound_pci_stalled_rd_events", PCIE_PERF_OFF(outbound_stalled_reads_events) },
 { "outbound_pci_stalled_wr_events", PCIE_PERF_OFF(outbound_stalled_writes_events) },
};

#define NUM_PCIE_PERF_COUNTERS  ARRAY_SIZE(pcie_perf_stats_desc)
#define NUM_PCIE_PERF_COUNTERS64 ARRAY_SIZE(pcie_perf_stats_desc64)
#define NUM_PCIE_PERF_STALL_COUNTERS ARRAY_SIZE(pcie_perf_stall_stats_desc)

static MLX5E_DECLARE_STATS_GRP_OP_NUM_STATS(pcie)
{
 int num_stats = 0;

 if (MLX5_CAP_MCAM_FEATURE((priv)->mdev, pcie_performance_group))
  num_stats += NUM_PCIE_PERF_COUNTERS;

 if (MLX5_CAP_MCAM_FEATURE((priv)->mdev, tx_overflow_buffer_pkt))
  num_stats += NUM_PCIE_PERF_COUNTERS64;

 if (MLX5_CAP_MCAM_FEATURE((priv)->mdev, pcie_outbound_stalled))
  num_stats += NUM_PCIE_PERF_STALL_COUNTERS;

 return num_stats;
}

static MLX5E_DECLARE_STATS_GRP_OP_FILL_STRS(pcie)
{
 int i;

 if (MLX5_CAP_MCAM_FEATURE((priv)->mdev, pcie_performance_group))
  for (i = 0; i < NUM_PCIE_PERF_COUNTERS; i++)
   ethtool_puts(data, pcie_perf_stats_desc[i].format);

 if (MLX5_CAP_MCAM_FEATURE((priv)->mdev, tx_overflow_buffer_pkt))
  for (i = 0; i < NUM_PCIE_PERF_COUNTERS64; i++)
   ethtool_puts(data, pcie_perf_stats_desc64[i].format);

 if (MLX5_CAP_MCAM_FEATURE((priv)->mdev, pcie_outbound_stalled))
  for (i = 0; i < NUM_PCIE_PERF_STALL_COUNTERS; i++)
   ethtool_puts(data,
         pcie_perf_stall_stats_desc[i].format);
}

static MLX5E_DECLARE_STATS_GRP_OP_FILL_STATS(pcie)
{
 int i;

 if (MLX5_CAP_MCAM_FEATURE((priv)->mdev, pcie_performance_group))
  for (i = 0; i < NUM_PCIE_PERF_COUNTERS; i++)
   mlx5e_ethtool_put_stat(
    data,
    MLX5E_READ_CTR32_BE(
     &priv->stats.pcie.pcie_perf_counters,
     pcie_perf_stats_desc, i));

 if (MLX5_CAP_MCAM_FEATURE((priv)->mdev, tx_overflow_buffer_pkt))
  for (i = 0; i < NUM_PCIE_PERF_COUNTERS64; i++)
   mlx5e_ethtool_put_stat(
    data,
    MLX5E_READ_CTR64_BE(
     &priv->stats.pcie.pcie_perf_counters,
     pcie_perf_stats_desc64, i));

 if (MLX5_CAP_MCAM_FEATURE((priv)->mdev, pcie_outbound_stalled))
  for (i = 0; i < NUM_PCIE_PERF_STALL_COUNTERS; i++)
   mlx5e_ethtool_put_stat(
    data,
    MLX5E_READ_CTR32_BE(
     &priv->stats.pcie.pcie_perf_counters,
     pcie_perf_stall_stats_desc, i));
}

static MLX5E_DECLARE_STATS_GRP_OP_UPDATE_STATS(pcie)
{
 struct mlx5e_pcie_stats *pcie_stats = &priv->stats.pcie;
 struct mlx5_core_dev *mdev = priv->mdev;
 u32 in[MLX5_ST_SZ_DW(mpcnt_reg)] = {0};
 int sz = MLX5_ST_SZ_BYTES(mpcnt_reg);
 void *out;

 if (!MLX5_CAP_MCAM_FEATURE(mdev, pcie_performance_group))
  return;

 out = pcie_stats->pcie_perf_counters;
 MLX5_SET(mpcnt_reg, in, grp, MLX5_PCIE_PERFORMANCE_COUNTERS_GROUP);
 mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_MPCNT, 0, 0);
}

#define PPORT_PER_TC_PRIO_OFF(c) \
 MLX5_BYTE_OFF(ppcnt_reg, \
        counter_set.eth_per_tc_prio_grp_data_layout.c##_high)

static const struct counter_desc pport_per_tc_prio_stats_desc[] = {
 { "rx_prio%d_buf_discard", PPORT_PER_TC_PRIO_OFF(no_buffer_discard_uc) },
};

#define NUM_PPORT_PER_TC_PRIO_COUNTERS ARRAY_SIZE(pport_per_tc_prio_stats_desc)

#define PPORT_PER_TC_CONGEST_PRIO_OFF(c) \
 MLX5_BYTE_OFF(ppcnt_reg, \
        counter_set.eth_per_tc_congest_prio_grp_data_layout.c##_high)

static const struct counter_desc pport_per_tc_congest_prio_stats_desc[] = {
 { "rx_prio%d_cong_discard", PPORT_PER_TC_CONGEST_PRIO_OFF(wred_discard) },
 { "rx_prio%d_marked", PPORT_PER_TC_CONGEST_PRIO_OFF(ecn_marked_tc) },
};

#define NUM_PPORT_PER_TC_CONGEST_PRIO_COUNTERS \
 ARRAY_SIZE(pport_per_tc_congest_prio_stats_desc)

static int mlx5e_grp_per_tc_prio_get_num_stats(struct mlx5e_priv *priv)
{
 struct mlx5_core_dev *mdev = priv->mdev;

 if (!MLX5_CAP_GEN(mdev, sbcam_reg))
  return 0;

 return NUM_PPORT_PER_TC_PRIO_COUNTERS * NUM_PPORT_PRIO;
}

static MLX5E_DECLARE_STATS_GRP_OP_FILL_STRS(per_port_buff_congest)
{
 struct mlx5_core_dev *mdev = priv->mdev;
 int i, prio;

 if (!MLX5_CAP_GEN(mdev, sbcam_reg))
  return;

 for (prio = 0; prio < NUM_PPORT_PRIO; prio++) {
  for (i = 0; i < NUM_PPORT_PER_TC_PRIO_COUNTERS; i++)
   ethtool_sprintf(data,
     pport_per_tc_prio_stats_desc[i].format,
     prio);
  for (i = 0; i < NUM_PPORT_PER_TC_CONGEST_PRIO_COUNTERS; i++)
   ethtool_sprintf(data,
     pport_per_tc_congest_prio_stats_desc[i].format,
     prio);
 }
}

static MLX5E_DECLARE_STATS_GRP_OP_FILL_STATS(per_port_buff_congest)
{
 struct mlx5e_pport_stats *pport = &priv->stats.pport;
 struct mlx5_core_dev *mdev = priv->mdev;
 int i, prio;

 if (!MLX5_CAP_GEN(mdev, sbcam_reg))
  return;

 for (prio = 0; prio < NUM_PPORT_PRIO; prio++) {
  for (i = 0; i < NUM_PPORT_PER_TC_PRIO_COUNTERS; i++)
   mlx5e_ethtool_put_stat(
    data,
    MLX5E_READ_CTR64_BE(
     &pport->per_tc_prio_counters[prio],
     pport_per_tc_prio_stats_desc, i));
  for (i = 0; i < NUM_PPORT_PER_TC_CONGEST_PRIO_COUNTERS ; i++)
   mlx5e_ethtool_put_stat(
    data,
    MLX5E_READ_CTR64_BE(
     &pport->per_tc_congest_prio_counters
       [prio],
     pport_per_tc_congest_prio_stats_desc,
     i));
 }
}

static void mlx5e_grp_per_tc_prio_update_stats(struct mlx5e_priv *priv)
{
 struct mlx5e_pport_stats *pstats = &priv->stats.pport;
 struct mlx5_core_dev *mdev = priv->mdev;
 u32 in[MLX5_ST_SZ_DW(ppcnt_reg)] = {};
 int sz = MLX5_ST_SZ_BYTES(ppcnt_reg);
 void *out;
 int prio;

 if (!MLX5_CAP_GEN(mdev, sbcam_reg))
  return;

 MLX5_SET(ppcnt_reg, in, pnat, 2);
 MLX5_SET(ppcnt_reg, in, grp, MLX5_PER_TRAFFIC_CLASS_COUNTERS_GROUP);
 for (prio = 0; prio < NUM_PPORT_PRIO; prio++) {
  out = pstats->per_tc_prio_counters[prio];
  MLX5_SET(ppcnt_reg, in, prio_tc, prio);
  mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPCNT, 0, 0);
 }
}

static int mlx5e_grp_per_tc_congest_prio_get_num_stats(struct mlx5e_priv *priv)
{
 struct mlx5_core_dev *mdev = priv->mdev;

 if (!MLX5_CAP_GEN(mdev, sbcam_reg))
  return 0;

 return NUM_PPORT_PER_TC_CONGEST_PRIO_COUNTERS * NUM_PPORT_PRIO;
}

static void mlx5e_grp_per_tc_congest_prio_update_stats(struct mlx5e_priv *priv)
{
 struct mlx5e_pport_stats *pstats = &priv->stats.pport;
 struct mlx5_core_dev *mdev = priv->mdev;
 u32 in[MLX5_ST_SZ_DW(ppcnt_reg)] = {};
 int sz = MLX5_ST_SZ_BYTES(ppcnt_reg);
 void *out;
 int prio;

 if (!MLX5_CAP_GEN(mdev, sbcam_reg))
  return;

 MLX5_SET(ppcnt_reg, in, pnat, 2);
 MLX5_SET(ppcnt_reg, in, grp, MLX5_PER_TRAFFIC_CLASS_CONGESTION_GROUP);
 for (prio = 0; prio < NUM_PPORT_PRIO; prio++) {
  out = pstats->per_tc_congest_prio_counters[prio];
  MLX5_SET(ppcnt_reg, in, prio_tc, prio);
  mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPCNT, 0, 0);
 }
}

static MLX5E_DECLARE_STATS_GRP_OP_NUM_STATS(per_port_buff_congest)
{
 return mlx5e_grp_per_tc_prio_get_num_stats(priv) +
  mlx5e_grp_per_tc_congest_prio_get_num_stats(priv);
}

static MLX5E_DECLARE_STATS_GRP_OP_UPDATE_STATS(per_port_buff_congest)
{
 mlx5e_grp_per_tc_prio_update_stats(priv);
 mlx5e_grp_per_tc_congest_prio_update_stats(priv);
}

#define PPORT_PER_PRIO_OFF(c) \
 MLX5_BYTE_OFF(ppcnt_reg, \
        counter_set.eth_per_prio_grp_data_layout.c##_high)
static const struct counter_desc pport_per_prio_traffic_stats_desc[] = {
 { "rx_prio%d_bytes", PPORT_PER_PRIO_OFF(rx_octets) },
 { "rx_prio%d_packets", PPORT_PER_PRIO_OFF(rx_frames) },
 { "rx_prio%d_discards", PPORT_PER_PRIO_OFF(rx_discards) },
 { "tx_prio%d_bytes", PPORT_PER_PRIO_OFF(tx_octets) },
 { "tx_prio%d_packets", PPORT_PER_PRIO_OFF(tx_frames) },
};

#define NUM_PPORT_PER_PRIO_TRAFFIC_COUNTERS ARRAY_SIZE(pport_per_prio_traffic_stats_desc)

static int mlx5e_grp_per_prio_traffic_get_num_stats(void)
{
 return NUM_PPORT_PER_PRIO_TRAFFIC_COUNTERS * NUM_PPORT_PRIO;
}

static void mlx5e_grp_per_prio_traffic_fill_strings(struct mlx5e_priv *priv,
          u8 **data)
{
 int i, prio;

 for (prio = 0; prio < NUM_PPORT_PRIO; prio++) {
  for (i = 0; i < NUM_PPORT_PER_PRIO_TRAFFIC_COUNTERS; i++)
   ethtool_sprintf(data,
     pport_per_prio_traffic_stats_desc[i].format,
     prio);
 }
}

static void mlx5e_grp_per_prio_traffic_fill_stats(struct mlx5e_priv *priv,
        u64 **data)
{
 int i, prio;

 for (prio = 0; prio < NUM_PPORT_PRIO; prio++) {
  for (i = 0; i < NUM_PPORT_PER_PRIO_TRAFFIC_COUNTERS; i++)
   mlx5e_ethtool_put_stat(
    data,
    MLX5E_READ_CTR64_BE(
     &priv->stats.pport
       .per_prio_counters[prio],
     pport_per_prio_traffic_stats_desc, i));
 }
}

static const struct counter_desc pport_per_prio_pfc_stats_desc[] = {
 /* %s is "global" or "prio{i}" */
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=99 H=84 G=91

¤ Dauer der Verarbeitung: 0.26 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge