162c1c2e6SDmitry Bogdanov // SPDX-License-Identifier: GPL-2.0-only
262c1c2e6SDmitry Bogdanov /* Atlantic Network Driver
362c1c2e6SDmitry Bogdanov * Copyright (C) 2020 Marvell International Ltd.
462c1c2e6SDmitry Bogdanov */
562c1c2e6SDmitry Bogdanov
662c1c2e6SDmitry Bogdanov #include "aq_macsec.h"
762c1c2e6SDmitry Bogdanov #include "aq_nic.h"
862c1c2e6SDmitry Bogdanov #include <linux/rtnetlink.h>
962c1c2e6SDmitry Bogdanov
1027736563SDmitry Bogdanov #include "macsec/macsec_api.h"
1127736563SDmitry Bogdanov #define AQ_MACSEC_KEY_LEN_128_BIT 16
1227736563SDmitry Bogdanov #define AQ_MACSEC_KEY_LEN_192_BIT 24
1327736563SDmitry Bogdanov #define AQ_MACSEC_KEY_LEN_256_BIT 32
1427736563SDmitry Bogdanov
1527736563SDmitry Bogdanov enum aq_clear_type {
1627736563SDmitry Bogdanov /* update HW configuration */
1727736563SDmitry Bogdanov AQ_CLEAR_HW = BIT(0),
1827736563SDmitry Bogdanov /* update SW configuration (busy bits, pointers) */
1927736563SDmitry Bogdanov AQ_CLEAR_SW = BIT(1),
2027736563SDmitry Bogdanov /* update both HW and SW configuration */
2127736563SDmitry Bogdanov AQ_CLEAR_ALL = AQ_CLEAR_HW | AQ_CLEAR_SW,
2227736563SDmitry Bogdanov };
2327736563SDmitry Bogdanov
2427736563SDmitry Bogdanov static int aq_clear_txsc(struct aq_nic_s *nic, const int txsc_idx,
2527736563SDmitry Bogdanov enum aq_clear_type clear_type);
2627736563SDmitry Bogdanov static int aq_clear_txsa(struct aq_nic_s *nic, struct aq_macsec_txsc *aq_txsc,
2727736563SDmitry Bogdanov const int sa_num, enum aq_clear_type clear_type);
289ff40a75SMark Starovoytov static int aq_clear_rxsc(struct aq_nic_s *nic, const int rxsc_idx,
299ff40a75SMark Starovoytov enum aq_clear_type clear_type);
309ff40a75SMark Starovoytov static int aq_clear_rxsa(struct aq_nic_s *nic, struct aq_macsec_rxsc *aq_rxsc,
319ff40a75SMark Starovoytov const int sa_num, enum aq_clear_type clear_type);
3227736563SDmitry Bogdanov static int aq_clear_secy(struct aq_nic_s *nic, const struct macsec_secy *secy,
3327736563SDmitry Bogdanov enum aq_clear_type clear_type);
3427736563SDmitry Bogdanov static int aq_apply_macsec_cfg(struct aq_nic_s *nic);
3527736563SDmitry Bogdanov static int aq_apply_secy_cfg(struct aq_nic_s *nic,
3627736563SDmitry Bogdanov const struct macsec_secy *secy);
3727736563SDmitry Bogdanov
aq_ether_addr_to_mac(u32 mac[2],const unsigned char * emac)3876660757SJakub Kicinski static void aq_ether_addr_to_mac(u32 mac[2], const unsigned char *emac)
3927736563SDmitry Bogdanov {
4027736563SDmitry Bogdanov u32 tmp[2] = { 0 };
4127736563SDmitry Bogdanov
4227736563SDmitry Bogdanov memcpy(((u8 *)tmp) + 2, emac, ETH_ALEN);
4327736563SDmitry Bogdanov
4427736563SDmitry Bogdanov mac[0] = swab32(tmp[1]);
4527736563SDmitry Bogdanov mac[1] = swab32(tmp[0]);
4627736563SDmitry Bogdanov }
4727736563SDmitry Bogdanov
4827736563SDmitry Bogdanov /* There's a 1:1 mapping between SecY and TX SC */
aq_get_txsc_idx_from_secy(struct aq_macsec_cfg * macsec_cfg,const struct macsec_secy * secy)4927736563SDmitry Bogdanov static int aq_get_txsc_idx_from_secy(struct aq_macsec_cfg *macsec_cfg,
5027736563SDmitry Bogdanov const struct macsec_secy *secy)
5127736563SDmitry Bogdanov {
5227736563SDmitry Bogdanov int i;
5327736563SDmitry Bogdanov
5427736563SDmitry Bogdanov if (unlikely(!secy))
5527736563SDmitry Bogdanov return -1;
5627736563SDmitry Bogdanov
5727736563SDmitry Bogdanov for (i = 0; i < AQ_MACSEC_MAX_SC; i++) {
5827736563SDmitry Bogdanov if (macsec_cfg->aq_txsc[i].sw_secy == secy)
5927736563SDmitry Bogdanov return i;
6027736563SDmitry Bogdanov }
6127736563SDmitry Bogdanov return -1;
6227736563SDmitry Bogdanov }
6327736563SDmitry Bogdanov
aq_get_rxsc_idx_from_rxsc(struct aq_macsec_cfg * macsec_cfg,const struct macsec_rx_sc * rxsc)649ff40a75SMark Starovoytov static int aq_get_rxsc_idx_from_rxsc(struct aq_macsec_cfg *macsec_cfg,
659ff40a75SMark Starovoytov const struct macsec_rx_sc *rxsc)
669ff40a75SMark Starovoytov {
679ff40a75SMark Starovoytov int i;
689ff40a75SMark Starovoytov
699ff40a75SMark Starovoytov if (unlikely(!rxsc))
709ff40a75SMark Starovoytov return -1;
719ff40a75SMark Starovoytov
729ff40a75SMark Starovoytov for (i = 0; i < AQ_MACSEC_MAX_SC; i++) {
739ff40a75SMark Starovoytov if (macsec_cfg->aq_rxsc[i].sw_rxsc == rxsc)
749ff40a75SMark Starovoytov return i;
759ff40a75SMark Starovoytov }
769ff40a75SMark Starovoytov
779ff40a75SMark Starovoytov return -1;
789ff40a75SMark Starovoytov }
799ff40a75SMark Starovoytov
aq_get_txsc_idx_from_sc_idx(const enum aq_macsec_sc_sa sc_sa,const int sc_idx)8027736563SDmitry Bogdanov static int aq_get_txsc_idx_from_sc_idx(const enum aq_macsec_sc_sa sc_sa,
8127736563SDmitry Bogdanov const int sc_idx)
8227736563SDmitry Bogdanov {
8327736563SDmitry Bogdanov switch (sc_sa) {
8427736563SDmitry Bogdanov case aq_macsec_sa_sc_4sa_8sc:
8527736563SDmitry Bogdanov return sc_idx >> 2;
8627736563SDmitry Bogdanov case aq_macsec_sa_sc_2sa_16sc:
8727736563SDmitry Bogdanov return sc_idx >> 1;
8827736563SDmitry Bogdanov case aq_macsec_sa_sc_1sa_32sc:
8927736563SDmitry Bogdanov return sc_idx;
9027736563SDmitry Bogdanov default:
9127736563SDmitry Bogdanov WARN_ONCE(true, "Invalid sc_sa");
9227736563SDmitry Bogdanov }
9327736563SDmitry Bogdanov return -1;
9427736563SDmitry Bogdanov }
9527736563SDmitry Bogdanov
9627736563SDmitry Bogdanov /* Rotate keys u32[8] */
aq_rotate_keys(u32 (* key)[8],const int key_len)9727736563SDmitry Bogdanov static void aq_rotate_keys(u32 (*key)[8], const int key_len)
9827736563SDmitry Bogdanov {
9927736563SDmitry Bogdanov u32 tmp[8] = { 0 };
10027736563SDmitry Bogdanov
10127736563SDmitry Bogdanov memcpy(&tmp, key, sizeof(tmp));
10227736563SDmitry Bogdanov memset(*key, 0, sizeof(*key));
10327736563SDmitry Bogdanov
10427736563SDmitry Bogdanov if (key_len == AQ_MACSEC_KEY_LEN_128_BIT) {
10527736563SDmitry Bogdanov (*key)[0] = swab32(tmp[3]);
10627736563SDmitry Bogdanov (*key)[1] = swab32(tmp[2]);
10727736563SDmitry Bogdanov (*key)[2] = swab32(tmp[1]);
10827736563SDmitry Bogdanov (*key)[3] = swab32(tmp[0]);
10927736563SDmitry Bogdanov } else if (key_len == AQ_MACSEC_KEY_LEN_192_BIT) {
11027736563SDmitry Bogdanov (*key)[0] = swab32(tmp[5]);
11127736563SDmitry Bogdanov (*key)[1] = swab32(tmp[4]);
11227736563SDmitry Bogdanov (*key)[2] = swab32(tmp[3]);
11327736563SDmitry Bogdanov (*key)[3] = swab32(tmp[2]);
11427736563SDmitry Bogdanov (*key)[4] = swab32(tmp[1]);
11527736563SDmitry Bogdanov (*key)[5] = swab32(tmp[0]);
11627736563SDmitry Bogdanov } else if (key_len == AQ_MACSEC_KEY_LEN_256_BIT) {
11727736563SDmitry Bogdanov (*key)[0] = swab32(tmp[7]);
11827736563SDmitry Bogdanov (*key)[1] = swab32(tmp[6]);
11927736563SDmitry Bogdanov (*key)[2] = swab32(tmp[5]);
12027736563SDmitry Bogdanov (*key)[3] = swab32(tmp[4]);
12127736563SDmitry Bogdanov (*key)[4] = swab32(tmp[3]);
12227736563SDmitry Bogdanov (*key)[5] = swab32(tmp[2]);
12327736563SDmitry Bogdanov (*key)[6] = swab32(tmp[1]);
12427736563SDmitry Bogdanov (*key)[7] = swab32(tmp[0]);
12527736563SDmitry Bogdanov } else {
12627736563SDmitry Bogdanov pr_warn("Rotate_keys: invalid key_len\n");
12727736563SDmitry Bogdanov }
12827736563SDmitry Bogdanov }
12927736563SDmitry Bogdanov
130aec0f1aaSDmitry Bogdanov #define STATS_2x32_TO_64(stat_field) \
131aec0f1aaSDmitry Bogdanov (((u64)stat_field[1] << 32) | stat_field[0])
132aec0f1aaSDmitry Bogdanov
aq_get_macsec_common_stats(struct aq_hw_s * hw,struct aq_macsec_common_stats * stats)133aec0f1aaSDmitry Bogdanov static int aq_get_macsec_common_stats(struct aq_hw_s *hw,
134aec0f1aaSDmitry Bogdanov struct aq_macsec_common_stats *stats)
135aec0f1aaSDmitry Bogdanov {
136aec0f1aaSDmitry Bogdanov struct aq_mss_ingress_common_counters ingress_counters;
137aec0f1aaSDmitry Bogdanov struct aq_mss_egress_common_counters egress_counters;
138aec0f1aaSDmitry Bogdanov int ret;
139aec0f1aaSDmitry Bogdanov
140aec0f1aaSDmitry Bogdanov /* MACSEC counters */
141aec0f1aaSDmitry Bogdanov ret = aq_mss_get_ingress_common_counters(hw, &ingress_counters);
142aec0f1aaSDmitry Bogdanov if (unlikely(ret))
143aec0f1aaSDmitry Bogdanov return ret;
144aec0f1aaSDmitry Bogdanov
145aec0f1aaSDmitry Bogdanov stats->in.ctl_pkts = STATS_2x32_TO_64(ingress_counters.ctl_pkts);
146aec0f1aaSDmitry Bogdanov stats->in.tagged_miss_pkts =
147aec0f1aaSDmitry Bogdanov STATS_2x32_TO_64(ingress_counters.tagged_miss_pkts);
148aec0f1aaSDmitry Bogdanov stats->in.untagged_miss_pkts =
149aec0f1aaSDmitry Bogdanov STATS_2x32_TO_64(ingress_counters.untagged_miss_pkts);
150aec0f1aaSDmitry Bogdanov stats->in.notag_pkts = STATS_2x32_TO_64(ingress_counters.notag_pkts);
151aec0f1aaSDmitry Bogdanov stats->in.untagged_pkts =
152aec0f1aaSDmitry Bogdanov STATS_2x32_TO_64(ingress_counters.untagged_pkts);
153aec0f1aaSDmitry Bogdanov stats->in.bad_tag_pkts =
154aec0f1aaSDmitry Bogdanov STATS_2x32_TO_64(ingress_counters.bad_tag_pkts);
155aec0f1aaSDmitry Bogdanov stats->in.no_sci_pkts = STATS_2x32_TO_64(ingress_counters.no_sci_pkts);
156aec0f1aaSDmitry Bogdanov stats->in.unknown_sci_pkts =
157aec0f1aaSDmitry Bogdanov STATS_2x32_TO_64(ingress_counters.unknown_sci_pkts);
158aec0f1aaSDmitry Bogdanov stats->in.ctrl_prt_pass_pkts =
159aec0f1aaSDmitry Bogdanov STATS_2x32_TO_64(ingress_counters.ctrl_prt_pass_pkts);
160aec0f1aaSDmitry Bogdanov stats->in.unctrl_prt_pass_pkts =
161aec0f1aaSDmitry Bogdanov STATS_2x32_TO_64(ingress_counters.unctrl_prt_pass_pkts);
162aec0f1aaSDmitry Bogdanov stats->in.ctrl_prt_fail_pkts =
163aec0f1aaSDmitry Bogdanov STATS_2x32_TO_64(ingress_counters.ctrl_prt_fail_pkts);
164aec0f1aaSDmitry Bogdanov stats->in.unctrl_prt_fail_pkts =
165aec0f1aaSDmitry Bogdanov STATS_2x32_TO_64(ingress_counters.unctrl_prt_fail_pkts);
166aec0f1aaSDmitry Bogdanov stats->in.too_long_pkts =
167aec0f1aaSDmitry Bogdanov STATS_2x32_TO_64(ingress_counters.too_long_pkts);
168aec0f1aaSDmitry Bogdanov stats->in.igpoc_ctl_pkts =
169aec0f1aaSDmitry Bogdanov STATS_2x32_TO_64(ingress_counters.igpoc_ctl_pkts);
170aec0f1aaSDmitry Bogdanov stats->in.ecc_error_pkts =
171aec0f1aaSDmitry Bogdanov STATS_2x32_TO_64(ingress_counters.ecc_error_pkts);
172aec0f1aaSDmitry Bogdanov stats->in.unctrl_hit_drop_redir =
173aec0f1aaSDmitry Bogdanov STATS_2x32_TO_64(ingress_counters.unctrl_hit_drop_redir);
174aec0f1aaSDmitry Bogdanov
175aec0f1aaSDmitry Bogdanov ret = aq_mss_get_egress_common_counters(hw, &egress_counters);
176aec0f1aaSDmitry Bogdanov if (unlikely(ret))
177aec0f1aaSDmitry Bogdanov return ret;
178aec0f1aaSDmitry Bogdanov stats->out.ctl_pkts = STATS_2x32_TO_64(egress_counters.ctl_pkt);
179aec0f1aaSDmitry Bogdanov stats->out.unknown_sa_pkts =
180aec0f1aaSDmitry Bogdanov STATS_2x32_TO_64(egress_counters.unknown_sa_pkts);
181aec0f1aaSDmitry Bogdanov stats->out.untagged_pkts =
182aec0f1aaSDmitry Bogdanov STATS_2x32_TO_64(egress_counters.untagged_pkts);
183aec0f1aaSDmitry Bogdanov stats->out.too_long = STATS_2x32_TO_64(egress_counters.too_long);
184aec0f1aaSDmitry Bogdanov stats->out.ecc_error_pkts =
185aec0f1aaSDmitry Bogdanov STATS_2x32_TO_64(egress_counters.ecc_error_pkts);
186aec0f1aaSDmitry Bogdanov stats->out.unctrl_hit_drop_redir =
187aec0f1aaSDmitry Bogdanov STATS_2x32_TO_64(egress_counters.unctrl_hit_drop_redir);
188aec0f1aaSDmitry Bogdanov
189aec0f1aaSDmitry Bogdanov return 0;
190aec0f1aaSDmitry Bogdanov }
191aec0f1aaSDmitry Bogdanov
aq_get_rxsa_stats(struct aq_hw_s * hw,const int sa_idx,struct aq_macsec_rx_sa_stats * stats)192aec0f1aaSDmitry Bogdanov static int aq_get_rxsa_stats(struct aq_hw_s *hw, const int sa_idx,
193aec0f1aaSDmitry Bogdanov struct aq_macsec_rx_sa_stats *stats)
194aec0f1aaSDmitry Bogdanov {
195aec0f1aaSDmitry Bogdanov struct aq_mss_ingress_sa_counters i_sa_counters;
196aec0f1aaSDmitry Bogdanov int ret;
197aec0f1aaSDmitry Bogdanov
198aec0f1aaSDmitry Bogdanov ret = aq_mss_get_ingress_sa_counters(hw, &i_sa_counters, sa_idx);
199aec0f1aaSDmitry Bogdanov if (unlikely(ret))
200aec0f1aaSDmitry Bogdanov return ret;
201aec0f1aaSDmitry Bogdanov
202aec0f1aaSDmitry Bogdanov stats->untagged_hit_pkts =
203aec0f1aaSDmitry Bogdanov STATS_2x32_TO_64(i_sa_counters.untagged_hit_pkts);
204aec0f1aaSDmitry Bogdanov stats->ctrl_hit_drop_redir_pkts =
205aec0f1aaSDmitry Bogdanov STATS_2x32_TO_64(i_sa_counters.ctrl_hit_drop_redir_pkts);
206aec0f1aaSDmitry Bogdanov stats->not_using_sa = STATS_2x32_TO_64(i_sa_counters.not_using_sa);
207aec0f1aaSDmitry Bogdanov stats->unused_sa = STATS_2x32_TO_64(i_sa_counters.unused_sa);
208aec0f1aaSDmitry Bogdanov stats->not_valid_pkts = STATS_2x32_TO_64(i_sa_counters.not_valid_pkts);
209aec0f1aaSDmitry Bogdanov stats->invalid_pkts = STATS_2x32_TO_64(i_sa_counters.invalid_pkts);
210aec0f1aaSDmitry Bogdanov stats->ok_pkts = STATS_2x32_TO_64(i_sa_counters.ok_pkts);
211aec0f1aaSDmitry Bogdanov stats->late_pkts = STATS_2x32_TO_64(i_sa_counters.late_pkts);
212aec0f1aaSDmitry Bogdanov stats->delayed_pkts = STATS_2x32_TO_64(i_sa_counters.delayed_pkts);
213aec0f1aaSDmitry Bogdanov stats->unchecked_pkts = STATS_2x32_TO_64(i_sa_counters.unchecked_pkts);
214aec0f1aaSDmitry Bogdanov stats->validated_octets =
215aec0f1aaSDmitry Bogdanov STATS_2x32_TO_64(i_sa_counters.validated_octets);
216aec0f1aaSDmitry Bogdanov stats->decrypted_octets =
217aec0f1aaSDmitry Bogdanov STATS_2x32_TO_64(i_sa_counters.decrypted_octets);
218aec0f1aaSDmitry Bogdanov
219aec0f1aaSDmitry Bogdanov return 0;
220aec0f1aaSDmitry Bogdanov }
221aec0f1aaSDmitry Bogdanov
aq_get_txsa_stats(struct aq_hw_s * hw,const int sa_idx,struct aq_macsec_tx_sa_stats * stats)222aec0f1aaSDmitry Bogdanov static int aq_get_txsa_stats(struct aq_hw_s *hw, const int sa_idx,
223aec0f1aaSDmitry Bogdanov struct aq_macsec_tx_sa_stats *stats)
224aec0f1aaSDmitry Bogdanov {
225aec0f1aaSDmitry Bogdanov struct aq_mss_egress_sa_counters e_sa_counters;
226aec0f1aaSDmitry Bogdanov int ret;
227aec0f1aaSDmitry Bogdanov
228aec0f1aaSDmitry Bogdanov ret = aq_mss_get_egress_sa_counters(hw, &e_sa_counters, sa_idx);
229aec0f1aaSDmitry Bogdanov if (unlikely(ret))
230aec0f1aaSDmitry Bogdanov return ret;
231aec0f1aaSDmitry Bogdanov
232aec0f1aaSDmitry Bogdanov stats->sa_hit_drop_redirect =
233aec0f1aaSDmitry Bogdanov STATS_2x32_TO_64(e_sa_counters.sa_hit_drop_redirect);
234aec0f1aaSDmitry Bogdanov stats->sa_protected2_pkts =
235aec0f1aaSDmitry Bogdanov STATS_2x32_TO_64(e_sa_counters.sa_protected2_pkts);
236aec0f1aaSDmitry Bogdanov stats->sa_protected_pkts =
237aec0f1aaSDmitry Bogdanov STATS_2x32_TO_64(e_sa_counters.sa_protected_pkts);
238aec0f1aaSDmitry Bogdanov stats->sa_encrypted_pkts =
239aec0f1aaSDmitry Bogdanov STATS_2x32_TO_64(e_sa_counters.sa_encrypted_pkts);
240aec0f1aaSDmitry Bogdanov
241aec0f1aaSDmitry Bogdanov return 0;
242aec0f1aaSDmitry Bogdanov }
243aec0f1aaSDmitry Bogdanov
aq_get_txsa_next_pn(struct aq_hw_s * hw,const int sa_idx,u32 * pn)244aec0f1aaSDmitry Bogdanov static int aq_get_txsa_next_pn(struct aq_hw_s *hw, const int sa_idx, u32 *pn)
245aec0f1aaSDmitry Bogdanov {
246aec0f1aaSDmitry Bogdanov struct aq_mss_egress_sa_record sa_rec;
247aec0f1aaSDmitry Bogdanov int ret;
248aec0f1aaSDmitry Bogdanov
249aec0f1aaSDmitry Bogdanov ret = aq_mss_get_egress_sa_record(hw, &sa_rec, sa_idx);
250aec0f1aaSDmitry Bogdanov if (likely(!ret))
251aec0f1aaSDmitry Bogdanov *pn = sa_rec.next_pn;
252aec0f1aaSDmitry Bogdanov
253aec0f1aaSDmitry Bogdanov return ret;
254aec0f1aaSDmitry Bogdanov }
255aec0f1aaSDmitry Bogdanov
aq_get_rxsa_next_pn(struct aq_hw_s * hw,const int sa_idx,u32 * pn)256aec0f1aaSDmitry Bogdanov static int aq_get_rxsa_next_pn(struct aq_hw_s *hw, const int sa_idx, u32 *pn)
257aec0f1aaSDmitry Bogdanov {
258aec0f1aaSDmitry Bogdanov struct aq_mss_ingress_sa_record sa_rec;
259aec0f1aaSDmitry Bogdanov int ret;
260aec0f1aaSDmitry Bogdanov
261aec0f1aaSDmitry Bogdanov ret = aq_mss_get_ingress_sa_record(hw, &sa_rec, sa_idx);
262aec0f1aaSDmitry Bogdanov if (likely(!ret))
263aec0f1aaSDmitry Bogdanov *pn = (!sa_rec.sat_nextpn) ? sa_rec.next_pn : 0;
264aec0f1aaSDmitry Bogdanov
265aec0f1aaSDmitry Bogdanov return ret;
266aec0f1aaSDmitry Bogdanov }
267aec0f1aaSDmitry Bogdanov
aq_get_txsc_stats(struct aq_hw_s * hw,const int sc_idx,struct aq_macsec_tx_sc_stats * stats)268aec0f1aaSDmitry Bogdanov static int aq_get_txsc_stats(struct aq_hw_s *hw, const int sc_idx,
269aec0f1aaSDmitry Bogdanov struct aq_macsec_tx_sc_stats *stats)
270aec0f1aaSDmitry Bogdanov {
271aec0f1aaSDmitry Bogdanov struct aq_mss_egress_sc_counters e_sc_counters;
272aec0f1aaSDmitry Bogdanov int ret;
273aec0f1aaSDmitry Bogdanov
274aec0f1aaSDmitry Bogdanov ret = aq_mss_get_egress_sc_counters(hw, &e_sc_counters, sc_idx);
275aec0f1aaSDmitry Bogdanov if (unlikely(ret))
276aec0f1aaSDmitry Bogdanov return ret;
277aec0f1aaSDmitry Bogdanov
278aec0f1aaSDmitry Bogdanov stats->sc_protected_pkts =
279aec0f1aaSDmitry Bogdanov STATS_2x32_TO_64(e_sc_counters.sc_protected_pkts);
280aec0f1aaSDmitry Bogdanov stats->sc_encrypted_pkts =
281aec0f1aaSDmitry Bogdanov STATS_2x32_TO_64(e_sc_counters.sc_encrypted_pkts);
282aec0f1aaSDmitry Bogdanov stats->sc_protected_octets =
283aec0f1aaSDmitry Bogdanov STATS_2x32_TO_64(e_sc_counters.sc_protected_octets);
284aec0f1aaSDmitry Bogdanov stats->sc_encrypted_octets =
285aec0f1aaSDmitry Bogdanov STATS_2x32_TO_64(e_sc_counters.sc_encrypted_octets);
286aec0f1aaSDmitry Bogdanov
287aec0f1aaSDmitry Bogdanov return 0;
288aec0f1aaSDmitry Bogdanov }
289aec0f1aaSDmitry Bogdanov
aq_mdo_dev_open(struct macsec_context * ctx)29062c1c2e6SDmitry Bogdanov static int aq_mdo_dev_open(struct macsec_context *ctx)
29162c1c2e6SDmitry Bogdanov {
292*bd9424efSSubbaraya Sundeep struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev);
29327736563SDmitry Bogdanov int ret = 0;
29427736563SDmitry Bogdanov
29527736563SDmitry Bogdanov if (netif_carrier_ok(nic->ndev))
29627736563SDmitry Bogdanov ret = aq_apply_secy_cfg(nic, ctx->secy);
29727736563SDmitry Bogdanov
29827736563SDmitry Bogdanov return ret;
29962c1c2e6SDmitry Bogdanov }
30062c1c2e6SDmitry Bogdanov
aq_mdo_dev_stop(struct macsec_context * ctx)30162c1c2e6SDmitry Bogdanov static int aq_mdo_dev_stop(struct macsec_context *ctx)
30262c1c2e6SDmitry Bogdanov {
303*bd9424efSSubbaraya Sundeep struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev);
30427736563SDmitry Bogdanov int i;
30527736563SDmitry Bogdanov
30627736563SDmitry Bogdanov for (i = 0; i < AQ_MACSEC_MAX_SC; i++) {
30727736563SDmitry Bogdanov if (nic->macsec_cfg->txsc_idx_busy & BIT(i))
30827736563SDmitry Bogdanov aq_clear_secy(nic, nic->macsec_cfg->aq_txsc[i].sw_secy,
30927736563SDmitry Bogdanov AQ_CLEAR_HW);
31027736563SDmitry Bogdanov }
31127736563SDmitry Bogdanov
31227736563SDmitry Bogdanov return 0;
31327736563SDmitry Bogdanov }
31427736563SDmitry Bogdanov
aq_set_txsc(struct aq_nic_s * nic,const int txsc_idx)31527736563SDmitry Bogdanov static int aq_set_txsc(struct aq_nic_s *nic, const int txsc_idx)
31627736563SDmitry Bogdanov {
31727736563SDmitry Bogdanov struct aq_macsec_txsc *aq_txsc = &nic->macsec_cfg->aq_txsc[txsc_idx];
31827736563SDmitry Bogdanov struct aq_mss_egress_class_record tx_class_rec = { 0 };
31927736563SDmitry Bogdanov const struct macsec_secy *secy = aq_txsc->sw_secy;
32027736563SDmitry Bogdanov struct aq_mss_egress_sc_record sc_rec = { 0 };
32127736563SDmitry Bogdanov unsigned int sc_idx = aq_txsc->hw_sc_idx;
32227736563SDmitry Bogdanov struct aq_hw_s *hw = nic->aq_hw;
32327736563SDmitry Bogdanov int ret = 0;
32427736563SDmitry Bogdanov
32527736563SDmitry Bogdanov aq_ether_addr_to_mac(tx_class_rec.mac_sa, secy->netdev->dev_addr);
32627736563SDmitry Bogdanov
32727736563SDmitry Bogdanov put_unaligned_be64((__force u64)secy->sci, tx_class_rec.sci);
32827736563SDmitry Bogdanov tx_class_rec.sci_mask = 0;
32927736563SDmitry Bogdanov
33027736563SDmitry Bogdanov tx_class_rec.sa_mask = 0x3f;
33127736563SDmitry Bogdanov
33227736563SDmitry Bogdanov tx_class_rec.action = 0; /* forward to SA/SC table */
33327736563SDmitry Bogdanov tx_class_rec.valid = 1;
33427736563SDmitry Bogdanov
33527736563SDmitry Bogdanov tx_class_rec.sc_idx = sc_idx;
33627736563SDmitry Bogdanov
33727736563SDmitry Bogdanov tx_class_rec.sc_sa = nic->macsec_cfg->sc_sa;
33827736563SDmitry Bogdanov
33927736563SDmitry Bogdanov ret = aq_mss_set_egress_class_record(hw, &tx_class_rec, txsc_idx);
34027736563SDmitry Bogdanov if (ret)
34127736563SDmitry Bogdanov return ret;
34227736563SDmitry Bogdanov
34327736563SDmitry Bogdanov sc_rec.protect = secy->protect_frames;
34427736563SDmitry Bogdanov if (secy->tx_sc.encrypt)
34527736563SDmitry Bogdanov sc_rec.tci |= BIT(1);
34627736563SDmitry Bogdanov if (secy->tx_sc.scb)
34727736563SDmitry Bogdanov sc_rec.tci |= BIT(2);
34827736563SDmitry Bogdanov if (secy->tx_sc.send_sci)
34927736563SDmitry Bogdanov sc_rec.tci |= BIT(3);
35027736563SDmitry Bogdanov if (secy->tx_sc.end_station)
35127736563SDmitry Bogdanov sc_rec.tci |= BIT(4);
35227736563SDmitry Bogdanov /* The C bit is clear if and only if the Secure Data is
35327736563SDmitry Bogdanov * exactly the same as the User Data and the ICV is 16 octets long.
35427736563SDmitry Bogdanov */
35527736563SDmitry Bogdanov if (!(secy->icv_len == 16 && !secy->tx_sc.encrypt))
35627736563SDmitry Bogdanov sc_rec.tci |= BIT(0);
35727736563SDmitry Bogdanov
35827736563SDmitry Bogdanov sc_rec.an_roll = 0;
35927736563SDmitry Bogdanov
36027736563SDmitry Bogdanov switch (secy->key_len) {
36127736563SDmitry Bogdanov case AQ_MACSEC_KEY_LEN_128_BIT:
36227736563SDmitry Bogdanov sc_rec.sak_len = 0;
36327736563SDmitry Bogdanov break;
36427736563SDmitry Bogdanov case AQ_MACSEC_KEY_LEN_192_BIT:
36527736563SDmitry Bogdanov sc_rec.sak_len = 1;
36627736563SDmitry Bogdanov break;
36727736563SDmitry Bogdanov case AQ_MACSEC_KEY_LEN_256_BIT:
36827736563SDmitry Bogdanov sc_rec.sak_len = 2;
36927736563SDmitry Bogdanov break;
37027736563SDmitry Bogdanov default:
37127736563SDmitry Bogdanov WARN_ONCE(true, "Invalid sc_sa");
37227736563SDmitry Bogdanov return -EINVAL;
37327736563SDmitry Bogdanov }
37427736563SDmitry Bogdanov
37527736563SDmitry Bogdanov sc_rec.curr_an = secy->tx_sc.encoding_sa;
37627736563SDmitry Bogdanov sc_rec.valid = 1;
37727736563SDmitry Bogdanov sc_rec.fresh = 1;
37827736563SDmitry Bogdanov
37927736563SDmitry Bogdanov return aq_mss_set_egress_sc_record(hw, &sc_rec, sc_idx);
38027736563SDmitry Bogdanov }
38127736563SDmitry Bogdanov
aq_sc_idx_max(const enum aq_macsec_sc_sa sc_sa)38227736563SDmitry Bogdanov static u32 aq_sc_idx_max(const enum aq_macsec_sc_sa sc_sa)
38327736563SDmitry Bogdanov {
38427736563SDmitry Bogdanov u32 result = 0;
38527736563SDmitry Bogdanov
38627736563SDmitry Bogdanov switch (sc_sa) {
38727736563SDmitry Bogdanov case aq_macsec_sa_sc_4sa_8sc:
38827736563SDmitry Bogdanov result = 8;
38927736563SDmitry Bogdanov break;
39027736563SDmitry Bogdanov case aq_macsec_sa_sc_2sa_16sc:
39127736563SDmitry Bogdanov result = 16;
39227736563SDmitry Bogdanov break;
39327736563SDmitry Bogdanov case aq_macsec_sa_sc_1sa_32sc:
39427736563SDmitry Bogdanov result = 32;
39527736563SDmitry Bogdanov break;
39627736563SDmitry Bogdanov default:
39727736563SDmitry Bogdanov break;
398d9e4171aSZheng Bin }
39927736563SDmitry Bogdanov
40027736563SDmitry Bogdanov return result;
40127736563SDmitry Bogdanov }
40227736563SDmitry Bogdanov
aq_to_hw_sc_idx(const u32 sc_idx,const enum aq_macsec_sc_sa sc_sa)40327736563SDmitry Bogdanov static u32 aq_to_hw_sc_idx(const u32 sc_idx, const enum aq_macsec_sc_sa sc_sa)
40427736563SDmitry Bogdanov {
40527736563SDmitry Bogdanov switch (sc_sa) {
40627736563SDmitry Bogdanov case aq_macsec_sa_sc_4sa_8sc:
40727736563SDmitry Bogdanov return sc_idx << 2;
40827736563SDmitry Bogdanov case aq_macsec_sa_sc_2sa_16sc:
40927736563SDmitry Bogdanov return sc_idx << 1;
41027736563SDmitry Bogdanov case aq_macsec_sa_sc_1sa_32sc:
41127736563SDmitry Bogdanov return sc_idx;
41227736563SDmitry Bogdanov default:
41327736563SDmitry Bogdanov WARN_ONCE(true, "Invalid sc_sa");
414d9e4171aSZheng Bin }
41527736563SDmitry Bogdanov
41627736563SDmitry Bogdanov return sc_idx;
41727736563SDmitry Bogdanov }
41827736563SDmitry Bogdanov
sc_sa_from_num_an(const int num_an)41927736563SDmitry Bogdanov static enum aq_macsec_sc_sa sc_sa_from_num_an(const int num_an)
42027736563SDmitry Bogdanov {
42127736563SDmitry Bogdanov enum aq_macsec_sc_sa sc_sa = aq_macsec_sa_sc_not_used;
42227736563SDmitry Bogdanov
42327736563SDmitry Bogdanov switch (num_an) {
42427736563SDmitry Bogdanov case 4:
42527736563SDmitry Bogdanov sc_sa = aq_macsec_sa_sc_4sa_8sc;
42627736563SDmitry Bogdanov break;
42727736563SDmitry Bogdanov case 2:
42827736563SDmitry Bogdanov sc_sa = aq_macsec_sa_sc_2sa_16sc;
42927736563SDmitry Bogdanov break;
43027736563SDmitry Bogdanov case 1:
43127736563SDmitry Bogdanov sc_sa = aq_macsec_sa_sc_1sa_32sc;
43227736563SDmitry Bogdanov break;
43327736563SDmitry Bogdanov default:
43427736563SDmitry Bogdanov break;
43527736563SDmitry Bogdanov }
43627736563SDmitry Bogdanov
43727736563SDmitry Bogdanov return sc_sa;
43862c1c2e6SDmitry Bogdanov }
43962c1c2e6SDmitry Bogdanov
aq_mdo_add_secy(struct macsec_context * ctx)44062c1c2e6SDmitry Bogdanov static int aq_mdo_add_secy(struct macsec_context *ctx)
44162c1c2e6SDmitry Bogdanov {
442*bd9424efSSubbaraya Sundeep struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev);
44327736563SDmitry Bogdanov struct aq_macsec_cfg *cfg = nic->macsec_cfg;
44427736563SDmitry Bogdanov const struct macsec_secy *secy = ctx->secy;
44527736563SDmitry Bogdanov enum aq_macsec_sc_sa sc_sa;
44627736563SDmitry Bogdanov u32 txsc_idx;
44727736563SDmitry Bogdanov int ret = 0;
44827736563SDmitry Bogdanov
449e8e9e13cSMark Starovoytov if (secy->xpn)
450e8e9e13cSMark Starovoytov return -EOPNOTSUPP;
451e8e9e13cSMark Starovoytov
45227736563SDmitry Bogdanov sc_sa = sc_sa_from_num_an(MACSEC_NUM_AN);
45327736563SDmitry Bogdanov if (sc_sa == aq_macsec_sa_sc_not_used)
45427736563SDmitry Bogdanov return -EINVAL;
45527736563SDmitry Bogdanov
45627736563SDmitry Bogdanov if (hweight32(cfg->txsc_idx_busy) >= aq_sc_idx_max(sc_sa))
45727736563SDmitry Bogdanov return -ENOSPC;
45827736563SDmitry Bogdanov
45927736563SDmitry Bogdanov txsc_idx = ffz(cfg->txsc_idx_busy);
46027736563SDmitry Bogdanov if (txsc_idx == AQ_MACSEC_MAX_SC)
46127736563SDmitry Bogdanov return -ENOSPC;
46227736563SDmitry Bogdanov
46327736563SDmitry Bogdanov cfg->sc_sa = sc_sa;
46427736563SDmitry Bogdanov cfg->aq_txsc[txsc_idx].hw_sc_idx = aq_to_hw_sc_idx(txsc_idx, sc_sa);
46527736563SDmitry Bogdanov cfg->aq_txsc[txsc_idx].sw_secy = secy;
46627736563SDmitry Bogdanov
46727736563SDmitry Bogdanov if (netif_carrier_ok(nic->ndev) && netif_running(secy->netdev))
46827736563SDmitry Bogdanov ret = aq_set_txsc(nic, txsc_idx);
46927736563SDmitry Bogdanov
47027736563SDmitry Bogdanov set_bit(txsc_idx, &cfg->txsc_idx_busy);
47127736563SDmitry Bogdanov
4728ce84271SDmitry Bezrukov return ret;
47362c1c2e6SDmitry Bogdanov }
47462c1c2e6SDmitry Bogdanov
aq_mdo_upd_secy(struct macsec_context * ctx)47562c1c2e6SDmitry Bogdanov static int aq_mdo_upd_secy(struct macsec_context *ctx)
47662c1c2e6SDmitry Bogdanov {
477*bd9424efSSubbaraya Sundeep struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev);
47827736563SDmitry Bogdanov const struct macsec_secy *secy = ctx->secy;
47927736563SDmitry Bogdanov int txsc_idx;
48027736563SDmitry Bogdanov int ret = 0;
48127736563SDmitry Bogdanov
48227736563SDmitry Bogdanov txsc_idx = aq_get_txsc_idx_from_secy(nic->macsec_cfg, secy);
48327736563SDmitry Bogdanov if (txsc_idx < 0)
48427736563SDmitry Bogdanov return -ENOENT;
48527736563SDmitry Bogdanov
48627736563SDmitry Bogdanov if (netif_carrier_ok(nic->ndev) && netif_running(secy->netdev))
48727736563SDmitry Bogdanov ret = aq_set_txsc(nic, txsc_idx);
48827736563SDmitry Bogdanov
48927736563SDmitry Bogdanov return ret;
49027736563SDmitry Bogdanov }
49127736563SDmitry Bogdanov
aq_clear_txsc(struct aq_nic_s * nic,const int txsc_idx,enum aq_clear_type clear_type)49227736563SDmitry Bogdanov static int aq_clear_txsc(struct aq_nic_s *nic, const int txsc_idx,
49327736563SDmitry Bogdanov enum aq_clear_type clear_type)
49427736563SDmitry Bogdanov {
49527736563SDmitry Bogdanov struct aq_macsec_txsc *tx_sc = &nic->macsec_cfg->aq_txsc[txsc_idx];
49627736563SDmitry Bogdanov struct aq_mss_egress_class_record tx_class_rec = { 0 };
49727736563SDmitry Bogdanov struct aq_mss_egress_sc_record sc_rec = { 0 };
49827736563SDmitry Bogdanov struct aq_hw_s *hw = nic->aq_hw;
49927736563SDmitry Bogdanov int ret = 0;
50027736563SDmitry Bogdanov int sa_num;
50127736563SDmitry Bogdanov
50227736563SDmitry Bogdanov for_each_set_bit (sa_num, &tx_sc->tx_sa_idx_busy, AQ_MACSEC_MAX_SA) {
50327736563SDmitry Bogdanov ret = aq_clear_txsa(nic, tx_sc, sa_num, clear_type);
50427736563SDmitry Bogdanov if (ret)
50527736563SDmitry Bogdanov return ret;
50627736563SDmitry Bogdanov }
50727736563SDmitry Bogdanov
50827736563SDmitry Bogdanov if (clear_type & AQ_CLEAR_HW) {
50927736563SDmitry Bogdanov ret = aq_mss_set_egress_class_record(hw, &tx_class_rec,
51027736563SDmitry Bogdanov txsc_idx);
51127736563SDmitry Bogdanov if (ret)
51227736563SDmitry Bogdanov return ret;
51327736563SDmitry Bogdanov
51427736563SDmitry Bogdanov sc_rec.fresh = 1;
51527736563SDmitry Bogdanov ret = aq_mss_set_egress_sc_record(hw, &sc_rec,
51627736563SDmitry Bogdanov tx_sc->hw_sc_idx);
51727736563SDmitry Bogdanov if (ret)
51827736563SDmitry Bogdanov return ret;
51927736563SDmitry Bogdanov }
52027736563SDmitry Bogdanov
52127736563SDmitry Bogdanov if (clear_type & AQ_CLEAR_SW) {
52227736563SDmitry Bogdanov clear_bit(txsc_idx, &nic->macsec_cfg->txsc_idx_busy);
52327736563SDmitry Bogdanov nic->macsec_cfg->aq_txsc[txsc_idx].sw_secy = NULL;
52427736563SDmitry Bogdanov }
52527736563SDmitry Bogdanov
52627736563SDmitry Bogdanov return ret;
52762c1c2e6SDmitry Bogdanov }
52862c1c2e6SDmitry Bogdanov
aq_mdo_del_secy(struct macsec_context * ctx)52962c1c2e6SDmitry Bogdanov static int aq_mdo_del_secy(struct macsec_context *ctx)
53062c1c2e6SDmitry Bogdanov {
531*bd9424efSSubbaraya Sundeep struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev);
53227736563SDmitry Bogdanov int ret = 0;
53327736563SDmitry Bogdanov
53427736563SDmitry Bogdanov if (!nic->macsec_cfg)
53527736563SDmitry Bogdanov return 0;
53627736563SDmitry Bogdanov
53727736563SDmitry Bogdanov ret = aq_clear_secy(nic, ctx->secy, AQ_CLEAR_ALL);
53827736563SDmitry Bogdanov
53927736563SDmitry Bogdanov return ret;
54027736563SDmitry Bogdanov }
54127736563SDmitry Bogdanov
aq_update_txsa(struct aq_nic_s * nic,const unsigned int sc_idx,const struct macsec_secy * secy,const struct macsec_tx_sa * tx_sa,const unsigned char * key,const unsigned char an)54227736563SDmitry Bogdanov static int aq_update_txsa(struct aq_nic_s *nic, const unsigned int sc_idx,
54327736563SDmitry Bogdanov const struct macsec_secy *secy,
54427736563SDmitry Bogdanov const struct macsec_tx_sa *tx_sa,
54527736563SDmitry Bogdanov const unsigned char *key, const unsigned char an)
54627736563SDmitry Bogdanov {
547e8e9e13cSMark Starovoytov const u32 next_pn = tx_sa->next_pn_halves.lower;
54827736563SDmitry Bogdanov struct aq_mss_egress_sakey_record key_rec;
54927736563SDmitry Bogdanov const unsigned int sa_idx = sc_idx | an;
55027736563SDmitry Bogdanov struct aq_mss_egress_sa_record sa_rec;
55127736563SDmitry Bogdanov struct aq_hw_s *hw = nic->aq_hw;
55227736563SDmitry Bogdanov int ret = 0;
55327736563SDmitry Bogdanov
55427736563SDmitry Bogdanov memset(&sa_rec, 0, sizeof(sa_rec));
55527736563SDmitry Bogdanov sa_rec.valid = tx_sa->active;
55627736563SDmitry Bogdanov sa_rec.fresh = 1;
557e8e9e13cSMark Starovoytov sa_rec.next_pn = next_pn;
55827736563SDmitry Bogdanov
55927736563SDmitry Bogdanov ret = aq_mss_set_egress_sa_record(hw, &sa_rec, sa_idx);
56027736563SDmitry Bogdanov if (ret)
56127736563SDmitry Bogdanov return ret;
56227736563SDmitry Bogdanov
56327736563SDmitry Bogdanov if (!key)
56427736563SDmitry Bogdanov return ret;
56527736563SDmitry Bogdanov
56627736563SDmitry Bogdanov memset(&key_rec, 0, sizeof(key_rec));
56727736563SDmitry Bogdanov memcpy(&key_rec.key, key, secy->key_len);
56827736563SDmitry Bogdanov
56927736563SDmitry Bogdanov aq_rotate_keys(&key_rec.key, secy->key_len);
57027736563SDmitry Bogdanov
57127736563SDmitry Bogdanov ret = aq_mss_set_egress_sakey_record(hw, &key_rec, sa_idx);
57227736563SDmitry Bogdanov
573879785deSAntoine Tenart memzero_explicit(&key_rec, sizeof(key_rec));
57427736563SDmitry Bogdanov return ret;
57562c1c2e6SDmitry Bogdanov }
57662c1c2e6SDmitry Bogdanov
aq_mdo_add_txsa(struct macsec_context * ctx)57762c1c2e6SDmitry Bogdanov static int aq_mdo_add_txsa(struct macsec_context *ctx)
57862c1c2e6SDmitry Bogdanov {
579*bd9424efSSubbaraya Sundeep struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev);
58027736563SDmitry Bogdanov struct aq_macsec_cfg *cfg = nic->macsec_cfg;
58127736563SDmitry Bogdanov const struct macsec_secy *secy = ctx->secy;
58227736563SDmitry Bogdanov struct aq_macsec_txsc *aq_txsc;
58327736563SDmitry Bogdanov int txsc_idx;
58427736563SDmitry Bogdanov int ret = 0;
58527736563SDmitry Bogdanov
58627736563SDmitry Bogdanov txsc_idx = aq_get_txsc_idx_from_secy(cfg, secy);
58727736563SDmitry Bogdanov if (txsc_idx < 0)
58827736563SDmitry Bogdanov return -EINVAL;
58927736563SDmitry Bogdanov
59027736563SDmitry Bogdanov aq_txsc = &cfg->aq_txsc[txsc_idx];
59127736563SDmitry Bogdanov set_bit(ctx->sa.assoc_num, &aq_txsc->tx_sa_idx_busy);
59227736563SDmitry Bogdanov
59327736563SDmitry Bogdanov memcpy(aq_txsc->tx_sa_key[ctx->sa.assoc_num], ctx->sa.key,
59427736563SDmitry Bogdanov secy->key_len);
59527736563SDmitry Bogdanov
59627736563SDmitry Bogdanov if (netif_carrier_ok(nic->ndev) && netif_running(secy->netdev))
59727736563SDmitry Bogdanov ret = aq_update_txsa(nic, aq_txsc->hw_sc_idx, secy,
59827736563SDmitry Bogdanov ctx->sa.tx_sa, ctx->sa.key,
59927736563SDmitry Bogdanov ctx->sa.assoc_num);
60027736563SDmitry Bogdanov
60127736563SDmitry Bogdanov return ret;
60262c1c2e6SDmitry Bogdanov }
60362c1c2e6SDmitry Bogdanov
aq_mdo_upd_txsa(struct macsec_context * ctx)60462c1c2e6SDmitry Bogdanov static int aq_mdo_upd_txsa(struct macsec_context *ctx)
60562c1c2e6SDmitry Bogdanov {
606*bd9424efSSubbaraya Sundeep struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev);
60727736563SDmitry Bogdanov struct aq_macsec_cfg *cfg = nic->macsec_cfg;
60827736563SDmitry Bogdanov const struct macsec_secy *secy = ctx->secy;
60927736563SDmitry Bogdanov struct aq_macsec_txsc *aq_txsc;
61027736563SDmitry Bogdanov int txsc_idx;
61127736563SDmitry Bogdanov int ret = 0;
61227736563SDmitry Bogdanov
61327736563SDmitry Bogdanov txsc_idx = aq_get_txsc_idx_from_secy(cfg, secy);
61427736563SDmitry Bogdanov if (txsc_idx < 0)
61527736563SDmitry Bogdanov return -EINVAL;
61627736563SDmitry Bogdanov
61727736563SDmitry Bogdanov aq_txsc = &cfg->aq_txsc[txsc_idx];
61827736563SDmitry Bogdanov if (netif_carrier_ok(nic->ndev) && netif_running(secy->netdev))
61927736563SDmitry Bogdanov ret = aq_update_txsa(nic, aq_txsc->hw_sc_idx, secy,
62027736563SDmitry Bogdanov ctx->sa.tx_sa, NULL, ctx->sa.assoc_num);
62127736563SDmitry Bogdanov
62227736563SDmitry Bogdanov return ret;
62327736563SDmitry Bogdanov }
62427736563SDmitry Bogdanov
aq_clear_txsa(struct aq_nic_s * nic,struct aq_macsec_txsc * aq_txsc,const int sa_num,enum aq_clear_type clear_type)62527736563SDmitry Bogdanov static int aq_clear_txsa(struct aq_nic_s *nic, struct aq_macsec_txsc *aq_txsc,
62627736563SDmitry Bogdanov const int sa_num, enum aq_clear_type clear_type)
62727736563SDmitry Bogdanov {
62827736563SDmitry Bogdanov const int sa_idx = aq_txsc->hw_sc_idx | sa_num;
62927736563SDmitry Bogdanov struct aq_hw_s *hw = nic->aq_hw;
63027736563SDmitry Bogdanov int ret = 0;
63127736563SDmitry Bogdanov
63227736563SDmitry Bogdanov if (clear_type & AQ_CLEAR_SW)
63327736563SDmitry Bogdanov clear_bit(sa_num, &aq_txsc->tx_sa_idx_busy);
63427736563SDmitry Bogdanov
63527736563SDmitry Bogdanov if ((clear_type & AQ_CLEAR_HW) && netif_carrier_ok(nic->ndev)) {
63627736563SDmitry Bogdanov struct aq_mss_egress_sakey_record key_rec;
63727736563SDmitry Bogdanov struct aq_mss_egress_sa_record sa_rec;
63827736563SDmitry Bogdanov
63927736563SDmitry Bogdanov memset(&sa_rec, 0, sizeof(sa_rec));
64027736563SDmitry Bogdanov sa_rec.fresh = 1;
64127736563SDmitry Bogdanov
64227736563SDmitry Bogdanov ret = aq_mss_set_egress_sa_record(hw, &sa_rec, sa_idx);
64327736563SDmitry Bogdanov if (ret)
64427736563SDmitry Bogdanov return ret;
64527736563SDmitry Bogdanov
64627736563SDmitry Bogdanov memset(&key_rec, 0, sizeof(key_rec));
64727736563SDmitry Bogdanov return aq_mss_set_egress_sakey_record(hw, &key_rec, sa_idx);
64827736563SDmitry Bogdanov }
64927736563SDmitry Bogdanov
65027736563SDmitry Bogdanov return 0;
65162c1c2e6SDmitry Bogdanov }
65262c1c2e6SDmitry Bogdanov
aq_mdo_del_txsa(struct macsec_context * ctx)65362c1c2e6SDmitry Bogdanov static int aq_mdo_del_txsa(struct macsec_context *ctx)
65462c1c2e6SDmitry Bogdanov {
655*bd9424efSSubbaraya Sundeep struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev);
65627736563SDmitry Bogdanov struct aq_macsec_cfg *cfg = nic->macsec_cfg;
65727736563SDmitry Bogdanov int txsc_idx;
65827736563SDmitry Bogdanov int ret = 0;
65927736563SDmitry Bogdanov
66027736563SDmitry Bogdanov txsc_idx = aq_get_txsc_idx_from_secy(cfg, ctx->secy);
66127736563SDmitry Bogdanov if (txsc_idx < 0)
66227736563SDmitry Bogdanov return -EINVAL;
66327736563SDmitry Bogdanov
66427736563SDmitry Bogdanov ret = aq_clear_txsa(nic, &cfg->aq_txsc[txsc_idx], ctx->sa.assoc_num,
66527736563SDmitry Bogdanov AQ_CLEAR_ALL);
66627736563SDmitry Bogdanov
66727736563SDmitry Bogdanov return ret;
66862c1c2e6SDmitry Bogdanov }
66962c1c2e6SDmitry Bogdanov
aq_rxsc_validate_frames(const enum macsec_validation_type validate)6709ff40a75SMark Starovoytov static int aq_rxsc_validate_frames(const enum macsec_validation_type validate)
6719ff40a75SMark Starovoytov {
6729ff40a75SMark Starovoytov switch (validate) {
6739ff40a75SMark Starovoytov case MACSEC_VALIDATE_DISABLED:
6749ff40a75SMark Starovoytov return 2;
6759ff40a75SMark Starovoytov case MACSEC_VALIDATE_CHECK:
6769ff40a75SMark Starovoytov return 1;
6779ff40a75SMark Starovoytov case MACSEC_VALIDATE_STRICT:
6789ff40a75SMark Starovoytov return 0;
6799ff40a75SMark Starovoytov default:
6809ff40a75SMark Starovoytov WARN_ONCE(true, "Invalid validation type");
6819ff40a75SMark Starovoytov }
6829ff40a75SMark Starovoytov
6839ff40a75SMark Starovoytov return 0;
6849ff40a75SMark Starovoytov }
6859ff40a75SMark Starovoytov
aq_set_rxsc(struct aq_nic_s * nic,const u32 rxsc_idx)6869ff40a75SMark Starovoytov static int aq_set_rxsc(struct aq_nic_s *nic, const u32 rxsc_idx)
6879ff40a75SMark Starovoytov {
6889ff40a75SMark Starovoytov const struct aq_macsec_rxsc *aq_rxsc =
6899ff40a75SMark Starovoytov &nic->macsec_cfg->aq_rxsc[rxsc_idx];
6909ff40a75SMark Starovoytov struct aq_mss_ingress_preclass_record pre_class_record;
6919ff40a75SMark Starovoytov const struct macsec_rx_sc *rx_sc = aq_rxsc->sw_rxsc;
6929ff40a75SMark Starovoytov const struct macsec_secy *secy = aq_rxsc->sw_secy;
6939ff40a75SMark Starovoytov const u32 hw_sc_idx = aq_rxsc->hw_sc_idx;
6949ff40a75SMark Starovoytov struct aq_mss_ingress_sc_record sc_record;
6959ff40a75SMark Starovoytov struct aq_hw_s *hw = nic->aq_hw;
6969ff40a75SMark Starovoytov int ret = 0;
6979ff40a75SMark Starovoytov
6989ff40a75SMark Starovoytov memset(&pre_class_record, 0, sizeof(pre_class_record));
6999ff40a75SMark Starovoytov put_unaligned_be64((__force u64)rx_sc->sci, pre_class_record.sci);
7009ff40a75SMark Starovoytov pre_class_record.sci_mask = 0xff;
7019ff40a75SMark Starovoytov /* match all MACSEC ethertype packets */
7029ff40a75SMark Starovoytov pre_class_record.eth_type = ETH_P_MACSEC;
7039ff40a75SMark Starovoytov pre_class_record.eth_type_mask = 0x3;
7049ff40a75SMark Starovoytov
7059ff40a75SMark Starovoytov aq_ether_addr_to_mac(pre_class_record.mac_sa, (char *)&rx_sc->sci);
7069ff40a75SMark Starovoytov pre_class_record.sa_mask = 0x3f;
7079ff40a75SMark Starovoytov
7089ff40a75SMark Starovoytov pre_class_record.an_mask = nic->macsec_cfg->sc_sa;
7099ff40a75SMark Starovoytov pre_class_record.sc_idx = hw_sc_idx;
7109ff40a75SMark Starovoytov /* strip SecTAG & forward for decryption */
7119ff40a75SMark Starovoytov pre_class_record.action = 0x0;
7129ff40a75SMark Starovoytov pre_class_record.valid = 1;
7139ff40a75SMark Starovoytov
7149ff40a75SMark Starovoytov ret = aq_mss_set_ingress_preclass_record(hw, &pre_class_record,
7159ff40a75SMark Starovoytov 2 * rxsc_idx + 1);
7169ff40a75SMark Starovoytov if (ret)
7179ff40a75SMark Starovoytov return ret;
7189ff40a75SMark Starovoytov
7199ff40a75SMark Starovoytov /* If SCI is absent, then match by SA alone */
7209ff40a75SMark Starovoytov pre_class_record.sci_mask = 0;
7219ff40a75SMark Starovoytov pre_class_record.sci_from_table = 1;
7229ff40a75SMark Starovoytov
7239ff40a75SMark Starovoytov ret = aq_mss_set_ingress_preclass_record(hw, &pre_class_record,
7249ff40a75SMark Starovoytov 2 * rxsc_idx);
7259ff40a75SMark Starovoytov if (ret)
7269ff40a75SMark Starovoytov return ret;
7279ff40a75SMark Starovoytov
7289ff40a75SMark Starovoytov memset(&sc_record, 0, sizeof(sc_record));
7299ff40a75SMark Starovoytov sc_record.validate_frames =
7309ff40a75SMark Starovoytov aq_rxsc_validate_frames(secy->validate_frames);
7319ff40a75SMark Starovoytov if (secy->replay_protect) {
7329ff40a75SMark Starovoytov sc_record.replay_protect = 1;
7339ff40a75SMark Starovoytov sc_record.anti_replay_window = secy->replay_window;
7349ff40a75SMark Starovoytov }
7359ff40a75SMark Starovoytov sc_record.valid = 1;
7369ff40a75SMark Starovoytov sc_record.fresh = 1;
7379ff40a75SMark Starovoytov
7389ff40a75SMark Starovoytov ret = aq_mss_set_ingress_sc_record(hw, &sc_record, hw_sc_idx);
7399ff40a75SMark Starovoytov if (ret)
7409ff40a75SMark Starovoytov return ret;
7419ff40a75SMark Starovoytov
7429ff40a75SMark Starovoytov return ret;
7439ff40a75SMark Starovoytov }
7449ff40a75SMark Starovoytov
aq_mdo_add_rxsc(struct macsec_context * ctx)74562c1c2e6SDmitry Bogdanov static int aq_mdo_add_rxsc(struct macsec_context *ctx)
74662c1c2e6SDmitry Bogdanov {
747*bd9424efSSubbaraya Sundeep struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev);
7489ff40a75SMark Starovoytov struct aq_macsec_cfg *cfg = nic->macsec_cfg;
7499ff40a75SMark Starovoytov const u32 rxsc_idx_max = aq_sc_idx_max(cfg->sc_sa);
7509ff40a75SMark Starovoytov u32 rxsc_idx;
7519ff40a75SMark Starovoytov int ret = 0;
7529ff40a75SMark Starovoytov
7539ff40a75SMark Starovoytov if (hweight32(cfg->rxsc_idx_busy) >= rxsc_idx_max)
7549ff40a75SMark Starovoytov return -ENOSPC;
7559ff40a75SMark Starovoytov
7569ff40a75SMark Starovoytov rxsc_idx = ffz(cfg->rxsc_idx_busy);
7579ff40a75SMark Starovoytov if (rxsc_idx >= rxsc_idx_max)
7589ff40a75SMark Starovoytov return -ENOSPC;
7599ff40a75SMark Starovoytov
7609ff40a75SMark Starovoytov cfg->aq_rxsc[rxsc_idx].hw_sc_idx = aq_to_hw_sc_idx(rxsc_idx,
7619ff40a75SMark Starovoytov cfg->sc_sa);
7629ff40a75SMark Starovoytov cfg->aq_rxsc[rxsc_idx].sw_secy = ctx->secy;
7639ff40a75SMark Starovoytov cfg->aq_rxsc[rxsc_idx].sw_rxsc = ctx->rx_sc;
7649ff40a75SMark Starovoytov
7659ff40a75SMark Starovoytov if (netif_carrier_ok(nic->ndev) && netif_running(ctx->secy->netdev))
7669ff40a75SMark Starovoytov ret = aq_set_rxsc(nic, rxsc_idx);
7679ff40a75SMark Starovoytov
7689ff40a75SMark Starovoytov if (ret < 0)
7699ff40a75SMark Starovoytov return ret;
7709ff40a75SMark Starovoytov
7719ff40a75SMark Starovoytov set_bit(rxsc_idx, &cfg->rxsc_idx_busy);
7729ff40a75SMark Starovoytov
7739ff40a75SMark Starovoytov return 0;
77462c1c2e6SDmitry Bogdanov }
77562c1c2e6SDmitry Bogdanov
aq_mdo_upd_rxsc(struct macsec_context * ctx)77662c1c2e6SDmitry Bogdanov static int aq_mdo_upd_rxsc(struct macsec_context *ctx)
77762c1c2e6SDmitry Bogdanov {
778*bd9424efSSubbaraya Sundeep struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev);
7799ff40a75SMark Starovoytov int rxsc_idx;
7809ff40a75SMark Starovoytov int ret = 0;
7819ff40a75SMark Starovoytov
7829ff40a75SMark Starovoytov rxsc_idx = aq_get_rxsc_idx_from_rxsc(nic->macsec_cfg, ctx->rx_sc);
7839ff40a75SMark Starovoytov if (rxsc_idx < 0)
7849ff40a75SMark Starovoytov return -ENOENT;
7859ff40a75SMark Starovoytov
7869ff40a75SMark Starovoytov if (netif_carrier_ok(nic->ndev) && netif_running(ctx->secy->netdev))
7879ff40a75SMark Starovoytov ret = aq_set_rxsc(nic, rxsc_idx);
7889ff40a75SMark Starovoytov
7899ff40a75SMark Starovoytov return ret;
7909ff40a75SMark Starovoytov }
7919ff40a75SMark Starovoytov
aq_clear_rxsc(struct aq_nic_s * nic,const int rxsc_idx,enum aq_clear_type clear_type)7929ff40a75SMark Starovoytov static int aq_clear_rxsc(struct aq_nic_s *nic, const int rxsc_idx,
7939ff40a75SMark Starovoytov enum aq_clear_type clear_type)
7949ff40a75SMark Starovoytov {
7959ff40a75SMark Starovoytov struct aq_macsec_rxsc *rx_sc = &nic->macsec_cfg->aq_rxsc[rxsc_idx];
7969ff40a75SMark Starovoytov struct aq_hw_s *hw = nic->aq_hw;
7979ff40a75SMark Starovoytov int ret = 0;
7989ff40a75SMark Starovoytov int sa_num;
7999ff40a75SMark Starovoytov
8009ff40a75SMark Starovoytov for_each_set_bit (sa_num, &rx_sc->rx_sa_idx_busy, AQ_MACSEC_MAX_SA) {
8019ff40a75SMark Starovoytov ret = aq_clear_rxsa(nic, rx_sc, sa_num, clear_type);
8029ff40a75SMark Starovoytov if (ret)
8039ff40a75SMark Starovoytov return ret;
8049ff40a75SMark Starovoytov }
8059ff40a75SMark Starovoytov
8069ff40a75SMark Starovoytov if (clear_type & AQ_CLEAR_HW) {
8079ff40a75SMark Starovoytov struct aq_mss_ingress_preclass_record pre_class_record;
8089ff40a75SMark Starovoytov struct aq_mss_ingress_sc_record sc_record;
8099ff40a75SMark Starovoytov
8109ff40a75SMark Starovoytov memset(&pre_class_record, 0, sizeof(pre_class_record));
8119ff40a75SMark Starovoytov memset(&sc_record, 0, sizeof(sc_record));
8129ff40a75SMark Starovoytov
8139ff40a75SMark Starovoytov ret = aq_mss_set_ingress_preclass_record(hw, &pre_class_record,
8149ff40a75SMark Starovoytov 2 * rxsc_idx);
8159ff40a75SMark Starovoytov if (ret)
8169ff40a75SMark Starovoytov return ret;
8179ff40a75SMark Starovoytov
8189ff40a75SMark Starovoytov ret = aq_mss_set_ingress_preclass_record(hw, &pre_class_record,
8199ff40a75SMark Starovoytov 2 * rxsc_idx + 1);
8209ff40a75SMark Starovoytov if (ret)
8219ff40a75SMark Starovoytov return ret;
8229ff40a75SMark Starovoytov
8239ff40a75SMark Starovoytov sc_record.fresh = 1;
8249ff40a75SMark Starovoytov ret = aq_mss_set_ingress_sc_record(hw, &sc_record,
8259ff40a75SMark Starovoytov rx_sc->hw_sc_idx);
8269ff40a75SMark Starovoytov if (ret)
8279ff40a75SMark Starovoytov return ret;
8289ff40a75SMark Starovoytov }
8299ff40a75SMark Starovoytov
8309ff40a75SMark Starovoytov if (clear_type & AQ_CLEAR_SW) {
8319ff40a75SMark Starovoytov clear_bit(rxsc_idx, &nic->macsec_cfg->rxsc_idx_busy);
8329ff40a75SMark Starovoytov rx_sc->sw_secy = NULL;
8339ff40a75SMark Starovoytov rx_sc->sw_rxsc = NULL;
8349ff40a75SMark Starovoytov }
8359ff40a75SMark Starovoytov
8369ff40a75SMark Starovoytov return ret;
83762c1c2e6SDmitry Bogdanov }
83862c1c2e6SDmitry Bogdanov
aq_mdo_del_rxsc(struct macsec_context * ctx)83962c1c2e6SDmitry Bogdanov static int aq_mdo_del_rxsc(struct macsec_context *ctx)
84062c1c2e6SDmitry Bogdanov {
841*bd9424efSSubbaraya Sundeep struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev);
8429ff40a75SMark Starovoytov enum aq_clear_type clear_type = AQ_CLEAR_SW;
8439ff40a75SMark Starovoytov int rxsc_idx;
8449ff40a75SMark Starovoytov int ret = 0;
8459ff40a75SMark Starovoytov
8469ff40a75SMark Starovoytov rxsc_idx = aq_get_rxsc_idx_from_rxsc(nic->macsec_cfg, ctx->rx_sc);
8479ff40a75SMark Starovoytov if (rxsc_idx < 0)
8489ff40a75SMark Starovoytov return -ENOENT;
8499ff40a75SMark Starovoytov
8509ff40a75SMark Starovoytov if (netif_carrier_ok(nic->ndev))
8519ff40a75SMark Starovoytov clear_type = AQ_CLEAR_ALL;
8529ff40a75SMark Starovoytov
8539ff40a75SMark Starovoytov ret = aq_clear_rxsc(nic, rxsc_idx, clear_type);
8549ff40a75SMark Starovoytov
8559ff40a75SMark Starovoytov return ret;
8569ff40a75SMark Starovoytov }
8579ff40a75SMark Starovoytov
aq_update_rxsa(struct aq_nic_s * nic,const unsigned int sc_idx,const struct macsec_secy * secy,const struct macsec_rx_sa * rx_sa,const unsigned char * key,const unsigned char an)8589ff40a75SMark Starovoytov static int aq_update_rxsa(struct aq_nic_s *nic, const unsigned int sc_idx,
8599ff40a75SMark Starovoytov const struct macsec_secy *secy,
8609ff40a75SMark Starovoytov const struct macsec_rx_sa *rx_sa,
8619ff40a75SMark Starovoytov const unsigned char *key, const unsigned char an)
8629ff40a75SMark Starovoytov {
8639ff40a75SMark Starovoytov struct aq_mss_ingress_sakey_record sa_key_record;
864e8e9e13cSMark Starovoytov const u32 next_pn = rx_sa->next_pn_halves.lower;
8659ff40a75SMark Starovoytov struct aq_mss_ingress_sa_record sa_record;
8669ff40a75SMark Starovoytov struct aq_hw_s *hw = nic->aq_hw;
8679ff40a75SMark Starovoytov const int sa_idx = sc_idx | an;
8689ff40a75SMark Starovoytov int ret = 0;
8699ff40a75SMark Starovoytov
8709ff40a75SMark Starovoytov memset(&sa_record, 0, sizeof(sa_record));
8719ff40a75SMark Starovoytov sa_record.valid = rx_sa->active;
8729ff40a75SMark Starovoytov sa_record.fresh = 1;
873e8e9e13cSMark Starovoytov sa_record.next_pn = next_pn;
8749ff40a75SMark Starovoytov
8759ff40a75SMark Starovoytov ret = aq_mss_set_ingress_sa_record(hw, &sa_record, sa_idx);
8769ff40a75SMark Starovoytov if (ret)
8779ff40a75SMark Starovoytov return ret;
8789ff40a75SMark Starovoytov
8799ff40a75SMark Starovoytov if (!key)
8809ff40a75SMark Starovoytov return ret;
8819ff40a75SMark Starovoytov
8829ff40a75SMark Starovoytov memset(&sa_key_record, 0, sizeof(sa_key_record));
8839ff40a75SMark Starovoytov memcpy(&sa_key_record.key, key, secy->key_len);
8849ff40a75SMark Starovoytov
8859ff40a75SMark Starovoytov switch (secy->key_len) {
8869ff40a75SMark Starovoytov case AQ_MACSEC_KEY_LEN_128_BIT:
8879ff40a75SMark Starovoytov sa_key_record.key_len = 0;
8889ff40a75SMark Starovoytov break;
8899ff40a75SMark Starovoytov case AQ_MACSEC_KEY_LEN_192_BIT:
8909ff40a75SMark Starovoytov sa_key_record.key_len = 1;
8919ff40a75SMark Starovoytov break;
8929ff40a75SMark Starovoytov case AQ_MACSEC_KEY_LEN_256_BIT:
8939ff40a75SMark Starovoytov sa_key_record.key_len = 2;
8949ff40a75SMark Starovoytov break;
8959ff40a75SMark Starovoytov default:
8969ff40a75SMark Starovoytov return -1;
8979ff40a75SMark Starovoytov }
8989ff40a75SMark Starovoytov
8999ff40a75SMark Starovoytov aq_rotate_keys(&sa_key_record.key, secy->key_len);
9009ff40a75SMark Starovoytov
9019ff40a75SMark Starovoytov ret = aq_mss_set_ingress_sakey_record(hw, &sa_key_record, sa_idx);
9029ff40a75SMark Starovoytov
903879785deSAntoine Tenart memzero_explicit(&sa_key_record, sizeof(sa_key_record));
9049ff40a75SMark Starovoytov return ret;
90562c1c2e6SDmitry Bogdanov }
90662c1c2e6SDmitry Bogdanov
aq_mdo_add_rxsa(struct macsec_context * ctx)90762c1c2e6SDmitry Bogdanov static int aq_mdo_add_rxsa(struct macsec_context *ctx)
90862c1c2e6SDmitry Bogdanov {
909*bd9424efSSubbaraya Sundeep struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev);
9109ff40a75SMark Starovoytov const struct macsec_rx_sc *rx_sc = ctx->sa.rx_sa->sc;
9119ff40a75SMark Starovoytov const struct macsec_secy *secy = ctx->secy;
9129ff40a75SMark Starovoytov struct aq_macsec_rxsc *aq_rxsc;
9139ff40a75SMark Starovoytov int rxsc_idx;
9149ff40a75SMark Starovoytov int ret = 0;
9159ff40a75SMark Starovoytov
9169ff40a75SMark Starovoytov rxsc_idx = aq_get_rxsc_idx_from_rxsc(nic->macsec_cfg, rx_sc);
9179ff40a75SMark Starovoytov if (rxsc_idx < 0)
9189ff40a75SMark Starovoytov return -EINVAL;
9199ff40a75SMark Starovoytov
9209ff40a75SMark Starovoytov aq_rxsc = &nic->macsec_cfg->aq_rxsc[rxsc_idx];
9219ff40a75SMark Starovoytov set_bit(ctx->sa.assoc_num, &aq_rxsc->rx_sa_idx_busy);
9229ff40a75SMark Starovoytov
9239ff40a75SMark Starovoytov memcpy(aq_rxsc->rx_sa_key[ctx->sa.assoc_num], ctx->sa.key,
9249ff40a75SMark Starovoytov secy->key_len);
9259ff40a75SMark Starovoytov
9269ff40a75SMark Starovoytov if (netif_carrier_ok(nic->ndev) && netif_running(secy->netdev))
9279ff40a75SMark Starovoytov ret = aq_update_rxsa(nic, aq_rxsc->hw_sc_idx, secy,
9289ff40a75SMark Starovoytov ctx->sa.rx_sa, ctx->sa.key,
9299ff40a75SMark Starovoytov ctx->sa.assoc_num);
9309ff40a75SMark Starovoytov
9319ff40a75SMark Starovoytov return ret;
93262c1c2e6SDmitry Bogdanov }
93362c1c2e6SDmitry Bogdanov
aq_mdo_upd_rxsa(struct macsec_context * ctx)93462c1c2e6SDmitry Bogdanov static int aq_mdo_upd_rxsa(struct macsec_context *ctx)
93562c1c2e6SDmitry Bogdanov {
936*bd9424efSSubbaraya Sundeep struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev);
9379ff40a75SMark Starovoytov const struct macsec_rx_sc *rx_sc = ctx->sa.rx_sa->sc;
9389ff40a75SMark Starovoytov struct aq_macsec_cfg *cfg = nic->macsec_cfg;
9399ff40a75SMark Starovoytov const struct macsec_secy *secy = ctx->secy;
9409ff40a75SMark Starovoytov int rxsc_idx;
9419ff40a75SMark Starovoytov int ret = 0;
9429ff40a75SMark Starovoytov
9439ff40a75SMark Starovoytov rxsc_idx = aq_get_rxsc_idx_from_rxsc(cfg, rx_sc);
9449ff40a75SMark Starovoytov if (rxsc_idx < 0)
9459ff40a75SMark Starovoytov return -EINVAL;
9469ff40a75SMark Starovoytov
9479ff40a75SMark Starovoytov if (netif_carrier_ok(nic->ndev) && netif_running(secy->netdev))
9489ff40a75SMark Starovoytov ret = aq_update_rxsa(nic, cfg->aq_rxsc[rxsc_idx].hw_sc_idx,
9499ff40a75SMark Starovoytov secy, ctx->sa.rx_sa, NULL,
9509ff40a75SMark Starovoytov ctx->sa.assoc_num);
9519ff40a75SMark Starovoytov
9529ff40a75SMark Starovoytov return ret;
9539ff40a75SMark Starovoytov }
9549ff40a75SMark Starovoytov
aq_clear_rxsa(struct aq_nic_s * nic,struct aq_macsec_rxsc * aq_rxsc,const int sa_num,enum aq_clear_type clear_type)9559ff40a75SMark Starovoytov static int aq_clear_rxsa(struct aq_nic_s *nic, struct aq_macsec_rxsc *aq_rxsc,
9569ff40a75SMark Starovoytov const int sa_num, enum aq_clear_type clear_type)
9579ff40a75SMark Starovoytov {
9589ff40a75SMark Starovoytov int sa_idx = aq_rxsc->hw_sc_idx | sa_num;
9599ff40a75SMark Starovoytov struct aq_hw_s *hw = nic->aq_hw;
9609ff40a75SMark Starovoytov int ret = 0;
9619ff40a75SMark Starovoytov
9629ff40a75SMark Starovoytov if (clear_type & AQ_CLEAR_SW)
9639ff40a75SMark Starovoytov clear_bit(sa_num, &aq_rxsc->rx_sa_idx_busy);
9649ff40a75SMark Starovoytov
9659ff40a75SMark Starovoytov if ((clear_type & AQ_CLEAR_HW) && netif_carrier_ok(nic->ndev)) {
9669ff40a75SMark Starovoytov struct aq_mss_ingress_sakey_record sa_key_record;
9679ff40a75SMark Starovoytov struct aq_mss_ingress_sa_record sa_record;
9689ff40a75SMark Starovoytov
9699ff40a75SMark Starovoytov memset(&sa_key_record, 0, sizeof(sa_key_record));
9709ff40a75SMark Starovoytov memset(&sa_record, 0, sizeof(sa_record));
9719ff40a75SMark Starovoytov sa_record.fresh = 1;
9729ff40a75SMark Starovoytov ret = aq_mss_set_ingress_sa_record(hw, &sa_record, sa_idx);
9739ff40a75SMark Starovoytov if (ret)
9749ff40a75SMark Starovoytov return ret;
9759ff40a75SMark Starovoytov
9769ff40a75SMark Starovoytov return aq_mss_set_ingress_sakey_record(hw, &sa_key_record,
9779ff40a75SMark Starovoytov sa_idx);
9789ff40a75SMark Starovoytov }
9799ff40a75SMark Starovoytov
9809ff40a75SMark Starovoytov return ret;
98162c1c2e6SDmitry Bogdanov }
98262c1c2e6SDmitry Bogdanov
aq_mdo_del_rxsa(struct macsec_context * ctx)98362c1c2e6SDmitry Bogdanov static int aq_mdo_del_rxsa(struct macsec_context *ctx)
98462c1c2e6SDmitry Bogdanov {
985*bd9424efSSubbaraya Sundeep struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev);
9869ff40a75SMark Starovoytov const struct macsec_rx_sc *rx_sc = ctx->sa.rx_sa->sc;
9879ff40a75SMark Starovoytov struct aq_macsec_cfg *cfg = nic->macsec_cfg;
9889ff40a75SMark Starovoytov int rxsc_idx;
9899ff40a75SMark Starovoytov int ret = 0;
9909ff40a75SMark Starovoytov
9919ff40a75SMark Starovoytov rxsc_idx = aq_get_rxsc_idx_from_rxsc(cfg, rx_sc);
9929ff40a75SMark Starovoytov if (rxsc_idx < 0)
9939ff40a75SMark Starovoytov return -EINVAL;
9949ff40a75SMark Starovoytov
9959ff40a75SMark Starovoytov ret = aq_clear_rxsa(nic, &cfg->aq_rxsc[rxsc_idx], ctx->sa.assoc_num,
9969ff40a75SMark Starovoytov AQ_CLEAR_ALL);
9979ff40a75SMark Starovoytov
9989ff40a75SMark Starovoytov return ret;
99962c1c2e6SDmitry Bogdanov }
100062c1c2e6SDmitry Bogdanov
aq_mdo_get_dev_stats(struct macsec_context * ctx)1001aec0f1aaSDmitry Bogdanov static int aq_mdo_get_dev_stats(struct macsec_context *ctx)
1002aec0f1aaSDmitry Bogdanov {
1003*bd9424efSSubbaraya Sundeep struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev);
1004aec0f1aaSDmitry Bogdanov struct aq_macsec_common_stats *stats = &nic->macsec_cfg->stats;
1005aec0f1aaSDmitry Bogdanov struct aq_hw_s *hw = nic->aq_hw;
1006aec0f1aaSDmitry Bogdanov
1007aec0f1aaSDmitry Bogdanov aq_get_macsec_common_stats(hw, stats);
1008aec0f1aaSDmitry Bogdanov
1009aec0f1aaSDmitry Bogdanov ctx->stats.dev_stats->OutPktsUntagged = stats->out.untagged_pkts;
1010aec0f1aaSDmitry Bogdanov ctx->stats.dev_stats->InPktsUntagged = stats->in.untagged_pkts;
1011aec0f1aaSDmitry Bogdanov ctx->stats.dev_stats->OutPktsTooLong = stats->out.too_long;
1012aec0f1aaSDmitry Bogdanov ctx->stats.dev_stats->InPktsNoTag = stats->in.notag_pkts;
1013aec0f1aaSDmitry Bogdanov ctx->stats.dev_stats->InPktsBadTag = stats->in.bad_tag_pkts;
1014aec0f1aaSDmitry Bogdanov ctx->stats.dev_stats->InPktsUnknownSCI = stats->in.unknown_sci_pkts;
1015aec0f1aaSDmitry Bogdanov ctx->stats.dev_stats->InPktsNoSCI = stats->in.no_sci_pkts;
1016aec0f1aaSDmitry Bogdanov ctx->stats.dev_stats->InPktsOverrun = 0;
1017aec0f1aaSDmitry Bogdanov
1018aec0f1aaSDmitry Bogdanov return 0;
1019aec0f1aaSDmitry Bogdanov }
1020aec0f1aaSDmitry Bogdanov
aq_mdo_get_tx_sc_stats(struct macsec_context * ctx)1021aec0f1aaSDmitry Bogdanov static int aq_mdo_get_tx_sc_stats(struct macsec_context *ctx)
1022aec0f1aaSDmitry Bogdanov {
1023*bd9424efSSubbaraya Sundeep struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev);
1024aec0f1aaSDmitry Bogdanov struct aq_macsec_tx_sc_stats *stats;
1025aec0f1aaSDmitry Bogdanov struct aq_hw_s *hw = nic->aq_hw;
1026aec0f1aaSDmitry Bogdanov struct aq_macsec_txsc *aq_txsc;
1027aec0f1aaSDmitry Bogdanov int txsc_idx;
1028aec0f1aaSDmitry Bogdanov
1029aec0f1aaSDmitry Bogdanov txsc_idx = aq_get_txsc_idx_from_secy(nic->macsec_cfg, ctx->secy);
1030aec0f1aaSDmitry Bogdanov if (txsc_idx < 0)
1031aec0f1aaSDmitry Bogdanov return -ENOENT;
1032aec0f1aaSDmitry Bogdanov
1033aec0f1aaSDmitry Bogdanov aq_txsc = &nic->macsec_cfg->aq_txsc[txsc_idx];
1034aec0f1aaSDmitry Bogdanov stats = &aq_txsc->stats;
1035aec0f1aaSDmitry Bogdanov aq_get_txsc_stats(hw, aq_txsc->hw_sc_idx, stats);
1036aec0f1aaSDmitry Bogdanov
1037aec0f1aaSDmitry Bogdanov ctx->stats.tx_sc_stats->OutPktsProtected = stats->sc_protected_pkts;
1038aec0f1aaSDmitry Bogdanov ctx->stats.tx_sc_stats->OutPktsEncrypted = stats->sc_encrypted_pkts;
1039aec0f1aaSDmitry Bogdanov ctx->stats.tx_sc_stats->OutOctetsProtected = stats->sc_protected_octets;
1040aec0f1aaSDmitry Bogdanov ctx->stats.tx_sc_stats->OutOctetsEncrypted = stats->sc_encrypted_octets;
1041aec0f1aaSDmitry Bogdanov
1042aec0f1aaSDmitry Bogdanov return 0;
1043aec0f1aaSDmitry Bogdanov }
1044aec0f1aaSDmitry Bogdanov
aq_mdo_get_tx_sa_stats(struct macsec_context * ctx)1045aec0f1aaSDmitry Bogdanov static int aq_mdo_get_tx_sa_stats(struct macsec_context *ctx)
1046aec0f1aaSDmitry Bogdanov {
1047*bd9424efSSubbaraya Sundeep struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev);
1048aec0f1aaSDmitry Bogdanov struct aq_macsec_cfg *cfg = nic->macsec_cfg;
1049aec0f1aaSDmitry Bogdanov struct aq_macsec_tx_sa_stats *stats;
1050aec0f1aaSDmitry Bogdanov struct aq_hw_s *hw = nic->aq_hw;
1051aec0f1aaSDmitry Bogdanov const struct macsec_secy *secy;
1052aec0f1aaSDmitry Bogdanov struct aq_macsec_txsc *aq_txsc;
1053aec0f1aaSDmitry Bogdanov struct macsec_tx_sa *tx_sa;
1054aec0f1aaSDmitry Bogdanov unsigned int sa_idx;
1055aec0f1aaSDmitry Bogdanov int txsc_idx;
1056aec0f1aaSDmitry Bogdanov u32 next_pn;
1057aec0f1aaSDmitry Bogdanov int ret;
1058aec0f1aaSDmitry Bogdanov
1059aec0f1aaSDmitry Bogdanov txsc_idx = aq_get_txsc_idx_from_secy(cfg, ctx->secy);
1060aec0f1aaSDmitry Bogdanov if (txsc_idx < 0)
1061aec0f1aaSDmitry Bogdanov return -EINVAL;
1062aec0f1aaSDmitry Bogdanov
1063aec0f1aaSDmitry Bogdanov aq_txsc = &cfg->aq_txsc[txsc_idx];
1064aec0f1aaSDmitry Bogdanov sa_idx = aq_txsc->hw_sc_idx | ctx->sa.assoc_num;
1065aec0f1aaSDmitry Bogdanov stats = &aq_txsc->tx_sa_stats[ctx->sa.assoc_num];
1066aec0f1aaSDmitry Bogdanov ret = aq_get_txsa_stats(hw, sa_idx, stats);
1067aec0f1aaSDmitry Bogdanov if (ret)
1068aec0f1aaSDmitry Bogdanov return ret;
1069aec0f1aaSDmitry Bogdanov
1070aec0f1aaSDmitry Bogdanov ctx->stats.tx_sa_stats->OutPktsProtected = stats->sa_protected_pkts;
1071aec0f1aaSDmitry Bogdanov ctx->stats.tx_sa_stats->OutPktsEncrypted = stats->sa_encrypted_pkts;
1072aec0f1aaSDmitry Bogdanov
1073aec0f1aaSDmitry Bogdanov secy = aq_txsc->sw_secy;
1074aec0f1aaSDmitry Bogdanov tx_sa = rcu_dereference_bh(secy->tx_sc.sa[ctx->sa.assoc_num]);
1075aec0f1aaSDmitry Bogdanov ret = aq_get_txsa_next_pn(hw, sa_idx, &next_pn);
1076aec0f1aaSDmitry Bogdanov if (ret == 0) {
1077aec0f1aaSDmitry Bogdanov spin_lock_bh(&tx_sa->lock);
1078aec0f1aaSDmitry Bogdanov tx_sa->next_pn = next_pn;
1079aec0f1aaSDmitry Bogdanov spin_unlock_bh(&tx_sa->lock);
1080aec0f1aaSDmitry Bogdanov }
1081aec0f1aaSDmitry Bogdanov
1082aec0f1aaSDmitry Bogdanov return ret;
1083aec0f1aaSDmitry Bogdanov }
1084aec0f1aaSDmitry Bogdanov
aq_mdo_get_rx_sc_stats(struct macsec_context * ctx)1085aec0f1aaSDmitry Bogdanov static int aq_mdo_get_rx_sc_stats(struct macsec_context *ctx)
1086aec0f1aaSDmitry Bogdanov {
1087*bd9424efSSubbaraya Sundeep struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev);
1088aec0f1aaSDmitry Bogdanov struct aq_macsec_cfg *cfg = nic->macsec_cfg;
1089aec0f1aaSDmitry Bogdanov struct aq_macsec_rx_sa_stats *stats;
1090aec0f1aaSDmitry Bogdanov struct aq_hw_s *hw = nic->aq_hw;
1091aec0f1aaSDmitry Bogdanov struct aq_macsec_rxsc *aq_rxsc;
1092aec0f1aaSDmitry Bogdanov unsigned int sa_idx;
1093aec0f1aaSDmitry Bogdanov int rxsc_idx;
1094aec0f1aaSDmitry Bogdanov int ret = 0;
1095aec0f1aaSDmitry Bogdanov int i;
1096aec0f1aaSDmitry Bogdanov
1097aec0f1aaSDmitry Bogdanov rxsc_idx = aq_get_rxsc_idx_from_rxsc(cfg, ctx->rx_sc);
1098aec0f1aaSDmitry Bogdanov if (rxsc_idx < 0)
1099aec0f1aaSDmitry Bogdanov return -ENOENT;
1100aec0f1aaSDmitry Bogdanov
1101aec0f1aaSDmitry Bogdanov aq_rxsc = &cfg->aq_rxsc[rxsc_idx];
1102aec0f1aaSDmitry Bogdanov for (i = 0; i < MACSEC_NUM_AN; i++) {
1103aec0f1aaSDmitry Bogdanov if (!test_bit(i, &aq_rxsc->rx_sa_idx_busy))
1104aec0f1aaSDmitry Bogdanov continue;
1105aec0f1aaSDmitry Bogdanov
1106aec0f1aaSDmitry Bogdanov stats = &aq_rxsc->rx_sa_stats[i];
1107aec0f1aaSDmitry Bogdanov sa_idx = aq_rxsc->hw_sc_idx | i;
1108aec0f1aaSDmitry Bogdanov ret = aq_get_rxsa_stats(hw, sa_idx, stats);
1109aec0f1aaSDmitry Bogdanov if (ret)
1110aec0f1aaSDmitry Bogdanov break;
1111aec0f1aaSDmitry Bogdanov
1112aec0f1aaSDmitry Bogdanov ctx->stats.rx_sc_stats->InOctetsValidated +=
1113aec0f1aaSDmitry Bogdanov stats->validated_octets;
1114aec0f1aaSDmitry Bogdanov ctx->stats.rx_sc_stats->InOctetsDecrypted +=
1115aec0f1aaSDmitry Bogdanov stats->decrypted_octets;
1116aec0f1aaSDmitry Bogdanov ctx->stats.rx_sc_stats->InPktsUnchecked +=
1117aec0f1aaSDmitry Bogdanov stats->unchecked_pkts;
1118aec0f1aaSDmitry Bogdanov ctx->stats.rx_sc_stats->InPktsDelayed += stats->delayed_pkts;
1119aec0f1aaSDmitry Bogdanov ctx->stats.rx_sc_stats->InPktsOK += stats->ok_pkts;
1120aec0f1aaSDmitry Bogdanov ctx->stats.rx_sc_stats->InPktsInvalid += stats->invalid_pkts;
1121aec0f1aaSDmitry Bogdanov ctx->stats.rx_sc_stats->InPktsLate += stats->late_pkts;
1122aec0f1aaSDmitry Bogdanov ctx->stats.rx_sc_stats->InPktsNotValid += stats->not_valid_pkts;
1123aec0f1aaSDmitry Bogdanov ctx->stats.rx_sc_stats->InPktsNotUsingSA += stats->not_using_sa;
1124aec0f1aaSDmitry Bogdanov ctx->stats.rx_sc_stats->InPktsUnusedSA += stats->unused_sa;
1125aec0f1aaSDmitry Bogdanov }
1126aec0f1aaSDmitry Bogdanov
1127aec0f1aaSDmitry Bogdanov return ret;
1128aec0f1aaSDmitry Bogdanov }
1129aec0f1aaSDmitry Bogdanov
aq_mdo_get_rx_sa_stats(struct macsec_context * ctx)1130aec0f1aaSDmitry Bogdanov static int aq_mdo_get_rx_sa_stats(struct macsec_context *ctx)
1131aec0f1aaSDmitry Bogdanov {
1132*bd9424efSSubbaraya Sundeep struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev);
1133aec0f1aaSDmitry Bogdanov struct aq_macsec_cfg *cfg = nic->macsec_cfg;
1134aec0f1aaSDmitry Bogdanov struct aq_macsec_rx_sa_stats *stats;
1135aec0f1aaSDmitry Bogdanov struct aq_hw_s *hw = nic->aq_hw;
1136aec0f1aaSDmitry Bogdanov struct aq_macsec_rxsc *aq_rxsc;
1137aec0f1aaSDmitry Bogdanov struct macsec_rx_sa *rx_sa;
1138aec0f1aaSDmitry Bogdanov unsigned int sa_idx;
1139aec0f1aaSDmitry Bogdanov int rxsc_idx;
1140aec0f1aaSDmitry Bogdanov u32 next_pn;
1141aec0f1aaSDmitry Bogdanov int ret;
1142aec0f1aaSDmitry Bogdanov
1143aec0f1aaSDmitry Bogdanov rxsc_idx = aq_get_rxsc_idx_from_rxsc(cfg, ctx->rx_sc);
1144aec0f1aaSDmitry Bogdanov if (rxsc_idx < 0)
1145aec0f1aaSDmitry Bogdanov return -EINVAL;
1146aec0f1aaSDmitry Bogdanov
1147aec0f1aaSDmitry Bogdanov aq_rxsc = &cfg->aq_rxsc[rxsc_idx];
1148aec0f1aaSDmitry Bogdanov stats = &aq_rxsc->rx_sa_stats[ctx->sa.assoc_num];
1149aec0f1aaSDmitry Bogdanov sa_idx = aq_rxsc->hw_sc_idx | ctx->sa.assoc_num;
1150aec0f1aaSDmitry Bogdanov ret = aq_get_rxsa_stats(hw, sa_idx, stats);
1151aec0f1aaSDmitry Bogdanov if (ret)
1152aec0f1aaSDmitry Bogdanov return ret;
1153aec0f1aaSDmitry Bogdanov
1154aec0f1aaSDmitry Bogdanov ctx->stats.rx_sa_stats->InPktsOK = stats->ok_pkts;
1155aec0f1aaSDmitry Bogdanov ctx->stats.rx_sa_stats->InPktsInvalid = stats->invalid_pkts;
1156aec0f1aaSDmitry Bogdanov ctx->stats.rx_sa_stats->InPktsNotValid = stats->not_valid_pkts;
1157aec0f1aaSDmitry Bogdanov ctx->stats.rx_sa_stats->InPktsNotUsingSA = stats->not_using_sa;
1158aec0f1aaSDmitry Bogdanov ctx->stats.rx_sa_stats->InPktsUnusedSA = stats->unused_sa;
1159aec0f1aaSDmitry Bogdanov
1160aec0f1aaSDmitry Bogdanov rx_sa = rcu_dereference_bh(aq_rxsc->sw_rxsc->sa[ctx->sa.assoc_num]);
1161aec0f1aaSDmitry Bogdanov ret = aq_get_rxsa_next_pn(hw, sa_idx, &next_pn);
1162aec0f1aaSDmitry Bogdanov if (ret == 0) {
1163aec0f1aaSDmitry Bogdanov spin_lock_bh(&rx_sa->lock);
1164aec0f1aaSDmitry Bogdanov rx_sa->next_pn = next_pn;
1165aec0f1aaSDmitry Bogdanov spin_unlock_bh(&rx_sa->lock);
1166aec0f1aaSDmitry Bogdanov }
1167aec0f1aaSDmitry Bogdanov
1168aec0f1aaSDmitry Bogdanov return ret;
1169aec0f1aaSDmitry Bogdanov }
1170aec0f1aaSDmitry Bogdanov
apply_txsc_cfg(struct aq_nic_s * nic,const int txsc_idx)117127736563SDmitry Bogdanov static int apply_txsc_cfg(struct aq_nic_s *nic, const int txsc_idx)
117227736563SDmitry Bogdanov {
117327736563SDmitry Bogdanov struct aq_macsec_txsc *aq_txsc = &nic->macsec_cfg->aq_txsc[txsc_idx];
117427736563SDmitry Bogdanov const struct macsec_secy *secy = aq_txsc->sw_secy;
117527736563SDmitry Bogdanov struct macsec_tx_sa *tx_sa;
117627736563SDmitry Bogdanov int ret = 0;
117727736563SDmitry Bogdanov int i;
117827736563SDmitry Bogdanov
117927736563SDmitry Bogdanov if (!netif_running(secy->netdev))
118027736563SDmitry Bogdanov return ret;
118127736563SDmitry Bogdanov
118227736563SDmitry Bogdanov ret = aq_set_txsc(nic, txsc_idx);
118327736563SDmitry Bogdanov if (ret)
118427736563SDmitry Bogdanov return ret;
118527736563SDmitry Bogdanov
118627736563SDmitry Bogdanov for (i = 0; i < MACSEC_NUM_AN; i++) {
118727736563SDmitry Bogdanov tx_sa = rcu_dereference_bh(secy->tx_sc.sa[i]);
118827736563SDmitry Bogdanov if (tx_sa) {
118927736563SDmitry Bogdanov ret = aq_update_txsa(nic, aq_txsc->hw_sc_idx, secy,
119027736563SDmitry Bogdanov tx_sa, aq_txsc->tx_sa_key[i], i);
119127736563SDmitry Bogdanov if (ret)
119227736563SDmitry Bogdanov return ret;
119327736563SDmitry Bogdanov }
119427736563SDmitry Bogdanov }
119527736563SDmitry Bogdanov
119627736563SDmitry Bogdanov return ret;
119727736563SDmitry Bogdanov }
119827736563SDmitry Bogdanov
apply_rxsc_cfg(struct aq_nic_s * nic,const int rxsc_idx)11999ff40a75SMark Starovoytov static int apply_rxsc_cfg(struct aq_nic_s *nic, const int rxsc_idx)
12009ff40a75SMark Starovoytov {
12019ff40a75SMark Starovoytov struct aq_macsec_rxsc *aq_rxsc = &nic->macsec_cfg->aq_rxsc[rxsc_idx];
12029ff40a75SMark Starovoytov const struct macsec_secy *secy = aq_rxsc->sw_secy;
12039ff40a75SMark Starovoytov struct macsec_rx_sa *rx_sa;
12049ff40a75SMark Starovoytov int ret = 0;
12059ff40a75SMark Starovoytov int i;
12069ff40a75SMark Starovoytov
12079ff40a75SMark Starovoytov if (!netif_running(secy->netdev))
12089ff40a75SMark Starovoytov return ret;
12099ff40a75SMark Starovoytov
12109ff40a75SMark Starovoytov ret = aq_set_rxsc(nic, rxsc_idx);
12119ff40a75SMark Starovoytov if (ret)
12129ff40a75SMark Starovoytov return ret;
12139ff40a75SMark Starovoytov
12149ff40a75SMark Starovoytov for (i = 0; i < MACSEC_NUM_AN; i++) {
12159ff40a75SMark Starovoytov rx_sa = rcu_dereference_bh(aq_rxsc->sw_rxsc->sa[i]);
12169ff40a75SMark Starovoytov if (rx_sa) {
12179ff40a75SMark Starovoytov ret = aq_update_rxsa(nic, aq_rxsc->hw_sc_idx, secy,
12189ff40a75SMark Starovoytov rx_sa, aq_rxsc->rx_sa_key[i], i);
12199ff40a75SMark Starovoytov if (ret)
12209ff40a75SMark Starovoytov return ret;
12219ff40a75SMark Starovoytov }
12229ff40a75SMark Starovoytov }
12239ff40a75SMark Starovoytov
12249ff40a75SMark Starovoytov return ret;
12259ff40a75SMark Starovoytov }
12269ff40a75SMark Starovoytov
aq_clear_secy(struct aq_nic_s * nic,const struct macsec_secy * secy,enum aq_clear_type clear_type)122727736563SDmitry Bogdanov static int aq_clear_secy(struct aq_nic_s *nic, const struct macsec_secy *secy,
122827736563SDmitry Bogdanov enum aq_clear_type clear_type)
122927736563SDmitry Bogdanov {
12309ff40a75SMark Starovoytov struct macsec_rx_sc *rx_sc;
123127736563SDmitry Bogdanov int txsc_idx;
12329ff40a75SMark Starovoytov int rxsc_idx;
123327736563SDmitry Bogdanov int ret = 0;
123427736563SDmitry Bogdanov
123527736563SDmitry Bogdanov txsc_idx = aq_get_txsc_idx_from_secy(nic->macsec_cfg, secy);
123627736563SDmitry Bogdanov if (txsc_idx >= 0) {
123727736563SDmitry Bogdanov ret = aq_clear_txsc(nic, txsc_idx, clear_type);
123827736563SDmitry Bogdanov if (ret)
123927736563SDmitry Bogdanov return ret;
124027736563SDmitry Bogdanov }
124127736563SDmitry Bogdanov
12429ff40a75SMark Starovoytov for (rx_sc = rcu_dereference_bh(secy->rx_sc); rx_sc;
12439ff40a75SMark Starovoytov rx_sc = rcu_dereference_bh(rx_sc->next)) {
12449ff40a75SMark Starovoytov rxsc_idx = aq_get_rxsc_idx_from_rxsc(nic->macsec_cfg, rx_sc);
12459ff40a75SMark Starovoytov if (rxsc_idx < 0)
12469ff40a75SMark Starovoytov continue;
12479ff40a75SMark Starovoytov
12489ff40a75SMark Starovoytov ret = aq_clear_rxsc(nic, rxsc_idx, clear_type);
12499ff40a75SMark Starovoytov if (ret)
12509ff40a75SMark Starovoytov return ret;
12519ff40a75SMark Starovoytov }
12529ff40a75SMark Starovoytov
125327736563SDmitry Bogdanov return ret;
125427736563SDmitry Bogdanov }
125527736563SDmitry Bogdanov
aq_apply_secy_cfg(struct aq_nic_s * nic,const struct macsec_secy * secy)125627736563SDmitry Bogdanov static int aq_apply_secy_cfg(struct aq_nic_s *nic,
125727736563SDmitry Bogdanov const struct macsec_secy *secy)
125827736563SDmitry Bogdanov {
12599ff40a75SMark Starovoytov struct macsec_rx_sc *rx_sc;
126027736563SDmitry Bogdanov int txsc_idx;
12619ff40a75SMark Starovoytov int rxsc_idx;
126227736563SDmitry Bogdanov int ret = 0;
126327736563SDmitry Bogdanov
126427736563SDmitry Bogdanov txsc_idx = aq_get_txsc_idx_from_secy(nic->macsec_cfg, secy);
126527736563SDmitry Bogdanov if (txsc_idx >= 0)
126627736563SDmitry Bogdanov apply_txsc_cfg(nic, txsc_idx);
126727736563SDmitry Bogdanov
12689ff40a75SMark Starovoytov for (rx_sc = rcu_dereference_bh(secy->rx_sc); rx_sc && rx_sc->active;
12699ff40a75SMark Starovoytov rx_sc = rcu_dereference_bh(rx_sc->next)) {
12709ff40a75SMark Starovoytov rxsc_idx = aq_get_rxsc_idx_from_rxsc(nic->macsec_cfg, rx_sc);
12719ff40a75SMark Starovoytov if (unlikely(rxsc_idx < 0))
12729ff40a75SMark Starovoytov continue;
12739ff40a75SMark Starovoytov
12749ff40a75SMark Starovoytov ret = apply_rxsc_cfg(nic, rxsc_idx);
12759ff40a75SMark Starovoytov if (ret)
12769ff40a75SMark Starovoytov return ret;
12779ff40a75SMark Starovoytov }
12789ff40a75SMark Starovoytov
127927736563SDmitry Bogdanov return ret;
128027736563SDmitry Bogdanov }
128127736563SDmitry Bogdanov
aq_apply_macsec_cfg(struct aq_nic_s * nic)128227736563SDmitry Bogdanov static int aq_apply_macsec_cfg(struct aq_nic_s *nic)
128327736563SDmitry Bogdanov {
128427736563SDmitry Bogdanov int ret = 0;
128527736563SDmitry Bogdanov int i;
128627736563SDmitry Bogdanov
128727736563SDmitry Bogdanov for (i = 0; i < AQ_MACSEC_MAX_SC; i++) {
128827736563SDmitry Bogdanov if (nic->macsec_cfg->txsc_idx_busy & BIT(i)) {
128927736563SDmitry Bogdanov ret = apply_txsc_cfg(nic, i);
129027736563SDmitry Bogdanov if (ret)
129127736563SDmitry Bogdanov return ret;
129227736563SDmitry Bogdanov }
129327736563SDmitry Bogdanov }
129427736563SDmitry Bogdanov
12959ff40a75SMark Starovoytov for (i = 0; i < AQ_MACSEC_MAX_SC; i++) {
12969ff40a75SMark Starovoytov if (nic->macsec_cfg->rxsc_idx_busy & BIT(i)) {
12979ff40a75SMark Starovoytov ret = apply_rxsc_cfg(nic, i);
12989ff40a75SMark Starovoytov if (ret)
12999ff40a75SMark Starovoytov return ret;
13009ff40a75SMark Starovoytov }
13019ff40a75SMark Starovoytov }
13029ff40a75SMark Starovoytov
130327736563SDmitry Bogdanov return ret;
130427736563SDmitry Bogdanov }
130527736563SDmitry Bogdanov
aq_sa_from_sa_idx(const enum aq_macsec_sc_sa sc_sa,const int sa_idx)130627736563SDmitry Bogdanov static int aq_sa_from_sa_idx(const enum aq_macsec_sc_sa sc_sa, const int sa_idx)
130727736563SDmitry Bogdanov {
130827736563SDmitry Bogdanov switch (sc_sa) {
130927736563SDmitry Bogdanov case aq_macsec_sa_sc_4sa_8sc:
131027736563SDmitry Bogdanov return sa_idx & 3;
131127736563SDmitry Bogdanov case aq_macsec_sa_sc_2sa_16sc:
131227736563SDmitry Bogdanov return sa_idx & 1;
131327736563SDmitry Bogdanov case aq_macsec_sa_sc_1sa_32sc:
131427736563SDmitry Bogdanov return 0;
131527736563SDmitry Bogdanov default:
131627736563SDmitry Bogdanov WARN_ONCE(true, "Invalid sc_sa");
131727736563SDmitry Bogdanov }
131827736563SDmitry Bogdanov return -EINVAL;
131927736563SDmitry Bogdanov }
132027736563SDmitry Bogdanov
aq_sc_idx_from_sa_idx(const enum aq_macsec_sc_sa sc_sa,const int sa_idx)132127736563SDmitry Bogdanov static int aq_sc_idx_from_sa_idx(const enum aq_macsec_sc_sa sc_sa,
132227736563SDmitry Bogdanov const int sa_idx)
132327736563SDmitry Bogdanov {
132427736563SDmitry Bogdanov switch (sc_sa) {
132527736563SDmitry Bogdanov case aq_macsec_sa_sc_4sa_8sc:
132627736563SDmitry Bogdanov return sa_idx & ~3;
132727736563SDmitry Bogdanov case aq_macsec_sa_sc_2sa_16sc:
132827736563SDmitry Bogdanov return sa_idx & ~1;
132927736563SDmitry Bogdanov case aq_macsec_sa_sc_1sa_32sc:
133027736563SDmitry Bogdanov return sa_idx;
133127736563SDmitry Bogdanov default:
133227736563SDmitry Bogdanov WARN_ONCE(true, "Invalid sc_sa");
133327736563SDmitry Bogdanov }
133427736563SDmitry Bogdanov return -EINVAL;
133527736563SDmitry Bogdanov }
133627736563SDmitry Bogdanov
aq_check_txsa_expiration(struct aq_nic_s * nic)133762c1c2e6SDmitry Bogdanov static void aq_check_txsa_expiration(struct aq_nic_s *nic)
133862c1c2e6SDmitry Bogdanov {
133927736563SDmitry Bogdanov u32 egress_sa_expired, egress_sa_threshold_expired;
134027736563SDmitry Bogdanov struct aq_macsec_cfg *cfg = nic->macsec_cfg;
134127736563SDmitry Bogdanov struct aq_hw_s *hw = nic->aq_hw;
134227736563SDmitry Bogdanov struct aq_macsec_txsc *aq_txsc;
134327736563SDmitry Bogdanov const struct macsec_secy *secy;
134427736563SDmitry Bogdanov int sc_idx = 0, txsc_idx = 0;
134527736563SDmitry Bogdanov enum aq_macsec_sc_sa sc_sa;
134627736563SDmitry Bogdanov struct macsec_tx_sa *tx_sa;
134727736563SDmitry Bogdanov unsigned char an = 0;
134827736563SDmitry Bogdanov int ret;
134927736563SDmitry Bogdanov int i;
135027736563SDmitry Bogdanov
135127736563SDmitry Bogdanov sc_sa = cfg->sc_sa;
135227736563SDmitry Bogdanov
135327736563SDmitry Bogdanov ret = aq_mss_get_egress_sa_expired(hw, &egress_sa_expired);
135427736563SDmitry Bogdanov if (unlikely(ret))
135527736563SDmitry Bogdanov return;
135627736563SDmitry Bogdanov
135727736563SDmitry Bogdanov ret = aq_mss_get_egress_sa_threshold_expired(hw,
135827736563SDmitry Bogdanov &egress_sa_threshold_expired);
135927736563SDmitry Bogdanov
136027736563SDmitry Bogdanov for (i = 0; i < AQ_MACSEC_MAX_SA; i++) {
136127736563SDmitry Bogdanov if (egress_sa_expired & BIT(i)) {
136227736563SDmitry Bogdanov an = aq_sa_from_sa_idx(sc_sa, i);
136327736563SDmitry Bogdanov sc_idx = aq_sc_idx_from_sa_idx(sc_sa, i);
136427736563SDmitry Bogdanov txsc_idx = aq_get_txsc_idx_from_sc_idx(sc_sa, sc_idx);
136527736563SDmitry Bogdanov if (txsc_idx < 0)
136627736563SDmitry Bogdanov continue;
136727736563SDmitry Bogdanov
136827736563SDmitry Bogdanov aq_txsc = &cfg->aq_txsc[txsc_idx];
136927736563SDmitry Bogdanov if (!(cfg->txsc_idx_busy & BIT(txsc_idx))) {
137027736563SDmitry Bogdanov netdev_warn(nic->ndev,
137127736563SDmitry Bogdanov "PN threshold expired on invalid TX SC");
137227736563SDmitry Bogdanov continue;
137327736563SDmitry Bogdanov }
137427736563SDmitry Bogdanov
137527736563SDmitry Bogdanov secy = aq_txsc->sw_secy;
137627736563SDmitry Bogdanov if (!netif_running(secy->netdev)) {
137727736563SDmitry Bogdanov netdev_warn(nic->ndev,
137827736563SDmitry Bogdanov "PN threshold expired on down TX SC");
137927736563SDmitry Bogdanov continue;
138027736563SDmitry Bogdanov }
138127736563SDmitry Bogdanov
138227736563SDmitry Bogdanov if (unlikely(!(aq_txsc->tx_sa_idx_busy & BIT(an)))) {
138327736563SDmitry Bogdanov netdev_warn(nic->ndev,
138427736563SDmitry Bogdanov "PN threshold expired on invalid TX SA");
138527736563SDmitry Bogdanov continue;
138627736563SDmitry Bogdanov }
138727736563SDmitry Bogdanov
138827736563SDmitry Bogdanov tx_sa = rcu_dereference_bh(secy->tx_sc.sa[an]);
138927736563SDmitry Bogdanov macsec_pn_wrapped((struct macsec_secy *)secy, tx_sa);
139027736563SDmitry Bogdanov }
139127736563SDmitry Bogdanov }
139227736563SDmitry Bogdanov
139327736563SDmitry Bogdanov aq_mss_set_egress_sa_expired(hw, egress_sa_expired);
139427736563SDmitry Bogdanov if (likely(!ret))
139527736563SDmitry Bogdanov aq_mss_set_egress_sa_threshold_expired(hw,
139627736563SDmitry Bogdanov egress_sa_threshold_expired);
139762c1c2e6SDmitry Bogdanov }
139862c1c2e6SDmitry Bogdanov
13996960d133SÍñigo Huguet #define AQ_LOCKED_MDO_DEF(mdo) \
14006960d133SÍñigo Huguet static int aq_locked_mdo_##mdo(struct macsec_context *ctx) \
14016960d133SÍñigo Huguet { \
1402*bd9424efSSubbaraya Sundeep struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev); \
14036960d133SÍñigo Huguet int ret; \
14046960d133SÍñigo Huguet mutex_lock(&nic->macsec_mutex); \
14056960d133SÍñigo Huguet ret = aq_mdo_##mdo(ctx); \
14066960d133SÍñigo Huguet mutex_unlock(&nic->macsec_mutex); \
14076960d133SÍñigo Huguet return ret; \
14086960d133SÍñigo Huguet }
14096960d133SÍñigo Huguet
14106960d133SÍñigo Huguet AQ_LOCKED_MDO_DEF(dev_open)
14116960d133SÍñigo Huguet AQ_LOCKED_MDO_DEF(dev_stop)
14126960d133SÍñigo Huguet AQ_LOCKED_MDO_DEF(add_secy)
14136960d133SÍñigo Huguet AQ_LOCKED_MDO_DEF(upd_secy)
14146960d133SÍñigo Huguet AQ_LOCKED_MDO_DEF(del_secy)
14156960d133SÍñigo Huguet AQ_LOCKED_MDO_DEF(add_rxsc)
14166960d133SÍñigo Huguet AQ_LOCKED_MDO_DEF(upd_rxsc)
14176960d133SÍñigo Huguet AQ_LOCKED_MDO_DEF(del_rxsc)
14186960d133SÍñigo Huguet AQ_LOCKED_MDO_DEF(add_rxsa)
14196960d133SÍñigo Huguet AQ_LOCKED_MDO_DEF(upd_rxsa)
14206960d133SÍñigo Huguet AQ_LOCKED_MDO_DEF(del_rxsa)
14216960d133SÍñigo Huguet AQ_LOCKED_MDO_DEF(add_txsa)
14226960d133SÍñigo Huguet AQ_LOCKED_MDO_DEF(upd_txsa)
14236960d133SÍñigo Huguet AQ_LOCKED_MDO_DEF(del_txsa)
14246960d133SÍñigo Huguet AQ_LOCKED_MDO_DEF(get_dev_stats)
14256960d133SÍñigo Huguet AQ_LOCKED_MDO_DEF(get_tx_sc_stats)
14266960d133SÍñigo Huguet AQ_LOCKED_MDO_DEF(get_tx_sa_stats)
14276960d133SÍñigo Huguet AQ_LOCKED_MDO_DEF(get_rx_sc_stats)
14286960d133SÍñigo Huguet AQ_LOCKED_MDO_DEF(get_rx_sa_stats)
14296960d133SÍñigo Huguet
143062c1c2e6SDmitry Bogdanov const struct macsec_ops aq_macsec_ops = {
14316960d133SÍñigo Huguet .mdo_dev_open = aq_locked_mdo_dev_open,
14326960d133SÍñigo Huguet .mdo_dev_stop = aq_locked_mdo_dev_stop,
14336960d133SÍñigo Huguet .mdo_add_secy = aq_locked_mdo_add_secy,
14346960d133SÍñigo Huguet .mdo_upd_secy = aq_locked_mdo_upd_secy,
14356960d133SÍñigo Huguet .mdo_del_secy = aq_locked_mdo_del_secy,
14366960d133SÍñigo Huguet .mdo_add_rxsc = aq_locked_mdo_add_rxsc,
14376960d133SÍñigo Huguet .mdo_upd_rxsc = aq_locked_mdo_upd_rxsc,
14386960d133SÍñigo Huguet .mdo_del_rxsc = aq_locked_mdo_del_rxsc,
14396960d133SÍñigo Huguet .mdo_add_rxsa = aq_locked_mdo_add_rxsa,
14406960d133SÍñigo Huguet .mdo_upd_rxsa = aq_locked_mdo_upd_rxsa,
14416960d133SÍñigo Huguet .mdo_del_rxsa = aq_locked_mdo_del_rxsa,
14426960d133SÍñigo Huguet .mdo_add_txsa = aq_locked_mdo_add_txsa,
14436960d133SÍñigo Huguet .mdo_upd_txsa = aq_locked_mdo_upd_txsa,
14446960d133SÍñigo Huguet .mdo_del_txsa = aq_locked_mdo_del_txsa,
14456960d133SÍñigo Huguet .mdo_get_dev_stats = aq_locked_mdo_get_dev_stats,
14466960d133SÍñigo Huguet .mdo_get_tx_sc_stats = aq_locked_mdo_get_tx_sc_stats,
14476960d133SÍñigo Huguet .mdo_get_tx_sa_stats = aq_locked_mdo_get_tx_sa_stats,
14486960d133SÍñigo Huguet .mdo_get_rx_sc_stats = aq_locked_mdo_get_rx_sc_stats,
14496960d133SÍñigo Huguet .mdo_get_rx_sa_stats = aq_locked_mdo_get_rx_sa_stats,
145062c1c2e6SDmitry Bogdanov };
145162c1c2e6SDmitry Bogdanov
aq_macsec_init(struct aq_nic_s * nic)145262c1c2e6SDmitry Bogdanov int aq_macsec_init(struct aq_nic_s *nic)
145362c1c2e6SDmitry Bogdanov {
145462c1c2e6SDmitry Bogdanov struct aq_macsec_cfg *cfg;
145562c1c2e6SDmitry Bogdanov u32 caps_lo;
145662c1c2e6SDmitry Bogdanov
145762c1c2e6SDmitry Bogdanov if (!nic->aq_fw_ops->get_link_capabilities)
145862c1c2e6SDmitry Bogdanov return 0;
145962c1c2e6SDmitry Bogdanov
146062c1c2e6SDmitry Bogdanov caps_lo = nic->aq_fw_ops->get_link_capabilities(nic->aq_hw);
146162c1c2e6SDmitry Bogdanov
146262c1c2e6SDmitry Bogdanov if (!(caps_lo & BIT(CAPS_LO_MACSEC)))
146362c1c2e6SDmitry Bogdanov return 0;
146462c1c2e6SDmitry Bogdanov
146562c1c2e6SDmitry Bogdanov nic->macsec_cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
146662c1c2e6SDmitry Bogdanov if (!nic->macsec_cfg)
146762c1c2e6SDmitry Bogdanov return -ENOMEM;
146862c1c2e6SDmitry Bogdanov
146962c1c2e6SDmitry Bogdanov nic->ndev->features |= NETIF_F_HW_MACSEC;
147062c1c2e6SDmitry Bogdanov nic->ndev->macsec_ops = &aq_macsec_ops;
14716960d133SÍñigo Huguet mutex_init(&nic->macsec_mutex);
147262c1c2e6SDmitry Bogdanov
147362c1c2e6SDmitry Bogdanov return 0;
147462c1c2e6SDmitry Bogdanov }
147562c1c2e6SDmitry Bogdanov
aq_macsec_free(struct aq_nic_s * nic)147662c1c2e6SDmitry Bogdanov void aq_macsec_free(struct aq_nic_s *nic)
147762c1c2e6SDmitry Bogdanov {
147862c1c2e6SDmitry Bogdanov kfree(nic->macsec_cfg);
147962c1c2e6SDmitry Bogdanov nic->macsec_cfg = NULL;
148062c1c2e6SDmitry Bogdanov }
148162c1c2e6SDmitry Bogdanov
aq_macsec_enable(struct aq_nic_s * nic)148262c1c2e6SDmitry Bogdanov int aq_macsec_enable(struct aq_nic_s *nic)
148362c1c2e6SDmitry Bogdanov {
148427736563SDmitry Bogdanov u32 ctl_ether_types[1] = { ETH_P_PAE };
148562c1c2e6SDmitry Bogdanov struct macsec_msg_fw_response resp = { 0 };
148662c1c2e6SDmitry Bogdanov struct macsec_msg_fw_request msg = { 0 };
148762c1c2e6SDmitry Bogdanov struct aq_hw_s *hw = nic->aq_hw;
148827736563SDmitry Bogdanov int num_ctl_ether_types = 0;
148927736563SDmitry Bogdanov int index = 0, tbl_idx;
149027736563SDmitry Bogdanov int ret;
149162c1c2e6SDmitry Bogdanov
149262c1c2e6SDmitry Bogdanov if (!nic->macsec_cfg)
149362c1c2e6SDmitry Bogdanov return 0;
149462c1c2e6SDmitry Bogdanov
14956960d133SÍñigo Huguet mutex_lock(&nic->macsec_mutex);
149662c1c2e6SDmitry Bogdanov
149762c1c2e6SDmitry Bogdanov if (nic->aq_fw_ops->send_macsec_req) {
149862c1c2e6SDmitry Bogdanov struct macsec_cfg_request cfg = { 0 };
149962c1c2e6SDmitry Bogdanov
150062c1c2e6SDmitry Bogdanov cfg.enabled = 1;
150162c1c2e6SDmitry Bogdanov cfg.egress_threshold = 0xffffffff;
150262c1c2e6SDmitry Bogdanov cfg.ingress_threshold = 0xffffffff;
150362c1c2e6SDmitry Bogdanov cfg.interrupts_enabled = 1;
150462c1c2e6SDmitry Bogdanov
150562c1c2e6SDmitry Bogdanov msg.msg_type = macsec_cfg_msg;
150662c1c2e6SDmitry Bogdanov msg.cfg = cfg;
150762c1c2e6SDmitry Bogdanov
150862c1c2e6SDmitry Bogdanov ret = nic->aq_fw_ops->send_macsec_req(hw, &msg, &resp);
150962c1c2e6SDmitry Bogdanov if (ret)
151062c1c2e6SDmitry Bogdanov goto unlock;
151162c1c2e6SDmitry Bogdanov }
151262c1c2e6SDmitry Bogdanov
151327736563SDmitry Bogdanov /* Init Ethertype bypass filters */
151427736563SDmitry Bogdanov for (index = 0; index < ARRAY_SIZE(ctl_ether_types); index++) {
15159ff40a75SMark Starovoytov struct aq_mss_ingress_prectlf_record rx_prectlf_rec;
151627736563SDmitry Bogdanov struct aq_mss_egress_ctlf_record tx_ctlf_rec;
151727736563SDmitry Bogdanov
151827736563SDmitry Bogdanov if (ctl_ether_types[index] == 0)
151927736563SDmitry Bogdanov continue;
152027736563SDmitry Bogdanov
152127736563SDmitry Bogdanov memset(&tx_ctlf_rec, 0, sizeof(tx_ctlf_rec));
152227736563SDmitry Bogdanov tx_ctlf_rec.eth_type = ctl_ether_types[index];
152327736563SDmitry Bogdanov tx_ctlf_rec.match_type = 4; /* Match eth_type only */
152427736563SDmitry Bogdanov tx_ctlf_rec.match_mask = 0xf; /* match for eth_type */
152527736563SDmitry Bogdanov tx_ctlf_rec.action = 0; /* Bypass MACSEC modules */
152627736563SDmitry Bogdanov tbl_idx = NUMROWS_EGRESSCTLFRECORD - num_ctl_ether_types - 1;
152727736563SDmitry Bogdanov aq_mss_set_egress_ctlf_record(hw, &tx_ctlf_rec, tbl_idx);
152827736563SDmitry Bogdanov
15299ff40a75SMark Starovoytov memset(&rx_prectlf_rec, 0, sizeof(rx_prectlf_rec));
15309ff40a75SMark Starovoytov rx_prectlf_rec.eth_type = ctl_ether_types[index];
15319ff40a75SMark Starovoytov rx_prectlf_rec.match_type = 4; /* Match eth_type only */
15329ff40a75SMark Starovoytov rx_prectlf_rec.match_mask = 0xf; /* match for eth_type */
15339ff40a75SMark Starovoytov rx_prectlf_rec.action = 0; /* Bypass MACSEC modules */
15349ff40a75SMark Starovoytov tbl_idx =
15359ff40a75SMark Starovoytov NUMROWS_INGRESSPRECTLFRECORD - num_ctl_ether_types - 1;
15369ff40a75SMark Starovoytov aq_mss_set_ingress_prectlf_record(hw, &rx_prectlf_rec, tbl_idx);
15379ff40a75SMark Starovoytov
153827736563SDmitry Bogdanov num_ctl_ether_types++;
153927736563SDmitry Bogdanov }
154027736563SDmitry Bogdanov
154127736563SDmitry Bogdanov ret = aq_apply_macsec_cfg(nic);
154227736563SDmitry Bogdanov
154362c1c2e6SDmitry Bogdanov unlock:
15446960d133SÍñigo Huguet mutex_unlock(&nic->macsec_mutex);
154562c1c2e6SDmitry Bogdanov return ret;
154662c1c2e6SDmitry Bogdanov }
154762c1c2e6SDmitry Bogdanov
aq_macsec_work(struct aq_nic_s * nic)154862c1c2e6SDmitry Bogdanov void aq_macsec_work(struct aq_nic_s *nic)
154962c1c2e6SDmitry Bogdanov {
155062c1c2e6SDmitry Bogdanov if (!nic->macsec_cfg)
155162c1c2e6SDmitry Bogdanov return;
155262c1c2e6SDmitry Bogdanov
155362c1c2e6SDmitry Bogdanov if (!netif_carrier_ok(nic->ndev))
155462c1c2e6SDmitry Bogdanov return;
155562c1c2e6SDmitry Bogdanov
15566960d133SÍñigo Huguet mutex_lock(&nic->macsec_mutex);
155762c1c2e6SDmitry Bogdanov aq_check_txsa_expiration(nic);
15586960d133SÍñigo Huguet mutex_unlock(&nic->macsec_mutex);
155962c1c2e6SDmitry Bogdanov }
1560aec0f1aaSDmitry Bogdanov
aq_macsec_rx_sa_cnt(struct aq_nic_s * nic)1561aec0f1aaSDmitry Bogdanov int aq_macsec_rx_sa_cnt(struct aq_nic_s *nic)
1562aec0f1aaSDmitry Bogdanov {
1563aec0f1aaSDmitry Bogdanov struct aq_macsec_cfg *cfg = nic->macsec_cfg;
1564aec0f1aaSDmitry Bogdanov int i, cnt = 0;
1565aec0f1aaSDmitry Bogdanov
1566aec0f1aaSDmitry Bogdanov if (!cfg)
1567aec0f1aaSDmitry Bogdanov return 0;
1568aec0f1aaSDmitry Bogdanov
15696960d133SÍñigo Huguet mutex_lock(&nic->macsec_mutex);
15706960d133SÍñigo Huguet
1571aec0f1aaSDmitry Bogdanov for (i = 0; i < AQ_MACSEC_MAX_SC; i++) {
1572aec0f1aaSDmitry Bogdanov if (!test_bit(i, &cfg->rxsc_idx_busy))
1573aec0f1aaSDmitry Bogdanov continue;
1574aec0f1aaSDmitry Bogdanov cnt += hweight_long(cfg->aq_rxsc[i].rx_sa_idx_busy);
1575aec0f1aaSDmitry Bogdanov }
1576aec0f1aaSDmitry Bogdanov
15776960d133SÍñigo Huguet mutex_unlock(&nic->macsec_mutex);
1578aec0f1aaSDmitry Bogdanov return cnt;
1579aec0f1aaSDmitry Bogdanov }
1580aec0f1aaSDmitry Bogdanov
aq_macsec_tx_sc_cnt(struct aq_nic_s * nic)1581aec0f1aaSDmitry Bogdanov int aq_macsec_tx_sc_cnt(struct aq_nic_s *nic)
1582aec0f1aaSDmitry Bogdanov {
15836960d133SÍñigo Huguet int cnt;
15846960d133SÍñigo Huguet
1585aec0f1aaSDmitry Bogdanov if (!nic->macsec_cfg)
1586aec0f1aaSDmitry Bogdanov return 0;
1587aec0f1aaSDmitry Bogdanov
15886960d133SÍñigo Huguet mutex_lock(&nic->macsec_mutex);
15896960d133SÍñigo Huguet cnt = hweight_long(nic->macsec_cfg->txsc_idx_busy);
15906960d133SÍñigo Huguet mutex_unlock(&nic->macsec_mutex);
15916960d133SÍñigo Huguet
15926960d133SÍñigo Huguet return cnt;
1593aec0f1aaSDmitry Bogdanov }
1594aec0f1aaSDmitry Bogdanov
aq_macsec_tx_sa_cnt(struct aq_nic_s * nic)1595aec0f1aaSDmitry Bogdanov int aq_macsec_tx_sa_cnt(struct aq_nic_s *nic)
1596aec0f1aaSDmitry Bogdanov {
1597aec0f1aaSDmitry Bogdanov struct aq_macsec_cfg *cfg = nic->macsec_cfg;
1598aec0f1aaSDmitry Bogdanov int i, cnt = 0;
1599aec0f1aaSDmitry Bogdanov
1600aec0f1aaSDmitry Bogdanov if (!cfg)
1601aec0f1aaSDmitry Bogdanov return 0;
1602aec0f1aaSDmitry Bogdanov
16036960d133SÍñigo Huguet mutex_lock(&nic->macsec_mutex);
16046960d133SÍñigo Huguet
1605aec0f1aaSDmitry Bogdanov for (i = 0; i < AQ_MACSEC_MAX_SC; i++) {
1606aec0f1aaSDmitry Bogdanov if (!test_bit(i, &cfg->txsc_idx_busy))
1607aec0f1aaSDmitry Bogdanov continue;
1608aec0f1aaSDmitry Bogdanov cnt += hweight_long(cfg->aq_txsc[i].tx_sa_idx_busy);
1609aec0f1aaSDmitry Bogdanov }
1610aec0f1aaSDmitry Bogdanov
16116960d133SÍñigo Huguet mutex_unlock(&nic->macsec_mutex);
1612aec0f1aaSDmitry Bogdanov return cnt;
1613aec0f1aaSDmitry Bogdanov }
1614aec0f1aaSDmitry Bogdanov
aq_macsec_update_stats(struct aq_nic_s * nic)1615aec0f1aaSDmitry Bogdanov static int aq_macsec_update_stats(struct aq_nic_s *nic)
1616aec0f1aaSDmitry Bogdanov {
1617aec0f1aaSDmitry Bogdanov struct aq_macsec_cfg *cfg = nic->macsec_cfg;
1618aec0f1aaSDmitry Bogdanov struct aq_hw_s *hw = nic->aq_hw;
1619aec0f1aaSDmitry Bogdanov struct aq_macsec_txsc *aq_txsc;
1620aec0f1aaSDmitry Bogdanov struct aq_macsec_rxsc *aq_rxsc;
1621aec0f1aaSDmitry Bogdanov int i, sa_idx, assoc_num;
1622aec0f1aaSDmitry Bogdanov int ret = 0;
1623aec0f1aaSDmitry Bogdanov
1624aec0f1aaSDmitry Bogdanov aq_get_macsec_common_stats(hw, &cfg->stats);
1625aec0f1aaSDmitry Bogdanov
1626aec0f1aaSDmitry Bogdanov for (i = 0; i < AQ_MACSEC_MAX_SC; i++) {
1627aec0f1aaSDmitry Bogdanov if (!(cfg->txsc_idx_busy & BIT(i)))
1628aec0f1aaSDmitry Bogdanov continue;
1629aec0f1aaSDmitry Bogdanov aq_txsc = &cfg->aq_txsc[i];
1630aec0f1aaSDmitry Bogdanov
1631aec0f1aaSDmitry Bogdanov ret = aq_get_txsc_stats(hw, aq_txsc->hw_sc_idx,
1632aec0f1aaSDmitry Bogdanov &aq_txsc->stats);
1633aec0f1aaSDmitry Bogdanov if (ret)
1634aec0f1aaSDmitry Bogdanov return ret;
1635aec0f1aaSDmitry Bogdanov
1636aec0f1aaSDmitry Bogdanov for (assoc_num = 0; assoc_num < MACSEC_NUM_AN; assoc_num++) {
1637aec0f1aaSDmitry Bogdanov if (!test_bit(assoc_num, &aq_txsc->tx_sa_idx_busy))
1638aec0f1aaSDmitry Bogdanov continue;
1639aec0f1aaSDmitry Bogdanov sa_idx = aq_txsc->hw_sc_idx | assoc_num;
1640aec0f1aaSDmitry Bogdanov ret = aq_get_txsa_stats(hw, sa_idx,
1641aec0f1aaSDmitry Bogdanov &aq_txsc->tx_sa_stats[assoc_num]);
1642aec0f1aaSDmitry Bogdanov if (ret)
1643aec0f1aaSDmitry Bogdanov return ret;
1644aec0f1aaSDmitry Bogdanov }
1645aec0f1aaSDmitry Bogdanov }
1646aec0f1aaSDmitry Bogdanov
1647aec0f1aaSDmitry Bogdanov for (i = 0; i < AQ_MACSEC_MAX_SC; i++) {
1648aec0f1aaSDmitry Bogdanov if (!(test_bit(i, &cfg->rxsc_idx_busy)))
1649aec0f1aaSDmitry Bogdanov continue;
1650aec0f1aaSDmitry Bogdanov aq_rxsc = &cfg->aq_rxsc[i];
1651aec0f1aaSDmitry Bogdanov
1652aec0f1aaSDmitry Bogdanov for (assoc_num = 0; assoc_num < MACSEC_NUM_AN; assoc_num++) {
1653aec0f1aaSDmitry Bogdanov if (!test_bit(assoc_num, &aq_rxsc->rx_sa_idx_busy))
1654aec0f1aaSDmitry Bogdanov continue;
1655aec0f1aaSDmitry Bogdanov sa_idx = aq_rxsc->hw_sc_idx | assoc_num;
1656aec0f1aaSDmitry Bogdanov
1657aec0f1aaSDmitry Bogdanov ret = aq_get_rxsa_stats(hw, sa_idx,
1658aec0f1aaSDmitry Bogdanov &aq_rxsc->rx_sa_stats[assoc_num]);
1659aec0f1aaSDmitry Bogdanov if (ret)
1660aec0f1aaSDmitry Bogdanov return ret;
1661aec0f1aaSDmitry Bogdanov }
1662aec0f1aaSDmitry Bogdanov }
1663aec0f1aaSDmitry Bogdanov
1664aec0f1aaSDmitry Bogdanov return ret;
1665aec0f1aaSDmitry Bogdanov }
1666aec0f1aaSDmitry Bogdanov
aq_macsec_get_stats(struct aq_nic_s * nic,u64 * data)1667aec0f1aaSDmitry Bogdanov u64 *aq_macsec_get_stats(struct aq_nic_s *nic, u64 *data)
1668aec0f1aaSDmitry Bogdanov {
1669aec0f1aaSDmitry Bogdanov struct aq_macsec_cfg *cfg = nic->macsec_cfg;
1670aec0f1aaSDmitry Bogdanov struct aq_macsec_common_stats *common_stats;
1671aec0f1aaSDmitry Bogdanov struct aq_macsec_tx_sc_stats *txsc_stats;
1672aec0f1aaSDmitry Bogdanov struct aq_macsec_tx_sa_stats *txsa_stats;
1673aec0f1aaSDmitry Bogdanov struct aq_macsec_rx_sa_stats *rxsa_stats;
1674aec0f1aaSDmitry Bogdanov struct aq_macsec_txsc *aq_txsc;
1675aec0f1aaSDmitry Bogdanov struct aq_macsec_rxsc *aq_rxsc;
1676aec0f1aaSDmitry Bogdanov unsigned int assoc_num;
1677aec0f1aaSDmitry Bogdanov unsigned int sc_num;
1678aec0f1aaSDmitry Bogdanov unsigned int i = 0U;
1679aec0f1aaSDmitry Bogdanov
1680aec0f1aaSDmitry Bogdanov if (!cfg)
1681aec0f1aaSDmitry Bogdanov return data;
1682aec0f1aaSDmitry Bogdanov
16836960d133SÍñigo Huguet mutex_lock(&nic->macsec_mutex);
16846960d133SÍñigo Huguet
1685aec0f1aaSDmitry Bogdanov aq_macsec_update_stats(nic);
1686aec0f1aaSDmitry Bogdanov
1687aec0f1aaSDmitry Bogdanov common_stats = &cfg->stats;
1688aec0f1aaSDmitry Bogdanov data[i] = common_stats->in.ctl_pkts;
1689aec0f1aaSDmitry Bogdanov data[++i] = common_stats->in.tagged_miss_pkts;
1690aec0f1aaSDmitry Bogdanov data[++i] = common_stats->in.untagged_miss_pkts;
1691aec0f1aaSDmitry Bogdanov data[++i] = common_stats->in.notag_pkts;
1692aec0f1aaSDmitry Bogdanov data[++i] = common_stats->in.untagged_pkts;
1693aec0f1aaSDmitry Bogdanov data[++i] = common_stats->in.bad_tag_pkts;
1694aec0f1aaSDmitry Bogdanov data[++i] = common_stats->in.no_sci_pkts;
1695aec0f1aaSDmitry Bogdanov data[++i] = common_stats->in.unknown_sci_pkts;
1696aec0f1aaSDmitry Bogdanov data[++i] = common_stats->in.ctrl_prt_pass_pkts;
1697aec0f1aaSDmitry Bogdanov data[++i] = common_stats->in.unctrl_prt_pass_pkts;
1698aec0f1aaSDmitry Bogdanov data[++i] = common_stats->in.ctrl_prt_fail_pkts;
1699aec0f1aaSDmitry Bogdanov data[++i] = common_stats->in.unctrl_prt_fail_pkts;
1700aec0f1aaSDmitry Bogdanov data[++i] = common_stats->in.too_long_pkts;
1701aec0f1aaSDmitry Bogdanov data[++i] = common_stats->in.igpoc_ctl_pkts;
1702aec0f1aaSDmitry Bogdanov data[++i] = common_stats->in.ecc_error_pkts;
1703aec0f1aaSDmitry Bogdanov data[++i] = common_stats->in.unctrl_hit_drop_redir;
1704aec0f1aaSDmitry Bogdanov data[++i] = common_stats->out.ctl_pkts;
1705aec0f1aaSDmitry Bogdanov data[++i] = common_stats->out.unknown_sa_pkts;
1706aec0f1aaSDmitry Bogdanov data[++i] = common_stats->out.untagged_pkts;
1707aec0f1aaSDmitry Bogdanov data[++i] = common_stats->out.too_long;
1708aec0f1aaSDmitry Bogdanov data[++i] = common_stats->out.ecc_error_pkts;
1709aec0f1aaSDmitry Bogdanov data[++i] = common_stats->out.unctrl_hit_drop_redir;
1710aec0f1aaSDmitry Bogdanov
1711aec0f1aaSDmitry Bogdanov for (sc_num = 0; sc_num < AQ_MACSEC_MAX_SC; sc_num++) {
1712aec0f1aaSDmitry Bogdanov if (!(test_bit(sc_num, &cfg->txsc_idx_busy)))
1713aec0f1aaSDmitry Bogdanov continue;
1714aec0f1aaSDmitry Bogdanov
1715aec0f1aaSDmitry Bogdanov aq_txsc = &cfg->aq_txsc[sc_num];
1716aec0f1aaSDmitry Bogdanov txsc_stats = &aq_txsc->stats;
1717aec0f1aaSDmitry Bogdanov
1718aec0f1aaSDmitry Bogdanov data[++i] = txsc_stats->sc_protected_pkts;
1719aec0f1aaSDmitry Bogdanov data[++i] = txsc_stats->sc_encrypted_pkts;
1720aec0f1aaSDmitry Bogdanov data[++i] = txsc_stats->sc_protected_octets;
1721aec0f1aaSDmitry Bogdanov data[++i] = txsc_stats->sc_encrypted_octets;
1722aec0f1aaSDmitry Bogdanov
1723aec0f1aaSDmitry Bogdanov for (assoc_num = 0; assoc_num < MACSEC_NUM_AN; assoc_num++) {
1724aec0f1aaSDmitry Bogdanov if (!test_bit(assoc_num, &aq_txsc->tx_sa_idx_busy))
1725aec0f1aaSDmitry Bogdanov continue;
1726aec0f1aaSDmitry Bogdanov
1727aec0f1aaSDmitry Bogdanov txsa_stats = &aq_txsc->tx_sa_stats[assoc_num];
1728aec0f1aaSDmitry Bogdanov
1729aec0f1aaSDmitry Bogdanov data[++i] = txsa_stats->sa_hit_drop_redirect;
1730aec0f1aaSDmitry Bogdanov data[++i] = txsa_stats->sa_protected2_pkts;
1731aec0f1aaSDmitry Bogdanov data[++i] = txsa_stats->sa_protected_pkts;
1732aec0f1aaSDmitry Bogdanov data[++i] = txsa_stats->sa_encrypted_pkts;
1733aec0f1aaSDmitry Bogdanov }
1734aec0f1aaSDmitry Bogdanov }
1735aec0f1aaSDmitry Bogdanov
1736aec0f1aaSDmitry Bogdanov for (sc_num = 0; sc_num < AQ_MACSEC_MAX_SC; sc_num++) {
1737aec0f1aaSDmitry Bogdanov if (!(test_bit(sc_num, &cfg->rxsc_idx_busy)))
1738aec0f1aaSDmitry Bogdanov continue;
1739aec0f1aaSDmitry Bogdanov
1740aec0f1aaSDmitry Bogdanov aq_rxsc = &cfg->aq_rxsc[sc_num];
1741aec0f1aaSDmitry Bogdanov
1742aec0f1aaSDmitry Bogdanov for (assoc_num = 0; assoc_num < MACSEC_NUM_AN; assoc_num++) {
1743aec0f1aaSDmitry Bogdanov if (!test_bit(assoc_num, &aq_rxsc->rx_sa_idx_busy))
1744aec0f1aaSDmitry Bogdanov continue;
1745aec0f1aaSDmitry Bogdanov
1746aec0f1aaSDmitry Bogdanov rxsa_stats = &aq_rxsc->rx_sa_stats[assoc_num];
1747aec0f1aaSDmitry Bogdanov
1748aec0f1aaSDmitry Bogdanov data[++i] = rxsa_stats->untagged_hit_pkts;
1749aec0f1aaSDmitry Bogdanov data[++i] = rxsa_stats->ctrl_hit_drop_redir_pkts;
1750aec0f1aaSDmitry Bogdanov data[++i] = rxsa_stats->not_using_sa;
1751aec0f1aaSDmitry Bogdanov data[++i] = rxsa_stats->unused_sa;
1752aec0f1aaSDmitry Bogdanov data[++i] = rxsa_stats->not_valid_pkts;
1753aec0f1aaSDmitry Bogdanov data[++i] = rxsa_stats->invalid_pkts;
1754aec0f1aaSDmitry Bogdanov data[++i] = rxsa_stats->ok_pkts;
1755aec0f1aaSDmitry Bogdanov data[++i] = rxsa_stats->late_pkts;
1756aec0f1aaSDmitry Bogdanov data[++i] = rxsa_stats->delayed_pkts;
1757aec0f1aaSDmitry Bogdanov data[++i] = rxsa_stats->unchecked_pkts;
1758aec0f1aaSDmitry Bogdanov data[++i] = rxsa_stats->validated_octets;
1759aec0f1aaSDmitry Bogdanov data[++i] = rxsa_stats->decrypted_octets;
1760aec0f1aaSDmitry Bogdanov }
1761aec0f1aaSDmitry Bogdanov }
1762aec0f1aaSDmitry Bogdanov
1763aec0f1aaSDmitry Bogdanov i++;
1764aec0f1aaSDmitry Bogdanov
1765aec0f1aaSDmitry Bogdanov data += i;
1766aec0f1aaSDmitry Bogdanov
17676960d133SÍñigo Huguet mutex_unlock(&nic->macsec_mutex);
17686960d133SÍñigo Huguet
1769aec0f1aaSDmitry Bogdanov return data;
1770aec0f1aaSDmitry Bogdanov }
1771