Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
   1// SPDX-License-Identifier: (GPL-2.0 OR MIT)
   2/*
   3 * Driver for Microsemi VSC85xx PHYs - MACsec support
   4 *
   5 * Author: Antoine Tenart
   6 * License: Dual MIT/GPL
   7 * Copyright (c) 2020 Microsemi Corporation
   8 */
   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	else
  40		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	else
  77		/* 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	else
 274		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	else
 418		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}