162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/* Atlantic Network Driver
362306a36Sopenharmony_ci * Copyright (C) 2020 Marvell International Ltd.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include "aq_macsec.h"
762306a36Sopenharmony_ci#include "aq_nic.h"
862306a36Sopenharmony_ci#include <linux/rtnetlink.h>
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include "macsec/macsec_api.h"
1162306a36Sopenharmony_ci#define AQ_MACSEC_KEY_LEN_128_BIT 16
1262306a36Sopenharmony_ci#define AQ_MACSEC_KEY_LEN_192_BIT 24
1362306a36Sopenharmony_ci#define AQ_MACSEC_KEY_LEN_256_BIT 32
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_cienum aq_clear_type {
1662306a36Sopenharmony_ci	/* update HW configuration */
1762306a36Sopenharmony_ci	AQ_CLEAR_HW = BIT(0),
1862306a36Sopenharmony_ci	/* update SW configuration (busy bits, pointers) */
1962306a36Sopenharmony_ci	AQ_CLEAR_SW = BIT(1),
2062306a36Sopenharmony_ci	/* update both HW and SW configuration */
2162306a36Sopenharmony_ci	AQ_CLEAR_ALL = AQ_CLEAR_HW | AQ_CLEAR_SW,
2262306a36Sopenharmony_ci};
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cistatic int aq_clear_txsc(struct aq_nic_s *nic, const int txsc_idx,
2562306a36Sopenharmony_ci			 enum aq_clear_type clear_type);
2662306a36Sopenharmony_cistatic int aq_clear_txsa(struct aq_nic_s *nic, struct aq_macsec_txsc *aq_txsc,
2762306a36Sopenharmony_ci			 const int sa_num, enum aq_clear_type clear_type);
2862306a36Sopenharmony_cistatic int aq_clear_rxsc(struct aq_nic_s *nic, const int rxsc_idx,
2962306a36Sopenharmony_ci			 enum aq_clear_type clear_type);
3062306a36Sopenharmony_cistatic int aq_clear_rxsa(struct aq_nic_s *nic, struct aq_macsec_rxsc *aq_rxsc,
3162306a36Sopenharmony_ci			 const int sa_num, enum aq_clear_type clear_type);
3262306a36Sopenharmony_cistatic int aq_clear_secy(struct aq_nic_s *nic, const struct macsec_secy *secy,
3362306a36Sopenharmony_ci			 enum aq_clear_type clear_type);
3462306a36Sopenharmony_cistatic int aq_apply_macsec_cfg(struct aq_nic_s *nic);
3562306a36Sopenharmony_cistatic int aq_apply_secy_cfg(struct aq_nic_s *nic,
3662306a36Sopenharmony_ci			     const struct macsec_secy *secy);
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cistatic void aq_ether_addr_to_mac(u32 mac[2], const unsigned char *emac)
3962306a36Sopenharmony_ci{
4062306a36Sopenharmony_ci	u32 tmp[2] = { 0 };
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	memcpy(((u8 *)tmp) + 2, emac, ETH_ALEN);
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	mac[0] = swab32(tmp[1]);
4562306a36Sopenharmony_ci	mac[1] = swab32(tmp[0]);
4662306a36Sopenharmony_ci}
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci/* There's a 1:1 mapping between SecY and TX SC */
4962306a36Sopenharmony_cistatic int aq_get_txsc_idx_from_secy(struct aq_macsec_cfg *macsec_cfg,
5062306a36Sopenharmony_ci				     const struct macsec_secy *secy)
5162306a36Sopenharmony_ci{
5262306a36Sopenharmony_ci	int i;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	if (unlikely(!secy))
5562306a36Sopenharmony_ci		return -1;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	for (i = 0; i < AQ_MACSEC_MAX_SC; i++) {
5862306a36Sopenharmony_ci		if (macsec_cfg->aq_txsc[i].sw_secy == secy)
5962306a36Sopenharmony_ci			return i;
6062306a36Sopenharmony_ci	}
6162306a36Sopenharmony_ci	return -1;
6262306a36Sopenharmony_ci}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic int aq_get_rxsc_idx_from_rxsc(struct aq_macsec_cfg *macsec_cfg,
6562306a36Sopenharmony_ci				     const struct macsec_rx_sc *rxsc)
6662306a36Sopenharmony_ci{
6762306a36Sopenharmony_ci	int i;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	if (unlikely(!rxsc))
7062306a36Sopenharmony_ci		return -1;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	for (i = 0; i < AQ_MACSEC_MAX_SC; i++) {
7362306a36Sopenharmony_ci		if (macsec_cfg->aq_rxsc[i].sw_rxsc == rxsc)
7462306a36Sopenharmony_ci			return i;
7562306a36Sopenharmony_ci	}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	return -1;
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistatic int aq_get_txsc_idx_from_sc_idx(const enum aq_macsec_sc_sa sc_sa,
8162306a36Sopenharmony_ci				       const int sc_idx)
8262306a36Sopenharmony_ci{
8362306a36Sopenharmony_ci	switch (sc_sa) {
8462306a36Sopenharmony_ci	case aq_macsec_sa_sc_4sa_8sc:
8562306a36Sopenharmony_ci		return sc_idx >> 2;
8662306a36Sopenharmony_ci	case aq_macsec_sa_sc_2sa_16sc:
8762306a36Sopenharmony_ci		return sc_idx >> 1;
8862306a36Sopenharmony_ci	case aq_macsec_sa_sc_1sa_32sc:
8962306a36Sopenharmony_ci		return sc_idx;
9062306a36Sopenharmony_ci	default:
9162306a36Sopenharmony_ci		WARN_ONCE(true, "Invalid sc_sa");
9262306a36Sopenharmony_ci	}
9362306a36Sopenharmony_ci	return -1;
9462306a36Sopenharmony_ci}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci/* Rotate keys u32[8] */
9762306a36Sopenharmony_cistatic void aq_rotate_keys(u32 (*key)[8], const int key_len)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	u32 tmp[8] = { 0 };
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	memcpy(&tmp, key, sizeof(tmp));
10262306a36Sopenharmony_ci	memset(*key, 0, sizeof(*key));
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	if (key_len == AQ_MACSEC_KEY_LEN_128_BIT) {
10562306a36Sopenharmony_ci		(*key)[0] = swab32(tmp[3]);
10662306a36Sopenharmony_ci		(*key)[1] = swab32(tmp[2]);
10762306a36Sopenharmony_ci		(*key)[2] = swab32(tmp[1]);
10862306a36Sopenharmony_ci		(*key)[3] = swab32(tmp[0]);
10962306a36Sopenharmony_ci	} else if (key_len == AQ_MACSEC_KEY_LEN_192_BIT) {
11062306a36Sopenharmony_ci		(*key)[0] = swab32(tmp[5]);
11162306a36Sopenharmony_ci		(*key)[1] = swab32(tmp[4]);
11262306a36Sopenharmony_ci		(*key)[2] = swab32(tmp[3]);
11362306a36Sopenharmony_ci		(*key)[3] = swab32(tmp[2]);
11462306a36Sopenharmony_ci		(*key)[4] = swab32(tmp[1]);
11562306a36Sopenharmony_ci		(*key)[5] = swab32(tmp[0]);
11662306a36Sopenharmony_ci	} else if (key_len == AQ_MACSEC_KEY_LEN_256_BIT) {
11762306a36Sopenharmony_ci		(*key)[0] = swab32(tmp[7]);
11862306a36Sopenharmony_ci		(*key)[1] = swab32(tmp[6]);
11962306a36Sopenharmony_ci		(*key)[2] = swab32(tmp[5]);
12062306a36Sopenharmony_ci		(*key)[3] = swab32(tmp[4]);
12162306a36Sopenharmony_ci		(*key)[4] = swab32(tmp[3]);
12262306a36Sopenharmony_ci		(*key)[5] = swab32(tmp[2]);
12362306a36Sopenharmony_ci		(*key)[6] = swab32(tmp[1]);
12462306a36Sopenharmony_ci		(*key)[7] = swab32(tmp[0]);
12562306a36Sopenharmony_ci	} else {
12662306a36Sopenharmony_ci		pr_warn("Rotate_keys: invalid key_len\n");
12762306a36Sopenharmony_ci	}
12862306a36Sopenharmony_ci}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci#define STATS_2x32_TO_64(stat_field)                                           \
13162306a36Sopenharmony_ci	(((u64)stat_field[1] << 32) | stat_field[0])
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_cistatic int aq_get_macsec_common_stats(struct aq_hw_s *hw,
13462306a36Sopenharmony_ci				      struct aq_macsec_common_stats *stats)
13562306a36Sopenharmony_ci{
13662306a36Sopenharmony_ci	struct aq_mss_ingress_common_counters ingress_counters;
13762306a36Sopenharmony_ci	struct aq_mss_egress_common_counters egress_counters;
13862306a36Sopenharmony_ci	int ret;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	/* MACSEC counters */
14162306a36Sopenharmony_ci	ret = aq_mss_get_ingress_common_counters(hw, &ingress_counters);
14262306a36Sopenharmony_ci	if (unlikely(ret))
14362306a36Sopenharmony_ci		return ret;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	stats->in.ctl_pkts = STATS_2x32_TO_64(ingress_counters.ctl_pkts);
14662306a36Sopenharmony_ci	stats->in.tagged_miss_pkts =
14762306a36Sopenharmony_ci		STATS_2x32_TO_64(ingress_counters.tagged_miss_pkts);
14862306a36Sopenharmony_ci	stats->in.untagged_miss_pkts =
14962306a36Sopenharmony_ci		STATS_2x32_TO_64(ingress_counters.untagged_miss_pkts);
15062306a36Sopenharmony_ci	stats->in.notag_pkts = STATS_2x32_TO_64(ingress_counters.notag_pkts);
15162306a36Sopenharmony_ci	stats->in.untagged_pkts =
15262306a36Sopenharmony_ci		STATS_2x32_TO_64(ingress_counters.untagged_pkts);
15362306a36Sopenharmony_ci	stats->in.bad_tag_pkts =
15462306a36Sopenharmony_ci		STATS_2x32_TO_64(ingress_counters.bad_tag_pkts);
15562306a36Sopenharmony_ci	stats->in.no_sci_pkts = STATS_2x32_TO_64(ingress_counters.no_sci_pkts);
15662306a36Sopenharmony_ci	stats->in.unknown_sci_pkts =
15762306a36Sopenharmony_ci		STATS_2x32_TO_64(ingress_counters.unknown_sci_pkts);
15862306a36Sopenharmony_ci	stats->in.ctrl_prt_pass_pkts =
15962306a36Sopenharmony_ci		STATS_2x32_TO_64(ingress_counters.ctrl_prt_pass_pkts);
16062306a36Sopenharmony_ci	stats->in.unctrl_prt_pass_pkts =
16162306a36Sopenharmony_ci		STATS_2x32_TO_64(ingress_counters.unctrl_prt_pass_pkts);
16262306a36Sopenharmony_ci	stats->in.ctrl_prt_fail_pkts =
16362306a36Sopenharmony_ci		STATS_2x32_TO_64(ingress_counters.ctrl_prt_fail_pkts);
16462306a36Sopenharmony_ci	stats->in.unctrl_prt_fail_pkts =
16562306a36Sopenharmony_ci		STATS_2x32_TO_64(ingress_counters.unctrl_prt_fail_pkts);
16662306a36Sopenharmony_ci	stats->in.too_long_pkts =
16762306a36Sopenharmony_ci		STATS_2x32_TO_64(ingress_counters.too_long_pkts);
16862306a36Sopenharmony_ci	stats->in.igpoc_ctl_pkts =
16962306a36Sopenharmony_ci		STATS_2x32_TO_64(ingress_counters.igpoc_ctl_pkts);
17062306a36Sopenharmony_ci	stats->in.ecc_error_pkts =
17162306a36Sopenharmony_ci		STATS_2x32_TO_64(ingress_counters.ecc_error_pkts);
17262306a36Sopenharmony_ci	stats->in.unctrl_hit_drop_redir =
17362306a36Sopenharmony_ci		STATS_2x32_TO_64(ingress_counters.unctrl_hit_drop_redir);
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	ret = aq_mss_get_egress_common_counters(hw, &egress_counters);
17662306a36Sopenharmony_ci	if (unlikely(ret))
17762306a36Sopenharmony_ci		return ret;
17862306a36Sopenharmony_ci	stats->out.ctl_pkts = STATS_2x32_TO_64(egress_counters.ctl_pkt);
17962306a36Sopenharmony_ci	stats->out.unknown_sa_pkts =
18062306a36Sopenharmony_ci		STATS_2x32_TO_64(egress_counters.unknown_sa_pkts);
18162306a36Sopenharmony_ci	stats->out.untagged_pkts =
18262306a36Sopenharmony_ci		STATS_2x32_TO_64(egress_counters.untagged_pkts);
18362306a36Sopenharmony_ci	stats->out.too_long = STATS_2x32_TO_64(egress_counters.too_long);
18462306a36Sopenharmony_ci	stats->out.ecc_error_pkts =
18562306a36Sopenharmony_ci		STATS_2x32_TO_64(egress_counters.ecc_error_pkts);
18662306a36Sopenharmony_ci	stats->out.unctrl_hit_drop_redir =
18762306a36Sopenharmony_ci		STATS_2x32_TO_64(egress_counters.unctrl_hit_drop_redir);
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	return 0;
19062306a36Sopenharmony_ci}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_cistatic int aq_get_rxsa_stats(struct aq_hw_s *hw, const int sa_idx,
19362306a36Sopenharmony_ci			     struct aq_macsec_rx_sa_stats *stats)
19462306a36Sopenharmony_ci{
19562306a36Sopenharmony_ci	struct aq_mss_ingress_sa_counters i_sa_counters;
19662306a36Sopenharmony_ci	int ret;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	ret = aq_mss_get_ingress_sa_counters(hw, &i_sa_counters, sa_idx);
19962306a36Sopenharmony_ci	if (unlikely(ret))
20062306a36Sopenharmony_ci		return ret;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	stats->untagged_hit_pkts =
20362306a36Sopenharmony_ci		STATS_2x32_TO_64(i_sa_counters.untagged_hit_pkts);
20462306a36Sopenharmony_ci	stats->ctrl_hit_drop_redir_pkts =
20562306a36Sopenharmony_ci		STATS_2x32_TO_64(i_sa_counters.ctrl_hit_drop_redir_pkts);
20662306a36Sopenharmony_ci	stats->not_using_sa = STATS_2x32_TO_64(i_sa_counters.not_using_sa);
20762306a36Sopenharmony_ci	stats->unused_sa = STATS_2x32_TO_64(i_sa_counters.unused_sa);
20862306a36Sopenharmony_ci	stats->not_valid_pkts = STATS_2x32_TO_64(i_sa_counters.not_valid_pkts);
20962306a36Sopenharmony_ci	stats->invalid_pkts = STATS_2x32_TO_64(i_sa_counters.invalid_pkts);
21062306a36Sopenharmony_ci	stats->ok_pkts = STATS_2x32_TO_64(i_sa_counters.ok_pkts);
21162306a36Sopenharmony_ci	stats->late_pkts = STATS_2x32_TO_64(i_sa_counters.late_pkts);
21262306a36Sopenharmony_ci	stats->delayed_pkts = STATS_2x32_TO_64(i_sa_counters.delayed_pkts);
21362306a36Sopenharmony_ci	stats->unchecked_pkts = STATS_2x32_TO_64(i_sa_counters.unchecked_pkts);
21462306a36Sopenharmony_ci	stats->validated_octets =
21562306a36Sopenharmony_ci		STATS_2x32_TO_64(i_sa_counters.validated_octets);
21662306a36Sopenharmony_ci	stats->decrypted_octets =
21762306a36Sopenharmony_ci		STATS_2x32_TO_64(i_sa_counters.decrypted_octets);
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	return 0;
22062306a36Sopenharmony_ci}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_cistatic int aq_get_txsa_stats(struct aq_hw_s *hw, const int sa_idx,
22362306a36Sopenharmony_ci			     struct aq_macsec_tx_sa_stats *stats)
22462306a36Sopenharmony_ci{
22562306a36Sopenharmony_ci	struct aq_mss_egress_sa_counters e_sa_counters;
22662306a36Sopenharmony_ci	int ret;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	ret = aq_mss_get_egress_sa_counters(hw, &e_sa_counters, sa_idx);
22962306a36Sopenharmony_ci	if (unlikely(ret))
23062306a36Sopenharmony_ci		return ret;
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	stats->sa_hit_drop_redirect =
23362306a36Sopenharmony_ci		STATS_2x32_TO_64(e_sa_counters.sa_hit_drop_redirect);
23462306a36Sopenharmony_ci	stats->sa_protected2_pkts =
23562306a36Sopenharmony_ci		STATS_2x32_TO_64(e_sa_counters.sa_protected2_pkts);
23662306a36Sopenharmony_ci	stats->sa_protected_pkts =
23762306a36Sopenharmony_ci		STATS_2x32_TO_64(e_sa_counters.sa_protected_pkts);
23862306a36Sopenharmony_ci	stats->sa_encrypted_pkts =
23962306a36Sopenharmony_ci		STATS_2x32_TO_64(e_sa_counters.sa_encrypted_pkts);
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	return 0;
24262306a36Sopenharmony_ci}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_cistatic int aq_get_txsa_next_pn(struct aq_hw_s *hw, const int sa_idx, u32 *pn)
24562306a36Sopenharmony_ci{
24662306a36Sopenharmony_ci	struct aq_mss_egress_sa_record sa_rec;
24762306a36Sopenharmony_ci	int ret;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	ret = aq_mss_get_egress_sa_record(hw, &sa_rec, sa_idx);
25062306a36Sopenharmony_ci	if (likely(!ret))
25162306a36Sopenharmony_ci		*pn = sa_rec.next_pn;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	return ret;
25462306a36Sopenharmony_ci}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_cistatic int aq_get_rxsa_next_pn(struct aq_hw_s *hw, const int sa_idx, u32 *pn)
25762306a36Sopenharmony_ci{
25862306a36Sopenharmony_ci	struct aq_mss_ingress_sa_record sa_rec;
25962306a36Sopenharmony_ci	int ret;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	ret = aq_mss_get_ingress_sa_record(hw, &sa_rec, sa_idx);
26262306a36Sopenharmony_ci	if (likely(!ret))
26362306a36Sopenharmony_ci		*pn = (!sa_rec.sat_nextpn) ? sa_rec.next_pn : 0;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	return ret;
26662306a36Sopenharmony_ci}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_cistatic int aq_get_txsc_stats(struct aq_hw_s *hw, const int sc_idx,
26962306a36Sopenharmony_ci			     struct aq_macsec_tx_sc_stats *stats)
27062306a36Sopenharmony_ci{
27162306a36Sopenharmony_ci	struct aq_mss_egress_sc_counters e_sc_counters;
27262306a36Sopenharmony_ci	int ret;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	ret = aq_mss_get_egress_sc_counters(hw, &e_sc_counters, sc_idx);
27562306a36Sopenharmony_ci	if (unlikely(ret))
27662306a36Sopenharmony_ci		return ret;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	stats->sc_protected_pkts =
27962306a36Sopenharmony_ci		STATS_2x32_TO_64(e_sc_counters.sc_protected_pkts);
28062306a36Sopenharmony_ci	stats->sc_encrypted_pkts =
28162306a36Sopenharmony_ci		STATS_2x32_TO_64(e_sc_counters.sc_encrypted_pkts);
28262306a36Sopenharmony_ci	stats->sc_protected_octets =
28362306a36Sopenharmony_ci		STATS_2x32_TO_64(e_sc_counters.sc_protected_octets);
28462306a36Sopenharmony_ci	stats->sc_encrypted_octets =
28562306a36Sopenharmony_ci		STATS_2x32_TO_64(e_sc_counters.sc_encrypted_octets);
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	return 0;
28862306a36Sopenharmony_ci}
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_cistatic int aq_mdo_dev_open(struct macsec_context *ctx)
29162306a36Sopenharmony_ci{
29262306a36Sopenharmony_ci	struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev);
29362306a36Sopenharmony_ci	int ret = 0;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	if (netif_carrier_ok(nic->ndev))
29662306a36Sopenharmony_ci		ret = aq_apply_secy_cfg(nic, ctx->secy);
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	return ret;
29962306a36Sopenharmony_ci}
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_cistatic int aq_mdo_dev_stop(struct macsec_context *ctx)
30262306a36Sopenharmony_ci{
30362306a36Sopenharmony_ci	struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev);
30462306a36Sopenharmony_ci	int i;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	for (i = 0; i < AQ_MACSEC_MAX_SC; i++) {
30762306a36Sopenharmony_ci		if (nic->macsec_cfg->txsc_idx_busy & BIT(i))
30862306a36Sopenharmony_ci			aq_clear_secy(nic, nic->macsec_cfg->aq_txsc[i].sw_secy,
30962306a36Sopenharmony_ci				      AQ_CLEAR_HW);
31062306a36Sopenharmony_ci	}
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	return 0;
31362306a36Sopenharmony_ci}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_cistatic int aq_set_txsc(struct aq_nic_s *nic, const int txsc_idx)
31662306a36Sopenharmony_ci{
31762306a36Sopenharmony_ci	struct aq_macsec_txsc *aq_txsc = &nic->macsec_cfg->aq_txsc[txsc_idx];
31862306a36Sopenharmony_ci	struct aq_mss_egress_class_record tx_class_rec = { 0 };
31962306a36Sopenharmony_ci	const struct macsec_secy *secy = aq_txsc->sw_secy;
32062306a36Sopenharmony_ci	struct aq_mss_egress_sc_record sc_rec = { 0 };
32162306a36Sopenharmony_ci	unsigned int sc_idx = aq_txsc->hw_sc_idx;
32262306a36Sopenharmony_ci	struct aq_hw_s *hw = nic->aq_hw;
32362306a36Sopenharmony_ci	int ret = 0;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	aq_ether_addr_to_mac(tx_class_rec.mac_sa, secy->netdev->dev_addr);
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	put_unaligned_be64((__force u64)secy->sci, tx_class_rec.sci);
32862306a36Sopenharmony_ci	tx_class_rec.sci_mask = 0;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	tx_class_rec.sa_mask = 0x3f;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	tx_class_rec.action = 0; /* forward to SA/SC table */
33362306a36Sopenharmony_ci	tx_class_rec.valid = 1;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	tx_class_rec.sc_idx = sc_idx;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	tx_class_rec.sc_sa = nic->macsec_cfg->sc_sa;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	ret = aq_mss_set_egress_class_record(hw, &tx_class_rec, txsc_idx);
34062306a36Sopenharmony_ci	if (ret)
34162306a36Sopenharmony_ci		return ret;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	sc_rec.protect = secy->protect_frames;
34462306a36Sopenharmony_ci	if (secy->tx_sc.encrypt)
34562306a36Sopenharmony_ci		sc_rec.tci |= BIT(1);
34662306a36Sopenharmony_ci	if (secy->tx_sc.scb)
34762306a36Sopenharmony_ci		sc_rec.tci |= BIT(2);
34862306a36Sopenharmony_ci	if (secy->tx_sc.send_sci)
34962306a36Sopenharmony_ci		sc_rec.tci |= BIT(3);
35062306a36Sopenharmony_ci	if (secy->tx_sc.end_station)
35162306a36Sopenharmony_ci		sc_rec.tci |= BIT(4);
35262306a36Sopenharmony_ci	/* The C bit is clear if and only if the Secure Data is
35362306a36Sopenharmony_ci	 * exactly the same as the User Data and the ICV is 16 octets long.
35462306a36Sopenharmony_ci	 */
35562306a36Sopenharmony_ci	if (!(secy->icv_len == 16 && !secy->tx_sc.encrypt))
35662306a36Sopenharmony_ci		sc_rec.tci |= BIT(0);
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	sc_rec.an_roll = 0;
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	switch (secy->key_len) {
36162306a36Sopenharmony_ci	case AQ_MACSEC_KEY_LEN_128_BIT:
36262306a36Sopenharmony_ci		sc_rec.sak_len = 0;
36362306a36Sopenharmony_ci		break;
36462306a36Sopenharmony_ci	case AQ_MACSEC_KEY_LEN_192_BIT:
36562306a36Sopenharmony_ci		sc_rec.sak_len = 1;
36662306a36Sopenharmony_ci		break;
36762306a36Sopenharmony_ci	case AQ_MACSEC_KEY_LEN_256_BIT:
36862306a36Sopenharmony_ci		sc_rec.sak_len = 2;
36962306a36Sopenharmony_ci		break;
37062306a36Sopenharmony_ci	default:
37162306a36Sopenharmony_ci		WARN_ONCE(true, "Invalid sc_sa");
37262306a36Sopenharmony_ci		return -EINVAL;
37362306a36Sopenharmony_ci	}
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	sc_rec.curr_an = secy->tx_sc.encoding_sa;
37662306a36Sopenharmony_ci	sc_rec.valid = 1;
37762306a36Sopenharmony_ci	sc_rec.fresh = 1;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	return aq_mss_set_egress_sc_record(hw, &sc_rec, sc_idx);
38062306a36Sopenharmony_ci}
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_cistatic u32 aq_sc_idx_max(const enum aq_macsec_sc_sa sc_sa)
38362306a36Sopenharmony_ci{
38462306a36Sopenharmony_ci	u32 result = 0;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	switch (sc_sa) {
38762306a36Sopenharmony_ci	case aq_macsec_sa_sc_4sa_8sc:
38862306a36Sopenharmony_ci		result = 8;
38962306a36Sopenharmony_ci		break;
39062306a36Sopenharmony_ci	case aq_macsec_sa_sc_2sa_16sc:
39162306a36Sopenharmony_ci		result = 16;
39262306a36Sopenharmony_ci		break;
39362306a36Sopenharmony_ci	case aq_macsec_sa_sc_1sa_32sc:
39462306a36Sopenharmony_ci		result = 32;
39562306a36Sopenharmony_ci		break;
39662306a36Sopenharmony_ci	default:
39762306a36Sopenharmony_ci		break;
39862306a36Sopenharmony_ci	}
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	return result;
40162306a36Sopenharmony_ci}
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_cistatic u32 aq_to_hw_sc_idx(const u32 sc_idx, const enum aq_macsec_sc_sa sc_sa)
40462306a36Sopenharmony_ci{
40562306a36Sopenharmony_ci	switch (sc_sa) {
40662306a36Sopenharmony_ci	case aq_macsec_sa_sc_4sa_8sc:
40762306a36Sopenharmony_ci		return sc_idx << 2;
40862306a36Sopenharmony_ci	case aq_macsec_sa_sc_2sa_16sc:
40962306a36Sopenharmony_ci		return sc_idx << 1;
41062306a36Sopenharmony_ci	case aq_macsec_sa_sc_1sa_32sc:
41162306a36Sopenharmony_ci		return sc_idx;
41262306a36Sopenharmony_ci	default:
41362306a36Sopenharmony_ci		WARN_ONCE(true, "Invalid sc_sa");
41462306a36Sopenharmony_ci	}
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	return sc_idx;
41762306a36Sopenharmony_ci}
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_cistatic enum aq_macsec_sc_sa sc_sa_from_num_an(const int num_an)
42062306a36Sopenharmony_ci{
42162306a36Sopenharmony_ci	enum aq_macsec_sc_sa sc_sa = aq_macsec_sa_sc_not_used;
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	switch (num_an) {
42462306a36Sopenharmony_ci	case 4:
42562306a36Sopenharmony_ci		sc_sa = aq_macsec_sa_sc_4sa_8sc;
42662306a36Sopenharmony_ci		break;
42762306a36Sopenharmony_ci	case 2:
42862306a36Sopenharmony_ci		sc_sa = aq_macsec_sa_sc_2sa_16sc;
42962306a36Sopenharmony_ci		break;
43062306a36Sopenharmony_ci	case 1:
43162306a36Sopenharmony_ci		sc_sa = aq_macsec_sa_sc_1sa_32sc;
43262306a36Sopenharmony_ci		break;
43362306a36Sopenharmony_ci	default:
43462306a36Sopenharmony_ci		break;
43562306a36Sopenharmony_ci	}
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	return sc_sa;
43862306a36Sopenharmony_ci}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_cistatic int aq_mdo_add_secy(struct macsec_context *ctx)
44162306a36Sopenharmony_ci{
44262306a36Sopenharmony_ci	struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev);
44362306a36Sopenharmony_ci	struct aq_macsec_cfg *cfg = nic->macsec_cfg;
44462306a36Sopenharmony_ci	const struct macsec_secy *secy = ctx->secy;
44562306a36Sopenharmony_ci	enum aq_macsec_sc_sa sc_sa;
44662306a36Sopenharmony_ci	u32 txsc_idx;
44762306a36Sopenharmony_ci	int ret = 0;
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	if (secy->xpn)
45062306a36Sopenharmony_ci		return -EOPNOTSUPP;
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	sc_sa = sc_sa_from_num_an(MACSEC_NUM_AN);
45362306a36Sopenharmony_ci	if (sc_sa == aq_macsec_sa_sc_not_used)
45462306a36Sopenharmony_ci		return -EINVAL;
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	if (hweight32(cfg->txsc_idx_busy) >= aq_sc_idx_max(sc_sa))
45762306a36Sopenharmony_ci		return -ENOSPC;
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	txsc_idx = ffz(cfg->txsc_idx_busy);
46062306a36Sopenharmony_ci	if (txsc_idx == AQ_MACSEC_MAX_SC)
46162306a36Sopenharmony_ci		return -ENOSPC;
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	cfg->sc_sa = sc_sa;
46462306a36Sopenharmony_ci	cfg->aq_txsc[txsc_idx].hw_sc_idx = aq_to_hw_sc_idx(txsc_idx, sc_sa);
46562306a36Sopenharmony_ci	cfg->aq_txsc[txsc_idx].sw_secy = secy;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	if (netif_carrier_ok(nic->ndev) && netif_running(secy->netdev))
46862306a36Sopenharmony_ci		ret = aq_set_txsc(nic, txsc_idx);
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	set_bit(txsc_idx, &cfg->txsc_idx_busy);
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	return ret;
47362306a36Sopenharmony_ci}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_cistatic int aq_mdo_upd_secy(struct macsec_context *ctx)
47662306a36Sopenharmony_ci{
47762306a36Sopenharmony_ci	struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev);
47862306a36Sopenharmony_ci	const struct macsec_secy *secy = ctx->secy;
47962306a36Sopenharmony_ci	int txsc_idx;
48062306a36Sopenharmony_ci	int ret = 0;
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	txsc_idx = aq_get_txsc_idx_from_secy(nic->macsec_cfg, secy);
48362306a36Sopenharmony_ci	if (txsc_idx < 0)
48462306a36Sopenharmony_ci		return -ENOENT;
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	if (netif_carrier_ok(nic->ndev) && netif_running(secy->netdev))
48762306a36Sopenharmony_ci		ret = aq_set_txsc(nic, txsc_idx);
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	return ret;
49062306a36Sopenharmony_ci}
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_cistatic int aq_clear_txsc(struct aq_nic_s *nic, const int txsc_idx,
49362306a36Sopenharmony_ci			 enum aq_clear_type clear_type)
49462306a36Sopenharmony_ci{
49562306a36Sopenharmony_ci	struct aq_macsec_txsc *tx_sc = &nic->macsec_cfg->aq_txsc[txsc_idx];
49662306a36Sopenharmony_ci	struct aq_mss_egress_class_record tx_class_rec = { 0 };
49762306a36Sopenharmony_ci	struct aq_mss_egress_sc_record sc_rec = { 0 };
49862306a36Sopenharmony_ci	struct aq_hw_s *hw = nic->aq_hw;
49962306a36Sopenharmony_ci	int ret = 0;
50062306a36Sopenharmony_ci	int sa_num;
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	for_each_set_bit (sa_num, &tx_sc->tx_sa_idx_busy, AQ_MACSEC_MAX_SA) {
50362306a36Sopenharmony_ci		ret = aq_clear_txsa(nic, tx_sc, sa_num, clear_type);
50462306a36Sopenharmony_ci		if (ret)
50562306a36Sopenharmony_ci			return ret;
50662306a36Sopenharmony_ci	}
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	if (clear_type & AQ_CLEAR_HW) {
50962306a36Sopenharmony_ci		ret = aq_mss_set_egress_class_record(hw, &tx_class_rec,
51062306a36Sopenharmony_ci						     txsc_idx);
51162306a36Sopenharmony_ci		if (ret)
51262306a36Sopenharmony_ci			return ret;
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci		sc_rec.fresh = 1;
51562306a36Sopenharmony_ci		ret = aq_mss_set_egress_sc_record(hw, &sc_rec,
51662306a36Sopenharmony_ci						  tx_sc->hw_sc_idx);
51762306a36Sopenharmony_ci		if (ret)
51862306a36Sopenharmony_ci			return ret;
51962306a36Sopenharmony_ci	}
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	if (clear_type & AQ_CLEAR_SW) {
52262306a36Sopenharmony_ci		clear_bit(txsc_idx, &nic->macsec_cfg->txsc_idx_busy);
52362306a36Sopenharmony_ci		nic->macsec_cfg->aq_txsc[txsc_idx].sw_secy = NULL;
52462306a36Sopenharmony_ci	}
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	return ret;
52762306a36Sopenharmony_ci}
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_cistatic int aq_mdo_del_secy(struct macsec_context *ctx)
53062306a36Sopenharmony_ci{
53162306a36Sopenharmony_ci	struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev);
53262306a36Sopenharmony_ci	int ret = 0;
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	if (!nic->macsec_cfg)
53562306a36Sopenharmony_ci		return 0;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	ret = aq_clear_secy(nic, ctx->secy, AQ_CLEAR_ALL);
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	return ret;
54062306a36Sopenharmony_ci}
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_cistatic int aq_update_txsa(struct aq_nic_s *nic, const unsigned int sc_idx,
54362306a36Sopenharmony_ci			  const struct macsec_secy *secy,
54462306a36Sopenharmony_ci			  const struct macsec_tx_sa *tx_sa,
54562306a36Sopenharmony_ci			  const unsigned char *key, const unsigned char an)
54662306a36Sopenharmony_ci{
54762306a36Sopenharmony_ci	const u32 next_pn = tx_sa->next_pn_halves.lower;
54862306a36Sopenharmony_ci	struct aq_mss_egress_sakey_record key_rec;
54962306a36Sopenharmony_ci	const unsigned int sa_idx = sc_idx | an;
55062306a36Sopenharmony_ci	struct aq_mss_egress_sa_record sa_rec;
55162306a36Sopenharmony_ci	struct aq_hw_s *hw = nic->aq_hw;
55262306a36Sopenharmony_ci	int ret = 0;
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	memset(&sa_rec, 0, sizeof(sa_rec));
55562306a36Sopenharmony_ci	sa_rec.valid = tx_sa->active;
55662306a36Sopenharmony_ci	sa_rec.fresh = 1;
55762306a36Sopenharmony_ci	sa_rec.next_pn = next_pn;
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	ret = aq_mss_set_egress_sa_record(hw, &sa_rec, sa_idx);
56062306a36Sopenharmony_ci	if (ret)
56162306a36Sopenharmony_ci		return ret;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	if (!key)
56462306a36Sopenharmony_ci		return ret;
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	memset(&key_rec, 0, sizeof(key_rec));
56762306a36Sopenharmony_ci	memcpy(&key_rec.key, key, secy->key_len);
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	aq_rotate_keys(&key_rec.key, secy->key_len);
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	ret = aq_mss_set_egress_sakey_record(hw, &key_rec, sa_idx);
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	memzero_explicit(&key_rec, sizeof(key_rec));
57462306a36Sopenharmony_ci	return ret;
57562306a36Sopenharmony_ci}
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_cistatic int aq_mdo_add_txsa(struct macsec_context *ctx)
57862306a36Sopenharmony_ci{
57962306a36Sopenharmony_ci	struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev);
58062306a36Sopenharmony_ci	struct aq_macsec_cfg *cfg = nic->macsec_cfg;
58162306a36Sopenharmony_ci	const struct macsec_secy *secy = ctx->secy;
58262306a36Sopenharmony_ci	struct aq_macsec_txsc *aq_txsc;
58362306a36Sopenharmony_ci	int txsc_idx;
58462306a36Sopenharmony_ci	int ret = 0;
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	txsc_idx = aq_get_txsc_idx_from_secy(cfg, secy);
58762306a36Sopenharmony_ci	if (txsc_idx < 0)
58862306a36Sopenharmony_ci		return -EINVAL;
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	aq_txsc = &cfg->aq_txsc[txsc_idx];
59162306a36Sopenharmony_ci	set_bit(ctx->sa.assoc_num, &aq_txsc->tx_sa_idx_busy);
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	memcpy(aq_txsc->tx_sa_key[ctx->sa.assoc_num], ctx->sa.key,
59462306a36Sopenharmony_ci	       secy->key_len);
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	if (netif_carrier_ok(nic->ndev) && netif_running(secy->netdev))
59762306a36Sopenharmony_ci		ret = aq_update_txsa(nic, aq_txsc->hw_sc_idx, secy,
59862306a36Sopenharmony_ci				     ctx->sa.tx_sa, ctx->sa.key,
59962306a36Sopenharmony_ci				     ctx->sa.assoc_num);
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	return ret;
60262306a36Sopenharmony_ci}
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_cistatic int aq_mdo_upd_txsa(struct macsec_context *ctx)
60562306a36Sopenharmony_ci{
60662306a36Sopenharmony_ci	struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev);
60762306a36Sopenharmony_ci	struct aq_macsec_cfg *cfg = nic->macsec_cfg;
60862306a36Sopenharmony_ci	const struct macsec_secy *secy = ctx->secy;
60962306a36Sopenharmony_ci	struct aq_macsec_txsc *aq_txsc;
61062306a36Sopenharmony_ci	int txsc_idx;
61162306a36Sopenharmony_ci	int ret = 0;
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	txsc_idx = aq_get_txsc_idx_from_secy(cfg, secy);
61462306a36Sopenharmony_ci	if (txsc_idx < 0)
61562306a36Sopenharmony_ci		return -EINVAL;
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	aq_txsc = &cfg->aq_txsc[txsc_idx];
61862306a36Sopenharmony_ci	if (netif_carrier_ok(nic->ndev) && netif_running(secy->netdev))
61962306a36Sopenharmony_ci		ret = aq_update_txsa(nic, aq_txsc->hw_sc_idx, secy,
62062306a36Sopenharmony_ci				     ctx->sa.tx_sa, NULL, ctx->sa.assoc_num);
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	return ret;
62362306a36Sopenharmony_ci}
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_cistatic int aq_clear_txsa(struct aq_nic_s *nic, struct aq_macsec_txsc *aq_txsc,
62662306a36Sopenharmony_ci			 const int sa_num, enum aq_clear_type clear_type)
62762306a36Sopenharmony_ci{
62862306a36Sopenharmony_ci	const int sa_idx = aq_txsc->hw_sc_idx | sa_num;
62962306a36Sopenharmony_ci	struct aq_hw_s *hw = nic->aq_hw;
63062306a36Sopenharmony_ci	int ret = 0;
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	if (clear_type & AQ_CLEAR_SW)
63362306a36Sopenharmony_ci		clear_bit(sa_num, &aq_txsc->tx_sa_idx_busy);
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	if ((clear_type & AQ_CLEAR_HW) && netif_carrier_ok(nic->ndev)) {
63662306a36Sopenharmony_ci		struct aq_mss_egress_sakey_record key_rec;
63762306a36Sopenharmony_ci		struct aq_mss_egress_sa_record sa_rec;
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci		memset(&sa_rec, 0, sizeof(sa_rec));
64062306a36Sopenharmony_ci		sa_rec.fresh = 1;
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci		ret = aq_mss_set_egress_sa_record(hw, &sa_rec, sa_idx);
64362306a36Sopenharmony_ci		if (ret)
64462306a36Sopenharmony_ci			return ret;
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci		memset(&key_rec, 0, sizeof(key_rec));
64762306a36Sopenharmony_ci		return aq_mss_set_egress_sakey_record(hw, &key_rec, sa_idx);
64862306a36Sopenharmony_ci	}
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	return 0;
65162306a36Sopenharmony_ci}
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_cistatic int aq_mdo_del_txsa(struct macsec_context *ctx)
65462306a36Sopenharmony_ci{
65562306a36Sopenharmony_ci	struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev);
65662306a36Sopenharmony_ci	struct aq_macsec_cfg *cfg = nic->macsec_cfg;
65762306a36Sopenharmony_ci	int txsc_idx;
65862306a36Sopenharmony_ci	int ret = 0;
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	txsc_idx = aq_get_txsc_idx_from_secy(cfg, ctx->secy);
66162306a36Sopenharmony_ci	if (txsc_idx < 0)
66262306a36Sopenharmony_ci		return -EINVAL;
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	ret = aq_clear_txsa(nic, &cfg->aq_txsc[txsc_idx], ctx->sa.assoc_num,
66562306a36Sopenharmony_ci			    AQ_CLEAR_ALL);
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	return ret;
66862306a36Sopenharmony_ci}
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_cistatic int aq_rxsc_validate_frames(const enum macsec_validation_type validate)
67162306a36Sopenharmony_ci{
67262306a36Sopenharmony_ci	switch (validate) {
67362306a36Sopenharmony_ci	case MACSEC_VALIDATE_DISABLED:
67462306a36Sopenharmony_ci		return 2;
67562306a36Sopenharmony_ci	case MACSEC_VALIDATE_CHECK:
67662306a36Sopenharmony_ci		return 1;
67762306a36Sopenharmony_ci	case MACSEC_VALIDATE_STRICT:
67862306a36Sopenharmony_ci		return 0;
67962306a36Sopenharmony_ci	default:
68062306a36Sopenharmony_ci		WARN_ONCE(true, "Invalid validation type");
68162306a36Sopenharmony_ci	}
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	return 0;
68462306a36Sopenharmony_ci}
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_cistatic int aq_set_rxsc(struct aq_nic_s *nic, const u32 rxsc_idx)
68762306a36Sopenharmony_ci{
68862306a36Sopenharmony_ci	const struct aq_macsec_rxsc *aq_rxsc =
68962306a36Sopenharmony_ci		&nic->macsec_cfg->aq_rxsc[rxsc_idx];
69062306a36Sopenharmony_ci	struct aq_mss_ingress_preclass_record pre_class_record;
69162306a36Sopenharmony_ci	const struct macsec_rx_sc *rx_sc = aq_rxsc->sw_rxsc;
69262306a36Sopenharmony_ci	const struct macsec_secy *secy = aq_rxsc->sw_secy;
69362306a36Sopenharmony_ci	const u32 hw_sc_idx = aq_rxsc->hw_sc_idx;
69462306a36Sopenharmony_ci	struct aq_mss_ingress_sc_record sc_record;
69562306a36Sopenharmony_ci	struct aq_hw_s *hw = nic->aq_hw;
69662306a36Sopenharmony_ci	int ret = 0;
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	memset(&pre_class_record, 0, sizeof(pre_class_record));
69962306a36Sopenharmony_ci	put_unaligned_be64((__force u64)rx_sc->sci, pre_class_record.sci);
70062306a36Sopenharmony_ci	pre_class_record.sci_mask = 0xff;
70162306a36Sopenharmony_ci	/* match all MACSEC ethertype packets */
70262306a36Sopenharmony_ci	pre_class_record.eth_type = ETH_P_MACSEC;
70362306a36Sopenharmony_ci	pre_class_record.eth_type_mask = 0x3;
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	aq_ether_addr_to_mac(pre_class_record.mac_sa, (char *)&rx_sc->sci);
70662306a36Sopenharmony_ci	pre_class_record.sa_mask = 0x3f;
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	pre_class_record.an_mask = nic->macsec_cfg->sc_sa;
70962306a36Sopenharmony_ci	pre_class_record.sc_idx = hw_sc_idx;
71062306a36Sopenharmony_ci	/* strip SecTAG & forward for decryption */
71162306a36Sopenharmony_ci	pre_class_record.action = 0x0;
71262306a36Sopenharmony_ci	pre_class_record.valid = 1;
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	ret = aq_mss_set_ingress_preclass_record(hw, &pre_class_record,
71562306a36Sopenharmony_ci						 2 * rxsc_idx + 1);
71662306a36Sopenharmony_ci	if (ret)
71762306a36Sopenharmony_ci		return ret;
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	/* If SCI is absent, then match by SA alone */
72062306a36Sopenharmony_ci	pre_class_record.sci_mask = 0;
72162306a36Sopenharmony_ci	pre_class_record.sci_from_table = 1;
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	ret = aq_mss_set_ingress_preclass_record(hw, &pre_class_record,
72462306a36Sopenharmony_ci						 2 * rxsc_idx);
72562306a36Sopenharmony_ci	if (ret)
72662306a36Sopenharmony_ci		return ret;
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	memset(&sc_record, 0, sizeof(sc_record));
72962306a36Sopenharmony_ci	sc_record.validate_frames =
73062306a36Sopenharmony_ci		aq_rxsc_validate_frames(secy->validate_frames);
73162306a36Sopenharmony_ci	if (secy->replay_protect) {
73262306a36Sopenharmony_ci		sc_record.replay_protect = 1;
73362306a36Sopenharmony_ci		sc_record.anti_replay_window = secy->replay_window;
73462306a36Sopenharmony_ci	}
73562306a36Sopenharmony_ci	sc_record.valid = 1;
73662306a36Sopenharmony_ci	sc_record.fresh = 1;
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	ret = aq_mss_set_ingress_sc_record(hw, &sc_record, hw_sc_idx);
73962306a36Sopenharmony_ci	if (ret)
74062306a36Sopenharmony_ci		return ret;
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	return ret;
74362306a36Sopenharmony_ci}
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_cistatic int aq_mdo_add_rxsc(struct macsec_context *ctx)
74662306a36Sopenharmony_ci{
74762306a36Sopenharmony_ci	struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev);
74862306a36Sopenharmony_ci	struct aq_macsec_cfg *cfg = nic->macsec_cfg;
74962306a36Sopenharmony_ci	const u32 rxsc_idx_max = aq_sc_idx_max(cfg->sc_sa);
75062306a36Sopenharmony_ci	u32 rxsc_idx;
75162306a36Sopenharmony_ci	int ret = 0;
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci	if (hweight32(cfg->rxsc_idx_busy) >= rxsc_idx_max)
75462306a36Sopenharmony_ci		return -ENOSPC;
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	rxsc_idx = ffz(cfg->rxsc_idx_busy);
75762306a36Sopenharmony_ci	if (rxsc_idx >= rxsc_idx_max)
75862306a36Sopenharmony_ci		return -ENOSPC;
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	cfg->aq_rxsc[rxsc_idx].hw_sc_idx = aq_to_hw_sc_idx(rxsc_idx,
76162306a36Sopenharmony_ci							   cfg->sc_sa);
76262306a36Sopenharmony_ci	cfg->aq_rxsc[rxsc_idx].sw_secy = ctx->secy;
76362306a36Sopenharmony_ci	cfg->aq_rxsc[rxsc_idx].sw_rxsc = ctx->rx_sc;
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	if (netif_carrier_ok(nic->ndev) && netif_running(ctx->secy->netdev))
76662306a36Sopenharmony_ci		ret = aq_set_rxsc(nic, rxsc_idx);
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	if (ret < 0)
76962306a36Sopenharmony_ci		return ret;
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci	set_bit(rxsc_idx, &cfg->rxsc_idx_busy);
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	return 0;
77462306a36Sopenharmony_ci}
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_cistatic int aq_mdo_upd_rxsc(struct macsec_context *ctx)
77762306a36Sopenharmony_ci{
77862306a36Sopenharmony_ci	struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev);
77962306a36Sopenharmony_ci	int rxsc_idx;
78062306a36Sopenharmony_ci	int ret = 0;
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	rxsc_idx = aq_get_rxsc_idx_from_rxsc(nic->macsec_cfg, ctx->rx_sc);
78362306a36Sopenharmony_ci	if (rxsc_idx < 0)
78462306a36Sopenharmony_ci		return -ENOENT;
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci	if (netif_carrier_ok(nic->ndev) && netif_running(ctx->secy->netdev))
78762306a36Sopenharmony_ci		ret = aq_set_rxsc(nic, rxsc_idx);
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	return ret;
79062306a36Sopenharmony_ci}
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_cistatic int aq_clear_rxsc(struct aq_nic_s *nic, const int rxsc_idx,
79362306a36Sopenharmony_ci			 enum aq_clear_type clear_type)
79462306a36Sopenharmony_ci{
79562306a36Sopenharmony_ci	struct aq_macsec_rxsc *rx_sc = &nic->macsec_cfg->aq_rxsc[rxsc_idx];
79662306a36Sopenharmony_ci	struct aq_hw_s *hw = nic->aq_hw;
79762306a36Sopenharmony_ci	int ret = 0;
79862306a36Sopenharmony_ci	int sa_num;
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	for_each_set_bit (sa_num, &rx_sc->rx_sa_idx_busy, AQ_MACSEC_MAX_SA) {
80162306a36Sopenharmony_ci		ret = aq_clear_rxsa(nic, rx_sc, sa_num, clear_type);
80262306a36Sopenharmony_ci		if (ret)
80362306a36Sopenharmony_ci			return ret;
80462306a36Sopenharmony_ci	}
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci	if (clear_type & AQ_CLEAR_HW) {
80762306a36Sopenharmony_ci		struct aq_mss_ingress_preclass_record pre_class_record;
80862306a36Sopenharmony_ci		struct aq_mss_ingress_sc_record sc_record;
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci		memset(&pre_class_record, 0, sizeof(pre_class_record));
81162306a36Sopenharmony_ci		memset(&sc_record, 0, sizeof(sc_record));
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci		ret = aq_mss_set_ingress_preclass_record(hw, &pre_class_record,
81462306a36Sopenharmony_ci							 2 * rxsc_idx);
81562306a36Sopenharmony_ci		if (ret)
81662306a36Sopenharmony_ci			return ret;
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci		ret = aq_mss_set_ingress_preclass_record(hw, &pre_class_record,
81962306a36Sopenharmony_ci							 2 * rxsc_idx + 1);
82062306a36Sopenharmony_ci		if (ret)
82162306a36Sopenharmony_ci			return ret;
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci		sc_record.fresh = 1;
82462306a36Sopenharmony_ci		ret = aq_mss_set_ingress_sc_record(hw, &sc_record,
82562306a36Sopenharmony_ci						   rx_sc->hw_sc_idx);
82662306a36Sopenharmony_ci		if (ret)
82762306a36Sopenharmony_ci			return ret;
82862306a36Sopenharmony_ci	}
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	if (clear_type & AQ_CLEAR_SW) {
83162306a36Sopenharmony_ci		clear_bit(rxsc_idx, &nic->macsec_cfg->rxsc_idx_busy);
83262306a36Sopenharmony_ci		rx_sc->sw_secy = NULL;
83362306a36Sopenharmony_ci		rx_sc->sw_rxsc = NULL;
83462306a36Sopenharmony_ci	}
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	return ret;
83762306a36Sopenharmony_ci}
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_cistatic int aq_mdo_del_rxsc(struct macsec_context *ctx)
84062306a36Sopenharmony_ci{
84162306a36Sopenharmony_ci	struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev);
84262306a36Sopenharmony_ci	enum aq_clear_type clear_type = AQ_CLEAR_SW;
84362306a36Sopenharmony_ci	int rxsc_idx;
84462306a36Sopenharmony_ci	int ret = 0;
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	rxsc_idx = aq_get_rxsc_idx_from_rxsc(nic->macsec_cfg, ctx->rx_sc);
84762306a36Sopenharmony_ci	if (rxsc_idx < 0)
84862306a36Sopenharmony_ci		return -ENOENT;
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci	if (netif_carrier_ok(nic->ndev))
85162306a36Sopenharmony_ci		clear_type = AQ_CLEAR_ALL;
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	ret = aq_clear_rxsc(nic, rxsc_idx, clear_type);
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	return ret;
85662306a36Sopenharmony_ci}
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_cistatic int aq_update_rxsa(struct aq_nic_s *nic, const unsigned int sc_idx,
85962306a36Sopenharmony_ci			  const struct macsec_secy *secy,
86062306a36Sopenharmony_ci			  const struct macsec_rx_sa *rx_sa,
86162306a36Sopenharmony_ci			  const unsigned char *key, const unsigned char an)
86262306a36Sopenharmony_ci{
86362306a36Sopenharmony_ci	struct aq_mss_ingress_sakey_record sa_key_record;
86462306a36Sopenharmony_ci	const u32 next_pn = rx_sa->next_pn_halves.lower;
86562306a36Sopenharmony_ci	struct aq_mss_ingress_sa_record sa_record;
86662306a36Sopenharmony_ci	struct aq_hw_s *hw = nic->aq_hw;
86762306a36Sopenharmony_ci	const int sa_idx = sc_idx | an;
86862306a36Sopenharmony_ci	int ret = 0;
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	memset(&sa_record, 0, sizeof(sa_record));
87162306a36Sopenharmony_ci	sa_record.valid = rx_sa->active;
87262306a36Sopenharmony_ci	sa_record.fresh = 1;
87362306a36Sopenharmony_ci	sa_record.next_pn = next_pn;
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci	ret = aq_mss_set_ingress_sa_record(hw, &sa_record, sa_idx);
87662306a36Sopenharmony_ci	if (ret)
87762306a36Sopenharmony_ci		return ret;
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	if (!key)
88062306a36Sopenharmony_ci		return ret;
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci	memset(&sa_key_record, 0, sizeof(sa_key_record));
88362306a36Sopenharmony_ci	memcpy(&sa_key_record.key, key, secy->key_len);
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	switch (secy->key_len) {
88662306a36Sopenharmony_ci	case AQ_MACSEC_KEY_LEN_128_BIT:
88762306a36Sopenharmony_ci		sa_key_record.key_len = 0;
88862306a36Sopenharmony_ci		break;
88962306a36Sopenharmony_ci	case AQ_MACSEC_KEY_LEN_192_BIT:
89062306a36Sopenharmony_ci		sa_key_record.key_len = 1;
89162306a36Sopenharmony_ci		break;
89262306a36Sopenharmony_ci	case AQ_MACSEC_KEY_LEN_256_BIT:
89362306a36Sopenharmony_ci		sa_key_record.key_len = 2;
89462306a36Sopenharmony_ci		break;
89562306a36Sopenharmony_ci	default:
89662306a36Sopenharmony_ci		return -1;
89762306a36Sopenharmony_ci	}
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci	aq_rotate_keys(&sa_key_record.key, secy->key_len);
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	ret = aq_mss_set_ingress_sakey_record(hw, &sa_key_record, sa_idx);
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci	memzero_explicit(&sa_key_record, sizeof(sa_key_record));
90462306a36Sopenharmony_ci	return ret;
90562306a36Sopenharmony_ci}
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_cistatic int aq_mdo_add_rxsa(struct macsec_context *ctx)
90862306a36Sopenharmony_ci{
90962306a36Sopenharmony_ci	struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev);
91062306a36Sopenharmony_ci	const struct macsec_rx_sc *rx_sc = ctx->sa.rx_sa->sc;
91162306a36Sopenharmony_ci	const struct macsec_secy *secy = ctx->secy;
91262306a36Sopenharmony_ci	struct aq_macsec_rxsc *aq_rxsc;
91362306a36Sopenharmony_ci	int rxsc_idx;
91462306a36Sopenharmony_ci	int ret = 0;
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci	rxsc_idx = aq_get_rxsc_idx_from_rxsc(nic->macsec_cfg, rx_sc);
91762306a36Sopenharmony_ci	if (rxsc_idx < 0)
91862306a36Sopenharmony_ci		return -EINVAL;
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	aq_rxsc = &nic->macsec_cfg->aq_rxsc[rxsc_idx];
92162306a36Sopenharmony_ci	set_bit(ctx->sa.assoc_num, &aq_rxsc->rx_sa_idx_busy);
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	memcpy(aq_rxsc->rx_sa_key[ctx->sa.assoc_num], ctx->sa.key,
92462306a36Sopenharmony_ci	       secy->key_len);
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci	if (netif_carrier_ok(nic->ndev) && netif_running(secy->netdev))
92762306a36Sopenharmony_ci		ret = aq_update_rxsa(nic, aq_rxsc->hw_sc_idx, secy,
92862306a36Sopenharmony_ci				     ctx->sa.rx_sa, ctx->sa.key,
92962306a36Sopenharmony_ci				     ctx->sa.assoc_num);
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci	return ret;
93262306a36Sopenharmony_ci}
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_cistatic int aq_mdo_upd_rxsa(struct macsec_context *ctx)
93562306a36Sopenharmony_ci{
93662306a36Sopenharmony_ci	struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev);
93762306a36Sopenharmony_ci	const struct macsec_rx_sc *rx_sc = ctx->sa.rx_sa->sc;
93862306a36Sopenharmony_ci	struct aq_macsec_cfg *cfg = nic->macsec_cfg;
93962306a36Sopenharmony_ci	const struct macsec_secy *secy = ctx->secy;
94062306a36Sopenharmony_ci	int rxsc_idx;
94162306a36Sopenharmony_ci	int ret = 0;
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci	rxsc_idx = aq_get_rxsc_idx_from_rxsc(cfg, rx_sc);
94462306a36Sopenharmony_ci	if (rxsc_idx < 0)
94562306a36Sopenharmony_ci		return -EINVAL;
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	if (netif_carrier_ok(nic->ndev) && netif_running(secy->netdev))
94862306a36Sopenharmony_ci		ret = aq_update_rxsa(nic, cfg->aq_rxsc[rxsc_idx].hw_sc_idx,
94962306a36Sopenharmony_ci				     secy, ctx->sa.rx_sa, NULL,
95062306a36Sopenharmony_ci				     ctx->sa.assoc_num);
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci	return ret;
95362306a36Sopenharmony_ci}
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_cistatic int aq_clear_rxsa(struct aq_nic_s *nic, struct aq_macsec_rxsc *aq_rxsc,
95662306a36Sopenharmony_ci			 const int sa_num, enum aq_clear_type clear_type)
95762306a36Sopenharmony_ci{
95862306a36Sopenharmony_ci	int sa_idx = aq_rxsc->hw_sc_idx | sa_num;
95962306a36Sopenharmony_ci	struct aq_hw_s *hw = nic->aq_hw;
96062306a36Sopenharmony_ci	int ret = 0;
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci	if (clear_type & AQ_CLEAR_SW)
96362306a36Sopenharmony_ci		clear_bit(sa_num, &aq_rxsc->rx_sa_idx_busy);
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	if ((clear_type & AQ_CLEAR_HW) && netif_carrier_ok(nic->ndev)) {
96662306a36Sopenharmony_ci		struct aq_mss_ingress_sakey_record sa_key_record;
96762306a36Sopenharmony_ci		struct aq_mss_ingress_sa_record sa_record;
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci		memset(&sa_key_record, 0, sizeof(sa_key_record));
97062306a36Sopenharmony_ci		memset(&sa_record, 0, sizeof(sa_record));
97162306a36Sopenharmony_ci		sa_record.fresh = 1;
97262306a36Sopenharmony_ci		ret = aq_mss_set_ingress_sa_record(hw, &sa_record, sa_idx);
97362306a36Sopenharmony_ci		if (ret)
97462306a36Sopenharmony_ci			return ret;
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci		return aq_mss_set_ingress_sakey_record(hw, &sa_key_record,
97762306a36Sopenharmony_ci						       sa_idx);
97862306a36Sopenharmony_ci	}
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci	return ret;
98162306a36Sopenharmony_ci}
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_cistatic int aq_mdo_del_rxsa(struct macsec_context *ctx)
98462306a36Sopenharmony_ci{
98562306a36Sopenharmony_ci	struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev);
98662306a36Sopenharmony_ci	const struct macsec_rx_sc *rx_sc = ctx->sa.rx_sa->sc;
98762306a36Sopenharmony_ci	struct aq_macsec_cfg *cfg = nic->macsec_cfg;
98862306a36Sopenharmony_ci	int rxsc_idx;
98962306a36Sopenharmony_ci	int ret = 0;
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci	rxsc_idx = aq_get_rxsc_idx_from_rxsc(cfg, rx_sc);
99262306a36Sopenharmony_ci	if (rxsc_idx < 0)
99362306a36Sopenharmony_ci		return -EINVAL;
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	ret = aq_clear_rxsa(nic, &cfg->aq_rxsc[rxsc_idx], ctx->sa.assoc_num,
99662306a36Sopenharmony_ci			    AQ_CLEAR_ALL);
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci	return ret;
99962306a36Sopenharmony_ci}
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_cistatic int aq_mdo_get_dev_stats(struct macsec_context *ctx)
100262306a36Sopenharmony_ci{
100362306a36Sopenharmony_ci	struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev);
100462306a36Sopenharmony_ci	struct aq_macsec_common_stats *stats = &nic->macsec_cfg->stats;
100562306a36Sopenharmony_ci	struct aq_hw_s *hw = nic->aq_hw;
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci	aq_get_macsec_common_stats(hw, stats);
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	ctx->stats.dev_stats->OutPktsUntagged = stats->out.untagged_pkts;
101062306a36Sopenharmony_ci	ctx->stats.dev_stats->InPktsUntagged = stats->in.untagged_pkts;
101162306a36Sopenharmony_ci	ctx->stats.dev_stats->OutPktsTooLong = stats->out.too_long;
101262306a36Sopenharmony_ci	ctx->stats.dev_stats->InPktsNoTag = stats->in.notag_pkts;
101362306a36Sopenharmony_ci	ctx->stats.dev_stats->InPktsBadTag = stats->in.bad_tag_pkts;
101462306a36Sopenharmony_ci	ctx->stats.dev_stats->InPktsUnknownSCI = stats->in.unknown_sci_pkts;
101562306a36Sopenharmony_ci	ctx->stats.dev_stats->InPktsNoSCI = stats->in.no_sci_pkts;
101662306a36Sopenharmony_ci	ctx->stats.dev_stats->InPktsOverrun = 0;
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci	return 0;
101962306a36Sopenharmony_ci}
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_cistatic int aq_mdo_get_tx_sc_stats(struct macsec_context *ctx)
102262306a36Sopenharmony_ci{
102362306a36Sopenharmony_ci	struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev);
102462306a36Sopenharmony_ci	struct aq_macsec_tx_sc_stats *stats;
102562306a36Sopenharmony_ci	struct aq_hw_s *hw = nic->aq_hw;
102662306a36Sopenharmony_ci	struct aq_macsec_txsc *aq_txsc;
102762306a36Sopenharmony_ci	int txsc_idx;
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci	txsc_idx = aq_get_txsc_idx_from_secy(nic->macsec_cfg, ctx->secy);
103062306a36Sopenharmony_ci	if (txsc_idx < 0)
103162306a36Sopenharmony_ci		return -ENOENT;
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci	aq_txsc = &nic->macsec_cfg->aq_txsc[txsc_idx];
103462306a36Sopenharmony_ci	stats = &aq_txsc->stats;
103562306a36Sopenharmony_ci	aq_get_txsc_stats(hw, aq_txsc->hw_sc_idx, stats);
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_ci	ctx->stats.tx_sc_stats->OutPktsProtected = stats->sc_protected_pkts;
103862306a36Sopenharmony_ci	ctx->stats.tx_sc_stats->OutPktsEncrypted = stats->sc_encrypted_pkts;
103962306a36Sopenharmony_ci	ctx->stats.tx_sc_stats->OutOctetsProtected = stats->sc_protected_octets;
104062306a36Sopenharmony_ci	ctx->stats.tx_sc_stats->OutOctetsEncrypted = stats->sc_encrypted_octets;
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci	return 0;
104362306a36Sopenharmony_ci}
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_cistatic int aq_mdo_get_tx_sa_stats(struct macsec_context *ctx)
104662306a36Sopenharmony_ci{
104762306a36Sopenharmony_ci	struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev);
104862306a36Sopenharmony_ci	struct aq_macsec_cfg *cfg = nic->macsec_cfg;
104962306a36Sopenharmony_ci	struct aq_macsec_tx_sa_stats *stats;
105062306a36Sopenharmony_ci	struct aq_hw_s *hw = nic->aq_hw;
105162306a36Sopenharmony_ci	const struct macsec_secy *secy;
105262306a36Sopenharmony_ci	struct aq_macsec_txsc *aq_txsc;
105362306a36Sopenharmony_ci	struct macsec_tx_sa *tx_sa;
105462306a36Sopenharmony_ci	unsigned int sa_idx;
105562306a36Sopenharmony_ci	int txsc_idx;
105662306a36Sopenharmony_ci	u32 next_pn;
105762306a36Sopenharmony_ci	int ret;
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	txsc_idx = aq_get_txsc_idx_from_secy(cfg, ctx->secy);
106062306a36Sopenharmony_ci	if (txsc_idx < 0)
106162306a36Sopenharmony_ci		return -EINVAL;
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_ci	aq_txsc = &cfg->aq_txsc[txsc_idx];
106462306a36Sopenharmony_ci	sa_idx = aq_txsc->hw_sc_idx | ctx->sa.assoc_num;
106562306a36Sopenharmony_ci	stats = &aq_txsc->tx_sa_stats[ctx->sa.assoc_num];
106662306a36Sopenharmony_ci	ret = aq_get_txsa_stats(hw, sa_idx, stats);
106762306a36Sopenharmony_ci	if (ret)
106862306a36Sopenharmony_ci		return ret;
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci	ctx->stats.tx_sa_stats->OutPktsProtected = stats->sa_protected_pkts;
107162306a36Sopenharmony_ci	ctx->stats.tx_sa_stats->OutPktsEncrypted = stats->sa_encrypted_pkts;
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	secy = aq_txsc->sw_secy;
107462306a36Sopenharmony_ci	tx_sa = rcu_dereference_bh(secy->tx_sc.sa[ctx->sa.assoc_num]);
107562306a36Sopenharmony_ci	ret = aq_get_txsa_next_pn(hw, sa_idx, &next_pn);
107662306a36Sopenharmony_ci	if (ret == 0) {
107762306a36Sopenharmony_ci		spin_lock_bh(&tx_sa->lock);
107862306a36Sopenharmony_ci		tx_sa->next_pn = next_pn;
107962306a36Sopenharmony_ci		spin_unlock_bh(&tx_sa->lock);
108062306a36Sopenharmony_ci	}
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci	return ret;
108362306a36Sopenharmony_ci}
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_cistatic int aq_mdo_get_rx_sc_stats(struct macsec_context *ctx)
108662306a36Sopenharmony_ci{
108762306a36Sopenharmony_ci	struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev);
108862306a36Sopenharmony_ci	struct aq_macsec_cfg *cfg = nic->macsec_cfg;
108962306a36Sopenharmony_ci	struct aq_macsec_rx_sa_stats *stats;
109062306a36Sopenharmony_ci	struct aq_hw_s *hw = nic->aq_hw;
109162306a36Sopenharmony_ci	struct aq_macsec_rxsc *aq_rxsc;
109262306a36Sopenharmony_ci	unsigned int sa_idx;
109362306a36Sopenharmony_ci	int rxsc_idx;
109462306a36Sopenharmony_ci	int ret = 0;
109562306a36Sopenharmony_ci	int i;
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci	rxsc_idx = aq_get_rxsc_idx_from_rxsc(cfg, ctx->rx_sc);
109862306a36Sopenharmony_ci	if (rxsc_idx < 0)
109962306a36Sopenharmony_ci		return -ENOENT;
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci	aq_rxsc = &cfg->aq_rxsc[rxsc_idx];
110262306a36Sopenharmony_ci	for (i = 0; i < MACSEC_NUM_AN; i++) {
110362306a36Sopenharmony_ci		if (!test_bit(i, &aq_rxsc->rx_sa_idx_busy))
110462306a36Sopenharmony_ci			continue;
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci		stats = &aq_rxsc->rx_sa_stats[i];
110762306a36Sopenharmony_ci		sa_idx = aq_rxsc->hw_sc_idx | i;
110862306a36Sopenharmony_ci		ret = aq_get_rxsa_stats(hw, sa_idx, stats);
110962306a36Sopenharmony_ci		if (ret)
111062306a36Sopenharmony_ci			break;
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci		ctx->stats.rx_sc_stats->InOctetsValidated +=
111362306a36Sopenharmony_ci			stats->validated_octets;
111462306a36Sopenharmony_ci		ctx->stats.rx_sc_stats->InOctetsDecrypted +=
111562306a36Sopenharmony_ci			stats->decrypted_octets;
111662306a36Sopenharmony_ci		ctx->stats.rx_sc_stats->InPktsUnchecked +=
111762306a36Sopenharmony_ci			stats->unchecked_pkts;
111862306a36Sopenharmony_ci		ctx->stats.rx_sc_stats->InPktsDelayed += stats->delayed_pkts;
111962306a36Sopenharmony_ci		ctx->stats.rx_sc_stats->InPktsOK += stats->ok_pkts;
112062306a36Sopenharmony_ci		ctx->stats.rx_sc_stats->InPktsInvalid += stats->invalid_pkts;
112162306a36Sopenharmony_ci		ctx->stats.rx_sc_stats->InPktsLate += stats->late_pkts;
112262306a36Sopenharmony_ci		ctx->stats.rx_sc_stats->InPktsNotValid += stats->not_valid_pkts;
112362306a36Sopenharmony_ci		ctx->stats.rx_sc_stats->InPktsNotUsingSA += stats->not_using_sa;
112462306a36Sopenharmony_ci		ctx->stats.rx_sc_stats->InPktsUnusedSA += stats->unused_sa;
112562306a36Sopenharmony_ci	}
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ci	return ret;
112862306a36Sopenharmony_ci}
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_cistatic int aq_mdo_get_rx_sa_stats(struct macsec_context *ctx)
113162306a36Sopenharmony_ci{
113262306a36Sopenharmony_ci	struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev);
113362306a36Sopenharmony_ci	struct aq_macsec_cfg *cfg = nic->macsec_cfg;
113462306a36Sopenharmony_ci	struct aq_macsec_rx_sa_stats *stats;
113562306a36Sopenharmony_ci	struct aq_hw_s *hw = nic->aq_hw;
113662306a36Sopenharmony_ci	struct aq_macsec_rxsc *aq_rxsc;
113762306a36Sopenharmony_ci	struct macsec_rx_sa *rx_sa;
113862306a36Sopenharmony_ci	unsigned int sa_idx;
113962306a36Sopenharmony_ci	int rxsc_idx;
114062306a36Sopenharmony_ci	u32 next_pn;
114162306a36Sopenharmony_ci	int ret;
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci	rxsc_idx = aq_get_rxsc_idx_from_rxsc(cfg, ctx->rx_sc);
114462306a36Sopenharmony_ci	if (rxsc_idx < 0)
114562306a36Sopenharmony_ci		return -EINVAL;
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci	aq_rxsc = &cfg->aq_rxsc[rxsc_idx];
114862306a36Sopenharmony_ci	stats = &aq_rxsc->rx_sa_stats[ctx->sa.assoc_num];
114962306a36Sopenharmony_ci	sa_idx = aq_rxsc->hw_sc_idx | ctx->sa.assoc_num;
115062306a36Sopenharmony_ci	ret = aq_get_rxsa_stats(hw, sa_idx, stats);
115162306a36Sopenharmony_ci	if (ret)
115262306a36Sopenharmony_ci		return ret;
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci	ctx->stats.rx_sa_stats->InPktsOK = stats->ok_pkts;
115562306a36Sopenharmony_ci	ctx->stats.rx_sa_stats->InPktsInvalid = stats->invalid_pkts;
115662306a36Sopenharmony_ci	ctx->stats.rx_sa_stats->InPktsNotValid = stats->not_valid_pkts;
115762306a36Sopenharmony_ci	ctx->stats.rx_sa_stats->InPktsNotUsingSA = stats->not_using_sa;
115862306a36Sopenharmony_ci	ctx->stats.rx_sa_stats->InPktsUnusedSA = stats->unused_sa;
115962306a36Sopenharmony_ci
116062306a36Sopenharmony_ci	rx_sa = rcu_dereference_bh(aq_rxsc->sw_rxsc->sa[ctx->sa.assoc_num]);
116162306a36Sopenharmony_ci	ret = aq_get_rxsa_next_pn(hw, sa_idx, &next_pn);
116262306a36Sopenharmony_ci	if (ret == 0) {
116362306a36Sopenharmony_ci		spin_lock_bh(&rx_sa->lock);
116462306a36Sopenharmony_ci		rx_sa->next_pn = next_pn;
116562306a36Sopenharmony_ci		spin_unlock_bh(&rx_sa->lock);
116662306a36Sopenharmony_ci	}
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci	return ret;
116962306a36Sopenharmony_ci}
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_cistatic int apply_txsc_cfg(struct aq_nic_s *nic, const int txsc_idx)
117262306a36Sopenharmony_ci{
117362306a36Sopenharmony_ci	struct aq_macsec_txsc *aq_txsc = &nic->macsec_cfg->aq_txsc[txsc_idx];
117462306a36Sopenharmony_ci	const struct macsec_secy *secy = aq_txsc->sw_secy;
117562306a36Sopenharmony_ci	struct macsec_tx_sa *tx_sa;
117662306a36Sopenharmony_ci	int ret = 0;
117762306a36Sopenharmony_ci	int i;
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci	if (!netif_running(secy->netdev))
118062306a36Sopenharmony_ci		return ret;
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci	ret = aq_set_txsc(nic, txsc_idx);
118362306a36Sopenharmony_ci	if (ret)
118462306a36Sopenharmony_ci		return ret;
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci	for (i = 0; i < MACSEC_NUM_AN; i++) {
118762306a36Sopenharmony_ci		tx_sa = rcu_dereference_bh(secy->tx_sc.sa[i]);
118862306a36Sopenharmony_ci		if (tx_sa) {
118962306a36Sopenharmony_ci			ret = aq_update_txsa(nic, aq_txsc->hw_sc_idx, secy,
119062306a36Sopenharmony_ci					     tx_sa, aq_txsc->tx_sa_key[i], i);
119162306a36Sopenharmony_ci			if (ret)
119262306a36Sopenharmony_ci				return ret;
119362306a36Sopenharmony_ci		}
119462306a36Sopenharmony_ci	}
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ci	return ret;
119762306a36Sopenharmony_ci}
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_cistatic int apply_rxsc_cfg(struct aq_nic_s *nic, const int rxsc_idx)
120062306a36Sopenharmony_ci{
120162306a36Sopenharmony_ci	struct aq_macsec_rxsc *aq_rxsc = &nic->macsec_cfg->aq_rxsc[rxsc_idx];
120262306a36Sopenharmony_ci	const struct macsec_secy *secy = aq_rxsc->sw_secy;
120362306a36Sopenharmony_ci	struct macsec_rx_sa *rx_sa;
120462306a36Sopenharmony_ci	int ret = 0;
120562306a36Sopenharmony_ci	int i;
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci	if (!netif_running(secy->netdev))
120862306a36Sopenharmony_ci		return ret;
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_ci	ret = aq_set_rxsc(nic, rxsc_idx);
121162306a36Sopenharmony_ci	if (ret)
121262306a36Sopenharmony_ci		return ret;
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci	for (i = 0; i < MACSEC_NUM_AN; i++) {
121562306a36Sopenharmony_ci		rx_sa = rcu_dereference_bh(aq_rxsc->sw_rxsc->sa[i]);
121662306a36Sopenharmony_ci		if (rx_sa) {
121762306a36Sopenharmony_ci			ret = aq_update_rxsa(nic, aq_rxsc->hw_sc_idx, secy,
121862306a36Sopenharmony_ci					     rx_sa, aq_rxsc->rx_sa_key[i], i);
121962306a36Sopenharmony_ci			if (ret)
122062306a36Sopenharmony_ci				return ret;
122162306a36Sopenharmony_ci		}
122262306a36Sopenharmony_ci	}
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	return ret;
122562306a36Sopenharmony_ci}
122662306a36Sopenharmony_ci
122762306a36Sopenharmony_cistatic int aq_clear_secy(struct aq_nic_s *nic, const struct macsec_secy *secy,
122862306a36Sopenharmony_ci			 enum aq_clear_type clear_type)
122962306a36Sopenharmony_ci{
123062306a36Sopenharmony_ci	struct macsec_rx_sc *rx_sc;
123162306a36Sopenharmony_ci	int txsc_idx;
123262306a36Sopenharmony_ci	int rxsc_idx;
123362306a36Sopenharmony_ci	int ret = 0;
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci	txsc_idx = aq_get_txsc_idx_from_secy(nic->macsec_cfg, secy);
123662306a36Sopenharmony_ci	if (txsc_idx >= 0) {
123762306a36Sopenharmony_ci		ret = aq_clear_txsc(nic, txsc_idx, clear_type);
123862306a36Sopenharmony_ci		if (ret)
123962306a36Sopenharmony_ci			return ret;
124062306a36Sopenharmony_ci	}
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci	for (rx_sc = rcu_dereference_bh(secy->rx_sc); rx_sc;
124362306a36Sopenharmony_ci	     rx_sc = rcu_dereference_bh(rx_sc->next)) {
124462306a36Sopenharmony_ci		rxsc_idx = aq_get_rxsc_idx_from_rxsc(nic->macsec_cfg, rx_sc);
124562306a36Sopenharmony_ci		if (rxsc_idx < 0)
124662306a36Sopenharmony_ci			continue;
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci		ret = aq_clear_rxsc(nic, rxsc_idx, clear_type);
124962306a36Sopenharmony_ci		if (ret)
125062306a36Sopenharmony_ci			return ret;
125162306a36Sopenharmony_ci	}
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_ci	return ret;
125462306a36Sopenharmony_ci}
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_cistatic int aq_apply_secy_cfg(struct aq_nic_s *nic,
125762306a36Sopenharmony_ci			     const struct macsec_secy *secy)
125862306a36Sopenharmony_ci{
125962306a36Sopenharmony_ci	struct macsec_rx_sc *rx_sc;
126062306a36Sopenharmony_ci	int txsc_idx;
126162306a36Sopenharmony_ci	int rxsc_idx;
126262306a36Sopenharmony_ci	int ret = 0;
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci	txsc_idx = aq_get_txsc_idx_from_secy(nic->macsec_cfg, secy);
126562306a36Sopenharmony_ci	if (txsc_idx >= 0)
126662306a36Sopenharmony_ci		apply_txsc_cfg(nic, txsc_idx);
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci	for (rx_sc = rcu_dereference_bh(secy->rx_sc); rx_sc && rx_sc->active;
126962306a36Sopenharmony_ci	     rx_sc = rcu_dereference_bh(rx_sc->next)) {
127062306a36Sopenharmony_ci		rxsc_idx = aq_get_rxsc_idx_from_rxsc(nic->macsec_cfg, rx_sc);
127162306a36Sopenharmony_ci		if (unlikely(rxsc_idx < 0))
127262306a36Sopenharmony_ci			continue;
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_ci		ret = apply_rxsc_cfg(nic, rxsc_idx);
127562306a36Sopenharmony_ci		if (ret)
127662306a36Sopenharmony_ci			return ret;
127762306a36Sopenharmony_ci	}
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_ci	return ret;
128062306a36Sopenharmony_ci}
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_cistatic int aq_apply_macsec_cfg(struct aq_nic_s *nic)
128362306a36Sopenharmony_ci{
128462306a36Sopenharmony_ci	int ret = 0;
128562306a36Sopenharmony_ci	int i;
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci	for (i = 0; i < AQ_MACSEC_MAX_SC; i++) {
128862306a36Sopenharmony_ci		if (nic->macsec_cfg->txsc_idx_busy & BIT(i)) {
128962306a36Sopenharmony_ci			ret = apply_txsc_cfg(nic, i);
129062306a36Sopenharmony_ci			if (ret)
129162306a36Sopenharmony_ci				return ret;
129262306a36Sopenharmony_ci		}
129362306a36Sopenharmony_ci	}
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci	for (i = 0; i < AQ_MACSEC_MAX_SC; i++) {
129662306a36Sopenharmony_ci		if (nic->macsec_cfg->rxsc_idx_busy & BIT(i)) {
129762306a36Sopenharmony_ci			ret = apply_rxsc_cfg(nic, i);
129862306a36Sopenharmony_ci			if (ret)
129962306a36Sopenharmony_ci				return ret;
130062306a36Sopenharmony_ci		}
130162306a36Sopenharmony_ci	}
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci	return ret;
130462306a36Sopenharmony_ci}
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_cistatic int aq_sa_from_sa_idx(const enum aq_macsec_sc_sa sc_sa, const int sa_idx)
130762306a36Sopenharmony_ci{
130862306a36Sopenharmony_ci	switch (sc_sa) {
130962306a36Sopenharmony_ci	case aq_macsec_sa_sc_4sa_8sc:
131062306a36Sopenharmony_ci		return sa_idx & 3;
131162306a36Sopenharmony_ci	case aq_macsec_sa_sc_2sa_16sc:
131262306a36Sopenharmony_ci		return sa_idx & 1;
131362306a36Sopenharmony_ci	case aq_macsec_sa_sc_1sa_32sc:
131462306a36Sopenharmony_ci		return 0;
131562306a36Sopenharmony_ci	default:
131662306a36Sopenharmony_ci		WARN_ONCE(true, "Invalid sc_sa");
131762306a36Sopenharmony_ci	}
131862306a36Sopenharmony_ci	return -EINVAL;
131962306a36Sopenharmony_ci}
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_cistatic int aq_sc_idx_from_sa_idx(const enum aq_macsec_sc_sa sc_sa,
132262306a36Sopenharmony_ci				 const int sa_idx)
132362306a36Sopenharmony_ci{
132462306a36Sopenharmony_ci	switch (sc_sa) {
132562306a36Sopenharmony_ci	case aq_macsec_sa_sc_4sa_8sc:
132662306a36Sopenharmony_ci		return sa_idx & ~3;
132762306a36Sopenharmony_ci	case aq_macsec_sa_sc_2sa_16sc:
132862306a36Sopenharmony_ci		return sa_idx & ~1;
132962306a36Sopenharmony_ci	case aq_macsec_sa_sc_1sa_32sc:
133062306a36Sopenharmony_ci		return sa_idx;
133162306a36Sopenharmony_ci	default:
133262306a36Sopenharmony_ci		WARN_ONCE(true, "Invalid sc_sa");
133362306a36Sopenharmony_ci	}
133462306a36Sopenharmony_ci	return -EINVAL;
133562306a36Sopenharmony_ci}
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_cistatic void aq_check_txsa_expiration(struct aq_nic_s *nic)
133862306a36Sopenharmony_ci{
133962306a36Sopenharmony_ci	u32 egress_sa_expired, egress_sa_threshold_expired;
134062306a36Sopenharmony_ci	struct aq_macsec_cfg *cfg = nic->macsec_cfg;
134162306a36Sopenharmony_ci	struct aq_hw_s *hw = nic->aq_hw;
134262306a36Sopenharmony_ci	struct aq_macsec_txsc *aq_txsc;
134362306a36Sopenharmony_ci	const struct macsec_secy *secy;
134462306a36Sopenharmony_ci	int sc_idx = 0, txsc_idx = 0;
134562306a36Sopenharmony_ci	enum aq_macsec_sc_sa sc_sa;
134662306a36Sopenharmony_ci	struct macsec_tx_sa *tx_sa;
134762306a36Sopenharmony_ci	unsigned char an = 0;
134862306a36Sopenharmony_ci	int ret;
134962306a36Sopenharmony_ci	int i;
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_ci	sc_sa = cfg->sc_sa;
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci	ret = aq_mss_get_egress_sa_expired(hw, &egress_sa_expired);
135462306a36Sopenharmony_ci	if (unlikely(ret))
135562306a36Sopenharmony_ci		return;
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci	ret = aq_mss_get_egress_sa_threshold_expired(hw,
135862306a36Sopenharmony_ci		&egress_sa_threshold_expired);
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci	for (i = 0; i < AQ_MACSEC_MAX_SA; i++) {
136162306a36Sopenharmony_ci		if (egress_sa_expired & BIT(i)) {
136262306a36Sopenharmony_ci			an = aq_sa_from_sa_idx(sc_sa, i);
136362306a36Sopenharmony_ci			sc_idx = aq_sc_idx_from_sa_idx(sc_sa, i);
136462306a36Sopenharmony_ci			txsc_idx = aq_get_txsc_idx_from_sc_idx(sc_sa, sc_idx);
136562306a36Sopenharmony_ci			if (txsc_idx < 0)
136662306a36Sopenharmony_ci				continue;
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_ci			aq_txsc = &cfg->aq_txsc[txsc_idx];
136962306a36Sopenharmony_ci			if (!(cfg->txsc_idx_busy & BIT(txsc_idx))) {
137062306a36Sopenharmony_ci				netdev_warn(nic->ndev,
137162306a36Sopenharmony_ci					"PN threshold expired on invalid TX SC");
137262306a36Sopenharmony_ci				continue;
137362306a36Sopenharmony_ci			}
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci			secy = aq_txsc->sw_secy;
137662306a36Sopenharmony_ci			if (!netif_running(secy->netdev)) {
137762306a36Sopenharmony_ci				netdev_warn(nic->ndev,
137862306a36Sopenharmony_ci					"PN threshold expired on down TX SC");
137962306a36Sopenharmony_ci				continue;
138062306a36Sopenharmony_ci			}
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_ci			if (unlikely(!(aq_txsc->tx_sa_idx_busy & BIT(an)))) {
138362306a36Sopenharmony_ci				netdev_warn(nic->ndev,
138462306a36Sopenharmony_ci					"PN threshold expired on invalid TX SA");
138562306a36Sopenharmony_ci				continue;
138662306a36Sopenharmony_ci			}
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci			tx_sa = rcu_dereference_bh(secy->tx_sc.sa[an]);
138962306a36Sopenharmony_ci			macsec_pn_wrapped((struct macsec_secy *)secy, tx_sa);
139062306a36Sopenharmony_ci		}
139162306a36Sopenharmony_ci	}
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci	aq_mss_set_egress_sa_expired(hw, egress_sa_expired);
139462306a36Sopenharmony_ci	if (likely(!ret))
139562306a36Sopenharmony_ci		aq_mss_set_egress_sa_threshold_expired(hw,
139662306a36Sopenharmony_ci			egress_sa_threshold_expired);
139762306a36Sopenharmony_ci}
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_ci#define AQ_LOCKED_MDO_DEF(mdo)						\
140062306a36Sopenharmony_cistatic int aq_locked_mdo_##mdo(struct macsec_context *ctx)		\
140162306a36Sopenharmony_ci{									\
140262306a36Sopenharmony_ci	struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev);		\
140362306a36Sopenharmony_ci	int ret;							\
140462306a36Sopenharmony_ci	mutex_lock(&nic->macsec_mutex);					\
140562306a36Sopenharmony_ci	ret = aq_mdo_##mdo(ctx);					\
140662306a36Sopenharmony_ci	mutex_unlock(&nic->macsec_mutex);				\
140762306a36Sopenharmony_ci	return ret;							\
140862306a36Sopenharmony_ci}
140962306a36Sopenharmony_ci
141062306a36Sopenharmony_ciAQ_LOCKED_MDO_DEF(dev_open)
141162306a36Sopenharmony_ciAQ_LOCKED_MDO_DEF(dev_stop)
141262306a36Sopenharmony_ciAQ_LOCKED_MDO_DEF(add_secy)
141362306a36Sopenharmony_ciAQ_LOCKED_MDO_DEF(upd_secy)
141462306a36Sopenharmony_ciAQ_LOCKED_MDO_DEF(del_secy)
141562306a36Sopenharmony_ciAQ_LOCKED_MDO_DEF(add_rxsc)
141662306a36Sopenharmony_ciAQ_LOCKED_MDO_DEF(upd_rxsc)
141762306a36Sopenharmony_ciAQ_LOCKED_MDO_DEF(del_rxsc)
141862306a36Sopenharmony_ciAQ_LOCKED_MDO_DEF(add_rxsa)
141962306a36Sopenharmony_ciAQ_LOCKED_MDO_DEF(upd_rxsa)
142062306a36Sopenharmony_ciAQ_LOCKED_MDO_DEF(del_rxsa)
142162306a36Sopenharmony_ciAQ_LOCKED_MDO_DEF(add_txsa)
142262306a36Sopenharmony_ciAQ_LOCKED_MDO_DEF(upd_txsa)
142362306a36Sopenharmony_ciAQ_LOCKED_MDO_DEF(del_txsa)
142462306a36Sopenharmony_ciAQ_LOCKED_MDO_DEF(get_dev_stats)
142562306a36Sopenharmony_ciAQ_LOCKED_MDO_DEF(get_tx_sc_stats)
142662306a36Sopenharmony_ciAQ_LOCKED_MDO_DEF(get_tx_sa_stats)
142762306a36Sopenharmony_ciAQ_LOCKED_MDO_DEF(get_rx_sc_stats)
142862306a36Sopenharmony_ciAQ_LOCKED_MDO_DEF(get_rx_sa_stats)
142962306a36Sopenharmony_ci
143062306a36Sopenharmony_ciconst struct macsec_ops aq_macsec_ops = {
143162306a36Sopenharmony_ci	.mdo_dev_open = aq_locked_mdo_dev_open,
143262306a36Sopenharmony_ci	.mdo_dev_stop = aq_locked_mdo_dev_stop,
143362306a36Sopenharmony_ci	.mdo_add_secy = aq_locked_mdo_add_secy,
143462306a36Sopenharmony_ci	.mdo_upd_secy = aq_locked_mdo_upd_secy,
143562306a36Sopenharmony_ci	.mdo_del_secy = aq_locked_mdo_del_secy,
143662306a36Sopenharmony_ci	.mdo_add_rxsc = aq_locked_mdo_add_rxsc,
143762306a36Sopenharmony_ci	.mdo_upd_rxsc = aq_locked_mdo_upd_rxsc,
143862306a36Sopenharmony_ci	.mdo_del_rxsc = aq_locked_mdo_del_rxsc,
143962306a36Sopenharmony_ci	.mdo_add_rxsa = aq_locked_mdo_add_rxsa,
144062306a36Sopenharmony_ci	.mdo_upd_rxsa = aq_locked_mdo_upd_rxsa,
144162306a36Sopenharmony_ci	.mdo_del_rxsa = aq_locked_mdo_del_rxsa,
144262306a36Sopenharmony_ci	.mdo_add_txsa = aq_locked_mdo_add_txsa,
144362306a36Sopenharmony_ci	.mdo_upd_txsa = aq_locked_mdo_upd_txsa,
144462306a36Sopenharmony_ci	.mdo_del_txsa = aq_locked_mdo_del_txsa,
144562306a36Sopenharmony_ci	.mdo_get_dev_stats = aq_locked_mdo_get_dev_stats,
144662306a36Sopenharmony_ci	.mdo_get_tx_sc_stats = aq_locked_mdo_get_tx_sc_stats,
144762306a36Sopenharmony_ci	.mdo_get_tx_sa_stats = aq_locked_mdo_get_tx_sa_stats,
144862306a36Sopenharmony_ci	.mdo_get_rx_sc_stats = aq_locked_mdo_get_rx_sc_stats,
144962306a36Sopenharmony_ci	.mdo_get_rx_sa_stats = aq_locked_mdo_get_rx_sa_stats,
145062306a36Sopenharmony_ci};
145162306a36Sopenharmony_ci
145262306a36Sopenharmony_ciint aq_macsec_init(struct aq_nic_s *nic)
145362306a36Sopenharmony_ci{
145462306a36Sopenharmony_ci	struct aq_macsec_cfg *cfg;
145562306a36Sopenharmony_ci	u32 caps_lo;
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_ci	if (!nic->aq_fw_ops->get_link_capabilities)
145862306a36Sopenharmony_ci		return 0;
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci	caps_lo = nic->aq_fw_ops->get_link_capabilities(nic->aq_hw);
146162306a36Sopenharmony_ci
146262306a36Sopenharmony_ci	if (!(caps_lo & BIT(CAPS_LO_MACSEC)))
146362306a36Sopenharmony_ci		return 0;
146462306a36Sopenharmony_ci
146562306a36Sopenharmony_ci	nic->macsec_cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
146662306a36Sopenharmony_ci	if (!nic->macsec_cfg)
146762306a36Sopenharmony_ci		return -ENOMEM;
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_ci	nic->ndev->features |= NETIF_F_HW_MACSEC;
147062306a36Sopenharmony_ci	nic->ndev->macsec_ops = &aq_macsec_ops;
147162306a36Sopenharmony_ci	mutex_init(&nic->macsec_mutex);
147262306a36Sopenharmony_ci
147362306a36Sopenharmony_ci	return 0;
147462306a36Sopenharmony_ci}
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_civoid aq_macsec_free(struct aq_nic_s *nic)
147762306a36Sopenharmony_ci{
147862306a36Sopenharmony_ci	kfree(nic->macsec_cfg);
147962306a36Sopenharmony_ci	nic->macsec_cfg = NULL;
148062306a36Sopenharmony_ci}
148162306a36Sopenharmony_ci
148262306a36Sopenharmony_ciint aq_macsec_enable(struct aq_nic_s *nic)
148362306a36Sopenharmony_ci{
148462306a36Sopenharmony_ci	u32 ctl_ether_types[1] = { ETH_P_PAE };
148562306a36Sopenharmony_ci	struct macsec_msg_fw_response resp = { 0 };
148662306a36Sopenharmony_ci	struct macsec_msg_fw_request msg = { 0 };
148762306a36Sopenharmony_ci	struct aq_hw_s *hw = nic->aq_hw;
148862306a36Sopenharmony_ci	int num_ctl_ether_types = 0;
148962306a36Sopenharmony_ci	int index = 0, tbl_idx;
149062306a36Sopenharmony_ci	int ret;
149162306a36Sopenharmony_ci
149262306a36Sopenharmony_ci	if (!nic->macsec_cfg)
149362306a36Sopenharmony_ci		return 0;
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_ci	mutex_lock(&nic->macsec_mutex);
149662306a36Sopenharmony_ci
149762306a36Sopenharmony_ci	if (nic->aq_fw_ops->send_macsec_req) {
149862306a36Sopenharmony_ci		struct macsec_cfg_request cfg = { 0 };
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ci		cfg.enabled = 1;
150162306a36Sopenharmony_ci		cfg.egress_threshold = 0xffffffff;
150262306a36Sopenharmony_ci		cfg.ingress_threshold = 0xffffffff;
150362306a36Sopenharmony_ci		cfg.interrupts_enabled = 1;
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_ci		msg.msg_type = macsec_cfg_msg;
150662306a36Sopenharmony_ci		msg.cfg = cfg;
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ci		ret = nic->aq_fw_ops->send_macsec_req(hw, &msg, &resp);
150962306a36Sopenharmony_ci		if (ret)
151062306a36Sopenharmony_ci			goto unlock;
151162306a36Sopenharmony_ci	}
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ci	/* Init Ethertype bypass filters */
151462306a36Sopenharmony_ci	for (index = 0; index < ARRAY_SIZE(ctl_ether_types); index++) {
151562306a36Sopenharmony_ci		struct aq_mss_ingress_prectlf_record rx_prectlf_rec;
151662306a36Sopenharmony_ci		struct aq_mss_egress_ctlf_record tx_ctlf_rec;
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_ci		if (ctl_ether_types[index] == 0)
151962306a36Sopenharmony_ci			continue;
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci		memset(&tx_ctlf_rec, 0, sizeof(tx_ctlf_rec));
152262306a36Sopenharmony_ci		tx_ctlf_rec.eth_type = ctl_ether_types[index];
152362306a36Sopenharmony_ci		tx_ctlf_rec.match_type = 4; /* Match eth_type only */
152462306a36Sopenharmony_ci		tx_ctlf_rec.match_mask = 0xf; /* match for eth_type */
152562306a36Sopenharmony_ci		tx_ctlf_rec.action = 0; /* Bypass MACSEC modules */
152662306a36Sopenharmony_ci		tbl_idx = NUMROWS_EGRESSCTLFRECORD - num_ctl_ether_types - 1;
152762306a36Sopenharmony_ci		aq_mss_set_egress_ctlf_record(hw, &tx_ctlf_rec, tbl_idx);
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_ci		memset(&rx_prectlf_rec, 0, sizeof(rx_prectlf_rec));
153062306a36Sopenharmony_ci		rx_prectlf_rec.eth_type = ctl_ether_types[index];
153162306a36Sopenharmony_ci		rx_prectlf_rec.match_type = 4; /* Match eth_type only */
153262306a36Sopenharmony_ci		rx_prectlf_rec.match_mask = 0xf; /* match for eth_type */
153362306a36Sopenharmony_ci		rx_prectlf_rec.action = 0; /* Bypass MACSEC modules */
153462306a36Sopenharmony_ci		tbl_idx =
153562306a36Sopenharmony_ci			NUMROWS_INGRESSPRECTLFRECORD - num_ctl_ether_types - 1;
153662306a36Sopenharmony_ci		aq_mss_set_ingress_prectlf_record(hw, &rx_prectlf_rec, tbl_idx);
153762306a36Sopenharmony_ci
153862306a36Sopenharmony_ci		num_ctl_ether_types++;
153962306a36Sopenharmony_ci	}
154062306a36Sopenharmony_ci
154162306a36Sopenharmony_ci	ret = aq_apply_macsec_cfg(nic);
154262306a36Sopenharmony_ci
154362306a36Sopenharmony_ciunlock:
154462306a36Sopenharmony_ci	mutex_unlock(&nic->macsec_mutex);
154562306a36Sopenharmony_ci	return ret;
154662306a36Sopenharmony_ci}
154762306a36Sopenharmony_ci
154862306a36Sopenharmony_civoid aq_macsec_work(struct aq_nic_s *nic)
154962306a36Sopenharmony_ci{
155062306a36Sopenharmony_ci	if (!nic->macsec_cfg)
155162306a36Sopenharmony_ci		return;
155262306a36Sopenharmony_ci
155362306a36Sopenharmony_ci	if (!netif_carrier_ok(nic->ndev))
155462306a36Sopenharmony_ci		return;
155562306a36Sopenharmony_ci
155662306a36Sopenharmony_ci	mutex_lock(&nic->macsec_mutex);
155762306a36Sopenharmony_ci	aq_check_txsa_expiration(nic);
155862306a36Sopenharmony_ci	mutex_unlock(&nic->macsec_mutex);
155962306a36Sopenharmony_ci}
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_ciint aq_macsec_rx_sa_cnt(struct aq_nic_s *nic)
156262306a36Sopenharmony_ci{
156362306a36Sopenharmony_ci	struct aq_macsec_cfg *cfg = nic->macsec_cfg;
156462306a36Sopenharmony_ci	int i, cnt = 0;
156562306a36Sopenharmony_ci
156662306a36Sopenharmony_ci	if (!cfg)
156762306a36Sopenharmony_ci		return 0;
156862306a36Sopenharmony_ci
156962306a36Sopenharmony_ci	mutex_lock(&nic->macsec_mutex);
157062306a36Sopenharmony_ci
157162306a36Sopenharmony_ci	for (i = 0; i < AQ_MACSEC_MAX_SC; i++) {
157262306a36Sopenharmony_ci		if (!test_bit(i, &cfg->rxsc_idx_busy))
157362306a36Sopenharmony_ci			continue;
157462306a36Sopenharmony_ci		cnt += hweight_long(cfg->aq_rxsc[i].rx_sa_idx_busy);
157562306a36Sopenharmony_ci	}
157662306a36Sopenharmony_ci
157762306a36Sopenharmony_ci	mutex_unlock(&nic->macsec_mutex);
157862306a36Sopenharmony_ci	return cnt;
157962306a36Sopenharmony_ci}
158062306a36Sopenharmony_ci
158162306a36Sopenharmony_ciint aq_macsec_tx_sc_cnt(struct aq_nic_s *nic)
158262306a36Sopenharmony_ci{
158362306a36Sopenharmony_ci	int cnt;
158462306a36Sopenharmony_ci
158562306a36Sopenharmony_ci	if (!nic->macsec_cfg)
158662306a36Sopenharmony_ci		return 0;
158762306a36Sopenharmony_ci
158862306a36Sopenharmony_ci	mutex_lock(&nic->macsec_mutex);
158962306a36Sopenharmony_ci	cnt = hweight_long(nic->macsec_cfg->txsc_idx_busy);
159062306a36Sopenharmony_ci	mutex_unlock(&nic->macsec_mutex);
159162306a36Sopenharmony_ci
159262306a36Sopenharmony_ci	return cnt;
159362306a36Sopenharmony_ci}
159462306a36Sopenharmony_ci
159562306a36Sopenharmony_ciint aq_macsec_tx_sa_cnt(struct aq_nic_s *nic)
159662306a36Sopenharmony_ci{
159762306a36Sopenharmony_ci	struct aq_macsec_cfg *cfg = nic->macsec_cfg;
159862306a36Sopenharmony_ci	int i, cnt = 0;
159962306a36Sopenharmony_ci
160062306a36Sopenharmony_ci	if (!cfg)
160162306a36Sopenharmony_ci		return 0;
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_ci	mutex_lock(&nic->macsec_mutex);
160462306a36Sopenharmony_ci
160562306a36Sopenharmony_ci	for (i = 0; i < AQ_MACSEC_MAX_SC; i++) {
160662306a36Sopenharmony_ci		if (!test_bit(i, &cfg->txsc_idx_busy))
160762306a36Sopenharmony_ci			continue;
160862306a36Sopenharmony_ci		cnt += hweight_long(cfg->aq_txsc[i].tx_sa_idx_busy);
160962306a36Sopenharmony_ci	}
161062306a36Sopenharmony_ci
161162306a36Sopenharmony_ci	mutex_unlock(&nic->macsec_mutex);
161262306a36Sopenharmony_ci	return cnt;
161362306a36Sopenharmony_ci}
161462306a36Sopenharmony_ci
161562306a36Sopenharmony_cistatic int aq_macsec_update_stats(struct aq_nic_s *nic)
161662306a36Sopenharmony_ci{
161762306a36Sopenharmony_ci	struct aq_macsec_cfg *cfg = nic->macsec_cfg;
161862306a36Sopenharmony_ci	struct aq_hw_s *hw = nic->aq_hw;
161962306a36Sopenharmony_ci	struct aq_macsec_txsc *aq_txsc;
162062306a36Sopenharmony_ci	struct aq_macsec_rxsc *aq_rxsc;
162162306a36Sopenharmony_ci	int i, sa_idx, assoc_num;
162262306a36Sopenharmony_ci	int ret = 0;
162362306a36Sopenharmony_ci
162462306a36Sopenharmony_ci	aq_get_macsec_common_stats(hw, &cfg->stats);
162562306a36Sopenharmony_ci
162662306a36Sopenharmony_ci	for (i = 0; i < AQ_MACSEC_MAX_SC; i++) {
162762306a36Sopenharmony_ci		if (!(cfg->txsc_idx_busy & BIT(i)))
162862306a36Sopenharmony_ci			continue;
162962306a36Sopenharmony_ci		aq_txsc = &cfg->aq_txsc[i];
163062306a36Sopenharmony_ci
163162306a36Sopenharmony_ci		ret = aq_get_txsc_stats(hw, aq_txsc->hw_sc_idx,
163262306a36Sopenharmony_ci					&aq_txsc->stats);
163362306a36Sopenharmony_ci		if (ret)
163462306a36Sopenharmony_ci			return ret;
163562306a36Sopenharmony_ci
163662306a36Sopenharmony_ci		for (assoc_num = 0; assoc_num < MACSEC_NUM_AN; assoc_num++) {
163762306a36Sopenharmony_ci			if (!test_bit(assoc_num, &aq_txsc->tx_sa_idx_busy))
163862306a36Sopenharmony_ci				continue;
163962306a36Sopenharmony_ci			sa_idx = aq_txsc->hw_sc_idx | assoc_num;
164062306a36Sopenharmony_ci			ret = aq_get_txsa_stats(hw, sa_idx,
164162306a36Sopenharmony_ci					      &aq_txsc->tx_sa_stats[assoc_num]);
164262306a36Sopenharmony_ci			if (ret)
164362306a36Sopenharmony_ci				return ret;
164462306a36Sopenharmony_ci		}
164562306a36Sopenharmony_ci	}
164662306a36Sopenharmony_ci
164762306a36Sopenharmony_ci	for (i = 0; i < AQ_MACSEC_MAX_SC; i++) {
164862306a36Sopenharmony_ci		if (!(test_bit(i, &cfg->rxsc_idx_busy)))
164962306a36Sopenharmony_ci			continue;
165062306a36Sopenharmony_ci		aq_rxsc = &cfg->aq_rxsc[i];
165162306a36Sopenharmony_ci
165262306a36Sopenharmony_ci		for (assoc_num = 0; assoc_num < MACSEC_NUM_AN; assoc_num++) {
165362306a36Sopenharmony_ci			if (!test_bit(assoc_num, &aq_rxsc->rx_sa_idx_busy))
165462306a36Sopenharmony_ci				continue;
165562306a36Sopenharmony_ci			sa_idx = aq_rxsc->hw_sc_idx | assoc_num;
165662306a36Sopenharmony_ci
165762306a36Sopenharmony_ci			ret = aq_get_rxsa_stats(hw, sa_idx,
165862306a36Sopenharmony_ci					      &aq_rxsc->rx_sa_stats[assoc_num]);
165962306a36Sopenharmony_ci			if (ret)
166062306a36Sopenharmony_ci				return ret;
166162306a36Sopenharmony_ci		}
166262306a36Sopenharmony_ci	}
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ci	return ret;
166562306a36Sopenharmony_ci}
166662306a36Sopenharmony_ci
166762306a36Sopenharmony_ciu64 *aq_macsec_get_stats(struct aq_nic_s *nic, u64 *data)
166862306a36Sopenharmony_ci{
166962306a36Sopenharmony_ci	struct aq_macsec_cfg *cfg = nic->macsec_cfg;
167062306a36Sopenharmony_ci	struct aq_macsec_common_stats *common_stats;
167162306a36Sopenharmony_ci	struct aq_macsec_tx_sc_stats *txsc_stats;
167262306a36Sopenharmony_ci	struct aq_macsec_tx_sa_stats *txsa_stats;
167362306a36Sopenharmony_ci	struct aq_macsec_rx_sa_stats *rxsa_stats;
167462306a36Sopenharmony_ci	struct aq_macsec_txsc *aq_txsc;
167562306a36Sopenharmony_ci	struct aq_macsec_rxsc *aq_rxsc;
167662306a36Sopenharmony_ci	unsigned int assoc_num;
167762306a36Sopenharmony_ci	unsigned int sc_num;
167862306a36Sopenharmony_ci	unsigned int i = 0U;
167962306a36Sopenharmony_ci
168062306a36Sopenharmony_ci	if (!cfg)
168162306a36Sopenharmony_ci		return data;
168262306a36Sopenharmony_ci
168362306a36Sopenharmony_ci	mutex_lock(&nic->macsec_mutex);
168462306a36Sopenharmony_ci
168562306a36Sopenharmony_ci	aq_macsec_update_stats(nic);
168662306a36Sopenharmony_ci
168762306a36Sopenharmony_ci	common_stats = &cfg->stats;
168862306a36Sopenharmony_ci	data[i] = common_stats->in.ctl_pkts;
168962306a36Sopenharmony_ci	data[++i] = common_stats->in.tagged_miss_pkts;
169062306a36Sopenharmony_ci	data[++i] = common_stats->in.untagged_miss_pkts;
169162306a36Sopenharmony_ci	data[++i] = common_stats->in.notag_pkts;
169262306a36Sopenharmony_ci	data[++i] = common_stats->in.untagged_pkts;
169362306a36Sopenharmony_ci	data[++i] = common_stats->in.bad_tag_pkts;
169462306a36Sopenharmony_ci	data[++i] = common_stats->in.no_sci_pkts;
169562306a36Sopenharmony_ci	data[++i] = common_stats->in.unknown_sci_pkts;
169662306a36Sopenharmony_ci	data[++i] = common_stats->in.ctrl_prt_pass_pkts;
169762306a36Sopenharmony_ci	data[++i] = common_stats->in.unctrl_prt_pass_pkts;
169862306a36Sopenharmony_ci	data[++i] = common_stats->in.ctrl_prt_fail_pkts;
169962306a36Sopenharmony_ci	data[++i] = common_stats->in.unctrl_prt_fail_pkts;
170062306a36Sopenharmony_ci	data[++i] = common_stats->in.too_long_pkts;
170162306a36Sopenharmony_ci	data[++i] = common_stats->in.igpoc_ctl_pkts;
170262306a36Sopenharmony_ci	data[++i] = common_stats->in.ecc_error_pkts;
170362306a36Sopenharmony_ci	data[++i] = common_stats->in.unctrl_hit_drop_redir;
170462306a36Sopenharmony_ci	data[++i] = common_stats->out.ctl_pkts;
170562306a36Sopenharmony_ci	data[++i] = common_stats->out.unknown_sa_pkts;
170662306a36Sopenharmony_ci	data[++i] = common_stats->out.untagged_pkts;
170762306a36Sopenharmony_ci	data[++i] = common_stats->out.too_long;
170862306a36Sopenharmony_ci	data[++i] = common_stats->out.ecc_error_pkts;
170962306a36Sopenharmony_ci	data[++i] = common_stats->out.unctrl_hit_drop_redir;
171062306a36Sopenharmony_ci
171162306a36Sopenharmony_ci	for (sc_num = 0; sc_num < AQ_MACSEC_MAX_SC; sc_num++) {
171262306a36Sopenharmony_ci		if (!(test_bit(sc_num, &cfg->txsc_idx_busy)))
171362306a36Sopenharmony_ci			continue;
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_ci		aq_txsc = &cfg->aq_txsc[sc_num];
171662306a36Sopenharmony_ci		txsc_stats = &aq_txsc->stats;
171762306a36Sopenharmony_ci
171862306a36Sopenharmony_ci		data[++i] = txsc_stats->sc_protected_pkts;
171962306a36Sopenharmony_ci		data[++i] = txsc_stats->sc_encrypted_pkts;
172062306a36Sopenharmony_ci		data[++i] = txsc_stats->sc_protected_octets;
172162306a36Sopenharmony_ci		data[++i] = txsc_stats->sc_encrypted_octets;
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_ci		for (assoc_num = 0; assoc_num < MACSEC_NUM_AN; assoc_num++) {
172462306a36Sopenharmony_ci			if (!test_bit(assoc_num, &aq_txsc->tx_sa_idx_busy))
172562306a36Sopenharmony_ci				continue;
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_ci			txsa_stats = &aq_txsc->tx_sa_stats[assoc_num];
172862306a36Sopenharmony_ci
172962306a36Sopenharmony_ci			data[++i] = txsa_stats->sa_hit_drop_redirect;
173062306a36Sopenharmony_ci			data[++i] = txsa_stats->sa_protected2_pkts;
173162306a36Sopenharmony_ci			data[++i] = txsa_stats->sa_protected_pkts;
173262306a36Sopenharmony_ci			data[++i] = txsa_stats->sa_encrypted_pkts;
173362306a36Sopenharmony_ci		}
173462306a36Sopenharmony_ci	}
173562306a36Sopenharmony_ci
173662306a36Sopenharmony_ci	for (sc_num = 0; sc_num < AQ_MACSEC_MAX_SC; sc_num++) {
173762306a36Sopenharmony_ci		if (!(test_bit(sc_num, &cfg->rxsc_idx_busy)))
173862306a36Sopenharmony_ci			continue;
173962306a36Sopenharmony_ci
174062306a36Sopenharmony_ci		aq_rxsc = &cfg->aq_rxsc[sc_num];
174162306a36Sopenharmony_ci
174262306a36Sopenharmony_ci		for (assoc_num = 0; assoc_num < MACSEC_NUM_AN; assoc_num++) {
174362306a36Sopenharmony_ci			if (!test_bit(assoc_num, &aq_rxsc->rx_sa_idx_busy))
174462306a36Sopenharmony_ci				continue;
174562306a36Sopenharmony_ci
174662306a36Sopenharmony_ci			rxsa_stats = &aq_rxsc->rx_sa_stats[assoc_num];
174762306a36Sopenharmony_ci
174862306a36Sopenharmony_ci			data[++i] = rxsa_stats->untagged_hit_pkts;
174962306a36Sopenharmony_ci			data[++i] = rxsa_stats->ctrl_hit_drop_redir_pkts;
175062306a36Sopenharmony_ci			data[++i] = rxsa_stats->not_using_sa;
175162306a36Sopenharmony_ci			data[++i] = rxsa_stats->unused_sa;
175262306a36Sopenharmony_ci			data[++i] = rxsa_stats->not_valid_pkts;
175362306a36Sopenharmony_ci			data[++i] = rxsa_stats->invalid_pkts;
175462306a36Sopenharmony_ci			data[++i] = rxsa_stats->ok_pkts;
175562306a36Sopenharmony_ci			data[++i] = rxsa_stats->late_pkts;
175662306a36Sopenharmony_ci			data[++i] = rxsa_stats->delayed_pkts;
175762306a36Sopenharmony_ci			data[++i] = rxsa_stats->unchecked_pkts;
175862306a36Sopenharmony_ci			data[++i] = rxsa_stats->validated_octets;
175962306a36Sopenharmony_ci			data[++i] = rxsa_stats->decrypted_octets;
176062306a36Sopenharmony_ci		}
176162306a36Sopenharmony_ci	}
176262306a36Sopenharmony_ci
176362306a36Sopenharmony_ci	i++;
176462306a36Sopenharmony_ci
176562306a36Sopenharmony_ci	data += i;
176662306a36Sopenharmony_ci
176762306a36Sopenharmony_ci	mutex_unlock(&nic->macsec_mutex);
176862306a36Sopenharmony_ci
176962306a36Sopenharmony_ci	return data;
177062306a36Sopenharmony_ci}
1771