1// SPDX-License-Identifier: GPL-2.0
2/* NXP C45 PTP PHY driver interface
3 * Copyright 2023 NXP
4 * Author: Radu Pirea <radu-nicolae.pirea@oss.nxp.com>
5 */
6
7#include <linux/delay.h>
8#include <linux/ethtool_netlink.h>
9#include <linux/kernel.h>
10#include <linux/mii.h>
11#include <linux/module.h>
12#include <linux/phy.h>
13#include <linux/processor.h>
14#include <net/dst_metadata.h>
15#include <net/macsec.h>
16
17#include "nxp-c45-tja11xx.h"
18
19#define MACSEC_REG_SIZE			32
20#define TX_SC_MAX			4
21
22#define TX_SC_BIT(secy_id)		BIT(MACSEC_REG_SIZE - (secy_id) - 1)
23
24#define VEND1_MACSEC_BASE		0x9000
25
26#define MACSEC_CFG			0x0000
27#define MACSEC_CFG_BYPASS		BIT(1)
28#define MACSEC_CFG_S0I			BIT(0)
29
30#define MACSEC_TPNET			0x0044
31#define PN_WRAP_THRESHOLD		0xffffffff
32
33#define MACSEC_RXSCA			0x0080
34#define MACSEC_RXSCKA			0x0084
35
36#define MACSEC_TXSCA			0x00C0
37#define MACSEC_TXSCKA			0x00C4
38
39#define MACSEC_RXSC_SCI_1H		0x0100
40
41#define MACSEC_RXSC_CFG			0x0128
42#define MACSEC_RXSC_CFG_XPN		BIT(25)
43#define MACSEC_RXSC_CFG_AES_256		BIT(24)
44#define MACSEC_RXSC_CFG_SCI_EN		BIT(11)
45#define MACSEC_RXSC_CFG_RP		BIT(10)
46#define MACSEC_RXSC_CFG_VF_MASK		GENMASK(9, 8)
47#define MACSEC_RXSC_CFG_VF_OFF		8
48
49#define MACSEC_RPW			0x012C
50
51#define MACSEC_RXSA_A_CS		0x0180
52#define MACSEC_RXSA_A_NPN		0x0184
53#define MACSEC_RXSA_A_XNPN		0x0188
54#define MACSEC_RXSA_A_LNPN		0x018C
55#define MACSEC_RXSA_A_LXNPN		0x0190
56
57#define MACSEC_RXSA_B_CS		0x01C0
58#define MACSEC_RXSA_B_NPN		0x01C4
59#define MACSEC_RXSA_B_XNPN		0x01C8
60#define MACSEC_RXSA_B_LNPN		0x01CC
61#define MACSEC_RXSA_B_LXNPN		0x01D0
62
63#define MACSEC_RXSA_CS_AN_OFF		1
64#define MACSEC_RXSA_CS_EN		BIT(0)
65
66#define MACSEC_TXSC_SCI_1H		0x0200
67#define MACSEC_TXSC_CFG			0x0228
68#define MACSEC_TXSC_CFG_XPN		BIT(25)
69#define MACSEC_TXSC_CFG_AES_256		BIT(24)
70#define MACSEC_TXSC_CFG_AN_MASK		GENMASK(19, 18)
71#define MACSEC_TXSC_CFG_AN_OFF		18
72#define MACSEC_TXSC_CFG_ASA		BIT(17)
73#define MACSEC_TXSC_CFG_SCE		BIT(16)
74#define MACSEC_TXSC_CFG_ENCRYPT		BIT(4)
75#define MACSEC_TXSC_CFG_PROTECT		BIT(3)
76#define MACSEC_TXSC_CFG_SEND_SCI	BIT(2)
77#define MACSEC_TXSC_CFG_END_STATION	BIT(1)
78#define MACSEC_TXSC_CFG_SCB		BIT(0)
79
80#define MACSEC_TXSA_A_CS		0x0280
81#define MACSEC_TXSA_A_NPN		0x0284
82#define MACSEC_TXSA_A_XNPN		0x0288
83
84#define MACSEC_TXSA_B_CS		0x02C0
85#define MACSEC_TXSA_B_NPN		0x02C4
86#define MACSEC_TXSA_B_XNPN		0x02C8
87
88#define MACSEC_SA_CS_A			BIT(31)
89
90#define MACSEC_EVR			0x0400
91#define MACSEC_EVER			0x0404
92
93#define MACSEC_RXSA_A_KA		0x0700
94#define MACSEC_RXSA_A_SSCI		0x0720
95#define MACSEC_RXSA_A_SALT		0x0724
96
97#define MACSEC_RXSA_B_KA		0x0740
98#define MACSEC_RXSA_B_SSCI		0x0760
99#define MACSEC_RXSA_B_SALT		0x0764
100
101#define MACSEC_TXSA_A_KA		0x0780
102#define MACSEC_TXSA_A_SSCI		0x07A0
103#define MACSEC_TXSA_A_SALT		0x07A4
104
105#define MACSEC_TXSA_B_KA		0x07C0
106#define MACSEC_TXSA_B_SSCI		0x07E0
107#define MACSEC_TXSA_B_SALT		0x07E4
108
109#define MACSEC_UPFR0D2			0x0A08
110#define MACSEC_UPFR0M1			0x0A10
111#define MACSEC_OVP			BIT(12)
112
113#define	MACSEC_UPFR0M2			0x0A14
114#define ETYPE_MASK			0xffff
115
116#define MACSEC_UPFR0R			0x0A18
117#define MACSEC_UPFR_EN			BIT(0)
118
119#define ADPTR_CNTRL			0x0F00
120#define ADPTR_CNTRL_CONFIG_EN		BIT(14)
121#define ADPTR_CNTRL_ADPTR_EN		BIT(12)
122#define ADPTR_TX_TAG_CNTRL		0x0F0C
123#define ADPTR_TX_TAG_CNTRL_ENA		BIT(31)
124
125#define TX_SC_FLT_BASE			0x800
126#define TX_SC_FLT_SIZE			0x10
127#define TX_FLT_BASE(flt_id)		(TX_SC_FLT_BASE + \
128	TX_SC_FLT_SIZE * (flt_id))
129
130#define TX_SC_FLT_OFF_MAC_DA_SA		0x04
131#define TX_SC_FLT_OFF_MAC_SA		0x08
132#define TX_SC_FLT_OFF_MAC_CFG		0x0C
133#define TX_SC_FLT_BY_SA			BIT(14)
134#define TX_SC_FLT_EN			BIT(8)
135
136#define TX_SC_FLT_MAC_DA_SA(base)	((base) + TX_SC_FLT_OFF_MAC_DA_SA)
137#define TX_SC_FLT_MAC_SA(base)		((base) + TX_SC_FLT_OFF_MAC_SA)
138#define TX_SC_FLT_MAC_CFG(base)		((base) + TX_SC_FLT_OFF_MAC_CFG)
139
140#define ADAPTER_EN	BIT(6)
141#define MACSEC_EN	BIT(5)
142
143#define MACSEC_INOV1HS			0x0140
144#define MACSEC_INOV2HS			0x0144
145#define MACSEC_INOD1HS			0x0148
146#define MACSEC_INOD2HS			0x014C
147#define MACSEC_RXSCIPUS			0x0150
148#define MACSEC_RXSCIPDS			0x0154
149#define MACSEC_RXSCIPLS			0x0158
150#define MACSEC_RXAN0INUSS		0x0160
151#define MACSEC_RXAN0IPUSS		0x0170
152#define MACSEC_RXSA_A_IPOS		0x0194
153#define MACSEC_RXSA_A_IPIS		0x01B0
154#define MACSEC_RXSA_A_IPNVS		0x01B4
155#define MACSEC_RXSA_B_IPOS		0x01D4
156#define MACSEC_RXSA_B_IPIS		0x01F0
157#define MACSEC_RXSA_B_IPNVS		0x01F4
158#define MACSEC_OPUS			0x021C
159#define MACSEC_OPTLS			0x022C
160#define MACSEC_OOP1HS			0x0240
161#define MACSEC_OOP2HS			0x0244
162#define MACSEC_OOE1HS			0x0248
163#define MACSEC_OOE2HS			0x024C
164#define MACSEC_TXSA_A_OPPS		0x028C
165#define MACSEC_TXSA_A_OPES		0x0290
166#define MACSEC_TXSA_B_OPPS		0x02CC
167#define MACSEC_TXSA_B_OPES		0x02D0
168#define MACSEC_INPWTS			0x0630
169#define MACSEC_INPBTS			0x0638
170#define MACSEC_IPSNFS			0x063C
171
172#define TJA11XX_TLV_TX_NEEDED_HEADROOM	(32)
173#define TJA11XX_TLV_NEEDED_TAILROOM	(0)
174
175#define ETH_P_TJA11XX_TLV		(0x4e58)
176
177enum nxp_c45_sa_type {
178	TX_SA,
179	RX_SA,
180};
181
182struct nxp_c45_sa {
183	void *sa;
184	const struct nxp_c45_sa_regs *regs;
185	enum nxp_c45_sa_type type;
186	bool is_key_a;
187	u8 an;
188	struct list_head list;
189};
190
191struct nxp_c45_secy {
192	struct macsec_secy *secy;
193	struct macsec_rx_sc *rx_sc;
194	struct list_head sa_list;
195	int secy_id;
196	bool rx_sc0_impl;
197	struct list_head list;
198};
199
200struct nxp_c45_macsec {
201	struct list_head secy_list;
202	DECLARE_BITMAP(secy_bitmap, TX_SC_MAX);
203	DECLARE_BITMAP(tx_sc_bitmap, TX_SC_MAX);
204};
205
206struct nxp_c45_sa_regs {
207	u16 cs;
208	u16 npn;
209	u16 xnpn;
210	u16 lnpn;
211	u16 lxnpn;
212	u16 ka;
213	u16 ssci;
214	u16 salt;
215	u16 ipis;
216	u16 ipnvs;
217	u16 ipos;
218	u16 opps;
219	u16 opes;
220};
221
222static const struct nxp_c45_sa_regs rx_sa_a_regs = {
223	.cs	= MACSEC_RXSA_A_CS,
224	.npn	= MACSEC_RXSA_A_NPN,
225	.xnpn	= MACSEC_RXSA_A_XNPN,
226	.lnpn	= MACSEC_RXSA_A_LNPN,
227	.lxnpn	= MACSEC_RXSA_A_LXNPN,
228	.ka	= MACSEC_RXSA_A_KA,
229	.ssci	= MACSEC_RXSA_A_SSCI,
230	.salt	= MACSEC_RXSA_A_SALT,
231	.ipis	= MACSEC_RXSA_A_IPIS,
232	.ipnvs	= MACSEC_RXSA_A_IPNVS,
233	.ipos	= MACSEC_RXSA_A_IPOS,
234};
235
236static const struct nxp_c45_sa_regs rx_sa_b_regs = {
237	.cs	= MACSEC_RXSA_B_CS,
238	.npn	= MACSEC_RXSA_B_NPN,
239	.xnpn	= MACSEC_RXSA_B_XNPN,
240	.lnpn	= MACSEC_RXSA_B_LNPN,
241	.lxnpn	= MACSEC_RXSA_B_LXNPN,
242	.ka	= MACSEC_RXSA_B_KA,
243	.ssci	= MACSEC_RXSA_B_SSCI,
244	.salt	= MACSEC_RXSA_B_SALT,
245	.ipis	= MACSEC_RXSA_B_IPIS,
246	.ipnvs	= MACSEC_RXSA_B_IPNVS,
247	.ipos	= MACSEC_RXSA_B_IPOS,
248};
249
250static const struct nxp_c45_sa_regs tx_sa_a_regs = {
251	.cs	= MACSEC_TXSA_A_CS,
252	.npn	= MACSEC_TXSA_A_NPN,
253	.xnpn	= MACSEC_TXSA_A_XNPN,
254	.ka	= MACSEC_TXSA_A_KA,
255	.ssci	= MACSEC_TXSA_A_SSCI,
256	.salt	= MACSEC_TXSA_A_SALT,
257	.opps	= MACSEC_TXSA_A_OPPS,
258	.opes	= MACSEC_TXSA_A_OPES,
259};
260
261static const struct nxp_c45_sa_regs tx_sa_b_regs = {
262	.cs	= MACSEC_TXSA_B_CS,
263	.npn	= MACSEC_TXSA_B_NPN,
264	.xnpn	= MACSEC_TXSA_B_XNPN,
265	.ka	= MACSEC_TXSA_B_KA,
266	.ssci	= MACSEC_TXSA_B_SSCI,
267	.salt	= MACSEC_TXSA_B_SALT,
268	.opps	= MACSEC_TXSA_B_OPPS,
269	.opes	= MACSEC_TXSA_B_OPES,
270};
271
272static const
273struct nxp_c45_sa_regs *nxp_c45_sa_regs_get(enum nxp_c45_sa_type sa_type,
274					    bool key_a)
275{
276	if (sa_type == RX_SA)
277		if (key_a)
278			return &rx_sa_a_regs;
279		else
280			return &rx_sa_b_regs;
281	else if (sa_type == TX_SA)
282		if (key_a)
283			return &tx_sa_a_regs;
284		else
285			return &tx_sa_b_regs;
286	else
287		return NULL;
288}
289
290static int nxp_c45_macsec_write(struct phy_device *phydev, u16 addr, u32 value)
291{
292	u32 lvalue = value;
293	u16 laddr;
294	int ret;
295
296	WARN_ON_ONCE(addr % 4);
297
298	phydev_dbg(phydev, "write addr 0x%x value 0x%x\n", addr, value);
299
300	laddr = VEND1_MACSEC_BASE + addr / 2;
301	ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, laddr, lvalue);
302	if (ret)
303		return ret;
304
305	laddr += 1;
306	lvalue >>= 16;
307	ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, laddr, lvalue);
308
309	return ret;
310}
311
312static int nxp_c45_macsec_read(struct phy_device *phydev, u16 addr, u32 *value)
313{
314	u32 lvalue;
315	u16 laddr;
316	int ret;
317
318	WARN_ON_ONCE(addr % 4);
319
320	laddr = VEND1_MACSEC_BASE + addr / 2;
321	ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, laddr);
322	if (ret < 0)
323		return ret;
324
325	laddr += 1;
326	lvalue = (u32)ret & 0xffff;
327	ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, laddr);
328	if (ret < 0)
329		return ret;
330
331	lvalue |= (u32)ret << 16;
332	*value = lvalue;
333
334	phydev_dbg(phydev, "read addr 0x%x value 0x%x\n", addr, *value);
335
336	return 0;
337}
338
339static void nxp_c45_macsec_read32_64(struct phy_device *phydev, u16 addr,
340				     u64 *value)
341{
342	u32 lvalue;
343
344	nxp_c45_macsec_read(phydev, addr, &lvalue);
345	*value = lvalue;
346}
347
348static void nxp_c45_macsec_read64(struct phy_device *phydev, u16 addr,
349				  u64 *value)
350{
351	u32 lvalue;
352
353	nxp_c45_macsec_read(phydev, addr, &lvalue);
354	*value = (u64)lvalue << 32;
355	nxp_c45_macsec_read(phydev, addr + 4, &lvalue);
356	*value |= lvalue;
357}
358
359static void nxp_c45_secy_irq_en(struct phy_device *phydev,
360				struct nxp_c45_secy *phy_secy, bool en)
361{
362	u32 reg;
363
364	nxp_c45_macsec_read(phydev, MACSEC_EVER, &reg);
365	if (en)
366		reg |= TX_SC_BIT(phy_secy->secy_id);
367	else
368		reg &= ~TX_SC_BIT(phy_secy->secy_id);
369	nxp_c45_macsec_write(phydev, MACSEC_EVER, reg);
370}
371
372static struct nxp_c45_secy *nxp_c45_find_secy(struct list_head *secy_list,
373					      sci_t sci)
374{
375	struct nxp_c45_secy *pos, *tmp;
376
377	list_for_each_entry_safe(pos, tmp, secy_list, list)
378		if (pos->secy->sci == sci)
379			return pos;
380
381	return ERR_PTR(-EINVAL);
382}
383
384static struct
385nxp_c45_secy *nxp_c45_find_secy_by_id(struct list_head *secy_list,
386				      int id)
387{
388	struct nxp_c45_secy *pos, *tmp;
389
390	list_for_each_entry_safe(pos, tmp, secy_list, list)
391		if (pos->secy_id == id)
392			return pos;
393
394	return ERR_PTR(-EINVAL);
395}
396
397static void nxp_c45_secy_free(struct nxp_c45_secy *phy_secy)
398{
399	list_del(&phy_secy->list);
400	kfree(phy_secy);
401}
402
403static struct nxp_c45_sa *nxp_c45_find_sa(struct list_head *sa_list,
404					  enum nxp_c45_sa_type sa_type, u8 an)
405{
406	struct nxp_c45_sa *pos, *tmp;
407
408	list_for_each_entry_safe(pos, tmp, sa_list, list)
409		if (pos->an == an && pos->type == sa_type)
410			return pos;
411
412	return ERR_PTR(-EINVAL);
413}
414
415static struct nxp_c45_sa *nxp_c45_sa_alloc(struct list_head *sa_list, void *sa,
416					   enum nxp_c45_sa_type sa_type, u8 an)
417{
418	struct nxp_c45_sa *first = NULL, *pos, *tmp;
419	int occurrences = 0;
420
421	list_for_each_entry_safe(pos, tmp, sa_list, list) {
422		if (pos->type != sa_type)
423			continue;
424
425		if (pos->an == an)
426			return ERR_PTR(-EINVAL);
427
428		first = pos;
429		occurrences++;
430		if (occurrences >= 2)
431			return ERR_PTR(-ENOSPC);
432	}
433
434	tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
435	if (!tmp)
436		return ERR_PTR(-ENOMEM);
437
438	if (first)
439		tmp->is_key_a = !first->is_key_a;
440	else
441		tmp->is_key_a = true;
442
443	tmp->sa = sa;
444	tmp->type = sa_type;
445	tmp->an = an;
446	tmp->regs = nxp_c45_sa_regs_get(tmp->type, tmp->is_key_a);
447	list_add_tail(&tmp->list, sa_list);
448
449	return tmp;
450}
451
452static void nxp_c45_sa_free(struct nxp_c45_sa *sa)
453{
454	list_del(&sa->list);
455	kfree(sa);
456}
457
458static void nxp_c45_sa_list_free(struct list_head *sa_list)
459{
460	struct nxp_c45_sa *pos, *tmp;
461
462	list_for_each_entry_safe(pos, tmp, sa_list, list)
463		nxp_c45_sa_free(pos);
464}
465
466static void nxp_c45_sa_set_pn(struct phy_device *phydev,
467			      struct nxp_c45_sa *sa, u64 pn,
468			      u32 replay_window)
469{
470	const struct nxp_c45_sa_regs *sa_regs = sa->regs;
471	pn_t npn = {.full64 = pn};
472	pn_t lnpn;
473
474	nxp_c45_macsec_write(phydev, sa_regs->npn, npn.lower);
475	nxp_c45_macsec_write(phydev, sa_regs->xnpn, npn.upper);
476	if (sa->type != RX_SA)
477		return;
478
479	if (pn > replay_window)
480		lnpn.full64 = pn - replay_window;
481	else
482		lnpn.full64 = 1;
483
484	nxp_c45_macsec_write(phydev, sa_regs->lnpn, lnpn.lower);
485	nxp_c45_macsec_write(phydev, sa_regs->lxnpn, lnpn.upper);
486}
487
488static void nxp_c45_sa_set_key(struct macsec_context *ctx,
489			       const struct nxp_c45_sa_regs *sa_regs,
490			       u8 *salt, ssci_t ssci)
491{
492	struct phy_device *phydev = ctx->phydev;
493	u32 key_size = ctx->secy->key_len / 4;
494	u32 salt_size = MACSEC_SALT_LEN / 4;
495	u32 *key_u32 = (u32 *)ctx->sa.key;
496	u32 *salt_u32 = (u32 *)salt;
497	u32 reg, value;
498	int i;
499
500	for (i = 0; i < key_size; i++) {
501		reg = sa_regs->ka + i * 4;
502		value = (__force u32)cpu_to_be32(key_u32[i]);
503		nxp_c45_macsec_write(phydev, reg, value);
504	}
505
506	if (ctx->secy->xpn) {
507		for (i = 0; i < salt_size; i++) {
508			reg = sa_regs->salt + (2 - i) * 4;
509			value = (__force u32)cpu_to_be32(salt_u32[i]);
510			nxp_c45_macsec_write(phydev, reg, value);
511		}
512
513		value = (__force u32)cpu_to_be32((__force u32)ssci);
514		nxp_c45_macsec_write(phydev, sa_regs->ssci, value);
515	}
516
517	nxp_c45_macsec_write(phydev, sa_regs->cs, MACSEC_SA_CS_A);
518}
519
520static void nxp_c45_rx_sa_clear_stats(struct phy_device *phydev,
521				      struct nxp_c45_sa *sa)
522{
523	nxp_c45_macsec_write(phydev, sa->regs->ipis, 0);
524	nxp_c45_macsec_write(phydev, sa->regs->ipnvs, 0);
525	nxp_c45_macsec_write(phydev, sa->regs->ipos, 0);
526
527	nxp_c45_macsec_write(phydev, MACSEC_RXAN0INUSS + sa->an * 4, 0);
528	nxp_c45_macsec_write(phydev, MACSEC_RXAN0IPUSS + sa->an * 4, 0);
529}
530
531static void nxp_c45_rx_sa_read_stats(struct phy_device *phydev,
532				     struct nxp_c45_sa *sa,
533				     struct macsec_rx_sa_stats *stats)
534{
535	nxp_c45_macsec_read(phydev, sa->regs->ipis, &stats->InPktsInvalid);
536	nxp_c45_macsec_read(phydev, sa->regs->ipnvs, &stats->InPktsNotValid);
537	nxp_c45_macsec_read(phydev, sa->regs->ipos, &stats->InPktsOK);
538}
539
540static void nxp_c45_tx_sa_clear_stats(struct phy_device *phydev,
541				      struct nxp_c45_sa *sa)
542{
543	nxp_c45_macsec_write(phydev, sa->regs->opps, 0);
544	nxp_c45_macsec_write(phydev, sa->regs->opes, 0);
545}
546
547static void nxp_c45_tx_sa_read_stats(struct phy_device *phydev,
548				     struct nxp_c45_sa *sa,
549				     struct macsec_tx_sa_stats *stats)
550{
551	nxp_c45_macsec_read(phydev, sa->regs->opps, &stats->OutPktsProtected);
552	nxp_c45_macsec_read(phydev, sa->regs->opes, &stats->OutPktsEncrypted);
553}
554
555static void nxp_c45_rx_sa_update(struct phy_device *phydev,
556				 struct nxp_c45_sa *sa, bool en)
557{
558	const struct nxp_c45_sa_regs *sa_regs = sa->regs;
559	u32 cfg;
560
561	cfg = sa->an << MACSEC_RXSA_CS_AN_OFF;
562	cfg |= en ? MACSEC_RXSA_CS_EN : 0;
563	nxp_c45_macsec_write(phydev, sa_regs->cs, cfg);
564}
565
566static void nxp_c45_tx_sa_update(struct phy_device *phydev,
567				 struct nxp_c45_sa *sa, bool en)
568{
569	u32 cfg = 0;
570
571	nxp_c45_macsec_read(phydev, MACSEC_TXSC_CFG, &cfg);
572
573	cfg &= ~MACSEC_TXSC_CFG_AN_MASK;
574	cfg |= sa->an << MACSEC_TXSC_CFG_AN_OFF;
575
576	if (sa->is_key_a)
577		cfg &= ~MACSEC_TXSC_CFG_ASA;
578	else
579		cfg |= MACSEC_TXSC_CFG_ASA;
580
581	if (en)
582		cfg |= MACSEC_TXSC_CFG_SCE;
583	else
584		cfg &= ~MACSEC_TXSC_CFG_SCE;
585
586	nxp_c45_macsec_write(phydev, MACSEC_TXSC_CFG, cfg);
587}
588
589static void nxp_c45_set_sci(struct phy_device *phydev, u16 sci_base_addr,
590			    sci_t sci)
591{
592	u64 lsci = sci_to_cpu(sci);
593
594	nxp_c45_macsec_write(phydev, sci_base_addr, lsci >> 32);
595	nxp_c45_macsec_write(phydev, sci_base_addr + 4, lsci);
596}
597
598static bool nxp_c45_port_is_1(sci_t sci)
599{
600	u16 port = sci_to_cpu(sci);
601
602	return port == 1;
603}
604
605static void nxp_c45_select_secy(struct phy_device *phydev, u8 id)
606{
607	nxp_c45_macsec_write(phydev, MACSEC_RXSCA, id);
608	nxp_c45_macsec_write(phydev, MACSEC_RXSCKA, id);
609	nxp_c45_macsec_write(phydev, MACSEC_TXSCA, id);
610	nxp_c45_macsec_write(phydev, MACSEC_TXSCKA, id);
611}
612
613static bool nxp_c45_secy_valid(struct nxp_c45_secy *phy_secy,
614			       bool can_rx_sc0_impl)
615{
616	bool end_station = phy_secy->secy->tx_sc.end_station;
617	bool scb = phy_secy->secy->tx_sc.scb;
618
619	phy_secy->rx_sc0_impl = false;
620
621	if (end_station) {
622		if (!nxp_c45_port_is_1(phy_secy->secy->sci))
623			return false;
624		if (!phy_secy->rx_sc)
625			return true;
626		return nxp_c45_port_is_1(phy_secy->rx_sc->sci);
627	}
628
629	if (scb)
630		return false;
631
632	if (!can_rx_sc0_impl)
633		return false;
634
635	if (phy_secy->secy_id != 0)
636		return false;
637
638	phy_secy->rx_sc0_impl = true;
639
640	return true;
641}
642
643static bool nxp_c45_rx_sc0_impl(struct nxp_c45_secy *phy_secy)
644{
645	bool end_station = phy_secy->secy->tx_sc.end_station;
646	bool send_sci = phy_secy->secy->tx_sc.send_sci;
647	bool scb = phy_secy->secy->tx_sc.scb;
648
649	return !end_station && !send_sci && !scb;
650}
651
652static bool nxp_c45_mac_addr_free(struct macsec_context *ctx)
653{
654	struct nxp_c45_phy *priv = ctx->phydev->priv;
655	struct nxp_c45_secy *pos, *tmp;
656
657	list_for_each_entry_safe(pos, tmp, &priv->macsec->secy_list, list) {
658		if (pos->secy == ctx->secy)
659			continue;
660
661		if (memcmp(pos->secy->netdev->dev_addr,
662			   ctx->secy->netdev->dev_addr, ETH_ALEN) == 0)
663			return false;
664	}
665
666	return true;
667}
668
669static void nxp_c45_tx_sc_en_flt(struct phy_device *phydev, int secy_id,
670				 bool en)
671{
672	u32 tx_flt_base = TX_FLT_BASE(secy_id);
673	u32 reg = 0;
674
675	nxp_c45_macsec_read(phydev, TX_SC_FLT_MAC_CFG(tx_flt_base), &reg);
676	if (en)
677		reg |= TX_SC_FLT_EN;
678	else
679		reg &= ~TX_SC_FLT_EN;
680	nxp_c45_macsec_write(phydev, TX_SC_FLT_MAC_CFG(tx_flt_base), reg);
681}
682
683static void nxp_c45_tx_sc_set_flt(struct phy_device *phydev,
684				  struct nxp_c45_secy *phy_secy)
685{
686	const u8 *dev_addr = phy_secy->secy->netdev->dev_addr;
687	u32 tx_flt_base = TX_FLT_BASE(phy_secy->secy_id);
688	u32 reg;
689
690	reg = dev_addr[0] << 8 | dev_addr[1];
691	nxp_c45_macsec_write(phydev, TX_SC_FLT_MAC_DA_SA(tx_flt_base), reg);
692	reg = dev_addr[5] | dev_addr[4] << 8 | dev_addr[3] << 16 |
693		dev_addr[2] << 24;
694
695	nxp_c45_macsec_write(phydev, TX_SC_FLT_MAC_SA(tx_flt_base), reg);
696	nxp_c45_macsec_read(phydev, TX_SC_FLT_MAC_CFG(tx_flt_base), &reg);
697	reg &= TX_SC_FLT_EN;
698	reg |= TX_SC_FLT_BY_SA | phy_secy->secy_id;
699	nxp_c45_macsec_write(phydev, TX_SC_FLT_MAC_CFG(tx_flt_base), reg);
700}
701
702static void nxp_c45_tx_sc_update(struct phy_device *phydev,
703				 struct nxp_c45_secy *phy_secy)
704{
705	u32 cfg = 0;
706
707	nxp_c45_macsec_read(phydev, MACSEC_TXSC_CFG, &cfg);
708
709	phydev_dbg(phydev, "XPN %s\n", phy_secy->secy->xpn ? "on" : "off");
710	if (phy_secy->secy->xpn)
711		cfg |= MACSEC_TXSC_CFG_XPN;
712	else
713		cfg &= ~MACSEC_TXSC_CFG_XPN;
714
715	phydev_dbg(phydev, "key len %u\n", phy_secy->secy->key_len);
716	if (phy_secy->secy->key_len == 32)
717		cfg |= MACSEC_TXSC_CFG_AES_256;
718	else
719		cfg &= ~MACSEC_TXSC_CFG_AES_256;
720
721	phydev_dbg(phydev, "encryption %s\n",
722		   phy_secy->secy->tx_sc.encrypt ? "on" : "off");
723	if (phy_secy->secy->tx_sc.encrypt)
724		cfg |= MACSEC_TXSC_CFG_ENCRYPT;
725	else
726		cfg &= ~MACSEC_TXSC_CFG_ENCRYPT;
727
728	phydev_dbg(phydev, "protect frames %s\n",
729		   phy_secy->secy->protect_frames ? "on" : "off");
730	if (phy_secy->secy->protect_frames)
731		cfg |= MACSEC_TXSC_CFG_PROTECT;
732	else
733		cfg &= ~MACSEC_TXSC_CFG_PROTECT;
734
735	phydev_dbg(phydev, "send sci %s\n",
736		   phy_secy->secy->tx_sc.send_sci ? "on" : "off");
737	if (phy_secy->secy->tx_sc.send_sci)
738		cfg |= MACSEC_TXSC_CFG_SEND_SCI;
739	else
740		cfg &= ~MACSEC_TXSC_CFG_SEND_SCI;
741
742	phydev_dbg(phydev, "end station %s\n",
743		   phy_secy->secy->tx_sc.end_station ? "on" : "off");
744	if (phy_secy->secy->tx_sc.end_station)
745		cfg |= MACSEC_TXSC_CFG_END_STATION;
746	else
747		cfg &= ~MACSEC_TXSC_CFG_END_STATION;
748
749	phydev_dbg(phydev, "scb %s\n",
750		   phy_secy->secy->tx_sc.scb ? "on" : "off");
751	if (phy_secy->secy->tx_sc.scb)
752		cfg |= MACSEC_TXSC_CFG_SCB;
753	else
754		cfg &= ~MACSEC_TXSC_CFG_SCB;
755
756	nxp_c45_macsec_write(phydev, MACSEC_TXSC_CFG, cfg);
757}
758
759static void nxp_c45_tx_sc_clear_stats(struct phy_device *phydev,
760				      struct nxp_c45_secy *phy_secy)
761{
762	struct nxp_c45_sa *pos, *tmp;
763
764	list_for_each_entry_safe(pos, tmp, &phy_secy->sa_list, list)
765		if (pos->type == TX_SA)
766			nxp_c45_tx_sa_clear_stats(phydev, pos);
767
768	nxp_c45_macsec_write(phydev, MACSEC_OPUS, 0);
769	nxp_c45_macsec_write(phydev, MACSEC_OPTLS, 0);
770	nxp_c45_macsec_write(phydev, MACSEC_OOP1HS, 0);
771	nxp_c45_macsec_write(phydev, MACSEC_OOP2HS, 0);
772	nxp_c45_macsec_write(phydev, MACSEC_OOE1HS, 0);
773	nxp_c45_macsec_write(phydev, MACSEC_OOE2HS, 0);
774}
775
776static void nxp_c45_set_rx_sc0_impl(struct phy_device *phydev,
777				    bool enable)
778{
779	u32 reg = 0;
780
781	nxp_c45_macsec_read(phydev, MACSEC_CFG, &reg);
782	if (enable)
783		reg |= MACSEC_CFG_S0I;
784	else
785		reg &= ~MACSEC_CFG_S0I;
786	nxp_c45_macsec_write(phydev, MACSEC_CFG, reg);
787}
788
789static bool nxp_c45_is_rx_sc0_impl(struct list_head *secy_list)
790{
791	struct nxp_c45_secy *pos, *tmp;
792
793	list_for_each_entry_safe(pos, tmp, secy_list, list)
794		if (pos->rx_sc0_impl)
795			return pos->rx_sc0_impl;
796
797	return false;
798}
799
800static void nxp_c45_rx_sc_en(struct phy_device *phydev,
801			     struct macsec_rx_sc *rx_sc, bool en)
802{
803	u32 reg = 0;
804
805	nxp_c45_macsec_read(phydev, MACSEC_RXSC_CFG, &reg);
806	if (rx_sc->active && en)
807		reg |= MACSEC_RXSC_CFG_SCI_EN;
808	else
809		reg &= ~MACSEC_RXSC_CFG_SCI_EN;
810	nxp_c45_macsec_write(phydev, MACSEC_RXSC_CFG, reg);
811}
812
813static void nxp_c45_rx_sc_update(struct phy_device *phydev,
814				 struct nxp_c45_secy *phy_secy)
815{
816	struct macsec_rx_sc *rx_sc = phy_secy->rx_sc;
817	struct nxp_c45_phy *priv = phydev->priv;
818	u32 cfg = 0;
819
820	nxp_c45_macsec_read(phydev, MACSEC_RXSC_CFG, &cfg);
821	cfg &= ~MACSEC_RXSC_CFG_VF_MASK;
822	cfg = phy_secy->secy->validate_frames << MACSEC_RXSC_CFG_VF_OFF;
823
824	phydev_dbg(phydev, "validate frames %u\n",
825		   phy_secy->secy->validate_frames);
826	phydev_dbg(phydev, "replay_protect %s window %u\n",
827		   phy_secy->secy->replay_protect ? "on" : "off",
828		   phy_secy->secy->replay_window);
829	if (phy_secy->secy->replay_protect) {
830		cfg |= MACSEC_RXSC_CFG_RP;
831		nxp_c45_macsec_write(phydev, MACSEC_RPW,
832				     phy_secy->secy->replay_window);
833	} else {
834		cfg &= ~MACSEC_RXSC_CFG_RP;
835	}
836
837	phydev_dbg(phydev, "rx_sc->active %s\n",
838		   rx_sc->active ? "on" : "off");
839	if (rx_sc->active &&
840	    test_bit(phy_secy->secy_id, priv->macsec->secy_bitmap))
841		cfg |= MACSEC_RXSC_CFG_SCI_EN;
842	else
843		cfg &= ~MACSEC_RXSC_CFG_SCI_EN;
844
845	phydev_dbg(phydev, "key len %u\n", phy_secy->secy->key_len);
846	if (phy_secy->secy->key_len == 32)
847		cfg |= MACSEC_RXSC_CFG_AES_256;
848	else
849		cfg &= ~MACSEC_RXSC_CFG_AES_256;
850
851	phydev_dbg(phydev, "XPN %s\n", phy_secy->secy->xpn ? "on" : "off");
852	if (phy_secy->secy->xpn)
853		cfg |= MACSEC_RXSC_CFG_XPN;
854	else
855		cfg &= ~MACSEC_RXSC_CFG_XPN;
856
857	nxp_c45_macsec_write(phydev, MACSEC_RXSC_CFG, cfg);
858}
859
860static void nxp_c45_rx_sc_clear_stats(struct phy_device *phydev,
861				      struct nxp_c45_secy *phy_secy)
862{
863	struct nxp_c45_sa *pos, *tmp;
864	int i;
865
866	list_for_each_entry_safe(pos, tmp, &phy_secy->sa_list, list)
867		if (pos->type == RX_SA)
868			nxp_c45_rx_sa_clear_stats(phydev, pos);
869
870	nxp_c45_macsec_write(phydev, MACSEC_INOD1HS, 0);
871	nxp_c45_macsec_write(phydev, MACSEC_INOD2HS, 0);
872
873	nxp_c45_macsec_write(phydev, MACSEC_INOV1HS, 0);
874	nxp_c45_macsec_write(phydev, MACSEC_INOV2HS, 0);
875
876	nxp_c45_macsec_write(phydev, MACSEC_RXSCIPDS, 0);
877	nxp_c45_macsec_write(phydev, MACSEC_RXSCIPLS, 0);
878	nxp_c45_macsec_write(phydev, MACSEC_RXSCIPUS, 0);
879
880	for (i = 0; i < MACSEC_NUM_AN; i++) {
881		nxp_c45_macsec_write(phydev, MACSEC_RXAN0INUSS + i * 4, 0);
882		nxp_c45_macsec_write(phydev, MACSEC_RXAN0IPUSS + i * 4, 0);
883	}
884}
885
886static void nxp_c45_rx_sc_del(struct phy_device *phydev,
887			      struct nxp_c45_secy *phy_secy)
888{
889	struct nxp_c45_sa *pos, *tmp;
890
891	nxp_c45_macsec_write(phydev, MACSEC_RXSC_CFG, 0);
892	nxp_c45_macsec_write(phydev, MACSEC_RPW, 0);
893	nxp_c45_set_sci(phydev, MACSEC_RXSC_SCI_1H, 0);
894
895	nxp_c45_rx_sc_clear_stats(phydev, phy_secy);
896
897	list_for_each_entry_safe(pos, tmp, &phy_secy->sa_list, list) {
898		if (pos->type == RX_SA) {
899			nxp_c45_rx_sa_update(phydev, pos, false);
900			nxp_c45_sa_free(pos);
901		}
902	}
903}
904
905static void nxp_c45_clear_global_stats(struct phy_device *phydev)
906{
907	nxp_c45_macsec_write(phydev, MACSEC_INPBTS, 0);
908	nxp_c45_macsec_write(phydev, MACSEC_INPWTS, 0);
909	nxp_c45_macsec_write(phydev, MACSEC_IPSNFS, 0);
910}
911
912static void nxp_c45_macsec_en(struct phy_device *phydev, bool en)
913{
914	u32 reg;
915
916	nxp_c45_macsec_read(phydev, MACSEC_CFG, &reg);
917	if (en)
918		reg |= MACSEC_CFG_BYPASS;
919	else
920		reg &= ~MACSEC_CFG_BYPASS;
921	nxp_c45_macsec_write(phydev, MACSEC_CFG, reg);
922}
923
924static int nxp_c45_mdo_dev_open(struct macsec_context *ctx)
925{
926	struct phy_device *phydev = ctx->phydev;
927	struct nxp_c45_phy *priv = phydev->priv;
928	struct nxp_c45_secy *phy_secy;
929	int any_bit_set;
930
931	phy_secy = nxp_c45_find_secy(&priv->macsec->secy_list, ctx->secy->sci);
932	if (IS_ERR(phy_secy))
933		return PTR_ERR(phy_secy);
934
935	nxp_c45_select_secy(phydev, phy_secy->secy_id);
936
937	nxp_c45_tx_sc_en_flt(phydev, phy_secy->secy_id, true);
938	nxp_c45_set_rx_sc0_impl(phydev, phy_secy->rx_sc0_impl);
939	if (phy_secy->rx_sc)
940		nxp_c45_rx_sc_en(phydev, phy_secy->rx_sc, true);
941
942	any_bit_set = find_first_bit(priv->macsec->secy_bitmap, TX_SC_MAX);
943	if (any_bit_set == TX_SC_MAX)
944		nxp_c45_macsec_en(phydev, true);
945
946	set_bit(phy_secy->secy_id, priv->macsec->secy_bitmap);
947
948	return 0;
949}
950
951static int nxp_c45_mdo_dev_stop(struct macsec_context *ctx)
952{
953	struct phy_device *phydev = ctx->phydev;
954	struct nxp_c45_phy *priv = phydev->priv;
955	struct nxp_c45_secy *phy_secy;
956	int any_bit_set;
957
958	phy_secy = nxp_c45_find_secy(&priv->macsec->secy_list, ctx->secy->sci);
959	if (IS_ERR(phy_secy))
960		return PTR_ERR(phy_secy);
961
962	nxp_c45_select_secy(phydev, phy_secy->secy_id);
963
964	nxp_c45_tx_sc_en_flt(phydev, phy_secy->secy_id, false);
965	if (phy_secy->rx_sc)
966		nxp_c45_rx_sc_en(phydev, phy_secy->rx_sc, false);
967	nxp_c45_set_rx_sc0_impl(phydev, false);
968
969	clear_bit(phy_secy->secy_id, priv->macsec->secy_bitmap);
970	any_bit_set = find_first_bit(priv->macsec->secy_bitmap, TX_SC_MAX);
971	if (any_bit_set == TX_SC_MAX)
972		nxp_c45_macsec_en(phydev, false);
973
974	return 0;
975}
976
977static int nxp_c45_mdo_add_secy(struct macsec_context *ctx)
978{
979	struct phy_device *phydev = ctx->phydev;
980	struct nxp_c45_phy *priv = phydev->priv;
981	struct nxp_c45_secy *phy_secy;
982	bool can_rx_sc0_impl;
983	int idx;
984
985	phydev_dbg(phydev, "add SecY SCI %016llx\n",
986		   sci_to_cpu(ctx->secy->sci));
987
988	if (!nxp_c45_mac_addr_free(ctx))
989		return -EBUSY;
990
991	if (nxp_c45_is_rx_sc0_impl(&priv->macsec->secy_list))
992		return -EBUSY;
993
994	idx = find_first_zero_bit(priv->macsec->tx_sc_bitmap, TX_SC_MAX);
995	if (idx == TX_SC_MAX)
996		return -ENOSPC;
997
998	phy_secy = kzalloc(sizeof(*phy_secy), GFP_KERNEL);
999	if (!phy_secy)
1000		return -ENOMEM;
1001
1002	INIT_LIST_HEAD(&phy_secy->sa_list);
1003	phy_secy->secy = ctx->secy;
1004	phy_secy->secy_id = idx;
1005
1006	/* If the point to point mode should be enabled, we should have no
1007	 * SecY added yet.
1008	 */
1009	can_rx_sc0_impl = list_count_nodes(&priv->macsec->secy_list) == 0;
1010	if (!nxp_c45_secy_valid(phy_secy, can_rx_sc0_impl)) {
1011		kfree(phy_secy);
1012		return -EINVAL;
1013	}
1014
1015	phy_secy->rx_sc0_impl = nxp_c45_rx_sc0_impl(phy_secy);
1016
1017	nxp_c45_select_secy(phydev, phy_secy->secy_id);
1018	nxp_c45_set_sci(phydev, MACSEC_TXSC_SCI_1H, ctx->secy->sci);
1019	nxp_c45_tx_sc_set_flt(phydev, phy_secy);
1020	nxp_c45_tx_sc_update(phydev, phy_secy);
1021	if (phy_interrupt_is_valid(phydev))
1022		nxp_c45_secy_irq_en(phydev, phy_secy, true);
1023
1024	set_bit(idx, priv->macsec->tx_sc_bitmap);
1025	list_add_tail(&phy_secy->list, &priv->macsec->secy_list);
1026
1027	return 0;
1028}
1029
1030static void nxp_c45_tx_sa_next(struct nxp_c45_secy *phy_secy,
1031			       struct nxp_c45_sa *next_sa, u8 encoding_sa)
1032{
1033	struct nxp_c45_sa *sa;
1034
1035	sa = nxp_c45_find_sa(&phy_secy->sa_list, TX_SA, encoding_sa);
1036	if (!IS_ERR(sa)) {
1037		memcpy(next_sa, sa, sizeof(*sa));
1038	} else {
1039		next_sa->is_key_a = true;
1040		next_sa->an = encoding_sa;
1041	}
1042}
1043
1044static int nxp_c45_mdo_upd_secy(struct macsec_context *ctx)
1045{
1046	u8 encoding_sa = ctx->secy->tx_sc.encoding_sa;
1047	struct phy_device *phydev = ctx->phydev;
1048	struct nxp_c45_phy *priv = phydev->priv;
1049	struct nxp_c45_secy *phy_secy;
1050	struct nxp_c45_sa next_sa;
1051	bool can_rx_sc0_impl;
1052
1053	phydev_dbg(phydev, "update SecY SCI %016llx\n",
1054		   sci_to_cpu(ctx->secy->sci));
1055
1056	phy_secy = nxp_c45_find_secy(&priv->macsec->secy_list, ctx->secy->sci);
1057	if (IS_ERR(phy_secy))
1058		return PTR_ERR(phy_secy);
1059
1060	if (!nxp_c45_mac_addr_free(ctx))
1061		return -EBUSY;
1062
1063	/* If the point to point mode should be enabled, we should have only
1064	 * one SecY added, respectively the updated one.
1065	 */
1066	can_rx_sc0_impl = list_count_nodes(&priv->macsec->secy_list) == 1;
1067	if (!nxp_c45_secy_valid(phy_secy, can_rx_sc0_impl))
1068		return -EINVAL;
1069	phy_secy->rx_sc0_impl = nxp_c45_rx_sc0_impl(phy_secy);
1070
1071	nxp_c45_select_secy(phydev, phy_secy->secy_id);
1072	nxp_c45_tx_sc_set_flt(phydev, phy_secy);
1073	nxp_c45_tx_sc_update(phydev, phy_secy);
1074	nxp_c45_tx_sa_next(phy_secy, &next_sa, encoding_sa);
1075	nxp_c45_tx_sa_update(phydev, &next_sa, ctx->secy->operational);
1076
1077	nxp_c45_set_rx_sc0_impl(phydev, phy_secy->rx_sc0_impl);
1078	if (phy_secy->rx_sc)
1079		nxp_c45_rx_sc_update(phydev, phy_secy);
1080
1081	return 0;
1082}
1083
1084static int nxp_c45_mdo_del_secy(struct macsec_context *ctx)
1085{
1086	u8 encoding_sa = ctx->secy->tx_sc.encoding_sa;
1087	struct phy_device *phydev = ctx->phydev;
1088	struct nxp_c45_phy *priv = phydev->priv;
1089	struct nxp_c45_secy *phy_secy;
1090	struct nxp_c45_sa next_sa;
1091
1092	phydev_dbg(phydev, "delete SecY SCI %016llx\n",
1093		   sci_to_cpu(ctx->secy->sci));
1094
1095	phy_secy = nxp_c45_find_secy(&priv->macsec->secy_list, ctx->secy->sci);
1096	if (IS_ERR(phy_secy))
1097		return PTR_ERR(phy_secy);
1098	nxp_c45_select_secy(phydev, phy_secy->secy_id);
1099
1100	nxp_c45_mdo_dev_stop(ctx);
1101	nxp_c45_tx_sa_next(phy_secy, &next_sa, encoding_sa);
1102	nxp_c45_tx_sa_update(phydev, &next_sa, false);
1103	nxp_c45_tx_sc_clear_stats(phydev, phy_secy);
1104	if (phy_secy->rx_sc)
1105		nxp_c45_rx_sc_del(phydev, phy_secy);
1106
1107	nxp_c45_sa_list_free(&phy_secy->sa_list);
1108	if (phy_interrupt_is_valid(phydev))
1109		nxp_c45_secy_irq_en(phydev, phy_secy, false);
1110
1111	clear_bit(phy_secy->secy_id, priv->macsec->tx_sc_bitmap);
1112	nxp_c45_secy_free(phy_secy);
1113
1114	if (list_empty(&priv->macsec->secy_list))
1115		nxp_c45_clear_global_stats(phydev);
1116
1117	return 0;
1118}
1119
1120static int nxp_c45_mdo_add_rxsc(struct macsec_context *ctx)
1121{
1122	struct phy_device *phydev = ctx->phydev;
1123	struct nxp_c45_phy *priv = phydev->priv;
1124	struct nxp_c45_secy *phy_secy;
1125
1126	phydev_dbg(phydev, "add RX SC SCI %016llx %s\n",
1127		   sci_to_cpu(ctx->rx_sc->sci),
1128		   ctx->rx_sc->active ? "enabled" : "disabled");
1129
1130	phy_secy = nxp_c45_find_secy(&priv->macsec->secy_list, ctx->secy->sci);
1131	if (IS_ERR(phy_secy))
1132		return PTR_ERR(phy_secy);
1133
1134	if (phy_secy->rx_sc)
1135		return -ENOSPC;
1136
1137	if (phy_secy->secy->tx_sc.end_station &&
1138	    !nxp_c45_port_is_1(ctx->rx_sc->sci))
1139		return -EINVAL;
1140
1141	phy_secy->rx_sc = ctx->rx_sc;
1142
1143	nxp_c45_select_secy(phydev, phy_secy->secy_id);
1144	nxp_c45_set_sci(phydev, MACSEC_RXSC_SCI_1H, ctx->rx_sc->sci);
1145	nxp_c45_rx_sc_update(phydev, phy_secy);
1146
1147	return 0;
1148}
1149
1150static int nxp_c45_mdo_upd_rxsc(struct macsec_context *ctx)
1151{
1152	struct phy_device *phydev = ctx->phydev;
1153	struct nxp_c45_phy *priv = phydev->priv;
1154	struct nxp_c45_secy *phy_secy;
1155
1156	phydev_dbg(phydev, "update RX SC SCI %016llx %s\n",
1157		   sci_to_cpu(ctx->rx_sc->sci),
1158		   ctx->rx_sc->active ? "enabled" : "disabled");
1159
1160	phy_secy = nxp_c45_find_secy(&priv->macsec->secy_list, ctx->secy->sci);
1161	if (IS_ERR(phy_secy))
1162		return PTR_ERR(phy_secy);
1163
1164	nxp_c45_select_secy(phydev, phy_secy->secy_id);
1165	nxp_c45_rx_sc_update(phydev, phy_secy);
1166
1167	return 0;
1168}
1169
1170static int nxp_c45_mdo_del_rxsc(struct macsec_context *ctx)
1171{
1172	struct phy_device *phydev = ctx->phydev;
1173	struct nxp_c45_phy *priv = phydev->priv;
1174	struct nxp_c45_secy *phy_secy;
1175
1176	phydev_dbg(phydev, "delete RX SC SCI %016llx %s\n",
1177		   sci_to_cpu(ctx->rx_sc->sci),
1178		   ctx->rx_sc->active ? "enabled" : "disabled");
1179
1180	phy_secy = nxp_c45_find_secy(&priv->macsec->secy_list, ctx->secy->sci);
1181	if (IS_ERR(phy_secy))
1182		return PTR_ERR(phy_secy);
1183
1184	nxp_c45_select_secy(phydev, phy_secy->secy_id);
1185	nxp_c45_rx_sc_del(phydev, phy_secy);
1186	phy_secy->rx_sc = NULL;
1187
1188	return 0;
1189}
1190
1191static int nxp_c45_mdo_add_rxsa(struct macsec_context *ctx)
1192{
1193	struct macsec_rx_sa *rx_sa = ctx->sa.rx_sa;
1194	struct phy_device *phydev = ctx->phydev;
1195	struct nxp_c45_phy *priv = phydev->priv;
1196	struct nxp_c45_secy *phy_secy;
1197	u8 an = ctx->sa.assoc_num;
1198	struct nxp_c45_sa *sa;
1199
1200	phydev_dbg(phydev, "add RX SA %u %s to RX SC SCI %016llx\n",
1201		   an, rx_sa->active ? "enabled" : "disabled",
1202		   sci_to_cpu(rx_sa->sc->sci));
1203
1204	phy_secy = nxp_c45_find_secy(&priv->macsec->secy_list, ctx->secy->sci);
1205	if (IS_ERR(phy_secy))
1206		return PTR_ERR(phy_secy);
1207
1208	sa = nxp_c45_sa_alloc(&phy_secy->sa_list, rx_sa, RX_SA, an);
1209	if (IS_ERR(sa))
1210		return PTR_ERR(sa);
1211
1212	nxp_c45_select_secy(phydev, phy_secy->secy_id);
1213	nxp_c45_sa_set_pn(phydev, sa, rx_sa->next_pn,
1214			  ctx->secy->replay_window);
1215	nxp_c45_sa_set_key(ctx, sa->regs, rx_sa->key.salt.bytes, rx_sa->ssci);
1216	nxp_c45_rx_sa_update(phydev, sa, rx_sa->active);
1217
1218	return 0;
1219}
1220
1221static int nxp_c45_mdo_upd_rxsa(struct macsec_context *ctx)
1222{
1223	struct macsec_rx_sa *rx_sa = ctx->sa.rx_sa;
1224	struct phy_device *phydev = ctx->phydev;
1225	struct nxp_c45_phy *priv = phydev->priv;
1226	struct nxp_c45_secy *phy_secy;
1227	u8 an = ctx->sa.assoc_num;
1228	struct nxp_c45_sa *sa;
1229
1230	phydev_dbg(phydev, "update RX SA %u %s to RX SC SCI %016llx\n",
1231		   an, rx_sa->active ? "enabled" : "disabled",
1232		   sci_to_cpu(rx_sa->sc->sci));
1233
1234	phy_secy = nxp_c45_find_secy(&priv->macsec->secy_list, ctx->secy->sci);
1235	if (IS_ERR(phy_secy))
1236		return PTR_ERR(phy_secy);
1237
1238	sa = nxp_c45_find_sa(&phy_secy->sa_list, RX_SA, an);
1239	if (IS_ERR(sa))
1240		return PTR_ERR(sa);
1241
1242	nxp_c45_select_secy(phydev, phy_secy->secy_id);
1243	if (ctx->sa.update_pn)
1244		nxp_c45_sa_set_pn(phydev, sa, rx_sa->next_pn,
1245				  ctx->secy->replay_window);
1246	nxp_c45_rx_sa_update(phydev, sa, rx_sa->active);
1247
1248	return 0;
1249}
1250
1251static int nxp_c45_mdo_del_rxsa(struct macsec_context *ctx)
1252{
1253	struct macsec_rx_sa *rx_sa = ctx->sa.rx_sa;
1254	struct phy_device *phydev = ctx->phydev;
1255	struct nxp_c45_phy *priv = phydev->priv;
1256	struct nxp_c45_secy *phy_secy;
1257	u8 an = ctx->sa.assoc_num;
1258	struct nxp_c45_sa *sa;
1259
1260	phydev_dbg(phydev, "delete RX SA %u %s to RX SC SCI %016llx\n",
1261		   an, rx_sa->active ? "enabled" : "disabled",
1262		   sci_to_cpu(rx_sa->sc->sci));
1263
1264	phy_secy = nxp_c45_find_secy(&priv->macsec->secy_list, ctx->secy->sci);
1265	if (IS_ERR(phy_secy))
1266		return PTR_ERR(phy_secy);
1267
1268	sa = nxp_c45_find_sa(&phy_secy->sa_list, RX_SA, an);
1269	if (IS_ERR(sa))
1270		return PTR_ERR(sa);
1271
1272	nxp_c45_select_secy(phydev, phy_secy->secy_id);
1273	nxp_c45_rx_sa_update(phydev, sa, false);
1274	nxp_c45_rx_sa_clear_stats(phydev, sa);
1275
1276	nxp_c45_sa_free(sa);
1277
1278	return 0;
1279}
1280
1281static int nxp_c45_mdo_add_txsa(struct macsec_context *ctx)
1282{
1283	struct macsec_tx_sa *tx_sa = ctx->sa.tx_sa;
1284	struct phy_device *phydev = ctx->phydev;
1285	struct nxp_c45_phy *priv = phydev->priv;
1286	struct nxp_c45_secy *phy_secy;
1287	u8 an = ctx->sa.assoc_num;
1288	struct nxp_c45_sa *sa;
1289
1290	phydev_dbg(phydev, "add TX SA %u %s to TX SC %016llx\n",
1291		   an, ctx->sa.tx_sa->active ? "enabled" : "disabled",
1292		   sci_to_cpu(ctx->secy->sci));
1293
1294	phy_secy = nxp_c45_find_secy(&priv->macsec->secy_list, ctx->secy->sci);
1295	if (IS_ERR(phy_secy))
1296		return PTR_ERR(phy_secy);
1297
1298	sa = nxp_c45_sa_alloc(&phy_secy->sa_list, tx_sa, TX_SA, an);
1299	if (IS_ERR(sa))
1300		return PTR_ERR(sa);
1301
1302	nxp_c45_select_secy(phydev, phy_secy->secy_id);
1303	nxp_c45_sa_set_pn(phydev, sa, tx_sa->next_pn, 0);
1304	nxp_c45_sa_set_key(ctx, sa->regs, tx_sa->key.salt.bytes, tx_sa->ssci);
1305	if (ctx->secy->tx_sc.encoding_sa == sa->an)
1306		nxp_c45_tx_sa_update(phydev, sa, tx_sa->active);
1307
1308	return 0;
1309}
1310
1311static int nxp_c45_mdo_upd_txsa(struct macsec_context *ctx)
1312{
1313	struct macsec_tx_sa *tx_sa = ctx->sa.tx_sa;
1314	struct phy_device *phydev = ctx->phydev;
1315	struct nxp_c45_phy *priv = phydev->priv;
1316	struct nxp_c45_secy *phy_secy;
1317	u8 an = ctx->sa.assoc_num;
1318	struct nxp_c45_sa *sa;
1319
1320	phydev_dbg(phydev, "update TX SA %u %s to TX SC %016llx\n",
1321		   an, ctx->sa.tx_sa->active ? "enabled" : "disabled",
1322		   sci_to_cpu(ctx->secy->sci));
1323
1324	phy_secy = nxp_c45_find_secy(&priv->macsec->secy_list, ctx->secy->sci);
1325	if (IS_ERR(phy_secy))
1326		return PTR_ERR(phy_secy);
1327
1328	sa = nxp_c45_find_sa(&phy_secy->sa_list, TX_SA, an);
1329	if (IS_ERR(sa))
1330		return PTR_ERR(sa);
1331
1332	nxp_c45_select_secy(phydev, phy_secy->secy_id);
1333	if (ctx->sa.update_pn)
1334		nxp_c45_sa_set_pn(phydev, sa, tx_sa->next_pn, 0);
1335	if (ctx->secy->tx_sc.encoding_sa == sa->an)
1336		nxp_c45_tx_sa_update(phydev, sa, tx_sa->active);
1337
1338	return 0;
1339}
1340
1341static int nxp_c45_mdo_del_txsa(struct macsec_context *ctx)
1342{
1343	struct phy_device *phydev = ctx->phydev;
1344	struct nxp_c45_phy *priv = phydev->priv;
1345	struct nxp_c45_secy *phy_secy;
1346	u8 an = ctx->sa.assoc_num;
1347	struct nxp_c45_sa *sa;
1348
1349	phydev_dbg(phydev, "delete TX SA %u %s to TX SC %016llx\n",
1350		   an, ctx->sa.tx_sa->active ? "enabled" : "disabled",
1351		   sci_to_cpu(ctx->secy->sci));
1352
1353	phy_secy = nxp_c45_find_secy(&priv->macsec->secy_list, ctx->secy->sci);
1354	if (IS_ERR(phy_secy))
1355		return PTR_ERR(phy_secy);
1356
1357	sa = nxp_c45_find_sa(&phy_secy->sa_list, TX_SA, an);
1358	if (IS_ERR(sa))
1359		return PTR_ERR(sa);
1360
1361	nxp_c45_select_secy(phydev, phy_secy->secy_id);
1362	if (ctx->secy->tx_sc.encoding_sa == sa->an)
1363		nxp_c45_tx_sa_update(phydev, sa, false);
1364	nxp_c45_tx_sa_clear_stats(phydev, sa);
1365
1366	nxp_c45_sa_free(sa);
1367
1368	return 0;
1369}
1370
1371static int nxp_c45_mdo_get_dev_stats(struct macsec_context *ctx)
1372{
1373	struct phy_device *phydev = ctx->phydev;
1374	struct nxp_c45_phy *priv = phydev->priv;
1375	struct macsec_dev_stats  *dev_stats;
1376	struct nxp_c45_secy *phy_secy;
1377
1378	phy_secy = nxp_c45_find_secy(&priv->macsec->secy_list, ctx->secy->sci);
1379	if (IS_ERR(phy_secy))
1380		return PTR_ERR(phy_secy);
1381
1382	dev_stats = ctx->stats.dev_stats;
1383	nxp_c45_select_secy(phydev, phy_secy->secy_id);
1384
1385	nxp_c45_macsec_read32_64(phydev, MACSEC_OPUS,
1386				 &dev_stats->OutPktsUntagged);
1387	nxp_c45_macsec_read32_64(phydev, MACSEC_OPTLS,
1388				 &dev_stats->OutPktsTooLong);
1389	nxp_c45_macsec_read32_64(phydev, MACSEC_INPBTS,
1390				 &dev_stats->InPktsBadTag);
1391
1392	if (phy_secy->secy->validate_frames == MACSEC_VALIDATE_STRICT)
1393		nxp_c45_macsec_read32_64(phydev, MACSEC_INPWTS,
1394					 &dev_stats->InPktsNoTag);
1395	else
1396		nxp_c45_macsec_read32_64(phydev, MACSEC_INPWTS,
1397					 &dev_stats->InPktsUntagged);
1398
1399	if (phy_secy->secy->validate_frames == MACSEC_VALIDATE_STRICT)
1400		nxp_c45_macsec_read32_64(phydev, MACSEC_IPSNFS,
1401					 &dev_stats->InPktsNoSCI);
1402	else
1403		nxp_c45_macsec_read32_64(phydev, MACSEC_IPSNFS,
1404					 &dev_stats->InPktsUnknownSCI);
1405
1406	/* Always 0. */
1407	dev_stats->InPktsOverrun = 0;
1408
1409	return 0;
1410}
1411
1412static int nxp_c45_mdo_get_tx_sc_stats(struct macsec_context *ctx)
1413{
1414	struct phy_device *phydev = ctx->phydev;
1415	struct nxp_c45_phy *priv = phydev->priv;
1416	struct macsec_tx_sa_stats tx_sa_stats;
1417	struct macsec_tx_sc_stats *stats;
1418	struct nxp_c45_secy *phy_secy;
1419	struct nxp_c45_sa *pos, *tmp;
1420
1421	phy_secy = nxp_c45_find_secy(&priv->macsec->secy_list, ctx->secy->sci);
1422	if (IS_ERR(phy_secy))
1423		return PTR_ERR(phy_secy);
1424
1425	stats = ctx->stats.tx_sc_stats;
1426	nxp_c45_select_secy(phydev, phy_secy->secy_id);
1427
1428	nxp_c45_macsec_read64(phydev, MACSEC_OOE1HS,
1429			      &stats->OutOctetsEncrypted);
1430	nxp_c45_macsec_read64(phydev, MACSEC_OOP1HS,
1431			      &stats->OutOctetsProtected);
1432	list_for_each_entry_safe(pos, tmp, &phy_secy->sa_list, list) {
1433		if (pos->type != TX_SA)
1434			continue;
1435
1436		memset(&tx_sa_stats, 0, sizeof(tx_sa_stats));
1437		nxp_c45_tx_sa_read_stats(phydev, pos, &tx_sa_stats);
1438
1439		stats->OutPktsEncrypted += tx_sa_stats.OutPktsEncrypted;
1440		stats->OutPktsProtected += tx_sa_stats.OutPktsProtected;
1441	}
1442
1443	return 0;
1444}
1445
1446static int nxp_c45_mdo_get_tx_sa_stats(struct macsec_context *ctx)
1447{
1448	struct phy_device *phydev = ctx->phydev;
1449	struct nxp_c45_phy *priv = phydev->priv;
1450	struct macsec_tx_sa_stats *stats;
1451	struct nxp_c45_secy *phy_secy;
1452	u8 an = ctx->sa.assoc_num;
1453	struct nxp_c45_sa *sa;
1454
1455	phy_secy = nxp_c45_find_secy(&priv->macsec->secy_list, ctx->secy->sci);
1456	if (IS_ERR(phy_secy))
1457		return PTR_ERR(phy_secy);
1458
1459	sa = nxp_c45_find_sa(&phy_secy->sa_list, TX_SA, an);
1460	if (IS_ERR(sa))
1461		return PTR_ERR(sa);
1462
1463	stats = ctx->stats.tx_sa_stats;
1464	nxp_c45_select_secy(phydev, phy_secy->secy_id);
1465	nxp_c45_tx_sa_read_stats(phydev, sa, stats);
1466
1467	return 0;
1468}
1469
1470static int nxp_c45_mdo_get_rx_sc_stats(struct macsec_context *ctx)
1471{
1472	struct phy_device *phydev = ctx->phydev;
1473	struct nxp_c45_phy *priv = phydev->priv;
1474	struct macsec_rx_sa_stats rx_sa_stats;
1475	struct macsec_rx_sc_stats *stats;
1476	struct nxp_c45_secy *phy_secy;
1477	struct nxp_c45_sa *pos, *tmp;
1478	u32 reg = 0;
1479	int i;
1480
1481	phy_secy = nxp_c45_find_secy(&priv->macsec->secy_list, ctx->secy->sci);
1482	if (IS_ERR(phy_secy))
1483		return PTR_ERR(phy_secy);
1484
1485	if (phy_secy->rx_sc != ctx->rx_sc)
1486		return -EINVAL;
1487
1488	stats = ctx->stats.rx_sc_stats;
1489	nxp_c45_select_secy(phydev, phy_secy->secy_id);
1490
1491	list_for_each_entry_safe(pos, tmp, &phy_secy->sa_list, list) {
1492		if (pos->type != RX_SA)
1493			continue;
1494
1495		memset(&rx_sa_stats, 0, sizeof(rx_sa_stats));
1496		nxp_c45_rx_sa_read_stats(phydev, pos, &rx_sa_stats);
1497
1498		stats->InPktsInvalid += rx_sa_stats.InPktsInvalid;
1499		stats->InPktsNotValid += rx_sa_stats.InPktsNotValid;
1500		stats->InPktsOK += rx_sa_stats.InPktsOK;
1501	}
1502
1503	for (i = 0; i < MACSEC_NUM_AN; i++) {
1504		nxp_c45_macsec_read(phydev, MACSEC_RXAN0INUSS + i * 4, &reg);
1505		stats->InPktsNotUsingSA += reg;
1506		nxp_c45_macsec_read(phydev, MACSEC_RXAN0IPUSS + i * 4, &reg);
1507		stats->InPktsUnusedSA += reg;
1508	}
1509
1510	nxp_c45_macsec_read64(phydev, MACSEC_INOD1HS,
1511			      &stats->InOctetsDecrypted);
1512	nxp_c45_macsec_read64(phydev, MACSEC_INOV1HS,
1513			      &stats->InOctetsValidated);
1514
1515	nxp_c45_macsec_read32_64(phydev, MACSEC_RXSCIPDS,
1516				 &stats->InPktsDelayed);
1517	nxp_c45_macsec_read32_64(phydev, MACSEC_RXSCIPLS,
1518				 &stats->InPktsLate);
1519	nxp_c45_macsec_read32_64(phydev, MACSEC_RXSCIPUS,
1520				 &stats->InPktsUnchecked);
1521
1522	return 0;
1523}
1524
1525static int nxp_c45_mdo_get_rx_sa_stats(struct macsec_context *ctx)
1526{
1527	struct phy_device *phydev = ctx->phydev;
1528	struct nxp_c45_phy *priv = phydev->priv;
1529	struct macsec_rx_sa_stats *stats;
1530	struct nxp_c45_secy *phy_secy;
1531	u8 an = ctx->sa.assoc_num;
1532	struct nxp_c45_sa *sa;
1533
1534	phy_secy = nxp_c45_find_secy(&priv->macsec->secy_list, ctx->secy->sci);
1535	if (IS_ERR(phy_secy))
1536		return PTR_ERR(phy_secy);
1537
1538	sa = nxp_c45_find_sa(&phy_secy->sa_list, RX_SA, an);
1539	if (IS_ERR(sa))
1540		return PTR_ERR(sa);
1541
1542	stats = ctx->stats.rx_sa_stats;
1543	nxp_c45_select_secy(phydev, phy_secy->secy_id);
1544
1545	nxp_c45_rx_sa_read_stats(phydev, sa, stats);
1546	nxp_c45_macsec_read(phydev, MACSEC_RXAN0INUSS + an * 4,
1547			    &stats->InPktsNotUsingSA);
1548	nxp_c45_macsec_read(phydev, MACSEC_RXAN0IPUSS + an * 4,
1549			    &stats->InPktsUnusedSA);
1550
1551	return 0;
1552}
1553
1554struct tja11xx_tlv_header {
1555	struct ethhdr eth;
1556	u8 subtype;
1557	u8 len;
1558	u8 payload[28];
1559};
1560
1561static int nxp_c45_mdo_insert_tx_tag(struct phy_device *phydev,
1562				     struct sk_buff *skb)
1563{
1564	struct tja11xx_tlv_header *tlv;
1565	struct ethhdr *eth;
1566
1567	eth = eth_hdr(skb);
1568	tlv = skb_push(skb, TJA11XX_TLV_TX_NEEDED_HEADROOM);
1569	memmove(tlv, eth, sizeof(*eth));
1570	skb_reset_mac_header(skb);
1571	tlv->eth.h_proto = htons(ETH_P_TJA11XX_TLV);
1572	tlv->subtype = 1;
1573	tlv->len = sizeof(tlv->payload);
1574	memset(tlv->payload, 0, sizeof(tlv->payload));
1575
1576	return 0;
1577}
1578
1579static const struct macsec_ops nxp_c45_macsec_ops = {
1580	.mdo_dev_open = nxp_c45_mdo_dev_open,
1581	.mdo_dev_stop = nxp_c45_mdo_dev_stop,
1582	.mdo_add_secy = nxp_c45_mdo_add_secy,
1583	.mdo_upd_secy = nxp_c45_mdo_upd_secy,
1584	.mdo_del_secy = nxp_c45_mdo_del_secy,
1585	.mdo_add_rxsc = nxp_c45_mdo_add_rxsc,
1586	.mdo_upd_rxsc = nxp_c45_mdo_upd_rxsc,
1587	.mdo_del_rxsc = nxp_c45_mdo_del_rxsc,
1588	.mdo_add_rxsa = nxp_c45_mdo_add_rxsa,
1589	.mdo_upd_rxsa = nxp_c45_mdo_upd_rxsa,
1590	.mdo_del_rxsa = nxp_c45_mdo_del_rxsa,
1591	.mdo_add_txsa = nxp_c45_mdo_add_txsa,
1592	.mdo_upd_txsa = nxp_c45_mdo_upd_txsa,
1593	.mdo_del_txsa = nxp_c45_mdo_del_txsa,
1594	.mdo_get_dev_stats = nxp_c45_mdo_get_dev_stats,
1595	.mdo_get_tx_sc_stats = nxp_c45_mdo_get_tx_sc_stats,
1596	.mdo_get_tx_sa_stats = nxp_c45_mdo_get_tx_sa_stats,
1597	.mdo_get_rx_sc_stats = nxp_c45_mdo_get_rx_sc_stats,
1598	.mdo_get_rx_sa_stats = nxp_c45_mdo_get_rx_sa_stats,
1599	.mdo_insert_tx_tag = nxp_c45_mdo_insert_tx_tag,
1600	.needed_headroom = TJA11XX_TLV_TX_NEEDED_HEADROOM,
1601	.needed_tailroom = TJA11XX_TLV_NEEDED_TAILROOM,
1602};
1603
1604int nxp_c45_macsec_config_init(struct phy_device *phydev)
1605{
1606	struct nxp_c45_phy *priv = phydev->priv;
1607	int ret;
1608
1609	if (!priv->macsec)
1610		return 0;
1611
1612	ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_PORT_FUNC_ENABLES,
1613			       MACSEC_EN | ADAPTER_EN);
1614	if (ret)
1615		return ret;
1616
1617	ret = nxp_c45_macsec_write(phydev, ADPTR_CNTRL, ADPTR_CNTRL_CONFIG_EN |
1618				   ADPTR_CNTRL_ADPTR_EN);
1619	if (ret)
1620		return ret;
1621
1622	ret = nxp_c45_macsec_write(phydev, ADPTR_TX_TAG_CNTRL,
1623				   ADPTR_TX_TAG_CNTRL_ENA);
1624	if (ret)
1625		return ret;
1626
1627	ret = nxp_c45_macsec_write(phydev, ADPTR_CNTRL, ADPTR_CNTRL_ADPTR_EN);
1628	if (ret)
1629		return ret;
1630
1631	ret = nxp_c45_macsec_write(phydev, MACSEC_TPNET, PN_WRAP_THRESHOLD);
1632	if (ret)
1633		return ret;
1634
1635	/* Set MKA filter. */
1636	ret = nxp_c45_macsec_write(phydev, MACSEC_UPFR0D2, ETH_P_PAE);
1637	if (ret)
1638		return ret;
1639
1640	ret = nxp_c45_macsec_write(phydev, MACSEC_UPFR0M1, MACSEC_OVP);
1641	if (ret)
1642		return ret;
1643
1644	ret = nxp_c45_macsec_write(phydev, MACSEC_UPFR0M2, ETYPE_MASK);
1645	if (ret)
1646		return ret;
1647
1648	ret = nxp_c45_macsec_write(phydev, MACSEC_UPFR0R, MACSEC_UPFR_EN);
1649
1650	return ret;
1651}
1652
1653int nxp_c45_macsec_probe(struct phy_device *phydev)
1654{
1655	struct nxp_c45_phy *priv = phydev->priv;
1656	struct device *dev = &phydev->mdio.dev;
1657
1658	priv->macsec = devm_kzalloc(dev, sizeof(*priv->macsec), GFP_KERNEL);
1659	if (!priv->macsec)
1660		return -ENOMEM;
1661
1662	INIT_LIST_HEAD(&priv->macsec->secy_list);
1663	phydev->macsec_ops = &nxp_c45_macsec_ops;
1664
1665	return 0;
1666}
1667
1668void nxp_c45_macsec_remove(struct phy_device *phydev)
1669{
1670	struct nxp_c45_phy *priv = phydev->priv;
1671	struct nxp_c45_secy *secy_p, *secy_t;
1672	struct nxp_c45_sa *sa_p, *sa_t;
1673	struct list_head *secy_list;
1674
1675	if (!priv->macsec)
1676		return;
1677
1678	secy_list = &priv->macsec->secy_list;
1679	nxp_c45_macsec_en(phydev, false);
1680
1681	list_for_each_entry_safe(secy_p, secy_t, secy_list, list) {
1682		list_for_each_entry_safe(sa_p, sa_t, &secy_p->sa_list, list)
1683			nxp_c45_sa_free(sa_p);
1684		nxp_c45_secy_free(secy_p);
1685	}
1686}
1687
1688void nxp_c45_handle_macsec_interrupt(struct phy_device *phydev,
1689				     irqreturn_t *ret)
1690{
1691	struct nxp_c45_phy *priv = phydev->priv;
1692	struct nxp_c45_secy *secy;
1693	struct nxp_c45_sa *sa;
1694	u8 encoding_sa;
1695	int secy_id;
1696	u32 reg = 0;
1697
1698	if (!priv->macsec)
1699		return;
1700
1701	do {
1702		nxp_c45_macsec_read(phydev, MACSEC_EVR, &reg);
1703		if (!reg)
1704			return;
1705
1706		secy_id = MACSEC_REG_SIZE - ffs(reg);
1707		secy = nxp_c45_find_secy_by_id(&priv->macsec->secy_list,
1708					       secy_id);
1709		if (IS_ERR(secy)) {
1710			WARN_ON(1);
1711			goto macsec_ack_irq;
1712		}
1713
1714		encoding_sa = secy->secy->tx_sc.encoding_sa;
1715		phydev_dbg(phydev, "pn_wrapped: TX SC %d, encoding_sa %u\n",
1716			   secy->secy_id, encoding_sa);
1717
1718		sa = nxp_c45_find_sa(&secy->sa_list, TX_SA, encoding_sa);
1719		if (!IS_ERR(sa))
1720			macsec_pn_wrapped(secy->secy, sa->sa);
1721		else
1722			WARN_ON(1);
1723
1724macsec_ack_irq:
1725		nxp_c45_macsec_write(phydev, MACSEC_EVR,
1726				     TX_SC_BIT(secy_id));
1727		*ret = IRQ_HANDLED;
1728	} while (reg);
1729}
1730