brintos

brintos / linux-shallow public Read only

0
0
Text · 44.6 KiB · 550ef08 Raw
1730 lines · c
1// SPDX-License-Identifier: GPL-2.02/* NXP C45 PTP PHY driver interface3 * Copyright 2023 NXP4 * 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			3220#define TX_SC_MAX			421 22#define TX_SC_BIT(secy_id)		BIT(MACSEC_REG_SIZE - (secy_id) - 1)23 24#define VEND1_MACSEC_BASE		0x900025 26#define MACSEC_CFG			0x000027#define MACSEC_CFG_BYPASS		BIT(1)28#define MACSEC_CFG_S0I			BIT(0)29 30#define MACSEC_TPNET			0x004431#define PN_WRAP_THRESHOLD		0xffffffff32 33#define MACSEC_RXSCA			0x008034#define MACSEC_RXSCKA			0x008435 36#define MACSEC_TXSCA			0x00C037#define MACSEC_TXSCKA			0x00C438 39#define MACSEC_RXSC_SCI_1H		0x010040 41#define MACSEC_RXSC_CFG			0x012842#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		848 49#define MACSEC_RPW			0x012C50 51#define MACSEC_RXSA_A_CS		0x018052#define MACSEC_RXSA_A_NPN		0x018453#define MACSEC_RXSA_A_XNPN		0x018854#define MACSEC_RXSA_A_LNPN		0x018C55#define MACSEC_RXSA_A_LXNPN		0x019056 57#define MACSEC_RXSA_B_CS		0x01C058#define MACSEC_RXSA_B_NPN		0x01C459#define MACSEC_RXSA_B_XNPN		0x01C860#define MACSEC_RXSA_B_LNPN		0x01CC61#define MACSEC_RXSA_B_LXNPN		0x01D062 63#define MACSEC_RXSA_CS_AN_OFF		164#define MACSEC_RXSA_CS_EN		BIT(0)65 66#define MACSEC_TXSC_SCI_1H		0x020067#define MACSEC_TXSC_CFG			0x022868#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		1872#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		0x028081#define MACSEC_TXSA_A_NPN		0x028482#define MACSEC_TXSA_A_XNPN		0x028883 84#define MACSEC_TXSA_B_CS		0x02C085#define MACSEC_TXSA_B_NPN		0x02C486#define MACSEC_TXSA_B_XNPN		0x02C887 88#define MACSEC_SA_CS_A			BIT(31)89 90#define MACSEC_EVR			0x040091#define MACSEC_EVER			0x040492 93#define MACSEC_RXSA_A_KA		0x070094#define MACSEC_RXSA_A_SSCI		0x072095#define MACSEC_RXSA_A_SALT		0x072496 97#define MACSEC_RXSA_B_KA		0x074098#define MACSEC_RXSA_B_SSCI		0x076099#define MACSEC_RXSA_B_SALT		0x0764100 101#define MACSEC_TXSA_A_KA		0x0780102#define MACSEC_TXSA_A_SSCI		0x07A0103#define MACSEC_TXSA_A_SALT		0x07A4104 105#define MACSEC_TXSA_B_KA		0x07C0106#define MACSEC_TXSA_B_SSCI		0x07E0107#define MACSEC_TXSA_B_SALT		0x07E4108 109#define MACSEC_UPFR0D2			0x0A08110#define MACSEC_UPFR0M1			0x0A10111#define MACSEC_OVP			BIT(12)112 113#define	MACSEC_UPFR0M2			0x0A14114#define ETYPE_MASK			0xffff115 116#define MACSEC_UPFR0R			0x0A18117#define MACSEC_UPFR_EN			BIT(0)118 119#define ADPTR_CNTRL			0x0F00120#define ADPTR_CNTRL_CONFIG_EN		BIT(14)121#define ADPTR_CNTRL_ADPTR_EN		BIT(12)122#define ADPTR_TX_TAG_CNTRL		0x0F0C123#define ADPTR_TX_TAG_CNTRL_ENA		BIT(31)124 125#define TX_SC_FLT_BASE			0x800126#define TX_SC_FLT_SIZE			0x10127#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		0x04131#define TX_SC_FLT_OFF_MAC_SA		0x08132#define TX_SC_FLT_OFF_MAC_CFG		0x0C133#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			0x0140144#define MACSEC_INOV2HS			0x0144145#define MACSEC_INOD1HS			0x0148146#define MACSEC_INOD2HS			0x014C147#define MACSEC_RXSCIPUS			0x0150148#define MACSEC_RXSCIPDS			0x0154149#define MACSEC_RXSCIPLS			0x0158150#define MACSEC_RXAN0INUSS		0x0160151#define MACSEC_RXAN0IPUSS		0x0170152#define MACSEC_RXSA_A_IPOS		0x0194153#define MACSEC_RXSA_A_IPIS		0x01B0154#define MACSEC_RXSA_A_IPNVS		0x01B4155#define MACSEC_RXSA_B_IPOS		0x01D4156#define MACSEC_RXSA_B_IPIS		0x01F0157#define MACSEC_RXSA_B_IPNVS		0x01F4158#define MACSEC_OPUS			0x021C159#define MACSEC_OPTLS			0x022C160#define MACSEC_OOP1HS			0x0240161#define MACSEC_OOP2HS			0x0244162#define MACSEC_OOE1HS			0x0248163#define MACSEC_OOE2HS			0x024C164#define MACSEC_TXSA_A_OPPS		0x028C165#define MACSEC_TXSA_A_OPES		0x0290166#define MACSEC_TXSA_B_OPPS		0x02CC167#define MACSEC_TXSA_B_OPES		0x02D0168#define MACSEC_INPWTS			0x0630169#define MACSEC_INPBTS			0x0638170#define MACSEC_IPSNFS			0x063C171 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 const273struct 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		else280			return &rx_sa_b_regs;281	else if (sa_type == TX_SA)282		if (key_a)283			return &tx_sa_a_regs;284		else285			return &tx_sa_b_regs;286	else287		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	else368		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 struct385nxp_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	else441		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	else482		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	else579		cfg |= MACSEC_TXSC_CFG_ASA;580 581	if (en)582		cfg |= MACSEC_TXSC_CFG_SCE;583	else584		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	else679		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	else713		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	else719		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	else726		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	else733		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	else740		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	else747		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	else754		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	else785		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	else809		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	else843		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	else849		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	else855		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	else920		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 no1007	 * 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 only1064	 * 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	else1396		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	else1403		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		else1722			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