Commit aec0f1aa authored by Dmitry Bogdanov's avatar Dmitry Bogdanov Committed by David S. Miller
Browse files

net: atlantic: MACSec offload statistics implementation



This patch adds support for MACSec statistics on Atlantic network cards.

Signed-off-by: default avatarDmitry Bogdanov <dbogdanov@marvell.com>
Signed-off-by: default avatarMark Starovoytov <mstarovoitov@marvell.com>
Signed-off-by: default avatarIgor Russkikh <irusskikh@marvell.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent aaa36515
Loading
Loading
Loading
Loading
+143 −17
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@
#include "aq_vec.h"
#include "aq_ptp.h"
#include "aq_filters.h"
#include "aq_macsec.h"

#include <linux/ptp_clock_kernel.h>

@@ -96,6 +97,62 @@ static const char aq_ethtool_queue_stat_names[][ETH_GSTRING_LEN] = {
	"Queue[%d] InErrors",
};

#if IS_ENABLED(CONFIG_MACSEC)
static const char aq_macsec_stat_names[][ETH_GSTRING_LEN] = {
	"MACSec InCtlPackets",
	"MACSec InTaggedMissPackets",
	"MACSec InUntaggedMissPackets",
	"MACSec InNotagPackets",
	"MACSec InUntaggedPackets",
	"MACSec InBadTagPackets",
	"MACSec InNoSciPackets",
	"MACSec InUnknownSciPackets",
	"MACSec InCtrlPortPassPackets",
	"MACSec InUnctrlPortPassPackets",
	"MACSec InCtrlPortFailPackets",
	"MACSec InUnctrlPortFailPackets",
	"MACSec InTooLongPackets",
	"MACSec InIgpocCtlPackets",
	"MACSec InEccErrorPackets",
	"MACSec InUnctrlHitDropRedir",
	"MACSec OutCtlPackets",
	"MACSec OutUnknownSaPackets",
	"MACSec OutUntaggedPackets",
	"MACSec OutTooLong",
	"MACSec OutEccErrorPackets",
	"MACSec OutUnctrlHitDropRedir",
};

static const char *aq_macsec_txsc_stat_names[] = {
	"MACSecTXSC%d ProtectedPkts",
	"MACSecTXSC%d EncryptedPkts",
	"MACSecTXSC%d ProtectedOctets",
	"MACSecTXSC%d EncryptedOctets",
};

static const char *aq_macsec_txsa_stat_names[] = {
	"MACSecTXSC%dSA%d HitDropRedirect",
	"MACSecTXSC%dSA%d Protected2Pkts",
	"MACSecTXSC%dSA%d ProtectedPkts",
	"MACSecTXSC%dSA%d EncryptedPkts",
};

static const char *aq_macsec_rxsa_stat_names[] = {
	"MACSecRXSC%dSA%d UntaggedHitPkts",
	"MACSecRXSC%dSA%d CtrlHitDrpRedir",
	"MACSecRXSC%dSA%d NotUsingSa",
	"MACSecRXSC%dSA%d UnusedSa",
	"MACSecRXSC%dSA%d NotValidPkts",
	"MACSecRXSC%dSA%d InvalidPkts",
	"MACSecRXSC%dSA%d OkPkts",
	"MACSecRXSC%dSA%d LatePkts",
	"MACSecRXSC%dSA%d DelayedPkts",
	"MACSecRXSC%dSA%d UncheckedPkts",
	"MACSecRXSC%dSA%d ValidatedOctets",
	"MACSecRXSC%dSA%d DecryptedOctets",
};
#endif

static const char aq_ethtool_priv_flag_names[][ETH_GSTRING_LEN] = {
	"DMASystemLoopback",
	"PKTSystemLoopback",
@@ -104,18 +161,38 @@ static const char aq_ethtool_priv_flag_names[][ETH_GSTRING_LEN] = {
	"PHYExternalLoopback",
};

static u32 aq_ethtool_n_stats(struct net_device *ndev)
{
	struct aq_nic_s *nic = netdev_priv(ndev);
	struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(nic);
	u32 n_stats = ARRAY_SIZE(aq_ethtool_stat_names) +
		      ARRAY_SIZE(aq_ethtool_queue_stat_names) * cfg->vecs;

#if IS_ENABLED(CONFIG_MACSEC)
	if (nic->macsec_cfg) {
		n_stats += ARRAY_SIZE(aq_macsec_stat_names) +
			   ARRAY_SIZE(aq_macsec_txsc_stat_names) *
				   aq_macsec_tx_sc_cnt(nic) +
			   ARRAY_SIZE(aq_macsec_txsa_stat_names) *
				   aq_macsec_tx_sa_cnt(nic) +
			   ARRAY_SIZE(aq_macsec_rxsa_stat_names) *
				   aq_macsec_rx_sa_cnt(nic);
	}
#endif

	return n_stats;
}

static void aq_ethtool_stats(struct net_device *ndev,
			     struct ethtool_stats *stats, u64 *data)
{
	struct aq_nic_s *aq_nic = netdev_priv(ndev);
	struct aq_nic_cfg_s *cfg;

	cfg = aq_nic_get_cfg(aq_nic);

	memset(data, 0, (ARRAY_SIZE(aq_ethtool_stat_names) +
			 ARRAY_SIZE(aq_ethtool_queue_stat_names) *
			 cfg->vecs) * sizeof(u64));
	aq_nic_get_stats(aq_nic, data);
	memset(data, 0, aq_ethtool_n_stats(ndev) * sizeof(u64));
	data = aq_nic_get_stats(aq_nic, data);
#if IS_ENABLED(CONFIG_MACSEC)
	data = aq_macsec_get_stats(aq_nic, data);
#endif
}

static void aq_ethtool_get_drvinfo(struct net_device *ndev,
@@ -123,11 +200,9 @@ static void aq_ethtool_get_drvinfo(struct net_device *ndev,
{
	struct pci_dev *pdev = to_pci_dev(ndev->dev.parent);
	struct aq_nic_s *aq_nic = netdev_priv(ndev);
	struct aq_nic_cfg_s *cfg;
	u32 firmware_version;
	u32 regs_count;

	cfg = aq_nic_get_cfg(aq_nic);
	firmware_version = aq_nic_get_fw_version(aq_nic);
	regs_count = aq_nic_get_regs_count(aq_nic);

@@ -139,8 +214,7 @@ static void aq_ethtool_get_drvinfo(struct net_device *ndev,

	strlcpy(drvinfo->bus_info, pdev ? pci_name(pdev) : "",
		sizeof(drvinfo->bus_info));
	drvinfo->n_stats = ARRAY_SIZE(aq_ethtool_stat_names) +
		cfg->vecs * ARRAY_SIZE(aq_ethtool_queue_stat_names);
	drvinfo->n_stats = aq_ethtool_n_stats(ndev);
	drvinfo->testinfo_len = 0;
	drvinfo->regdump_len = regs_count;
	drvinfo->eedump_len = 0;
@@ -153,6 +227,9 @@ static void aq_ethtool_get_strings(struct net_device *ndev,
	struct aq_nic_cfg_s *cfg;
	u8 *p = data;
	int i, si;
#if IS_ENABLED(CONFIG_MACSEC)
	int sa;
#endif

	cfg = aq_nic_get_cfg(aq_nic);

@@ -170,6 +247,60 @@ static void aq_ethtool_get_strings(struct net_device *ndev,
				p += ETH_GSTRING_LEN;
			}
		}
#if IS_ENABLED(CONFIG_MACSEC)
		if (!aq_nic->macsec_cfg)
			break;

		memcpy(p, aq_macsec_stat_names, sizeof(aq_macsec_stat_names));
		p = p + sizeof(aq_macsec_stat_names);
		for (i = 0; i < AQ_MACSEC_MAX_SC; i++) {
			struct aq_macsec_txsc *aq_txsc;

			if (!(test_bit(i, &aq_nic->macsec_cfg->txsc_idx_busy)))
				continue;

			for (si = 0;
				si < ARRAY_SIZE(aq_macsec_txsc_stat_names);
				si++) {
				snprintf(p, ETH_GSTRING_LEN,
					 aq_macsec_txsc_stat_names[si], i);
				p += ETH_GSTRING_LEN;
			}
			aq_txsc = &aq_nic->macsec_cfg->aq_txsc[i];
			for (sa = 0; sa < MACSEC_NUM_AN; sa++) {
				if (!(test_bit(sa, &aq_txsc->tx_sa_idx_busy)))
					continue;
				for (si = 0;
				     si < ARRAY_SIZE(aq_macsec_txsa_stat_names);
				     si++) {
					snprintf(p, ETH_GSTRING_LEN,
						 aq_macsec_txsa_stat_names[si],
						 i, sa);
					p += ETH_GSTRING_LEN;
				}
			}
		}
		for (i = 0; i < AQ_MACSEC_MAX_SC; i++) {
			struct aq_macsec_rxsc *aq_rxsc;

			if (!(test_bit(i, &aq_nic->macsec_cfg->rxsc_idx_busy)))
				continue;

			aq_rxsc = &aq_nic->macsec_cfg->aq_rxsc[i];
			for (sa = 0; sa < MACSEC_NUM_AN; sa++) {
				if (!(test_bit(sa, &aq_rxsc->rx_sa_idx_busy)))
					continue;
				for (si = 0;
				     si < ARRAY_SIZE(aq_macsec_rxsa_stat_names);
				     si++) {
					snprintf(p, ETH_GSTRING_LEN,
						 aq_macsec_rxsa_stat_names[si],
						 i, sa);
					p += ETH_GSTRING_LEN;
				}
			}
		}
#endif
		break;
	case ETH_SS_PRIV_FLAGS:
		memcpy(p, aq_ethtool_priv_flag_names,
@@ -209,16 +340,11 @@ static int aq_ethtool_set_phys_id(struct net_device *ndev,

static int aq_ethtool_get_sset_count(struct net_device *ndev, int stringset)
{
	struct aq_nic_s *aq_nic = netdev_priv(ndev);
	struct aq_nic_cfg_s *cfg;
	int ret = 0;

	cfg = aq_nic_get_cfg(aq_nic);

	switch (stringset) {
	case ETH_SS_STATS:
		ret = ARRAY_SIZE(aq_ethtool_stat_names) +
			cfg->vecs * ARRAY_SIZE(aq_ethtool_queue_stat_names);
		ret = aq_ethtool_n_stats(ndev);
		break;
	case ETH_SS_PRIV_FLAGS:
		ret = ARRAY_SIZE(aq_ethtool_priv_flag_names);
+545 −0
Original line number Diff line number Diff line
@@ -127,6 +127,166 @@ static void aq_rotate_keys(u32 (*key)[8], const int key_len)
	}
}

#define STATS_2x32_TO_64(stat_field)                                           \
	(((u64)stat_field[1] << 32) | stat_field[0])

static int aq_get_macsec_common_stats(struct aq_hw_s *hw,
				      struct aq_macsec_common_stats *stats)
{
	struct aq_mss_ingress_common_counters ingress_counters;
	struct aq_mss_egress_common_counters egress_counters;
	int ret;

	/* MACSEC counters */
	ret = aq_mss_get_ingress_common_counters(hw, &ingress_counters);
	if (unlikely(ret))
		return ret;

	stats->in.ctl_pkts = STATS_2x32_TO_64(ingress_counters.ctl_pkts);
	stats->in.tagged_miss_pkts =
		STATS_2x32_TO_64(ingress_counters.tagged_miss_pkts);
	stats->in.untagged_miss_pkts =
		STATS_2x32_TO_64(ingress_counters.untagged_miss_pkts);
	stats->in.notag_pkts = STATS_2x32_TO_64(ingress_counters.notag_pkts);
	stats->in.untagged_pkts =
		STATS_2x32_TO_64(ingress_counters.untagged_pkts);
	stats->in.bad_tag_pkts =
		STATS_2x32_TO_64(ingress_counters.bad_tag_pkts);
	stats->in.no_sci_pkts = STATS_2x32_TO_64(ingress_counters.no_sci_pkts);
	stats->in.unknown_sci_pkts =
		STATS_2x32_TO_64(ingress_counters.unknown_sci_pkts);
	stats->in.ctrl_prt_pass_pkts =
		STATS_2x32_TO_64(ingress_counters.ctrl_prt_pass_pkts);
	stats->in.unctrl_prt_pass_pkts =
		STATS_2x32_TO_64(ingress_counters.unctrl_prt_pass_pkts);
	stats->in.ctrl_prt_fail_pkts =
		STATS_2x32_TO_64(ingress_counters.ctrl_prt_fail_pkts);
	stats->in.unctrl_prt_fail_pkts =
		STATS_2x32_TO_64(ingress_counters.unctrl_prt_fail_pkts);
	stats->in.too_long_pkts =
		STATS_2x32_TO_64(ingress_counters.too_long_pkts);
	stats->in.igpoc_ctl_pkts =
		STATS_2x32_TO_64(ingress_counters.igpoc_ctl_pkts);
	stats->in.ecc_error_pkts =
		STATS_2x32_TO_64(ingress_counters.ecc_error_pkts);
	stats->in.unctrl_hit_drop_redir =
		STATS_2x32_TO_64(ingress_counters.unctrl_hit_drop_redir);

	ret = aq_mss_get_egress_common_counters(hw, &egress_counters);
	if (unlikely(ret))
		return ret;
	stats->out.ctl_pkts = STATS_2x32_TO_64(egress_counters.ctl_pkt);
	stats->out.unknown_sa_pkts =
		STATS_2x32_TO_64(egress_counters.unknown_sa_pkts);
	stats->out.untagged_pkts =
		STATS_2x32_TO_64(egress_counters.untagged_pkts);
	stats->out.too_long = STATS_2x32_TO_64(egress_counters.too_long);
	stats->out.ecc_error_pkts =
		STATS_2x32_TO_64(egress_counters.ecc_error_pkts);
	stats->out.unctrl_hit_drop_redir =
		STATS_2x32_TO_64(egress_counters.unctrl_hit_drop_redir);

	return 0;
}

static int aq_get_rxsa_stats(struct aq_hw_s *hw, const int sa_idx,
			     struct aq_macsec_rx_sa_stats *stats)
{
	struct aq_mss_ingress_sa_counters i_sa_counters;
	int ret;

	ret = aq_mss_get_ingress_sa_counters(hw, &i_sa_counters, sa_idx);
	if (unlikely(ret))
		return ret;

	stats->untagged_hit_pkts =
		STATS_2x32_TO_64(i_sa_counters.untagged_hit_pkts);
	stats->ctrl_hit_drop_redir_pkts =
		STATS_2x32_TO_64(i_sa_counters.ctrl_hit_drop_redir_pkts);
	stats->not_using_sa = STATS_2x32_TO_64(i_sa_counters.not_using_sa);
	stats->unused_sa = STATS_2x32_TO_64(i_sa_counters.unused_sa);
	stats->not_valid_pkts = STATS_2x32_TO_64(i_sa_counters.not_valid_pkts);
	stats->invalid_pkts = STATS_2x32_TO_64(i_sa_counters.invalid_pkts);
	stats->ok_pkts = STATS_2x32_TO_64(i_sa_counters.ok_pkts);
	stats->late_pkts = STATS_2x32_TO_64(i_sa_counters.late_pkts);
	stats->delayed_pkts = STATS_2x32_TO_64(i_sa_counters.delayed_pkts);
	stats->unchecked_pkts = STATS_2x32_TO_64(i_sa_counters.unchecked_pkts);
	stats->validated_octets =
		STATS_2x32_TO_64(i_sa_counters.validated_octets);
	stats->decrypted_octets =
		STATS_2x32_TO_64(i_sa_counters.decrypted_octets);

	return 0;
}

static int aq_get_txsa_stats(struct aq_hw_s *hw, const int sa_idx,
			     struct aq_macsec_tx_sa_stats *stats)
{
	struct aq_mss_egress_sa_counters e_sa_counters;
	int ret;

	ret = aq_mss_get_egress_sa_counters(hw, &e_sa_counters, sa_idx);
	if (unlikely(ret))
		return ret;

	stats->sa_hit_drop_redirect =
		STATS_2x32_TO_64(e_sa_counters.sa_hit_drop_redirect);
	stats->sa_protected2_pkts =
		STATS_2x32_TO_64(e_sa_counters.sa_protected2_pkts);
	stats->sa_protected_pkts =
		STATS_2x32_TO_64(e_sa_counters.sa_protected_pkts);
	stats->sa_encrypted_pkts =
		STATS_2x32_TO_64(e_sa_counters.sa_encrypted_pkts);

	return 0;
}

static int aq_get_txsa_next_pn(struct aq_hw_s *hw, const int sa_idx, u32 *pn)
{
	struct aq_mss_egress_sa_record sa_rec;
	int ret;

	ret = aq_mss_get_egress_sa_record(hw, &sa_rec, sa_idx);
	if (likely(!ret))
		*pn = sa_rec.next_pn;

	return ret;
}

static int aq_get_rxsa_next_pn(struct aq_hw_s *hw, const int sa_idx, u32 *pn)
{
	struct aq_mss_ingress_sa_record sa_rec;
	int ret;

	ret = aq_mss_get_ingress_sa_record(hw, &sa_rec, sa_idx);
	if (likely(!ret))
		*pn = (!sa_rec.sat_nextpn) ? sa_rec.next_pn : 0;

	return ret;
}

static int aq_get_txsc_stats(struct aq_hw_s *hw, const int sc_idx,
			     struct aq_macsec_tx_sc_stats *stats)
{
	struct aq_mss_egress_sc_counters e_sc_counters;
	int ret;

	ret = aq_mss_get_egress_sc_counters(hw, &e_sc_counters, sc_idx);
	if (unlikely(ret))
		return ret;

	stats->sc_protected_pkts =
		STATS_2x32_TO_64(e_sc_counters.sc_protected_pkts);
	stats->sc_encrypted_pkts =
		STATS_2x32_TO_64(e_sc_counters.sc_encrypted_pkts);
	stats->sc_protected_octets =
		STATS_2x32_TO_64(e_sc_counters.sc_protected_octets);
	stats->sc_encrypted_octets =
		STATS_2x32_TO_64(e_sc_counters.sc_encrypted_octets);

	return 0;
}

static int aq_mdo_dev_open(struct macsec_context *ctx)
{
	struct aq_nic_s *nic = netdev_priv(ctx->netdev);
@@ -873,6 +1033,191 @@ static int aq_mdo_del_rxsa(struct macsec_context *ctx)
	return ret;
}

static int aq_mdo_get_dev_stats(struct macsec_context *ctx)
{
	struct aq_nic_s *nic = netdev_priv(ctx->netdev);
	struct aq_macsec_common_stats *stats = &nic->macsec_cfg->stats;
	struct aq_hw_s *hw = nic->aq_hw;

	if (ctx->prepare)
		return 0;

	aq_get_macsec_common_stats(hw, stats);

	ctx->stats.dev_stats->OutPktsUntagged = stats->out.untagged_pkts;
	ctx->stats.dev_stats->InPktsUntagged = stats->in.untagged_pkts;
	ctx->stats.dev_stats->OutPktsTooLong = stats->out.too_long;
	ctx->stats.dev_stats->InPktsNoTag = stats->in.notag_pkts;
	ctx->stats.dev_stats->InPktsBadTag = stats->in.bad_tag_pkts;
	ctx->stats.dev_stats->InPktsUnknownSCI = stats->in.unknown_sci_pkts;
	ctx->stats.dev_stats->InPktsNoSCI = stats->in.no_sci_pkts;
	ctx->stats.dev_stats->InPktsOverrun = 0;

	return 0;
}

static int aq_mdo_get_tx_sc_stats(struct macsec_context *ctx)
{
	struct aq_nic_s *nic = netdev_priv(ctx->netdev);
	struct aq_macsec_tx_sc_stats *stats;
	struct aq_hw_s *hw = nic->aq_hw;
	struct aq_macsec_txsc *aq_txsc;
	int txsc_idx;

	txsc_idx = aq_get_txsc_idx_from_secy(nic->macsec_cfg, ctx->secy);
	if (txsc_idx < 0)
		return -ENOENT;

	if (ctx->prepare)
		return 0;

	aq_txsc = &nic->macsec_cfg->aq_txsc[txsc_idx];
	stats = &aq_txsc->stats;
	aq_get_txsc_stats(hw, aq_txsc->hw_sc_idx, stats);

	ctx->stats.tx_sc_stats->OutPktsProtected = stats->sc_protected_pkts;
	ctx->stats.tx_sc_stats->OutPktsEncrypted = stats->sc_encrypted_pkts;
	ctx->stats.tx_sc_stats->OutOctetsProtected = stats->sc_protected_octets;
	ctx->stats.tx_sc_stats->OutOctetsEncrypted = stats->sc_encrypted_octets;

	return 0;
}

static int aq_mdo_get_tx_sa_stats(struct macsec_context *ctx)
{
	struct aq_nic_s *nic = netdev_priv(ctx->netdev);
	struct aq_macsec_cfg *cfg = nic->macsec_cfg;
	struct aq_macsec_tx_sa_stats *stats;
	struct aq_hw_s *hw = nic->aq_hw;
	const struct macsec_secy *secy;
	struct aq_macsec_txsc *aq_txsc;
	struct macsec_tx_sa *tx_sa;
	unsigned int sa_idx;
	int txsc_idx;
	u32 next_pn;
	int ret;

	txsc_idx = aq_get_txsc_idx_from_secy(cfg, ctx->secy);
	if (txsc_idx < 0)
		return -EINVAL;

	if (ctx->prepare)
		return 0;

	aq_txsc = &cfg->aq_txsc[txsc_idx];
	sa_idx = aq_txsc->hw_sc_idx | ctx->sa.assoc_num;
	stats = &aq_txsc->tx_sa_stats[ctx->sa.assoc_num];
	ret = aq_get_txsa_stats(hw, sa_idx, stats);
	if (ret)
		return ret;

	ctx->stats.tx_sa_stats->OutPktsProtected = stats->sa_protected_pkts;
	ctx->stats.tx_sa_stats->OutPktsEncrypted = stats->sa_encrypted_pkts;

	secy = aq_txsc->sw_secy;
	tx_sa = rcu_dereference_bh(secy->tx_sc.sa[ctx->sa.assoc_num]);
	ret = aq_get_txsa_next_pn(hw, sa_idx, &next_pn);
	if (ret == 0) {
		spin_lock_bh(&tx_sa->lock);
		tx_sa->next_pn = next_pn;
		spin_unlock_bh(&tx_sa->lock);
	}

	return ret;
}

static int aq_mdo_get_rx_sc_stats(struct macsec_context *ctx)
{
	struct aq_nic_s *nic = netdev_priv(ctx->netdev);
	struct aq_macsec_cfg *cfg = nic->macsec_cfg;
	struct aq_macsec_rx_sa_stats *stats;
	struct aq_hw_s *hw = nic->aq_hw;
	struct aq_macsec_rxsc *aq_rxsc;
	unsigned int sa_idx;
	int rxsc_idx;
	int ret = 0;
	int i;

	rxsc_idx = aq_get_rxsc_idx_from_rxsc(cfg, ctx->rx_sc);
	if (rxsc_idx < 0)
		return -ENOENT;

	if (ctx->prepare)
		return 0;

	aq_rxsc = &cfg->aq_rxsc[rxsc_idx];
	for (i = 0; i < MACSEC_NUM_AN; i++) {
		if (!test_bit(i, &aq_rxsc->rx_sa_idx_busy))
			continue;

		stats = &aq_rxsc->rx_sa_stats[i];
		sa_idx = aq_rxsc->hw_sc_idx | i;
		ret = aq_get_rxsa_stats(hw, sa_idx, stats);
		if (ret)
			break;

		ctx->stats.rx_sc_stats->InOctetsValidated +=
			stats->validated_octets;
		ctx->stats.rx_sc_stats->InOctetsDecrypted +=
			stats->decrypted_octets;
		ctx->stats.rx_sc_stats->InPktsUnchecked +=
			stats->unchecked_pkts;
		ctx->stats.rx_sc_stats->InPktsDelayed += stats->delayed_pkts;
		ctx->stats.rx_sc_stats->InPktsOK += stats->ok_pkts;
		ctx->stats.rx_sc_stats->InPktsInvalid += stats->invalid_pkts;
		ctx->stats.rx_sc_stats->InPktsLate += stats->late_pkts;
		ctx->stats.rx_sc_stats->InPktsNotValid += stats->not_valid_pkts;
		ctx->stats.rx_sc_stats->InPktsNotUsingSA += stats->not_using_sa;
		ctx->stats.rx_sc_stats->InPktsUnusedSA += stats->unused_sa;
	}

	return ret;
}

static int aq_mdo_get_rx_sa_stats(struct macsec_context *ctx)
{
	struct aq_nic_s *nic = netdev_priv(ctx->netdev);
	struct aq_macsec_cfg *cfg = nic->macsec_cfg;
	struct aq_macsec_rx_sa_stats *stats;
	struct aq_hw_s *hw = nic->aq_hw;
	struct aq_macsec_rxsc *aq_rxsc;
	struct macsec_rx_sa *rx_sa;
	unsigned int sa_idx;
	int rxsc_idx;
	u32 next_pn;
	int ret;

	rxsc_idx = aq_get_rxsc_idx_from_rxsc(cfg, ctx->rx_sc);
	if (rxsc_idx < 0)
		return -EINVAL;

	if (ctx->prepare)
		return 0;

	aq_rxsc = &cfg->aq_rxsc[rxsc_idx];
	stats = &aq_rxsc->rx_sa_stats[ctx->sa.assoc_num];
	sa_idx = aq_rxsc->hw_sc_idx | ctx->sa.assoc_num;
	ret = aq_get_rxsa_stats(hw, sa_idx, stats);
	if (ret)
		return ret;

	ctx->stats.rx_sa_stats->InPktsOK = stats->ok_pkts;
	ctx->stats.rx_sa_stats->InPktsInvalid = stats->invalid_pkts;
	ctx->stats.rx_sa_stats->InPktsNotValid = stats->not_valid_pkts;
	ctx->stats.rx_sa_stats->InPktsNotUsingSA = stats->not_using_sa;
	ctx->stats.rx_sa_stats->InPktsUnusedSA = stats->unused_sa;

	rx_sa = rcu_dereference_bh(aq_rxsc->sw_rxsc->sa[ctx->sa.assoc_num]);
	ret = aq_get_rxsa_next_pn(hw, sa_idx, &next_pn);
	if (ret == 0) {
		spin_lock_bh(&rx_sa->lock);
		rx_sa->next_pn = next_pn;
		spin_unlock_bh(&rx_sa->lock);
	}

	return ret;
}

static int apply_txsc_cfg(struct aq_nic_s *nic, const int txsc_idx)
{
	struct aq_macsec_txsc *aq_txsc = &nic->macsec_cfg->aq_txsc[txsc_idx];
@@ -1116,6 +1461,11 @@ const struct macsec_ops aq_macsec_ops = {
	.mdo_add_txsa = aq_mdo_add_txsa,
	.mdo_upd_txsa = aq_mdo_upd_txsa,
	.mdo_del_txsa = aq_mdo_del_txsa,
	.mdo_get_dev_stats = aq_mdo_get_dev_stats,
	.mdo_get_tx_sc_stats = aq_mdo_get_tx_sc_stats,
	.mdo_get_tx_sa_stats = aq_mdo_get_tx_sa_stats,
	.mdo_get_rx_sc_stats = aq_mdo_get_rx_sc_stats,
	.mdo_get_rx_sa_stats = aq_mdo_get_rx_sa_stats,
};

int aq_macsec_init(struct aq_nic_s *nic)
@@ -1225,3 +1575,198 @@ void aq_macsec_work(struct aq_nic_s *nic)
	aq_check_txsa_expiration(nic);
	rtnl_unlock();
}

int aq_macsec_rx_sa_cnt(struct aq_nic_s *nic)
{
	struct aq_macsec_cfg *cfg = nic->macsec_cfg;
	int i, cnt = 0;

	if (!cfg)
		return 0;

	for (i = 0; i < AQ_MACSEC_MAX_SC; i++) {
		if (!test_bit(i, &cfg->rxsc_idx_busy))
			continue;
		cnt += hweight_long(cfg->aq_rxsc[i].rx_sa_idx_busy);
	}

	return cnt;
}

int aq_macsec_tx_sc_cnt(struct aq_nic_s *nic)
{
	if (!nic->macsec_cfg)
		return 0;

	return hweight_long(nic->macsec_cfg->txsc_idx_busy);
}

int aq_macsec_tx_sa_cnt(struct aq_nic_s *nic)
{
	struct aq_macsec_cfg *cfg = nic->macsec_cfg;
	int i, cnt = 0;

	if (!cfg)
		return 0;

	for (i = 0; i < AQ_MACSEC_MAX_SC; i++) {
		if (!test_bit(i, &cfg->txsc_idx_busy))
			continue;
		cnt += hweight_long(cfg->aq_txsc[i].tx_sa_idx_busy);
	}

	return cnt;
}

static int aq_macsec_update_stats(struct aq_nic_s *nic)
{
	struct aq_macsec_cfg *cfg = nic->macsec_cfg;
	struct aq_hw_s *hw = nic->aq_hw;
	struct aq_macsec_txsc *aq_txsc;
	struct aq_macsec_rxsc *aq_rxsc;
	int i, sa_idx, assoc_num;
	int ret = 0;

	aq_get_macsec_common_stats(hw, &cfg->stats);

	for (i = 0; i < AQ_MACSEC_MAX_SC; i++) {
		if (!(cfg->txsc_idx_busy & BIT(i)))
			continue;
		aq_txsc = &cfg->aq_txsc[i];

		ret = aq_get_txsc_stats(hw, aq_txsc->hw_sc_idx,
					&aq_txsc->stats);
		if (ret)
			return ret;

		for (assoc_num = 0; assoc_num < MACSEC_NUM_AN; assoc_num++) {
			if (!test_bit(assoc_num, &aq_txsc->tx_sa_idx_busy))
				continue;
			sa_idx = aq_txsc->hw_sc_idx | assoc_num;
			ret = aq_get_txsa_stats(hw, sa_idx,
					      &aq_txsc->tx_sa_stats[assoc_num]);
			if (ret)
				return ret;
		}
	}

	for (i = 0; i < AQ_MACSEC_MAX_SC; i++) {
		if (!(test_bit(i, &cfg->rxsc_idx_busy)))
			continue;
		aq_rxsc = &cfg->aq_rxsc[i];

		for (assoc_num = 0; assoc_num < MACSEC_NUM_AN; assoc_num++) {
			if (!test_bit(assoc_num, &aq_rxsc->rx_sa_idx_busy))
				continue;
			sa_idx = aq_rxsc->hw_sc_idx | assoc_num;

			ret = aq_get_rxsa_stats(hw, sa_idx,
					      &aq_rxsc->rx_sa_stats[assoc_num]);
			if (ret)
				return ret;
		}
	}

	return ret;
}

u64 *aq_macsec_get_stats(struct aq_nic_s *nic, u64 *data)
{
	struct aq_macsec_cfg *cfg = nic->macsec_cfg;
	struct aq_macsec_common_stats *common_stats;
	struct aq_macsec_tx_sc_stats *txsc_stats;
	struct aq_macsec_tx_sa_stats *txsa_stats;
	struct aq_macsec_rx_sa_stats *rxsa_stats;
	struct aq_macsec_txsc *aq_txsc;
	struct aq_macsec_rxsc *aq_rxsc;
	unsigned int assoc_num;
	unsigned int sc_num;
	unsigned int i = 0U;

	if (!cfg)
		return data;

	aq_macsec_update_stats(nic);

	common_stats = &cfg->stats;
	data[i] = common_stats->in.ctl_pkts;
	data[++i] = common_stats->in.tagged_miss_pkts;
	data[++i] = common_stats->in.untagged_miss_pkts;
	data[++i] = common_stats->in.notag_pkts;
	data[++i] = common_stats->in.untagged_pkts;
	data[++i] = common_stats->in.bad_tag_pkts;
	data[++i] = common_stats->in.no_sci_pkts;
	data[++i] = common_stats->in.unknown_sci_pkts;
	data[++i] = common_stats->in.ctrl_prt_pass_pkts;
	data[++i] = common_stats->in.unctrl_prt_pass_pkts;
	data[++i] = common_stats->in.ctrl_prt_fail_pkts;
	data[++i] = common_stats->in.unctrl_prt_fail_pkts;
	data[++i] = common_stats->in.too_long_pkts;
	data[++i] = common_stats->in.igpoc_ctl_pkts;
	data[++i] = common_stats->in.ecc_error_pkts;
	data[++i] = common_stats->in.unctrl_hit_drop_redir;
	data[++i] = common_stats->out.ctl_pkts;
	data[++i] = common_stats->out.unknown_sa_pkts;
	data[++i] = common_stats->out.untagged_pkts;
	data[++i] = common_stats->out.too_long;
	data[++i] = common_stats->out.ecc_error_pkts;
	data[++i] = common_stats->out.unctrl_hit_drop_redir;

	for (sc_num = 0; sc_num < AQ_MACSEC_MAX_SC; sc_num++) {
		if (!(test_bit(sc_num, &cfg->txsc_idx_busy)))
			continue;

		aq_txsc = &cfg->aq_txsc[sc_num];
		txsc_stats = &aq_txsc->stats;

		data[++i] = txsc_stats->sc_protected_pkts;
		data[++i] = txsc_stats->sc_encrypted_pkts;
		data[++i] = txsc_stats->sc_protected_octets;
		data[++i] = txsc_stats->sc_encrypted_octets;

		for (assoc_num = 0; assoc_num < MACSEC_NUM_AN; assoc_num++) {
			if (!test_bit(assoc_num, &aq_txsc->tx_sa_idx_busy))
				continue;

			txsa_stats = &aq_txsc->tx_sa_stats[assoc_num];

			data[++i] = txsa_stats->sa_hit_drop_redirect;
			data[++i] = txsa_stats->sa_protected2_pkts;
			data[++i] = txsa_stats->sa_protected_pkts;
			data[++i] = txsa_stats->sa_encrypted_pkts;
		}
	}

	for (sc_num = 0; sc_num < AQ_MACSEC_MAX_SC; sc_num++) {
		if (!(test_bit(sc_num, &cfg->rxsc_idx_busy)))
			continue;

		aq_rxsc = &cfg->aq_rxsc[sc_num];

		for (assoc_num = 0; assoc_num < MACSEC_NUM_AN; assoc_num++) {
			if (!test_bit(assoc_num, &aq_rxsc->rx_sa_idx_busy))
				continue;

			rxsa_stats = &aq_rxsc->rx_sa_stats[assoc_num];

			data[++i] = rxsa_stats->untagged_hit_pkts;
			data[++i] = rxsa_stats->ctrl_hit_drop_redir_pkts;
			data[++i] = rxsa_stats->not_using_sa;
			data[++i] = rxsa_stats->unused_sa;
			data[++i] = rxsa_stats->not_valid_pkts;
			data[++i] = rxsa_stats->invalid_pkts;
			data[++i] = rxsa_stats->ok_pkts;
			data[++i] = rxsa_stats->late_pkts;
			data[++i] = rxsa_stats->delayed_pkts;
			data[++i] = rxsa_stats->unchecked_pkts;
			data[++i] = rxsa_stats->validated_octets;
			data[++i] = rxsa_stats->decrypted_octets;
		}
	}

	i++;

	data += i;

	return data;
}
+73 −0

File changed.

Preview size limit exceeded, changes collapsed.

+4 −1
Original line number Diff line number Diff line
@@ -781,7 +781,7 @@ int aq_nic_get_regs_count(struct aq_nic_s *self)
	return self->aq_nic_cfg.aq_hw_caps->mac_regs_count;
}

void aq_nic_get_stats(struct aq_nic_s *self, u64 *data)
u64 *aq_nic_get_stats(struct aq_nic_s *self, u64 *data)
{
	struct aq_vec_s *aq_vec = NULL;
	struct aq_stats_s *stats;
@@ -831,7 +831,10 @@ void aq_nic_get_stats(struct aq_nic_s *self, u64 *data)
		aq_vec_get_sw_stats(aq_vec, data, &count);
	}

	data += count;

err_exit:;
	return data;
}

static void aq_nic_update_ndev_stats(struct aq_nic_s *self)
+1 −1
Original line number Diff line number Diff line
@@ -158,7 +158,7 @@ unsigned int aq_nic_map_skb(struct aq_nic_s *self, struct sk_buff *skb,
int aq_nic_xmit(struct aq_nic_s *self, struct sk_buff *skb);
int aq_nic_get_regs(struct aq_nic_s *self, struct ethtool_regs *regs, void *p);
int aq_nic_get_regs_count(struct aq_nic_s *self);
void aq_nic_get_stats(struct aq_nic_s *self, u64 *data);
u64 *aq_nic_get_stats(struct aq_nic_s *self, u64 *data);
int aq_nic_stop(struct aq_nic_s *self);
void aq_nic_deinit(struct aq_nic_s *self, bool link_down);
void aq_nic_set_power(struct aq_nic_s *self);