xref: /linux/drivers/net/phy/nxp-c45-tja11xx-macsec.c (revision e6a901a00822659181c93c86d8bbc2a17779fddc)
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 
177 enum nxp_c45_sa_type {
178 	TX_SA,
179 	RX_SA,
180 };
181 
182 struct 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 
191 struct 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 
200 struct 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 
206 struct 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 
222 static 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 
236 static 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 
250 static 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 
261 static 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 
272 static const
273 struct 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 
290 static 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 
312 static 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 
339 static 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 
348 static 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 
359 static 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 
372 static 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 
384 static struct
385 nxp_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 
397 static void nxp_c45_secy_free(struct nxp_c45_secy *phy_secy)
398 {
399 	list_del(&phy_secy->list);
400 	kfree(phy_secy);
401 }
402 
403 static 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 
415 static 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 
452 static void nxp_c45_sa_free(struct nxp_c45_sa *sa)
453 {
454 	list_del(&sa->list);
455 	kfree(sa);
456 }
457 
458 static 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 
466 static 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 
488 static 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 
520 static 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 
531 static 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 
540 static 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 
547 static 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 
555 static 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 
566 static 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 
589 static 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 
598 static bool nxp_c45_port_is_1(sci_t sci)
599 {
600 	u16 port = sci_to_cpu(sci);
601 
602 	return port == 1;
603 }
604 
605 static 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 
613 static 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 
643 static 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 
652 static 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 
669 static 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 
683 static 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 
702 static 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 
759 static 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 
776 static 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 
789 static 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 
800 static 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 
813 static 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 
860 static 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 
886 static 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 
905 static 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 
912 static 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 
924 static 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 
951 static 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 
977 static 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 
1030 static 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 
1044 static 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 
1084 static 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 
1120 static 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 
1150 static 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 
1170 static 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 
1191 static 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 
1221 static 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 
1251 static 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 
1281 static 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 
1311 static 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 
1341 static 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 
1371 static 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 
1412 static 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 
1446 static 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 
1470 static 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 
1525 static 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 
1554 struct tja11xx_tlv_header {
1555 	struct ethhdr eth;
1556 	u8 subtype;
1557 	u8 len;
1558 	u8 payload[28];
1559 };
1560 
1561 static 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 
1579 static 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 
1604 int 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 
1653 int 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 
1668 void 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 
1688 void 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 
1724 macsec_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