brintos

brintos / linux-shallow public Read only

0
0
Text · 29.6 KiB · 4f39ba6 Raw
1012 lines · c
1// SPDX-License-Identifier: (GPL-2.0 OR MIT)2/*3 * Driver for Microsemi VSC85xx PHYs - MACsec support4 *5 * Author: Antoine Tenart6 * License: Dual MIT/GPL7 * Copyright (c) 2020 Microsemi Corporation8 */9 10#include <linux/phy.h>11#include <dt-bindings/net/mscc-phy-vsc8531.h>12 13#include <crypto/aes.h>14 15#include <net/macsec.h>16 17#include "mscc.h"18#include "mscc_mac.h"19#include "mscc_macsec.h"20#include "mscc_fc_buffer.h"21 22static u32 vsc8584_macsec_phy_read(struct phy_device *phydev,23				   enum macsec_bank bank, u32 reg)24{25	u32 val, val_l = 0, val_h = 0;26	unsigned long deadline;27	int rc;28 29	rc = phy_select_page(phydev, MSCC_PHY_PAGE_MACSEC);30	if (rc < 0)31		goto failed;32 33	__phy_write(phydev, MSCC_EXT_PAGE_MACSEC_20,34		    MSCC_PHY_MACSEC_20_TARGET(bank >> 2));35 36	if (bank >> 2 == 0x1)37		/* non-MACsec access */38		bank &= 0x3;39	else40		bank = 0;41 42	__phy_write(phydev, MSCC_EXT_PAGE_MACSEC_19,43		    MSCC_PHY_MACSEC_19_CMD | MSCC_PHY_MACSEC_19_READ |44		    MSCC_PHY_MACSEC_19_REG_ADDR(reg) |45		    MSCC_PHY_MACSEC_19_TARGET(bank));46 47	deadline = jiffies + msecs_to_jiffies(PROC_CMD_NCOMPLETED_TIMEOUT_MS);48	do {49		val = __phy_read(phydev, MSCC_EXT_PAGE_MACSEC_19);50	} while (time_before(jiffies, deadline) && !(val & MSCC_PHY_MACSEC_19_CMD));51 52	val_l = __phy_read(phydev, MSCC_EXT_PAGE_MACSEC_17);53	val_h = __phy_read(phydev, MSCC_EXT_PAGE_MACSEC_18);54 55failed:56	phy_restore_page(phydev, rc, rc);57 58	return (val_h << 16) | val_l;59}60 61static void vsc8584_macsec_phy_write(struct phy_device *phydev,62				     enum macsec_bank bank, u32 reg, u32 val)63{64	unsigned long deadline;65	int rc;66 67	rc = phy_select_page(phydev, MSCC_PHY_PAGE_MACSEC);68	if (rc < 0)69		goto failed;70 71	__phy_write(phydev, MSCC_EXT_PAGE_MACSEC_20,72		    MSCC_PHY_MACSEC_20_TARGET(bank >> 2));73 74	if ((bank >> 2 == 0x1) || (bank >> 2 == 0x3))75		bank &= 0x3;76	else77		/* MACsec access */78		bank = 0;79 80	__phy_write(phydev, MSCC_EXT_PAGE_MACSEC_17, (u16)val);81	__phy_write(phydev, MSCC_EXT_PAGE_MACSEC_18, (u16)(val >> 16));82 83	__phy_write(phydev, MSCC_EXT_PAGE_MACSEC_19,84		    MSCC_PHY_MACSEC_19_CMD | MSCC_PHY_MACSEC_19_REG_ADDR(reg) |85		    MSCC_PHY_MACSEC_19_TARGET(bank));86 87	deadline = jiffies + msecs_to_jiffies(PROC_CMD_NCOMPLETED_TIMEOUT_MS);88	do {89		val = __phy_read(phydev, MSCC_EXT_PAGE_MACSEC_19);90	} while (time_before(jiffies, deadline) && !(val & MSCC_PHY_MACSEC_19_CMD));91 92failed:93	phy_restore_page(phydev, rc, rc);94}95 96static void vsc8584_macsec_classification(struct phy_device *phydev,97					  enum macsec_bank bank)98{99	/* enable VLAN tag parsing */100	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_CP_TAG,101				 MSCC_MS_SAM_CP_TAG_PARSE_STAG |102				 MSCC_MS_SAM_CP_TAG_PARSE_QTAG |103				 MSCC_MS_SAM_CP_TAG_PARSE_QINQ);104}105 106static void vsc8584_macsec_flow_default_action(struct phy_device *phydev,107					       enum macsec_bank bank,108					       bool block)109{110	u32 port = (bank == MACSEC_INGR) ?111		    MSCC_MS_PORT_UNCONTROLLED : MSCC_MS_PORT_COMMON;112	u32 action = MSCC_MS_FLOW_BYPASS;113 114	if (block)115		action = MSCC_MS_FLOW_DROP;116 117	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_NM_FLOW_NCP,118				 /* MACsec untagged */119				 MSCC_MS_SAM_NM_FLOW_NCP_UNTAGGED_FLOW_TYPE(action) |120				 MSCC_MS_SAM_NM_FLOW_NCP_UNTAGGED_DROP_ACTION(MSCC_MS_ACTION_DROP) |121				 MSCC_MS_SAM_NM_FLOW_NCP_UNTAGGED_DEST_PORT(port) |122				 /* MACsec tagged */123				 MSCC_MS_SAM_NM_FLOW_NCP_TAGGED_FLOW_TYPE(action) |124				 MSCC_MS_SAM_NM_FLOW_NCP_TAGGED_DROP_ACTION(MSCC_MS_ACTION_DROP) |125				 MSCC_MS_SAM_NM_FLOW_NCP_TAGGED_DEST_PORT(port) |126				 /* Bad tag */127				 MSCC_MS_SAM_NM_FLOW_NCP_BADTAG_FLOW_TYPE(action) |128				 MSCC_MS_SAM_NM_FLOW_NCP_BADTAG_DROP_ACTION(MSCC_MS_ACTION_DROP) |129				 MSCC_MS_SAM_NM_FLOW_NCP_BADTAG_DEST_PORT(port) |130				 /* Kay tag */131				 MSCC_MS_SAM_NM_FLOW_NCP_KAY_FLOW_TYPE(action) |132				 MSCC_MS_SAM_NM_FLOW_NCP_KAY_DROP_ACTION(MSCC_MS_ACTION_DROP) |133				 MSCC_MS_SAM_NM_FLOW_NCP_KAY_DEST_PORT(port));134	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_NM_FLOW_CP,135				 /* MACsec untagged */136				 MSCC_MS_SAM_NM_FLOW_NCP_UNTAGGED_FLOW_TYPE(action) |137				 MSCC_MS_SAM_NM_FLOW_CP_UNTAGGED_DROP_ACTION(MSCC_MS_ACTION_DROP) |138				 MSCC_MS_SAM_NM_FLOW_CP_UNTAGGED_DEST_PORT(port) |139				 /* MACsec tagged */140				 MSCC_MS_SAM_NM_FLOW_NCP_TAGGED_FLOW_TYPE(action) |141				 MSCC_MS_SAM_NM_FLOW_CP_TAGGED_DROP_ACTION(MSCC_MS_ACTION_DROP) |142				 MSCC_MS_SAM_NM_FLOW_CP_TAGGED_DEST_PORT(port) |143				 /* Bad tag */144				 MSCC_MS_SAM_NM_FLOW_NCP_BADTAG_FLOW_TYPE(action) |145				 MSCC_MS_SAM_NM_FLOW_CP_BADTAG_DROP_ACTION(MSCC_MS_ACTION_DROP) |146				 MSCC_MS_SAM_NM_FLOW_CP_BADTAG_DEST_PORT(port) |147				 /* Kay tag */148				 MSCC_MS_SAM_NM_FLOW_NCP_KAY_FLOW_TYPE(action) |149				 MSCC_MS_SAM_NM_FLOW_CP_KAY_DROP_ACTION(MSCC_MS_ACTION_DROP) |150				 MSCC_MS_SAM_NM_FLOW_CP_KAY_DEST_PORT(port));151}152 153static void vsc8584_macsec_integrity_checks(struct phy_device *phydev,154					    enum macsec_bank bank)155{156	u32 val;157 158	if (bank != MACSEC_INGR)159		return;160 161	/* Set default rules to pass unmatched frames */162	val = vsc8584_macsec_phy_read(phydev, bank,163				      MSCC_MS_PARAMS2_IG_CC_CONTROL);164	val |= MSCC_MS_PARAMS2_IG_CC_CONTROL_NON_MATCH_CTRL_ACT |165	       MSCC_MS_PARAMS2_IG_CC_CONTROL_NON_MATCH_ACT;166	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_PARAMS2_IG_CC_CONTROL,167				 val);168 169	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_PARAMS2_IG_CP_TAG,170				 MSCC_MS_PARAMS2_IG_CP_TAG_PARSE_STAG |171				 MSCC_MS_PARAMS2_IG_CP_TAG_PARSE_QTAG |172				 MSCC_MS_PARAMS2_IG_CP_TAG_PARSE_QINQ);173}174 175static void vsc8584_macsec_block_init(struct phy_device *phydev,176				      enum macsec_bank bank)177{178	u32 val;179	int i;180 181	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_ENA_CFG,182				 MSCC_MS_ENA_CFG_SW_RST |183				 MSCC_MS_ENA_CFG_MACSEC_BYPASS_ENA);184 185	/* Set the MACsec block out of s/w reset and enable clocks */186	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_ENA_CFG,187				 MSCC_MS_ENA_CFG_CLK_ENA);188 189	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_STATUS_CONTEXT_CTRL,190				 bank == MACSEC_INGR ? 0xe5880214 : 0xe5880218);191	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_MISC_CONTROL,192				 MSCC_MS_MISC_CONTROL_MC_LATENCY_FIX(bank == MACSEC_INGR ? 57 : 40) |193				 MSCC_MS_MISC_CONTROL_XFORM_REC_SIZE(bank == MACSEC_INGR ? 1 : 2));194 195	/* Clear the counters */196	val = vsc8584_macsec_phy_read(phydev, bank, MSCC_MS_COUNT_CONTROL);197	val |= MSCC_MS_COUNT_CONTROL_AUTO_CNTR_RESET;198	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_COUNT_CONTROL, val);199 200	/* Enable octet increment mode */201	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_PP_CTRL,202				 MSCC_MS_PP_CTRL_MACSEC_OCTET_INCR_MODE);203 204	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_BLOCK_CTX_UPDATE, 0x3);205 206	val = vsc8584_macsec_phy_read(phydev, bank, MSCC_MS_COUNT_CONTROL);207	val |= MSCC_MS_COUNT_CONTROL_RESET_ALL;208	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_COUNT_CONTROL, val);209 210	/* Set the MTU */211	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_NON_VLAN_MTU_CHECK,212				 MSCC_MS_NON_VLAN_MTU_CHECK_NV_MTU_COMPARE(32761) |213				 MSCC_MS_NON_VLAN_MTU_CHECK_NV_MTU_COMP_DROP);214 215	for (i = 0; i < 8; i++)216		vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_VLAN_MTU_CHECK(i),217					 MSCC_MS_VLAN_MTU_CHECK_MTU_COMPARE(32761) |218					 MSCC_MS_VLAN_MTU_CHECK_MTU_COMP_DROP);219 220	if (bank == MACSEC_EGR) {221		val = vsc8584_macsec_phy_read(phydev, bank, MSCC_MS_INTR_CTRL_STATUS);222		val &= ~MSCC_MS_INTR_CTRL_STATUS_INTR_ENABLE_M;223		vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_INTR_CTRL_STATUS, val);224 225		vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_FC_CFG,226					 MSCC_MS_FC_CFG_FCBUF_ENA |227					 MSCC_MS_FC_CFG_LOW_THRESH(0x1) |228					 MSCC_MS_FC_CFG_HIGH_THRESH(0x4) |229					 MSCC_MS_FC_CFG_LOW_BYTES_VAL(0x4) |230					 MSCC_MS_FC_CFG_HIGH_BYTES_VAL(0x6));231	}232 233	vsc8584_macsec_classification(phydev, bank);234	vsc8584_macsec_flow_default_action(phydev, bank, false);235	vsc8584_macsec_integrity_checks(phydev, bank);236 237	/* Enable the MACsec block */238	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_ENA_CFG,239				 MSCC_MS_ENA_CFG_CLK_ENA |240				 MSCC_MS_ENA_CFG_MACSEC_ENA |241				 MSCC_MS_ENA_CFG_MACSEC_SPEED_MODE(0x5));242}243 244static void vsc8584_macsec_mac_init(struct phy_device *phydev,245				    enum macsec_bank bank)246{247	u32 val;248	int i;249 250	/* Clear host & line stats */251	for (i = 0; i < 36; i++)252		vsc8584_macsec_phy_write(phydev, bank, 0x1c + i, 0);253 254	val = vsc8584_macsec_phy_read(phydev, bank,255				      MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL);256	val &= ~MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL_PAUSE_MODE_M;257	val |= MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL_PAUSE_MODE(2) |258	       MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL_PAUSE_VALUE(0xffff);259	vsc8584_macsec_phy_write(phydev, bank,260				 MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL, val);261 262	val = vsc8584_macsec_phy_read(phydev, bank,263				      MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL_2);264	val |= 0xffff;265	vsc8584_macsec_phy_write(phydev, bank,266				 MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL_2, val);267 268	val = vsc8584_macsec_phy_read(phydev, bank,269				      MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL);270	if (bank == HOST_MAC)271		val |= MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL_PAUSE_TIMER_ENA |272		       MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL_PAUSE_FRAME_DROP_ENA;273	else274		val |= MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL_PAUSE_REACT_ENA |275		       MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL_PAUSE_FRAME_DROP_ENA |276		       MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL_PAUSE_MODE |277		       MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL_EARLY_PAUSE_DETECT_ENA;278	vsc8584_macsec_phy_write(phydev, bank,279				 MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL, val);280 281	vsc8584_macsec_phy_write(phydev, bank, MSCC_MAC_CFG_PKTINF_CFG,282				 MSCC_MAC_CFG_PKTINF_CFG_STRIP_FCS_ENA |283				 MSCC_MAC_CFG_PKTINF_CFG_INSERT_FCS_ENA |284				 MSCC_MAC_CFG_PKTINF_CFG_LPI_RELAY_ENA |285				 MSCC_MAC_CFG_PKTINF_CFG_STRIP_PREAMBLE_ENA |286				 MSCC_MAC_CFG_PKTINF_CFG_INSERT_PREAMBLE_ENA |287				 (bank == HOST_MAC ?288				  MSCC_MAC_CFG_PKTINF_CFG_ENABLE_TX_PADDING : 0) |289				 (IS_ENABLED(CONFIG_NETWORK_PHY_TIMESTAMPING) ?290				  MSCC_MAC_CFG_PKTINF_CFG_MACSEC_BYPASS_NUM_PTP_STALL_CLKS(0x8) : 0));291 292	val = vsc8584_macsec_phy_read(phydev, bank, MSCC_MAC_CFG_MODE_CFG);293	val &= ~MSCC_MAC_CFG_MODE_CFG_DISABLE_DIC;294	vsc8584_macsec_phy_write(phydev, bank, MSCC_MAC_CFG_MODE_CFG, val);295 296	val = vsc8584_macsec_phy_read(phydev, bank, MSCC_MAC_CFG_MAXLEN_CFG);297	val &= ~MSCC_MAC_CFG_MAXLEN_CFG_MAX_LEN_M;298	val |= MSCC_MAC_CFG_MAXLEN_CFG_MAX_LEN(10240);299	vsc8584_macsec_phy_write(phydev, bank, MSCC_MAC_CFG_MAXLEN_CFG, val);300 301	vsc8584_macsec_phy_write(phydev, bank, MSCC_MAC_CFG_ADV_CHK_CFG,302				 MSCC_MAC_CFG_ADV_CHK_CFG_SFD_CHK_ENA |303				 MSCC_MAC_CFG_ADV_CHK_CFG_PRM_CHK_ENA |304				 MSCC_MAC_CFG_ADV_CHK_CFG_OOR_ERR_ENA |305				 MSCC_MAC_CFG_ADV_CHK_CFG_INR_ERR_ENA);306 307	val = vsc8584_macsec_phy_read(phydev, bank, MSCC_MAC_CFG_LFS_CFG);308	val &= ~MSCC_MAC_CFG_LFS_CFG_LFS_MODE_ENA;309	vsc8584_macsec_phy_write(phydev, bank, MSCC_MAC_CFG_LFS_CFG, val);310 311	vsc8584_macsec_phy_write(phydev, bank, MSCC_MAC_CFG_ENA_CFG,312				 MSCC_MAC_CFG_ENA_CFG_RX_CLK_ENA |313				 MSCC_MAC_CFG_ENA_CFG_TX_CLK_ENA |314				 MSCC_MAC_CFG_ENA_CFG_RX_ENA |315				 MSCC_MAC_CFG_ENA_CFG_TX_ENA);316}317 318/* Must be called with mdio_lock taken */319static int __vsc8584_macsec_init(struct phy_device *phydev)320{321	struct vsc8531_private *priv = phydev->priv;322	enum macsec_bank proc_bank;323	u32 val;324 325	vsc8584_macsec_block_init(phydev, MACSEC_INGR);326	vsc8584_macsec_block_init(phydev, MACSEC_EGR);327	vsc8584_macsec_mac_init(phydev, HOST_MAC);328	vsc8584_macsec_mac_init(phydev, LINE_MAC);329 330	vsc8584_macsec_phy_write(phydev, FC_BUFFER,331				 MSCC_FCBUF_FC_READ_THRESH_CFG,332				 MSCC_FCBUF_FC_READ_THRESH_CFG_TX_THRESH(4) |333				 MSCC_FCBUF_FC_READ_THRESH_CFG_RX_THRESH(5));334 335	val = vsc8584_macsec_phy_read(phydev, FC_BUFFER, MSCC_FCBUF_MODE_CFG);336	val |= MSCC_FCBUF_MODE_CFG_PAUSE_GEN_ENA |337	       MSCC_FCBUF_MODE_CFG_RX_PPM_RATE_ADAPT_ENA |338	       MSCC_FCBUF_MODE_CFG_TX_PPM_RATE_ADAPT_ENA;339	vsc8584_macsec_phy_write(phydev, FC_BUFFER, MSCC_FCBUF_MODE_CFG, val);340 341	vsc8584_macsec_phy_write(phydev, FC_BUFFER, MSCC_FCBUF_PPM_RATE_ADAPT_THRESH_CFG,342				 MSCC_FCBUF_PPM_RATE_ADAPT_THRESH_CFG_TX_THRESH(8) |343				 MSCC_FCBUF_PPM_RATE_ADAPT_THRESH_CFG_TX_OFFSET(9));344 345	val = vsc8584_macsec_phy_read(phydev, FC_BUFFER,346				      MSCC_FCBUF_TX_DATA_QUEUE_CFG);347	val &= ~(MSCC_FCBUF_TX_DATA_QUEUE_CFG_START_M |348		 MSCC_FCBUF_TX_DATA_QUEUE_CFG_END_M);349	val |= MSCC_FCBUF_TX_DATA_QUEUE_CFG_START(0) |350		MSCC_FCBUF_TX_DATA_QUEUE_CFG_END(5119);351	vsc8584_macsec_phy_write(phydev, FC_BUFFER,352				 MSCC_FCBUF_TX_DATA_QUEUE_CFG, val);353 354	val = vsc8584_macsec_phy_read(phydev, FC_BUFFER, MSCC_FCBUF_ENA_CFG);355	val |= MSCC_FCBUF_ENA_CFG_TX_ENA | MSCC_FCBUF_ENA_CFG_RX_ENA;356	vsc8584_macsec_phy_write(phydev, FC_BUFFER, MSCC_FCBUF_ENA_CFG, val);357 358	proc_bank = (priv->addr < 2) ? PROC_0 : PROC_2;359 360	val = vsc8584_macsec_phy_read(phydev, proc_bank,361				      MSCC_PROC_IP_1588_TOP_CFG_STAT_MODE_CTL);362	val &= ~MSCC_PROC_IP_1588_TOP_CFG_STAT_MODE_CTL_PROTOCOL_MODE_M;363	val |= MSCC_PROC_IP_1588_TOP_CFG_STAT_MODE_CTL_PROTOCOL_MODE(4);364	vsc8584_macsec_phy_write(phydev, proc_bank,365				 MSCC_PROC_IP_1588_TOP_CFG_STAT_MODE_CTL, val);366 367	return 0;368}369 370static void vsc8584_macsec_flow(struct phy_device *phydev,371				struct macsec_flow *flow)372{373	struct vsc8531_private *priv = phydev->priv;374	enum macsec_bank bank = flow->bank;375	u32 val, match = 0, mask = 0, action = 0, idx = flow->index;376 377	if (flow->match.tagged)378		match |= MSCC_MS_SAM_MISC_MATCH_TAGGED;379	if (flow->match.untagged)380		match |= MSCC_MS_SAM_MISC_MATCH_UNTAGGED;381 382	if (bank == MACSEC_INGR && flow->assoc_num >= 0) {383		match |= MSCC_MS_SAM_MISC_MATCH_AN(flow->assoc_num);384		mask |= MSCC_MS_SAM_MASK_AN_MASK(0x3);385	}386 387	if (bank == MACSEC_INGR && flow->match.sci && flow->rx_sa->sc->sci) {388		u64 sci = (__force u64)flow->rx_sa->sc->sci;389 390		match |= MSCC_MS_SAM_MISC_MATCH_TCI(BIT(3));391		mask |= MSCC_MS_SAM_MASK_TCI_MASK(BIT(3)) |392			MSCC_MS_SAM_MASK_SCI_MASK;393 394		vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_MATCH_SCI_LO(idx),395					 lower_32_bits(sci));396		vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_MATCH_SCI_HI(idx),397					 upper_32_bits(sci));398	}399 400	if (flow->match.etype) {401		mask |= MSCC_MS_SAM_MASK_MAC_ETYPE_MASK;402 403		vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_MAC_SA_MATCH_HI(idx),404					 MSCC_MS_SAM_MAC_SA_MATCH_HI_ETYPE((__force u32)htons(flow->etype)));405	}406 407	match |= MSCC_MS_SAM_MISC_MATCH_PRIORITY(flow->priority);408 409	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_MISC_MATCH(idx), match);410	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_MASK(idx), mask);411 412	/* Action for matching packets */413	if (flow->action.drop)414		action = MSCC_MS_FLOW_DROP;415	else if (flow->action.bypass || flow->port == MSCC_MS_PORT_UNCONTROLLED)416		action = MSCC_MS_FLOW_BYPASS;417	else418		action = (bank == MACSEC_INGR) ?419			 MSCC_MS_FLOW_INGRESS : MSCC_MS_FLOW_EGRESS;420 421	val = MSCC_MS_SAM_FLOW_CTRL_FLOW_TYPE(action) |422	      MSCC_MS_SAM_FLOW_CTRL_DROP_ACTION(MSCC_MS_ACTION_DROP) |423	      MSCC_MS_SAM_FLOW_CTRL_DEST_PORT(flow->port);424 425	if (action == MSCC_MS_FLOW_BYPASS)426		goto write_ctrl;427 428	if (bank == MACSEC_INGR) {429		if (priv->secy->replay_protect)430			val |= MSCC_MS_SAM_FLOW_CTRL_REPLAY_PROTECT;431		if (priv->secy->validate_frames == MACSEC_VALIDATE_STRICT)432			val |= MSCC_MS_SAM_FLOW_CTRL_VALIDATE_FRAMES(MSCC_MS_VALIDATE_STRICT);433		else if (priv->secy->validate_frames == MACSEC_VALIDATE_CHECK)434			val |= MSCC_MS_SAM_FLOW_CTRL_VALIDATE_FRAMES(MSCC_MS_VALIDATE_CHECK);435	} else if (bank == MACSEC_EGR) {436		if (priv->secy->protect_frames)437			val |= MSCC_MS_SAM_FLOW_CTRL_PROTECT_FRAME;438		if (priv->secy->tx_sc.encrypt)439			val |= MSCC_MS_SAM_FLOW_CTRL_CONF_PROTECT;440		if (priv->secy->tx_sc.send_sci)441			val |= MSCC_MS_SAM_FLOW_CTRL_INCLUDE_SCI;442	}443 444write_ctrl:445	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_FLOW_CTRL(idx), val);446}447 448static struct macsec_flow *vsc8584_macsec_find_flow(struct macsec_context *ctx,449						    enum macsec_bank bank)450{451	struct vsc8531_private *priv = ctx->phydev->priv;452	struct macsec_flow *pos, *tmp;453 454	list_for_each_entry_safe(pos, tmp, &priv->macsec_flows, list)455		if (pos->assoc_num == ctx->sa.assoc_num && pos->bank == bank)456			return pos;457 458	return ERR_PTR(-ENOENT);459}460 461static void vsc8584_macsec_flow_enable(struct phy_device *phydev,462				       struct macsec_flow *flow)463{464	enum macsec_bank bank = flow->bank;465	u32 val, idx = flow->index;466 467	if ((flow->bank == MACSEC_INGR && flow->rx_sa && !flow->rx_sa->active) ||468	    (flow->bank == MACSEC_EGR && flow->tx_sa && !flow->tx_sa->active))469		return;470 471	/* Enable */472	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_ENTRY_SET1, BIT(idx));473 474	/* Set in-use */475	val = vsc8584_macsec_phy_read(phydev, bank, MSCC_MS_SAM_FLOW_CTRL(idx));476	val |= MSCC_MS_SAM_FLOW_CTRL_SA_IN_USE;477	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_FLOW_CTRL(idx), val);478}479 480static void vsc8584_macsec_flow_disable(struct phy_device *phydev,481					struct macsec_flow *flow)482{483	enum macsec_bank bank = flow->bank;484	u32 val, idx = flow->index;485 486	/* Disable */487	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_ENTRY_CLEAR1, BIT(idx));488 489	/* Clear in-use */490	val = vsc8584_macsec_phy_read(phydev, bank, MSCC_MS_SAM_FLOW_CTRL(idx));491	val &= ~MSCC_MS_SAM_FLOW_CTRL_SA_IN_USE;492	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_FLOW_CTRL(idx), val);493}494 495static u32 vsc8584_macsec_flow_context_id(struct macsec_flow *flow)496{497	if (flow->bank == MACSEC_INGR)498		return flow->index + MSCC_MS_MAX_FLOWS;499 500	return flow->index;501}502 503/* Derive the AES key to get a key for the hash autentication */504static int vsc8584_macsec_derive_key(const u8 *key, u16 key_len, u8 hkey[16])505{506	const u8 input[AES_BLOCK_SIZE] = {0};507	struct crypto_aes_ctx ctx;508	int ret;509 510	ret = aes_expandkey(&ctx, key, key_len);511	if (ret)512		return ret;513 514	aes_encrypt(&ctx, hkey, input);515	memzero_explicit(&ctx, sizeof(ctx));516	return 0;517}518 519static int vsc8584_macsec_transformation(struct phy_device *phydev,520					 struct macsec_flow *flow,521					 const u8 *key)522{523	struct vsc8531_private *priv = phydev->priv;524	enum macsec_bank bank = flow->bank;525	int i, ret, index = flow->index;526	u32 rec = 0, control = 0;527	u8 hkey[16];528	u64 sci;529 530	ret = vsc8584_macsec_derive_key(key, priv->secy->key_len, hkey);531	if (ret)532		return ret;533 534	switch (priv->secy->key_len) {535	case 16:536		control |= CONTROL_CRYPTO_ALG(CTRYPTO_ALG_AES_CTR_128);537		break;538	case 32:539		control |= CONTROL_CRYPTO_ALG(CTRYPTO_ALG_AES_CTR_256);540		break;541	default:542		return -EINVAL;543	}544 545	control |= (bank == MACSEC_EGR) ?546		   (CONTROL_TYPE_EGRESS | CONTROL_AN(priv->secy->tx_sc.encoding_sa)) :547		   (CONTROL_TYPE_INGRESS | CONTROL_SEQ_MASK);548 549	control |= CONTROL_UPDATE_SEQ | CONTROL_ENCRYPT_AUTH | CONTROL_KEY_IN_CTX |550		   CONTROL_IV0 | CONTROL_IV1 | CONTROL_IV_IN_SEQ |551		   CONTROL_DIGEST_TYPE(0x2) | CONTROL_SEQ_TYPE(0x1) |552		   CONTROL_AUTH_ALG(AUTH_ALG_AES_GHAS) | CONTROL_CONTEXT_ID;553 554	/* Set the control word */555	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_XFORM_REC(index, rec++),556				 control);557 558	/* Set the context ID. Must be unique. */559	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_XFORM_REC(index, rec++),560				 vsc8584_macsec_flow_context_id(flow));561 562	/* Set the encryption/decryption key */563	for (i = 0; i < priv->secy->key_len / sizeof(u32); i++)564		vsc8584_macsec_phy_write(phydev, bank,565					 MSCC_MS_XFORM_REC(index, rec++),566					 ((u32 *)key)[i]);567 568	/* Set the authentication key */569	for (i = 0; i < 4; i++)570		vsc8584_macsec_phy_write(phydev, bank,571					 MSCC_MS_XFORM_REC(index, rec++),572					 ((u32 *)hkey)[i]);573 574	/* Initial sequence number */575	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_XFORM_REC(index, rec++),576				 bank == MACSEC_INGR ?577				 flow->rx_sa->next_pn : flow->tx_sa->next_pn);578 579	if (bank == MACSEC_INGR)580		/* Set the mask (replay window size) */581		vsc8584_macsec_phy_write(phydev, bank,582					 MSCC_MS_XFORM_REC(index, rec++),583					 priv->secy->replay_window);584 585	/* Set the input vectors */586	sci = (__force u64)(bank == MACSEC_INGR ? flow->rx_sa->sc->sci : priv->secy->sci);587	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_XFORM_REC(index, rec++),588				 lower_32_bits(sci));589	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_XFORM_REC(index, rec++),590				 upper_32_bits(sci));591 592	while (rec < 20)593		vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_XFORM_REC(index, rec++),594					 0);595 596	flow->has_transformation = true;597	return 0;598}599 600static struct macsec_flow *vsc8584_macsec_alloc_flow(struct vsc8531_private *priv,601						     enum macsec_bank bank)602{603	unsigned long *bitmap = bank == MACSEC_INGR ?604				&priv->ingr_flows : &priv->egr_flows;605	struct macsec_flow *flow;606	int index;607 608	index = find_first_zero_bit(bitmap, MSCC_MS_MAX_FLOWS);609 610	if (index == MSCC_MS_MAX_FLOWS)611		return ERR_PTR(-ENOMEM);612 613	flow = kzalloc(sizeof(*flow), GFP_KERNEL);614	if (!flow)615		return ERR_PTR(-ENOMEM);616 617	set_bit(index, bitmap);618	flow->index = index;619	flow->bank = bank;620	flow->priority = 8;621	flow->assoc_num = -1;622 623	list_add_tail(&flow->list, &priv->macsec_flows);624	return flow;625}626 627static void vsc8584_macsec_free_flow(struct vsc8531_private *priv,628				     struct macsec_flow *flow)629{630	unsigned long *bitmap = flow->bank == MACSEC_INGR ?631				&priv->ingr_flows : &priv->egr_flows;632 633	list_del(&flow->list);634	clear_bit(flow->index, bitmap);635	kfree(flow);636}637 638static void vsc8584_macsec_add_flow(struct phy_device *phydev,639				    struct macsec_flow *flow)640{641	flow->port = MSCC_MS_PORT_CONTROLLED;642	vsc8584_macsec_flow(phydev, flow);643}644 645static int vsc8584_macsec_default_flows(struct phy_device *phydev)646{647	struct macsec_flow *flow;648 649	/* Add a rule to let the MKA traffic go through, ingress */650	flow = vsc8584_macsec_alloc_flow(phydev->priv, MACSEC_INGR);651	if (IS_ERR(flow))652		return PTR_ERR(flow);653 654	flow->priority = 15;655	flow->port = MSCC_MS_PORT_UNCONTROLLED;656	flow->match.tagged = 1;657	flow->match.untagged = 1;658	flow->match.etype = 1;659	flow->etype = ETH_P_PAE;660	flow->action.bypass = 1;661 662	vsc8584_macsec_flow(phydev, flow);663	vsc8584_macsec_flow_enable(phydev, flow);664 665	/* Add a rule to let the MKA traffic go through, egress */666	flow = vsc8584_macsec_alloc_flow(phydev->priv, MACSEC_EGR);667	if (IS_ERR(flow))668		return PTR_ERR(flow);669 670	flow->priority = 15;671	flow->port = MSCC_MS_PORT_COMMON;672	flow->match.untagged = 1;673	flow->match.etype = 1;674	flow->etype = ETH_P_PAE;675	flow->action.bypass = 1;676 677	vsc8584_macsec_flow(phydev, flow);678	vsc8584_macsec_flow_enable(phydev, flow);679 680	return 0;681}682 683static void vsc8584_macsec_del_flow(struct phy_device *phydev,684				    struct macsec_flow *flow)685{686	vsc8584_macsec_flow_disable(phydev, flow);687	vsc8584_macsec_free_flow(phydev->priv, flow);688}689 690static int __vsc8584_macsec_add_rxsa(struct macsec_context *ctx,691				     struct macsec_flow *flow, bool update)692{693	struct phy_device *phydev = ctx->phydev;694	struct vsc8531_private *priv = phydev->priv;695	int ret;696 697	flow->assoc_num = ctx->sa.assoc_num;698	flow->rx_sa = ctx->sa.rx_sa;699 700	/* Always match tagged packets on ingress */701	flow->match.tagged = 1;702	flow->match.sci = 1;703 704	if (priv->secy->validate_frames != MACSEC_VALIDATE_DISABLED)705		flow->match.untagged = 1;706 707	vsc8584_macsec_add_flow(phydev, flow);708 709	if (update)710		return 0;711 712	ret = vsc8584_macsec_transformation(phydev, flow, ctx->sa.key);713	if (ret)714		vsc8584_macsec_free_flow(phydev->priv, flow);715 716	return ret;717}718 719static int __vsc8584_macsec_add_txsa(struct macsec_context *ctx,720				     struct macsec_flow *flow, bool update)721{722	int ret;723 724	flow->assoc_num = ctx->sa.assoc_num;725	flow->tx_sa = ctx->sa.tx_sa;726 727	/* Always match untagged packets on egress */728	flow->match.untagged = 1;729 730	vsc8584_macsec_add_flow(ctx->phydev, flow);731 732	if (update)733		return 0;734 735	ret = vsc8584_macsec_transformation(ctx->phydev, flow, ctx->sa.key);736	if (ret)737		vsc8584_macsec_free_flow(ctx->phydev->priv, flow);738 739	return ret;740}741 742static int vsc8584_macsec_dev_open(struct macsec_context *ctx)743{744	struct vsc8531_private *priv = ctx->phydev->priv;745	struct macsec_flow *flow, *tmp;746 747	list_for_each_entry_safe(flow, tmp, &priv->macsec_flows, list)748		vsc8584_macsec_flow_enable(ctx->phydev, flow);749 750	return 0;751}752 753static int vsc8584_macsec_dev_stop(struct macsec_context *ctx)754{755	struct vsc8531_private *priv = ctx->phydev->priv;756	struct macsec_flow *flow, *tmp;757 758	list_for_each_entry_safe(flow, tmp, &priv->macsec_flows, list)759		vsc8584_macsec_flow_disable(ctx->phydev, flow);760 761	return 0;762}763 764static int vsc8584_macsec_add_secy(struct macsec_context *ctx)765{766	struct vsc8531_private *priv = ctx->phydev->priv;767	struct macsec_secy *secy = ctx->secy;768 769	if (priv->secy)770		return -EEXIST;771 772	priv->secy = secy;773 774	vsc8584_macsec_flow_default_action(ctx->phydev, MACSEC_EGR,775					   secy->validate_frames != MACSEC_VALIDATE_DISABLED);776	vsc8584_macsec_flow_default_action(ctx->phydev, MACSEC_INGR,777					   secy->validate_frames != MACSEC_VALIDATE_DISABLED);778 779	return vsc8584_macsec_default_flows(ctx->phydev);780}781 782static int vsc8584_macsec_del_secy(struct macsec_context *ctx)783{784	struct vsc8531_private *priv = ctx->phydev->priv;785	struct macsec_flow *flow, *tmp;786 787	list_for_each_entry_safe(flow, tmp, &priv->macsec_flows, list)788		vsc8584_macsec_del_flow(ctx->phydev, flow);789 790	vsc8584_macsec_flow_default_action(ctx->phydev, MACSEC_EGR, false);791	vsc8584_macsec_flow_default_action(ctx->phydev, MACSEC_INGR, false);792 793	priv->secy = NULL;794	return 0;795}796 797static int vsc8584_macsec_upd_secy(struct macsec_context *ctx)798{799	vsc8584_macsec_del_secy(ctx);800	return vsc8584_macsec_add_secy(ctx);801}802 803static int vsc8584_macsec_add_rxsc(struct macsec_context *ctx)804{805	/* Nothing to do */806	return 0;807}808 809static int vsc8584_macsec_upd_rxsc(struct macsec_context *ctx)810{811	return -EOPNOTSUPP;812}813 814static int vsc8584_macsec_del_rxsc(struct macsec_context *ctx)815{816	struct vsc8531_private *priv = ctx->phydev->priv;817	struct macsec_flow *flow, *tmp;818 819	list_for_each_entry_safe(flow, tmp, &priv->macsec_flows, list) {820		if (flow->bank == MACSEC_INGR && flow->rx_sa &&821		    flow->rx_sa->sc->sci == ctx->rx_sc->sci)822			vsc8584_macsec_del_flow(ctx->phydev, flow);823	}824 825	return 0;826}827 828static int vsc8584_macsec_add_rxsa(struct macsec_context *ctx)829{830	struct phy_device *phydev = ctx->phydev;831	struct vsc8531_private *priv = phydev->priv;832	struct macsec_flow *flow;833	int ret;834 835	flow = vsc8584_macsec_alloc_flow(priv, MACSEC_INGR);836	if (IS_ERR(flow))837		return PTR_ERR(flow);838 839	ret = __vsc8584_macsec_add_rxsa(ctx, flow, false);840	if (ret)841		return ret;842 843	vsc8584_macsec_flow_enable(phydev, flow);844	return 0;845}846 847static int vsc8584_macsec_upd_rxsa(struct macsec_context *ctx)848{849	struct macsec_flow *flow;850	int ret;851 852	if (ctx->sa.update_pn)853		return -EINVAL;854 855	flow = vsc8584_macsec_find_flow(ctx, MACSEC_INGR);856	if (IS_ERR(flow))857		return PTR_ERR(flow);858 859	/* Make sure the flow is disabled before updating it */860	vsc8584_macsec_flow_disable(ctx->phydev, flow);861 862	ret = __vsc8584_macsec_add_rxsa(ctx, flow, true);863	if (ret)864		return ret;865 866	vsc8584_macsec_flow_enable(ctx->phydev, flow);867	return 0;868}869 870static int vsc8584_macsec_del_rxsa(struct macsec_context *ctx)871{872	struct macsec_flow *flow;873 874	flow = vsc8584_macsec_find_flow(ctx, MACSEC_INGR);875	if (IS_ERR(flow))876		return PTR_ERR(flow);877 878	vsc8584_macsec_del_flow(ctx->phydev, flow);879	return 0;880}881 882static int vsc8584_macsec_add_txsa(struct macsec_context *ctx)883{884	struct phy_device *phydev = ctx->phydev;885	struct vsc8531_private *priv = phydev->priv;886	struct macsec_flow *flow;887	int ret;888 889	flow = vsc8584_macsec_alloc_flow(priv, MACSEC_EGR);890	if (IS_ERR(flow))891		return PTR_ERR(flow);892 893	ret = __vsc8584_macsec_add_txsa(ctx, flow, false);894	if (ret)895		return ret;896 897	vsc8584_macsec_flow_enable(phydev, flow);898	return 0;899}900 901static int vsc8584_macsec_upd_txsa(struct macsec_context *ctx)902{903	struct macsec_flow *flow;904	int ret;905 906	if (ctx->sa.update_pn)907		return -EINVAL;908 909	flow = vsc8584_macsec_find_flow(ctx, MACSEC_EGR);910	if (IS_ERR(flow))911		return PTR_ERR(flow);912 913	/* Make sure the flow is disabled before updating it */914	vsc8584_macsec_flow_disable(ctx->phydev, flow);915 916	ret = __vsc8584_macsec_add_txsa(ctx, flow, true);917	if (ret)918		return ret;919 920	vsc8584_macsec_flow_enable(ctx->phydev, flow);921	return 0;922}923 924static int vsc8584_macsec_del_txsa(struct macsec_context *ctx)925{926	struct macsec_flow *flow;927 928	flow = vsc8584_macsec_find_flow(ctx, MACSEC_EGR);929	if (IS_ERR(flow))930		return PTR_ERR(flow);931 932	vsc8584_macsec_del_flow(ctx->phydev, flow);933	return 0;934}935 936static const struct macsec_ops vsc8584_macsec_ops = {937	.mdo_dev_open = vsc8584_macsec_dev_open,938	.mdo_dev_stop = vsc8584_macsec_dev_stop,939	.mdo_add_secy = vsc8584_macsec_add_secy,940	.mdo_upd_secy = vsc8584_macsec_upd_secy,941	.mdo_del_secy = vsc8584_macsec_del_secy,942	.mdo_add_rxsc = vsc8584_macsec_add_rxsc,943	.mdo_upd_rxsc = vsc8584_macsec_upd_rxsc,944	.mdo_del_rxsc = vsc8584_macsec_del_rxsc,945	.mdo_add_rxsa = vsc8584_macsec_add_rxsa,946	.mdo_upd_rxsa = vsc8584_macsec_upd_rxsa,947	.mdo_del_rxsa = vsc8584_macsec_del_rxsa,948	.mdo_add_txsa = vsc8584_macsec_add_txsa,949	.mdo_upd_txsa = vsc8584_macsec_upd_txsa,950	.mdo_del_txsa = vsc8584_macsec_del_txsa,951};952 953int vsc8584_macsec_init(struct phy_device *phydev)954{955	struct vsc8531_private *vsc8531 = phydev->priv;956 957	switch (phydev->phy_id & phydev->drv->phy_id_mask) {958	case PHY_ID_VSC856X:959	case PHY_ID_VSC8582:960	case PHY_ID_VSC8584:961		INIT_LIST_HEAD(&vsc8531->macsec_flows);962		vsc8531->secy = NULL;963 964		phydev->macsec_ops = &vsc8584_macsec_ops;965 966		return __vsc8584_macsec_init(phydev);967	}968 969	return 0;970}971 972void vsc8584_handle_macsec_interrupt(struct phy_device *phydev)973{974	struct vsc8531_private *priv = phydev->priv;975	struct macsec_flow *flow, *tmp;976	u32 cause, rec;977 978	/* Check MACsec PN rollover */979	cause = vsc8584_macsec_phy_read(phydev, MACSEC_EGR,980					MSCC_MS_INTR_CTRL_STATUS);981	cause &= MSCC_MS_INTR_CTRL_STATUS_INTR_CLR_STATUS_M;982	if (!(cause & MACSEC_INTR_CTRL_STATUS_ROLLOVER))983		return;984 985	rec = 6 + priv->secy->key_len / sizeof(u32);986	list_for_each_entry_safe(flow, tmp, &priv->macsec_flows, list) {987		u32 val;988 989		if (flow->bank != MACSEC_EGR || !flow->has_transformation)990			continue;991 992		val = vsc8584_macsec_phy_read(phydev, MACSEC_EGR,993					      MSCC_MS_XFORM_REC(flow->index, rec));994		if (val == 0xffffffff) {995			vsc8584_macsec_flow_disable(phydev, flow);996			macsec_pn_wrapped(priv->secy, flow->tx_sa);997			return;998		}999	}1000}1001 1002void vsc8584_config_macsec_intr(struct phy_device *phydev)1003{1004	phy_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED_2);1005	phy_write(phydev, MSCC_PHY_EXTENDED_INT, MSCC_PHY_EXTENDED_INT_MS_EGR);1006	phy_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);1007 1008	vsc8584_macsec_phy_write(phydev, MACSEC_EGR, MSCC_MS_AIC_CTRL, 0xf);1009	vsc8584_macsec_phy_write(phydev, MACSEC_EGR, MSCC_MS_INTR_CTRL_STATUS,1010				 MSCC_MS_INTR_CTRL_STATUS_INTR_ENABLE(MACSEC_INTR_CTRL_STATUS_ROLLOVER));1011}1012