162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0 OR MIT) 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Driver for Microsemi VSC85xx PHYs - MACsec support 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Author: Antoine Tenart 662306a36Sopenharmony_ci * License: Dual MIT/GPL 762306a36Sopenharmony_ci * Copyright (c) 2020 Microsemi Corporation 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/phy.h> 1162306a36Sopenharmony_ci#include <dt-bindings/net/mscc-phy-vsc8531.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <crypto/aes.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <net/macsec.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include "mscc.h" 1862306a36Sopenharmony_ci#include "mscc_mac.h" 1962306a36Sopenharmony_ci#include "mscc_macsec.h" 2062306a36Sopenharmony_ci#include "mscc_fc_buffer.h" 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistatic u32 vsc8584_macsec_phy_read(struct phy_device *phydev, 2362306a36Sopenharmony_ci enum macsec_bank bank, u32 reg) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci u32 val, val_l = 0, val_h = 0; 2662306a36Sopenharmony_ci unsigned long deadline; 2762306a36Sopenharmony_ci int rc; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci rc = phy_select_page(phydev, MSCC_PHY_PAGE_MACSEC); 3062306a36Sopenharmony_ci if (rc < 0) 3162306a36Sopenharmony_ci goto failed; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci __phy_write(phydev, MSCC_EXT_PAGE_MACSEC_20, 3462306a36Sopenharmony_ci MSCC_PHY_MACSEC_20_TARGET(bank >> 2)); 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci if (bank >> 2 == 0x1) 3762306a36Sopenharmony_ci /* non-MACsec access */ 3862306a36Sopenharmony_ci bank &= 0x3; 3962306a36Sopenharmony_ci else 4062306a36Sopenharmony_ci bank = 0; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci __phy_write(phydev, MSCC_EXT_PAGE_MACSEC_19, 4362306a36Sopenharmony_ci MSCC_PHY_MACSEC_19_CMD | MSCC_PHY_MACSEC_19_READ | 4462306a36Sopenharmony_ci MSCC_PHY_MACSEC_19_REG_ADDR(reg) | 4562306a36Sopenharmony_ci MSCC_PHY_MACSEC_19_TARGET(bank)); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci deadline = jiffies + msecs_to_jiffies(PROC_CMD_NCOMPLETED_TIMEOUT_MS); 4862306a36Sopenharmony_ci do { 4962306a36Sopenharmony_ci val = __phy_read(phydev, MSCC_EXT_PAGE_MACSEC_19); 5062306a36Sopenharmony_ci } while (time_before(jiffies, deadline) && !(val & MSCC_PHY_MACSEC_19_CMD)); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci val_l = __phy_read(phydev, MSCC_EXT_PAGE_MACSEC_17); 5362306a36Sopenharmony_ci val_h = __phy_read(phydev, MSCC_EXT_PAGE_MACSEC_18); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cifailed: 5662306a36Sopenharmony_ci phy_restore_page(phydev, rc, rc); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci return (val_h << 16) | val_l; 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic void vsc8584_macsec_phy_write(struct phy_device *phydev, 6262306a36Sopenharmony_ci enum macsec_bank bank, u32 reg, u32 val) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci unsigned long deadline; 6562306a36Sopenharmony_ci int rc; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci rc = phy_select_page(phydev, MSCC_PHY_PAGE_MACSEC); 6862306a36Sopenharmony_ci if (rc < 0) 6962306a36Sopenharmony_ci goto failed; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci __phy_write(phydev, MSCC_EXT_PAGE_MACSEC_20, 7262306a36Sopenharmony_ci MSCC_PHY_MACSEC_20_TARGET(bank >> 2)); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci if ((bank >> 2 == 0x1) || (bank >> 2 == 0x3)) 7562306a36Sopenharmony_ci bank &= 0x3; 7662306a36Sopenharmony_ci else 7762306a36Sopenharmony_ci /* MACsec access */ 7862306a36Sopenharmony_ci bank = 0; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci __phy_write(phydev, MSCC_EXT_PAGE_MACSEC_17, (u16)val); 8162306a36Sopenharmony_ci __phy_write(phydev, MSCC_EXT_PAGE_MACSEC_18, (u16)(val >> 16)); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci __phy_write(phydev, MSCC_EXT_PAGE_MACSEC_19, 8462306a36Sopenharmony_ci MSCC_PHY_MACSEC_19_CMD | MSCC_PHY_MACSEC_19_REG_ADDR(reg) | 8562306a36Sopenharmony_ci MSCC_PHY_MACSEC_19_TARGET(bank)); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci deadline = jiffies + msecs_to_jiffies(PROC_CMD_NCOMPLETED_TIMEOUT_MS); 8862306a36Sopenharmony_ci do { 8962306a36Sopenharmony_ci val = __phy_read(phydev, MSCC_EXT_PAGE_MACSEC_19); 9062306a36Sopenharmony_ci } while (time_before(jiffies, deadline) && !(val & MSCC_PHY_MACSEC_19_CMD)); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cifailed: 9362306a36Sopenharmony_ci phy_restore_page(phydev, rc, rc); 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cistatic void vsc8584_macsec_classification(struct phy_device *phydev, 9762306a36Sopenharmony_ci enum macsec_bank bank) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci /* enable VLAN tag parsing */ 10062306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_CP_TAG, 10162306a36Sopenharmony_ci MSCC_MS_SAM_CP_TAG_PARSE_STAG | 10262306a36Sopenharmony_ci MSCC_MS_SAM_CP_TAG_PARSE_QTAG | 10362306a36Sopenharmony_ci MSCC_MS_SAM_CP_TAG_PARSE_QINQ); 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic void vsc8584_macsec_flow_default_action(struct phy_device *phydev, 10762306a36Sopenharmony_ci enum macsec_bank bank, 10862306a36Sopenharmony_ci bool block) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci u32 port = (bank == MACSEC_INGR) ? 11162306a36Sopenharmony_ci MSCC_MS_PORT_UNCONTROLLED : MSCC_MS_PORT_COMMON; 11262306a36Sopenharmony_ci u32 action = MSCC_MS_FLOW_BYPASS; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci if (block) 11562306a36Sopenharmony_ci action = MSCC_MS_FLOW_DROP; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_NM_FLOW_NCP, 11862306a36Sopenharmony_ci /* MACsec untagged */ 11962306a36Sopenharmony_ci MSCC_MS_SAM_NM_FLOW_NCP_UNTAGGED_FLOW_TYPE(action) | 12062306a36Sopenharmony_ci MSCC_MS_SAM_NM_FLOW_NCP_UNTAGGED_DROP_ACTION(MSCC_MS_ACTION_DROP) | 12162306a36Sopenharmony_ci MSCC_MS_SAM_NM_FLOW_NCP_UNTAGGED_DEST_PORT(port) | 12262306a36Sopenharmony_ci /* MACsec tagged */ 12362306a36Sopenharmony_ci MSCC_MS_SAM_NM_FLOW_NCP_TAGGED_FLOW_TYPE(action) | 12462306a36Sopenharmony_ci MSCC_MS_SAM_NM_FLOW_NCP_TAGGED_DROP_ACTION(MSCC_MS_ACTION_DROP) | 12562306a36Sopenharmony_ci MSCC_MS_SAM_NM_FLOW_NCP_TAGGED_DEST_PORT(port) | 12662306a36Sopenharmony_ci /* Bad tag */ 12762306a36Sopenharmony_ci MSCC_MS_SAM_NM_FLOW_NCP_BADTAG_FLOW_TYPE(action) | 12862306a36Sopenharmony_ci MSCC_MS_SAM_NM_FLOW_NCP_BADTAG_DROP_ACTION(MSCC_MS_ACTION_DROP) | 12962306a36Sopenharmony_ci MSCC_MS_SAM_NM_FLOW_NCP_BADTAG_DEST_PORT(port) | 13062306a36Sopenharmony_ci /* Kay tag */ 13162306a36Sopenharmony_ci MSCC_MS_SAM_NM_FLOW_NCP_KAY_FLOW_TYPE(action) | 13262306a36Sopenharmony_ci MSCC_MS_SAM_NM_FLOW_NCP_KAY_DROP_ACTION(MSCC_MS_ACTION_DROP) | 13362306a36Sopenharmony_ci MSCC_MS_SAM_NM_FLOW_NCP_KAY_DEST_PORT(port)); 13462306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_NM_FLOW_CP, 13562306a36Sopenharmony_ci /* MACsec untagged */ 13662306a36Sopenharmony_ci MSCC_MS_SAM_NM_FLOW_NCP_UNTAGGED_FLOW_TYPE(action) | 13762306a36Sopenharmony_ci MSCC_MS_SAM_NM_FLOW_CP_UNTAGGED_DROP_ACTION(MSCC_MS_ACTION_DROP) | 13862306a36Sopenharmony_ci MSCC_MS_SAM_NM_FLOW_CP_UNTAGGED_DEST_PORT(port) | 13962306a36Sopenharmony_ci /* MACsec tagged */ 14062306a36Sopenharmony_ci MSCC_MS_SAM_NM_FLOW_NCP_TAGGED_FLOW_TYPE(action) | 14162306a36Sopenharmony_ci MSCC_MS_SAM_NM_FLOW_CP_TAGGED_DROP_ACTION(MSCC_MS_ACTION_DROP) | 14262306a36Sopenharmony_ci MSCC_MS_SAM_NM_FLOW_CP_TAGGED_DEST_PORT(port) | 14362306a36Sopenharmony_ci /* Bad tag */ 14462306a36Sopenharmony_ci MSCC_MS_SAM_NM_FLOW_NCP_BADTAG_FLOW_TYPE(action) | 14562306a36Sopenharmony_ci MSCC_MS_SAM_NM_FLOW_CP_BADTAG_DROP_ACTION(MSCC_MS_ACTION_DROP) | 14662306a36Sopenharmony_ci MSCC_MS_SAM_NM_FLOW_CP_BADTAG_DEST_PORT(port) | 14762306a36Sopenharmony_ci /* Kay tag */ 14862306a36Sopenharmony_ci MSCC_MS_SAM_NM_FLOW_NCP_KAY_FLOW_TYPE(action) | 14962306a36Sopenharmony_ci MSCC_MS_SAM_NM_FLOW_CP_KAY_DROP_ACTION(MSCC_MS_ACTION_DROP) | 15062306a36Sopenharmony_ci MSCC_MS_SAM_NM_FLOW_CP_KAY_DEST_PORT(port)); 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cistatic void vsc8584_macsec_integrity_checks(struct phy_device *phydev, 15462306a36Sopenharmony_ci enum macsec_bank bank) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci u32 val; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci if (bank != MACSEC_INGR) 15962306a36Sopenharmony_ci return; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci /* Set default rules to pass unmatched frames */ 16262306a36Sopenharmony_ci val = vsc8584_macsec_phy_read(phydev, bank, 16362306a36Sopenharmony_ci MSCC_MS_PARAMS2_IG_CC_CONTROL); 16462306a36Sopenharmony_ci val |= MSCC_MS_PARAMS2_IG_CC_CONTROL_NON_MATCH_CTRL_ACT | 16562306a36Sopenharmony_ci MSCC_MS_PARAMS2_IG_CC_CONTROL_NON_MATCH_ACT; 16662306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_PARAMS2_IG_CC_CONTROL, 16762306a36Sopenharmony_ci val); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_PARAMS2_IG_CP_TAG, 17062306a36Sopenharmony_ci MSCC_MS_PARAMS2_IG_CP_TAG_PARSE_STAG | 17162306a36Sopenharmony_ci MSCC_MS_PARAMS2_IG_CP_TAG_PARSE_QTAG | 17262306a36Sopenharmony_ci MSCC_MS_PARAMS2_IG_CP_TAG_PARSE_QINQ); 17362306a36Sopenharmony_ci} 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistatic void vsc8584_macsec_block_init(struct phy_device *phydev, 17662306a36Sopenharmony_ci enum macsec_bank bank) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci u32 val; 17962306a36Sopenharmony_ci int i; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_ENA_CFG, 18262306a36Sopenharmony_ci MSCC_MS_ENA_CFG_SW_RST | 18362306a36Sopenharmony_ci MSCC_MS_ENA_CFG_MACSEC_BYPASS_ENA); 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci /* Set the MACsec block out of s/w reset and enable clocks */ 18662306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_ENA_CFG, 18762306a36Sopenharmony_ci MSCC_MS_ENA_CFG_CLK_ENA); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_STATUS_CONTEXT_CTRL, 19062306a36Sopenharmony_ci bank == MACSEC_INGR ? 0xe5880214 : 0xe5880218); 19162306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_MISC_CONTROL, 19262306a36Sopenharmony_ci MSCC_MS_MISC_CONTROL_MC_LATENCY_FIX(bank == MACSEC_INGR ? 57 : 40) | 19362306a36Sopenharmony_ci MSCC_MS_MISC_CONTROL_XFORM_REC_SIZE(bank == MACSEC_INGR ? 1 : 2)); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci /* Clear the counters */ 19662306a36Sopenharmony_ci val = vsc8584_macsec_phy_read(phydev, bank, MSCC_MS_COUNT_CONTROL); 19762306a36Sopenharmony_ci val |= MSCC_MS_COUNT_CONTROL_AUTO_CNTR_RESET; 19862306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_COUNT_CONTROL, val); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci /* Enable octet increment mode */ 20162306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_PP_CTRL, 20262306a36Sopenharmony_ci MSCC_MS_PP_CTRL_MACSEC_OCTET_INCR_MODE); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_BLOCK_CTX_UPDATE, 0x3); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci val = vsc8584_macsec_phy_read(phydev, bank, MSCC_MS_COUNT_CONTROL); 20762306a36Sopenharmony_ci val |= MSCC_MS_COUNT_CONTROL_RESET_ALL; 20862306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_COUNT_CONTROL, val); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci /* Set the MTU */ 21162306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_NON_VLAN_MTU_CHECK, 21262306a36Sopenharmony_ci MSCC_MS_NON_VLAN_MTU_CHECK_NV_MTU_COMPARE(32761) | 21362306a36Sopenharmony_ci MSCC_MS_NON_VLAN_MTU_CHECK_NV_MTU_COMP_DROP); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci for (i = 0; i < 8; i++) 21662306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_VLAN_MTU_CHECK(i), 21762306a36Sopenharmony_ci MSCC_MS_VLAN_MTU_CHECK_MTU_COMPARE(32761) | 21862306a36Sopenharmony_ci MSCC_MS_VLAN_MTU_CHECK_MTU_COMP_DROP); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci if (bank == MACSEC_EGR) { 22162306a36Sopenharmony_ci val = vsc8584_macsec_phy_read(phydev, bank, MSCC_MS_INTR_CTRL_STATUS); 22262306a36Sopenharmony_ci val &= ~MSCC_MS_INTR_CTRL_STATUS_INTR_ENABLE_M; 22362306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_INTR_CTRL_STATUS, val); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_FC_CFG, 22662306a36Sopenharmony_ci MSCC_MS_FC_CFG_FCBUF_ENA | 22762306a36Sopenharmony_ci MSCC_MS_FC_CFG_LOW_THRESH(0x1) | 22862306a36Sopenharmony_ci MSCC_MS_FC_CFG_HIGH_THRESH(0x4) | 22962306a36Sopenharmony_ci MSCC_MS_FC_CFG_LOW_BYTES_VAL(0x4) | 23062306a36Sopenharmony_ci MSCC_MS_FC_CFG_HIGH_BYTES_VAL(0x6)); 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci vsc8584_macsec_classification(phydev, bank); 23462306a36Sopenharmony_ci vsc8584_macsec_flow_default_action(phydev, bank, false); 23562306a36Sopenharmony_ci vsc8584_macsec_integrity_checks(phydev, bank); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci /* Enable the MACsec block */ 23862306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_ENA_CFG, 23962306a36Sopenharmony_ci MSCC_MS_ENA_CFG_CLK_ENA | 24062306a36Sopenharmony_ci MSCC_MS_ENA_CFG_MACSEC_ENA | 24162306a36Sopenharmony_ci MSCC_MS_ENA_CFG_MACSEC_SPEED_MODE(0x5)); 24262306a36Sopenharmony_ci} 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_cistatic void vsc8584_macsec_mac_init(struct phy_device *phydev, 24562306a36Sopenharmony_ci enum macsec_bank bank) 24662306a36Sopenharmony_ci{ 24762306a36Sopenharmony_ci u32 val; 24862306a36Sopenharmony_ci int i; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci /* Clear host & line stats */ 25162306a36Sopenharmony_ci for (i = 0; i < 36; i++) 25262306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, 0x1c + i, 0); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci val = vsc8584_macsec_phy_read(phydev, bank, 25562306a36Sopenharmony_ci MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL); 25662306a36Sopenharmony_ci val &= ~MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL_PAUSE_MODE_M; 25762306a36Sopenharmony_ci val |= MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL_PAUSE_MODE(2) | 25862306a36Sopenharmony_ci MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL_PAUSE_VALUE(0xffff); 25962306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, 26062306a36Sopenharmony_ci MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL, val); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci val = vsc8584_macsec_phy_read(phydev, bank, 26362306a36Sopenharmony_ci MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL_2); 26462306a36Sopenharmony_ci val |= 0xffff; 26562306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, 26662306a36Sopenharmony_ci MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL_2, val); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci val = vsc8584_macsec_phy_read(phydev, bank, 26962306a36Sopenharmony_ci MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL); 27062306a36Sopenharmony_ci if (bank == HOST_MAC) 27162306a36Sopenharmony_ci val |= MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL_PAUSE_TIMER_ENA | 27262306a36Sopenharmony_ci MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL_PAUSE_FRAME_DROP_ENA; 27362306a36Sopenharmony_ci else 27462306a36Sopenharmony_ci val |= MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL_PAUSE_REACT_ENA | 27562306a36Sopenharmony_ci MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL_PAUSE_FRAME_DROP_ENA | 27662306a36Sopenharmony_ci MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL_PAUSE_MODE | 27762306a36Sopenharmony_ci MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL_EARLY_PAUSE_DETECT_ENA; 27862306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, 27962306a36Sopenharmony_ci MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL, val); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, MSCC_MAC_CFG_PKTINF_CFG, 28262306a36Sopenharmony_ci MSCC_MAC_CFG_PKTINF_CFG_STRIP_FCS_ENA | 28362306a36Sopenharmony_ci MSCC_MAC_CFG_PKTINF_CFG_INSERT_FCS_ENA | 28462306a36Sopenharmony_ci MSCC_MAC_CFG_PKTINF_CFG_LPI_RELAY_ENA | 28562306a36Sopenharmony_ci MSCC_MAC_CFG_PKTINF_CFG_STRIP_PREAMBLE_ENA | 28662306a36Sopenharmony_ci MSCC_MAC_CFG_PKTINF_CFG_INSERT_PREAMBLE_ENA | 28762306a36Sopenharmony_ci (bank == HOST_MAC ? 28862306a36Sopenharmony_ci MSCC_MAC_CFG_PKTINF_CFG_ENABLE_TX_PADDING : 0) | 28962306a36Sopenharmony_ci (IS_ENABLED(CONFIG_NETWORK_PHY_TIMESTAMPING) ? 29062306a36Sopenharmony_ci MSCC_MAC_CFG_PKTINF_CFG_MACSEC_BYPASS_NUM_PTP_STALL_CLKS(0x8) : 0)); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci val = vsc8584_macsec_phy_read(phydev, bank, MSCC_MAC_CFG_MODE_CFG); 29362306a36Sopenharmony_ci val &= ~MSCC_MAC_CFG_MODE_CFG_DISABLE_DIC; 29462306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, MSCC_MAC_CFG_MODE_CFG, val); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci val = vsc8584_macsec_phy_read(phydev, bank, MSCC_MAC_CFG_MAXLEN_CFG); 29762306a36Sopenharmony_ci val &= ~MSCC_MAC_CFG_MAXLEN_CFG_MAX_LEN_M; 29862306a36Sopenharmony_ci val |= MSCC_MAC_CFG_MAXLEN_CFG_MAX_LEN(10240); 29962306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, MSCC_MAC_CFG_MAXLEN_CFG, val); 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, MSCC_MAC_CFG_ADV_CHK_CFG, 30262306a36Sopenharmony_ci MSCC_MAC_CFG_ADV_CHK_CFG_SFD_CHK_ENA | 30362306a36Sopenharmony_ci MSCC_MAC_CFG_ADV_CHK_CFG_PRM_CHK_ENA | 30462306a36Sopenharmony_ci MSCC_MAC_CFG_ADV_CHK_CFG_OOR_ERR_ENA | 30562306a36Sopenharmony_ci MSCC_MAC_CFG_ADV_CHK_CFG_INR_ERR_ENA); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci val = vsc8584_macsec_phy_read(phydev, bank, MSCC_MAC_CFG_LFS_CFG); 30862306a36Sopenharmony_ci val &= ~MSCC_MAC_CFG_LFS_CFG_LFS_MODE_ENA; 30962306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, MSCC_MAC_CFG_LFS_CFG, val); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, MSCC_MAC_CFG_ENA_CFG, 31262306a36Sopenharmony_ci MSCC_MAC_CFG_ENA_CFG_RX_CLK_ENA | 31362306a36Sopenharmony_ci MSCC_MAC_CFG_ENA_CFG_TX_CLK_ENA | 31462306a36Sopenharmony_ci MSCC_MAC_CFG_ENA_CFG_RX_ENA | 31562306a36Sopenharmony_ci MSCC_MAC_CFG_ENA_CFG_TX_ENA); 31662306a36Sopenharmony_ci} 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci/* Must be called with mdio_lock taken */ 31962306a36Sopenharmony_cistatic int __vsc8584_macsec_init(struct phy_device *phydev) 32062306a36Sopenharmony_ci{ 32162306a36Sopenharmony_ci struct vsc8531_private *priv = phydev->priv; 32262306a36Sopenharmony_ci enum macsec_bank proc_bank; 32362306a36Sopenharmony_ci u32 val; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci vsc8584_macsec_block_init(phydev, MACSEC_INGR); 32662306a36Sopenharmony_ci vsc8584_macsec_block_init(phydev, MACSEC_EGR); 32762306a36Sopenharmony_ci vsc8584_macsec_mac_init(phydev, HOST_MAC); 32862306a36Sopenharmony_ci vsc8584_macsec_mac_init(phydev, LINE_MAC); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, FC_BUFFER, 33162306a36Sopenharmony_ci MSCC_FCBUF_FC_READ_THRESH_CFG, 33262306a36Sopenharmony_ci MSCC_FCBUF_FC_READ_THRESH_CFG_TX_THRESH(4) | 33362306a36Sopenharmony_ci MSCC_FCBUF_FC_READ_THRESH_CFG_RX_THRESH(5)); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci val = vsc8584_macsec_phy_read(phydev, FC_BUFFER, MSCC_FCBUF_MODE_CFG); 33662306a36Sopenharmony_ci val |= MSCC_FCBUF_MODE_CFG_PAUSE_GEN_ENA | 33762306a36Sopenharmony_ci MSCC_FCBUF_MODE_CFG_RX_PPM_RATE_ADAPT_ENA | 33862306a36Sopenharmony_ci MSCC_FCBUF_MODE_CFG_TX_PPM_RATE_ADAPT_ENA; 33962306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, FC_BUFFER, MSCC_FCBUF_MODE_CFG, val); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, FC_BUFFER, MSCC_FCBUF_PPM_RATE_ADAPT_THRESH_CFG, 34262306a36Sopenharmony_ci MSCC_FCBUF_PPM_RATE_ADAPT_THRESH_CFG_TX_THRESH(8) | 34362306a36Sopenharmony_ci MSCC_FCBUF_PPM_RATE_ADAPT_THRESH_CFG_TX_OFFSET(9)); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci val = vsc8584_macsec_phy_read(phydev, FC_BUFFER, 34662306a36Sopenharmony_ci MSCC_FCBUF_TX_DATA_QUEUE_CFG); 34762306a36Sopenharmony_ci val &= ~(MSCC_FCBUF_TX_DATA_QUEUE_CFG_START_M | 34862306a36Sopenharmony_ci MSCC_FCBUF_TX_DATA_QUEUE_CFG_END_M); 34962306a36Sopenharmony_ci val |= MSCC_FCBUF_TX_DATA_QUEUE_CFG_START(0) | 35062306a36Sopenharmony_ci MSCC_FCBUF_TX_DATA_QUEUE_CFG_END(5119); 35162306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, FC_BUFFER, 35262306a36Sopenharmony_ci MSCC_FCBUF_TX_DATA_QUEUE_CFG, val); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci val = vsc8584_macsec_phy_read(phydev, FC_BUFFER, MSCC_FCBUF_ENA_CFG); 35562306a36Sopenharmony_ci val |= MSCC_FCBUF_ENA_CFG_TX_ENA | MSCC_FCBUF_ENA_CFG_RX_ENA; 35662306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, FC_BUFFER, MSCC_FCBUF_ENA_CFG, val); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci proc_bank = (priv->addr < 2) ? PROC_0 : PROC_2; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci val = vsc8584_macsec_phy_read(phydev, proc_bank, 36162306a36Sopenharmony_ci MSCC_PROC_IP_1588_TOP_CFG_STAT_MODE_CTL); 36262306a36Sopenharmony_ci val &= ~MSCC_PROC_IP_1588_TOP_CFG_STAT_MODE_CTL_PROTOCOL_MODE_M; 36362306a36Sopenharmony_ci val |= MSCC_PROC_IP_1588_TOP_CFG_STAT_MODE_CTL_PROTOCOL_MODE(4); 36462306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, proc_bank, 36562306a36Sopenharmony_ci MSCC_PROC_IP_1588_TOP_CFG_STAT_MODE_CTL, val); 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci return 0; 36862306a36Sopenharmony_ci} 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_cistatic void vsc8584_macsec_flow(struct phy_device *phydev, 37162306a36Sopenharmony_ci struct macsec_flow *flow) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci struct vsc8531_private *priv = phydev->priv; 37462306a36Sopenharmony_ci enum macsec_bank bank = flow->bank; 37562306a36Sopenharmony_ci u32 val, match = 0, mask = 0, action = 0, idx = flow->index; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci if (flow->match.tagged) 37862306a36Sopenharmony_ci match |= MSCC_MS_SAM_MISC_MATCH_TAGGED; 37962306a36Sopenharmony_ci if (flow->match.untagged) 38062306a36Sopenharmony_ci match |= MSCC_MS_SAM_MISC_MATCH_UNTAGGED; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci if (bank == MACSEC_INGR && flow->assoc_num >= 0) { 38362306a36Sopenharmony_ci match |= MSCC_MS_SAM_MISC_MATCH_AN(flow->assoc_num); 38462306a36Sopenharmony_ci mask |= MSCC_MS_SAM_MASK_AN_MASK(0x3); 38562306a36Sopenharmony_ci } 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci if (bank == MACSEC_INGR && flow->match.sci && flow->rx_sa->sc->sci) { 38862306a36Sopenharmony_ci u64 sci = (__force u64)flow->rx_sa->sc->sci; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci match |= MSCC_MS_SAM_MISC_MATCH_TCI(BIT(3)); 39162306a36Sopenharmony_ci mask |= MSCC_MS_SAM_MASK_TCI_MASK(BIT(3)) | 39262306a36Sopenharmony_ci MSCC_MS_SAM_MASK_SCI_MASK; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_MATCH_SCI_LO(idx), 39562306a36Sopenharmony_ci lower_32_bits(sci)); 39662306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_MATCH_SCI_HI(idx), 39762306a36Sopenharmony_ci upper_32_bits(sci)); 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci if (flow->match.etype) { 40162306a36Sopenharmony_ci mask |= MSCC_MS_SAM_MASK_MAC_ETYPE_MASK; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_MAC_SA_MATCH_HI(idx), 40462306a36Sopenharmony_ci MSCC_MS_SAM_MAC_SA_MATCH_HI_ETYPE((__force u32)htons(flow->etype))); 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci match |= MSCC_MS_SAM_MISC_MATCH_PRIORITY(flow->priority); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_MISC_MATCH(idx), match); 41062306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_MASK(idx), mask); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci /* Action for matching packets */ 41362306a36Sopenharmony_ci if (flow->action.drop) 41462306a36Sopenharmony_ci action = MSCC_MS_FLOW_DROP; 41562306a36Sopenharmony_ci else if (flow->action.bypass || flow->port == MSCC_MS_PORT_UNCONTROLLED) 41662306a36Sopenharmony_ci action = MSCC_MS_FLOW_BYPASS; 41762306a36Sopenharmony_ci else 41862306a36Sopenharmony_ci action = (bank == MACSEC_INGR) ? 41962306a36Sopenharmony_ci MSCC_MS_FLOW_INGRESS : MSCC_MS_FLOW_EGRESS; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci val = MSCC_MS_SAM_FLOW_CTRL_FLOW_TYPE(action) | 42262306a36Sopenharmony_ci MSCC_MS_SAM_FLOW_CTRL_DROP_ACTION(MSCC_MS_ACTION_DROP) | 42362306a36Sopenharmony_ci MSCC_MS_SAM_FLOW_CTRL_DEST_PORT(flow->port); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci if (action == MSCC_MS_FLOW_BYPASS) 42662306a36Sopenharmony_ci goto write_ctrl; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci if (bank == MACSEC_INGR) { 42962306a36Sopenharmony_ci if (priv->secy->replay_protect) 43062306a36Sopenharmony_ci val |= MSCC_MS_SAM_FLOW_CTRL_REPLAY_PROTECT; 43162306a36Sopenharmony_ci if (priv->secy->validate_frames == MACSEC_VALIDATE_STRICT) 43262306a36Sopenharmony_ci val |= MSCC_MS_SAM_FLOW_CTRL_VALIDATE_FRAMES(MSCC_MS_VALIDATE_STRICT); 43362306a36Sopenharmony_ci else if (priv->secy->validate_frames == MACSEC_VALIDATE_CHECK) 43462306a36Sopenharmony_ci val |= MSCC_MS_SAM_FLOW_CTRL_VALIDATE_FRAMES(MSCC_MS_VALIDATE_CHECK); 43562306a36Sopenharmony_ci } else if (bank == MACSEC_EGR) { 43662306a36Sopenharmony_ci if (priv->secy->protect_frames) 43762306a36Sopenharmony_ci val |= MSCC_MS_SAM_FLOW_CTRL_PROTECT_FRAME; 43862306a36Sopenharmony_ci if (priv->secy->tx_sc.encrypt) 43962306a36Sopenharmony_ci val |= MSCC_MS_SAM_FLOW_CTRL_CONF_PROTECT; 44062306a36Sopenharmony_ci if (priv->secy->tx_sc.send_sci) 44162306a36Sopenharmony_ci val |= MSCC_MS_SAM_FLOW_CTRL_INCLUDE_SCI; 44262306a36Sopenharmony_ci } 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ciwrite_ctrl: 44562306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_FLOW_CTRL(idx), val); 44662306a36Sopenharmony_ci} 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_cistatic struct macsec_flow *vsc8584_macsec_find_flow(struct macsec_context *ctx, 44962306a36Sopenharmony_ci enum macsec_bank bank) 45062306a36Sopenharmony_ci{ 45162306a36Sopenharmony_ci struct vsc8531_private *priv = ctx->phydev->priv; 45262306a36Sopenharmony_ci struct macsec_flow *pos, *tmp; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci list_for_each_entry_safe(pos, tmp, &priv->macsec_flows, list) 45562306a36Sopenharmony_ci if (pos->assoc_num == ctx->sa.assoc_num && pos->bank == bank) 45662306a36Sopenharmony_ci return pos; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci return ERR_PTR(-ENOENT); 45962306a36Sopenharmony_ci} 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_cistatic void vsc8584_macsec_flow_enable(struct phy_device *phydev, 46262306a36Sopenharmony_ci struct macsec_flow *flow) 46362306a36Sopenharmony_ci{ 46462306a36Sopenharmony_ci enum macsec_bank bank = flow->bank; 46562306a36Sopenharmony_ci u32 val, idx = flow->index; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci if ((flow->bank == MACSEC_INGR && flow->rx_sa && !flow->rx_sa->active) || 46862306a36Sopenharmony_ci (flow->bank == MACSEC_EGR && flow->tx_sa && !flow->tx_sa->active)) 46962306a36Sopenharmony_ci return; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci /* Enable */ 47262306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_ENTRY_SET1, BIT(idx)); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci /* Set in-use */ 47562306a36Sopenharmony_ci val = vsc8584_macsec_phy_read(phydev, bank, MSCC_MS_SAM_FLOW_CTRL(idx)); 47662306a36Sopenharmony_ci val |= MSCC_MS_SAM_FLOW_CTRL_SA_IN_USE; 47762306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_FLOW_CTRL(idx), val); 47862306a36Sopenharmony_ci} 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_cistatic void vsc8584_macsec_flow_disable(struct phy_device *phydev, 48162306a36Sopenharmony_ci struct macsec_flow *flow) 48262306a36Sopenharmony_ci{ 48362306a36Sopenharmony_ci enum macsec_bank bank = flow->bank; 48462306a36Sopenharmony_ci u32 val, idx = flow->index; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci /* Disable */ 48762306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_ENTRY_CLEAR1, BIT(idx)); 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci /* Clear in-use */ 49062306a36Sopenharmony_ci val = vsc8584_macsec_phy_read(phydev, bank, MSCC_MS_SAM_FLOW_CTRL(idx)); 49162306a36Sopenharmony_ci val &= ~MSCC_MS_SAM_FLOW_CTRL_SA_IN_USE; 49262306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_FLOW_CTRL(idx), val); 49362306a36Sopenharmony_ci} 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_cistatic u32 vsc8584_macsec_flow_context_id(struct macsec_flow *flow) 49662306a36Sopenharmony_ci{ 49762306a36Sopenharmony_ci if (flow->bank == MACSEC_INGR) 49862306a36Sopenharmony_ci return flow->index + MSCC_MS_MAX_FLOWS; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci return flow->index; 50162306a36Sopenharmony_ci} 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci/* Derive the AES key to get a key for the hash autentication */ 50462306a36Sopenharmony_cistatic int vsc8584_macsec_derive_key(const u8 *key, u16 key_len, u8 hkey[16]) 50562306a36Sopenharmony_ci{ 50662306a36Sopenharmony_ci const u8 input[AES_BLOCK_SIZE] = {0}; 50762306a36Sopenharmony_ci struct crypto_aes_ctx ctx; 50862306a36Sopenharmony_ci int ret; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci ret = aes_expandkey(&ctx, key, key_len); 51162306a36Sopenharmony_ci if (ret) 51262306a36Sopenharmony_ci return ret; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci aes_encrypt(&ctx, hkey, input); 51562306a36Sopenharmony_ci memzero_explicit(&ctx, sizeof(ctx)); 51662306a36Sopenharmony_ci return 0; 51762306a36Sopenharmony_ci} 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_cistatic int vsc8584_macsec_transformation(struct phy_device *phydev, 52062306a36Sopenharmony_ci struct macsec_flow *flow, 52162306a36Sopenharmony_ci const u8 *key) 52262306a36Sopenharmony_ci{ 52362306a36Sopenharmony_ci struct vsc8531_private *priv = phydev->priv; 52462306a36Sopenharmony_ci enum macsec_bank bank = flow->bank; 52562306a36Sopenharmony_ci int i, ret, index = flow->index; 52662306a36Sopenharmony_ci u32 rec = 0, control = 0; 52762306a36Sopenharmony_ci u8 hkey[16]; 52862306a36Sopenharmony_ci u64 sci; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci ret = vsc8584_macsec_derive_key(key, priv->secy->key_len, hkey); 53162306a36Sopenharmony_ci if (ret) 53262306a36Sopenharmony_ci return ret; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci switch (priv->secy->key_len) { 53562306a36Sopenharmony_ci case 16: 53662306a36Sopenharmony_ci control |= CONTROL_CRYPTO_ALG(CTRYPTO_ALG_AES_CTR_128); 53762306a36Sopenharmony_ci break; 53862306a36Sopenharmony_ci case 32: 53962306a36Sopenharmony_ci control |= CONTROL_CRYPTO_ALG(CTRYPTO_ALG_AES_CTR_256); 54062306a36Sopenharmony_ci break; 54162306a36Sopenharmony_ci default: 54262306a36Sopenharmony_ci return -EINVAL; 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci control |= (bank == MACSEC_EGR) ? 54662306a36Sopenharmony_ci (CONTROL_TYPE_EGRESS | CONTROL_AN(priv->secy->tx_sc.encoding_sa)) : 54762306a36Sopenharmony_ci (CONTROL_TYPE_INGRESS | CONTROL_SEQ_MASK); 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci control |= CONTROL_UPDATE_SEQ | CONTROL_ENCRYPT_AUTH | CONTROL_KEY_IN_CTX | 55062306a36Sopenharmony_ci CONTROL_IV0 | CONTROL_IV1 | CONTROL_IV_IN_SEQ | 55162306a36Sopenharmony_ci CONTROL_DIGEST_TYPE(0x2) | CONTROL_SEQ_TYPE(0x1) | 55262306a36Sopenharmony_ci CONTROL_AUTH_ALG(AUTH_ALG_AES_GHAS) | CONTROL_CONTEXT_ID; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci /* Set the control word */ 55562306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_XFORM_REC(index, rec++), 55662306a36Sopenharmony_ci control); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci /* Set the context ID. Must be unique. */ 55962306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_XFORM_REC(index, rec++), 56062306a36Sopenharmony_ci vsc8584_macsec_flow_context_id(flow)); 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci /* Set the encryption/decryption key */ 56362306a36Sopenharmony_ci for (i = 0; i < priv->secy->key_len / sizeof(u32); i++) 56462306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, 56562306a36Sopenharmony_ci MSCC_MS_XFORM_REC(index, rec++), 56662306a36Sopenharmony_ci ((u32 *)key)[i]); 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci /* Set the authentication key */ 56962306a36Sopenharmony_ci for (i = 0; i < 4; i++) 57062306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, 57162306a36Sopenharmony_ci MSCC_MS_XFORM_REC(index, rec++), 57262306a36Sopenharmony_ci ((u32 *)hkey)[i]); 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci /* Initial sequence number */ 57562306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_XFORM_REC(index, rec++), 57662306a36Sopenharmony_ci bank == MACSEC_INGR ? 57762306a36Sopenharmony_ci flow->rx_sa->next_pn : flow->tx_sa->next_pn); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci if (bank == MACSEC_INGR) 58062306a36Sopenharmony_ci /* Set the mask (replay window size) */ 58162306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, 58262306a36Sopenharmony_ci MSCC_MS_XFORM_REC(index, rec++), 58362306a36Sopenharmony_ci priv->secy->replay_window); 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci /* Set the input vectors */ 58662306a36Sopenharmony_ci sci = (__force u64)(bank == MACSEC_INGR ? flow->rx_sa->sc->sci : priv->secy->sci); 58762306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_XFORM_REC(index, rec++), 58862306a36Sopenharmony_ci lower_32_bits(sci)); 58962306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_XFORM_REC(index, rec++), 59062306a36Sopenharmony_ci upper_32_bits(sci)); 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci while (rec < 20) 59362306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_XFORM_REC(index, rec++), 59462306a36Sopenharmony_ci 0); 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci flow->has_transformation = true; 59762306a36Sopenharmony_ci return 0; 59862306a36Sopenharmony_ci} 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_cistatic struct macsec_flow *vsc8584_macsec_alloc_flow(struct vsc8531_private *priv, 60162306a36Sopenharmony_ci enum macsec_bank bank) 60262306a36Sopenharmony_ci{ 60362306a36Sopenharmony_ci unsigned long *bitmap = bank == MACSEC_INGR ? 60462306a36Sopenharmony_ci &priv->ingr_flows : &priv->egr_flows; 60562306a36Sopenharmony_ci struct macsec_flow *flow; 60662306a36Sopenharmony_ci int index; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci index = find_first_zero_bit(bitmap, MSCC_MS_MAX_FLOWS); 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci if (index == MSCC_MS_MAX_FLOWS) 61162306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci flow = kzalloc(sizeof(*flow), GFP_KERNEL); 61462306a36Sopenharmony_ci if (!flow) 61562306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci set_bit(index, bitmap); 61862306a36Sopenharmony_ci flow->index = index; 61962306a36Sopenharmony_ci flow->bank = bank; 62062306a36Sopenharmony_ci flow->priority = 8; 62162306a36Sopenharmony_ci flow->assoc_num = -1; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci list_add_tail(&flow->list, &priv->macsec_flows); 62462306a36Sopenharmony_ci return flow; 62562306a36Sopenharmony_ci} 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_cistatic void vsc8584_macsec_free_flow(struct vsc8531_private *priv, 62862306a36Sopenharmony_ci struct macsec_flow *flow) 62962306a36Sopenharmony_ci{ 63062306a36Sopenharmony_ci unsigned long *bitmap = flow->bank == MACSEC_INGR ? 63162306a36Sopenharmony_ci &priv->ingr_flows : &priv->egr_flows; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci list_del(&flow->list); 63462306a36Sopenharmony_ci clear_bit(flow->index, bitmap); 63562306a36Sopenharmony_ci kfree(flow); 63662306a36Sopenharmony_ci} 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_cistatic void vsc8584_macsec_add_flow(struct phy_device *phydev, 63962306a36Sopenharmony_ci struct macsec_flow *flow) 64062306a36Sopenharmony_ci{ 64162306a36Sopenharmony_ci flow->port = MSCC_MS_PORT_CONTROLLED; 64262306a36Sopenharmony_ci vsc8584_macsec_flow(phydev, flow); 64362306a36Sopenharmony_ci} 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_cistatic int vsc8584_macsec_default_flows(struct phy_device *phydev) 64662306a36Sopenharmony_ci{ 64762306a36Sopenharmony_ci struct macsec_flow *flow; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci /* Add a rule to let the MKA traffic go through, ingress */ 65062306a36Sopenharmony_ci flow = vsc8584_macsec_alloc_flow(phydev->priv, MACSEC_INGR); 65162306a36Sopenharmony_ci if (IS_ERR(flow)) 65262306a36Sopenharmony_ci return PTR_ERR(flow); 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci flow->priority = 15; 65562306a36Sopenharmony_ci flow->port = MSCC_MS_PORT_UNCONTROLLED; 65662306a36Sopenharmony_ci flow->match.tagged = 1; 65762306a36Sopenharmony_ci flow->match.untagged = 1; 65862306a36Sopenharmony_ci flow->match.etype = 1; 65962306a36Sopenharmony_ci flow->etype = ETH_P_PAE; 66062306a36Sopenharmony_ci flow->action.bypass = 1; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci vsc8584_macsec_flow(phydev, flow); 66362306a36Sopenharmony_ci vsc8584_macsec_flow_enable(phydev, flow); 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci /* Add a rule to let the MKA traffic go through, egress */ 66662306a36Sopenharmony_ci flow = vsc8584_macsec_alloc_flow(phydev->priv, MACSEC_EGR); 66762306a36Sopenharmony_ci if (IS_ERR(flow)) 66862306a36Sopenharmony_ci return PTR_ERR(flow); 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci flow->priority = 15; 67162306a36Sopenharmony_ci flow->port = MSCC_MS_PORT_COMMON; 67262306a36Sopenharmony_ci flow->match.untagged = 1; 67362306a36Sopenharmony_ci flow->match.etype = 1; 67462306a36Sopenharmony_ci flow->etype = ETH_P_PAE; 67562306a36Sopenharmony_ci flow->action.bypass = 1; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci vsc8584_macsec_flow(phydev, flow); 67862306a36Sopenharmony_ci vsc8584_macsec_flow_enable(phydev, flow); 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci return 0; 68162306a36Sopenharmony_ci} 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_cistatic void vsc8584_macsec_del_flow(struct phy_device *phydev, 68462306a36Sopenharmony_ci struct macsec_flow *flow) 68562306a36Sopenharmony_ci{ 68662306a36Sopenharmony_ci vsc8584_macsec_flow_disable(phydev, flow); 68762306a36Sopenharmony_ci vsc8584_macsec_free_flow(phydev->priv, flow); 68862306a36Sopenharmony_ci} 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_cistatic int __vsc8584_macsec_add_rxsa(struct macsec_context *ctx, 69162306a36Sopenharmony_ci struct macsec_flow *flow, bool update) 69262306a36Sopenharmony_ci{ 69362306a36Sopenharmony_ci struct phy_device *phydev = ctx->phydev; 69462306a36Sopenharmony_ci struct vsc8531_private *priv = phydev->priv; 69562306a36Sopenharmony_ci int ret; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci flow->assoc_num = ctx->sa.assoc_num; 69862306a36Sopenharmony_ci flow->rx_sa = ctx->sa.rx_sa; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci /* Always match tagged packets on ingress */ 70162306a36Sopenharmony_ci flow->match.tagged = 1; 70262306a36Sopenharmony_ci flow->match.sci = 1; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci if (priv->secy->validate_frames != MACSEC_VALIDATE_DISABLED) 70562306a36Sopenharmony_ci flow->match.untagged = 1; 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci vsc8584_macsec_add_flow(phydev, flow); 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci if (update) 71062306a36Sopenharmony_ci return 0; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci ret = vsc8584_macsec_transformation(phydev, flow, ctx->sa.key); 71362306a36Sopenharmony_ci if (ret) 71462306a36Sopenharmony_ci vsc8584_macsec_free_flow(phydev->priv, flow); 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci return ret; 71762306a36Sopenharmony_ci} 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_cistatic int __vsc8584_macsec_add_txsa(struct macsec_context *ctx, 72062306a36Sopenharmony_ci struct macsec_flow *flow, bool update) 72162306a36Sopenharmony_ci{ 72262306a36Sopenharmony_ci int ret; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci flow->assoc_num = ctx->sa.assoc_num; 72562306a36Sopenharmony_ci flow->tx_sa = ctx->sa.tx_sa; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci /* Always match untagged packets on egress */ 72862306a36Sopenharmony_ci flow->match.untagged = 1; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci vsc8584_macsec_add_flow(ctx->phydev, flow); 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci if (update) 73362306a36Sopenharmony_ci return 0; 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci ret = vsc8584_macsec_transformation(ctx->phydev, flow, ctx->sa.key); 73662306a36Sopenharmony_ci if (ret) 73762306a36Sopenharmony_ci vsc8584_macsec_free_flow(ctx->phydev->priv, flow); 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci return ret; 74062306a36Sopenharmony_ci} 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_cistatic int vsc8584_macsec_dev_open(struct macsec_context *ctx) 74362306a36Sopenharmony_ci{ 74462306a36Sopenharmony_ci struct vsc8531_private *priv = ctx->phydev->priv; 74562306a36Sopenharmony_ci struct macsec_flow *flow, *tmp; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci list_for_each_entry_safe(flow, tmp, &priv->macsec_flows, list) 74862306a36Sopenharmony_ci vsc8584_macsec_flow_enable(ctx->phydev, flow); 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci return 0; 75162306a36Sopenharmony_ci} 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_cistatic int vsc8584_macsec_dev_stop(struct macsec_context *ctx) 75462306a36Sopenharmony_ci{ 75562306a36Sopenharmony_ci struct vsc8531_private *priv = ctx->phydev->priv; 75662306a36Sopenharmony_ci struct macsec_flow *flow, *tmp; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci list_for_each_entry_safe(flow, tmp, &priv->macsec_flows, list) 75962306a36Sopenharmony_ci vsc8584_macsec_flow_disable(ctx->phydev, flow); 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci return 0; 76262306a36Sopenharmony_ci} 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_cistatic int vsc8584_macsec_add_secy(struct macsec_context *ctx) 76562306a36Sopenharmony_ci{ 76662306a36Sopenharmony_ci struct vsc8531_private *priv = ctx->phydev->priv; 76762306a36Sopenharmony_ci struct macsec_secy *secy = ctx->secy; 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci if (priv->secy) 77062306a36Sopenharmony_ci return -EEXIST; 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci priv->secy = secy; 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci vsc8584_macsec_flow_default_action(ctx->phydev, MACSEC_EGR, 77562306a36Sopenharmony_ci secy->validate_frames != MACSEC_VALIDATE_DISABLED); 77662306a36Sopenharmony_ci vsc8584_macsec_flow_default_action(ctx->phydev, MACSEC_INGR, 77762306a36Sopenharmony_ci secy->validate_frames != MACSEC_VALIDATE_DISABLED); 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci return vsc8584_macsec_default_flows(ctx->phydev); 78062306a36Sopenharmony_ci} 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_cistatic int vsc8584_macsec_del_secy(struct macsec_context *ctx) 78362306a36Sopenharmony_ci{ 78462306a36Sopenharmony_ci struct vsc8531_private *priv = ctx->phydev->priv; 78562306a36Sopenharmony_ci struct macsec_flow *flow, *tmp; 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci list_for_each_entry_safe(flow, tmp, &priv->macsec_flows, list) 78862306a36Sopenharmony_ci vsc8584_macsec_del_flow(ctx->phydev, flow); 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci vsc8584_macsec_flow_default_action(ctx->phydev, MACSEC_EGR, false); 79162306a36Sopenharmony_ci vsc8584_macsec_flow_default_action(ctx->phydev, MACSEC_INGR, false); 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci priv->secy = NULL; 79462306a36Sopenharmony_ci return 0; 79562306a36Sopenharmony_ci} 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_cistatic int vsc8584_macsec_upd_secy(struct macsec_context *ctx) 79862306a36Sopenharmony_ci{ 79962306a36Sopenharmony_ci vsc8584_macsec_del_secy(ctx); 80062306a36Sopenharmony_ci return vsc8584_macsec_add_secy(ctx); 80162306a36Sopenharmony_ci} 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_cistatic int vsc8584_macsec_add_rxsc(struct macsec_context *ctx) 80462306a36Sopenharmony_ci{ 80562306a36Sopenharmony_ci /* Nothing to do */ 80662306a36Sopenharmony_ci return 0; 80762306a36Sopenharmony_ci} 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_cistatic int vsc8584_macsec_upd_rxsc(struct macsec_context *ctx) 81062306a36Sopenharmony_ci{ 81162306a36Sopenharmony_ci return -EOPNOTSUPP; 81262306a36Sopenharmony_ci} 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_cistatic int vsc8584_macsec_del_rxsc(struct macsec_context *ctx) 81562306a36Sopenharmony_ci{ 81662306a36Sopenharmony_ci struct vsc8531_private *priv = ctx->phydev->priv; 81762306a36Sopenharmony_ci struct macsec_flow *flow, *tmp; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci list_for_each_entry_safe(flow, tmp, &priv->macsec_flows, list) { 82062306a36Sopenharmony_ci if (flow->bank == MACSEC_INGR && flow->rx_sa && 82162306a36Sopenharmony_ci flow->rx_sa->sc->sci == ctx->rx_sc->sci) 82262306a36Sopenharmony_ci vsc8584_macsec_del_flow(ctx->phydev, flow); 82362306a36Sopenharmony_ci } 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci return 0; 82662306a36Sopenharmony_ci} 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_cistatic int vsc8584_macsec_add_rxsa(struct macsec_context *ctx) 82962306a36Sopenharmony_ci{ 83062306a36Sopenharmony_ci struct phy_device *phydev = ctx->phydev; 83162306a36Sopenharmony_ci struct vsc8531_private *priv = phydev->priv; 83262306a36Sopenharmony_ci struct macsec_flow *flow; 83362306a36Sopenharmony_ci int ret; 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci flow = vsc8584_macsec_alloc_flow(priv, MACSEC_INGR); 83662306a36Sopenharmony_ci if (IS_ERR(flow)) 83762306a36Sopenharmony_ci return PTR_ERR(flow); 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci ret = __vsc8584_macsec_add_rxsa(ctx, flow, false); 84062306a36Sopenharmony_ci if (ret) 84162306a36Sopenharmony_ci return ret; 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci vsc8584_macsec_flow_enable(phydev, flow); 84462306a36Sopenharmony_ci return 0; 84562306a36Sopenharmony_ci} 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_cistatic int vsc8584_macsec_upd_rxsa(struct macsec_context *ctx) 84862306a36Sopenharmony_ci{ 84962306a36Sopenharmony_ci struct macsec_flow *flow; 85062306a36Sopenharmony_ci int ret; 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci if (ctx->sa.update_pn) 85362306a36Sopenharmony_ci return -EINVAL; 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci flow = vsc8584_macsec_find_flow(ctx, MACSEC_INGR); 85662306a36Sopenharmony_ci if (IS_ERR(flow)) 85762306a36Sopenharmony_ci return PTR_ERR(flow); 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci /* Make sure the flow is disabled before updating it */ 86062306a36Sopenharmony_ci vsc8584_macsec_flow_disable(ctx->phydev, flow); 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci ret = __vsc8584_macsec_add_rxsa(ctx, flow, true); 86362306a36Sopenharmony_ci if (ret) 86462306a36Sopenharmony_ci return ret; 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci vsc8584_macsec_flow_enable(ctx->phydev, flow); 86762306a36Sopenharmony_ci return 0; 86862306a36Sopenharmony_ci} 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_cistatic int vsc8584_macsec_del_rxsa(struct macsec_context *ctx) 87162306a36Sopenharmony_ci{ 87262306a36Sopenharmony_ci struct macsec_flow *flow; 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci flow = vsc8584_macsec_find_flow(ctx, MACSEC_INGR); 87562306a36Sopenharmony_ci if (IS_ERR(flow)) 87662306a36Sopenharmony_ci return PTR_ERR(flow); 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci vsc8584_macsec_del_flow(ctx->phydev, flow); 87962306a36Sopenharmony_ci return 0; 88062306a36Sopenharmony_ci} 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_cistatic int vsc8584_macsec_add_txsa(struct macsec_context *ctx) 88362306a36Sopenharmony_ci{ 88462306a36Sopenharmony_ci struct phy_device *phydev = ctx->phydev; 88562306a36Sopenharmony_ci struct vsc8531_private *priv = phydev->priv; 88662306a36Sopenharmony_ci struct macsec_flow *flow; 88762306a36Sopenharmony_ci int ret; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci flow = vsc8584_macsec_alloc_flow(priv, MACSEC_EGR); 89062306a36Sopenharmony_ci if (IS_ERR(flow)) 89162306a36Sopenharmony_ci return PTR_ERR(flow); 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci ret = __vsc8584_macsec_add_txsa(ctx, flow, false); 89462306a36Sopenharmony_ci if (ret) 89562306a36Sopenharmony_ci return ret; 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci vsc8584_macsec_flow_enable(phydev, flow); 89862306a36Sopenharmony_ci return 0; 89962306a36Sopenharmony_ci} 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_cistatic int vsc8584_macsec_upd_txsa(struct macsec_context *ctx) 90262306a36Sopenharmony_ci{ 90362306a36Sopenharmony_ci struct macsec_flow *flow; 90462306a36Sopenharmony_ci int ret; 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci if (ctx->sa.update_pn) 90762306a36Sopenharmony_ci return -EINVAL; 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci flow = vsc8584_macsec_find_flow(ctx, MACSEC_EGR); 91062306a36Sopenharmony_ci if (IS_ERR(flow)) 91162306a36Sopenharmony_ci return PTR_ERR(flow); 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci /* Make sure the flow is disabled before updating it */ 91462306a36Sopenharmony_ci vsc8584_macsec_flow_disable(ctx->phydev, flow); 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci ret = __vsc8584_macsec_add_txsa(ctx, flow, true); 91762306a36Sopenharmony_ci if (ret) 91862306a36Sopenharmony_ci return ret; 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci vsc8584_macsec_flow_enable(ctx->phydev, flow); 92162306a36Sopenharmony_ci return 0; 92262306a36Sopenharmony_ci} 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_cistatic int vsc8584_macsec_del_txsa(struct macsec_context *ctx) 92562306a36Sopenharmony_ci{ 92662306a36Sopenharmony_ci struct macsec_flow *flow; 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci flow = vsc8584_macsec_find_flow(ctx, MACSEC_EGR); 92962306a36Sopenharmony_ci if (IS_ERR(flow)) 93062306a36Sopenharmony_ci return PTR_ERR(flow); 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci vsc8584_macsec_del_flow(ctx->phydev, flow); 93362306a36Sopenharmony_ci return 0; 93462306a36Sopenharmony_ci} 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_cistatic const struct macsec_ops vsc8584_macsec_ops = { 93762306a36Sopenharmony_ci .mdo_dev_open = vsc8584_macsec_dev_open, 93862306a36Sopenharmony_ci .mdo_dev_stop = vsc8584_macsec_dev_stop, 93962306a36Sopenharmony_ci .mdo_add_secy = vsc8584_macsec_add_secy, 94062306a36Sopenharmony_ci .mdo_upd_secy = vsc8584_macsec_upd_secy, 94162306a36Sopenharmony_ci .mdo_del_secy = vsc8584_macsec_del_secy, 94262306a36Sopenharmony_ci .mdo_add_rxsc = vsc8584_macsec_add_rxsc, 94362306a36Sopenharmony_ci .mdo_upd_rxsc = vsc8584_macsec_upd_rxsc, 94462306a36Sopenharmony_ci .mdo_del_rxsc = vsc8584_macsec_del_rxsc, 94562306a36Sopenharmony_ci .mdo_add_rxsa = vsc8584_macsec_add_rxsa, 94662306a36Sopenharmony_ci .mdo_upd_rxsa = vsc8584_macsec_upd_rxsa, 94762306a36Sopenharmony_ci .mdo_del_rxsa = vsc8584_macsec_del_rxsa, 94862306a36Sopenharmony_ci .mdo_add_txsa = vsc8584_macsec_add_txsa, 94962306a36Sopenharmony_ci .mdo_upd_txsa = vsc8584_macsec_upd_txsa, 95062306a36Sopenharmony_ci .mdo_del_txsa = vsc8584_macsec_del_txsa, 95162306a36Sopenharmony_ci}; 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ciint vsc8584_macsec_init(struct phy_device *phydev) 95462306a36Sopenharmony_ci{ 95562306a36Sopenharmony_ci struct vsc8531_private *vsc8531 = phydev->priv; 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci switch (phydev->phy_id & phydev->drv->phy_id_mask) { 95862306a36Sopenharmony_ci case PHY_ID_VSC856X: 95962306a36Sopenharmony_ci case PHY_ID_VSC8582: 96062306a36Sopenharmony_ci case PHY_ID_VSC8584: 96162306a36Sopenharmony_ci INIT_LIST_HEAD(&vsc8531->macsec_flows); 96262306a36Sopenharmony_ci vsc8531->secy = NULL; 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci phydev->macsec_ops = &vsc8584_macsec_ops; 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci return __vsc8584_macsec_init(phydev); 96762306a36Sopenharmony_ci } 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci return 0; 97062306a36Sopenharmony_ci} 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_civoid vsc8584_handle_macsec_interrupt(struct phy_device *phydev) 97362306a36Sopenharmony_ci{ 97462306a36Sopenharmony_ci struct vsc8531_private *priv = phydev->priv; 97562306a36Sopenharmony_ci struct macsec_flow *flow, *tmp; 97662306a36Sopenharmony_ci u32 cause, rec; 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci /* Check MACsec PN rollover */ 97962306a36Sopenharmony_ci cause = vsc8584_macsec_phy_read(phydev, MACSEC_EGR, 98062306a36Sopenharmony_ci MSCC_MS_INTR_CTRL_STATUS); 98162306a36Sopenharmony_ci cause &= MSCC_MS_INTR_CTRL_STATUS_INTR_CLR_STATUS_M; 98262306a36Sopenharmony_ci if (!(cause & MACSEC_INTR_CTRL_STATUS_ROLLOVER)) 98362306a36Sopenharmony_ci return; 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci rec = 6 + priv->secy->key_len / sizeof(u32); 98662306a36Sopenharmony_ci list_for_each_entry_safe(flow, tmp, &priv->macsec_flows, list) { 98762306a36Sopenharmony_ci u32 val; 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci if (flow->bank != MACSEC_EGR || !flow->has_transformation) 99062306a36Sopenharmony_ci continue; 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci val = vsc8584_macsec_phy_read(phydev, MACSEC_EGR, 99362306a36Sopenharmony_ci MSCC_MS_XFORM_REC(flow->index, rec)); 99462306a36Sopenharmony_ci if (val == 0xffffffff) { 99562306a36Sopenharmony_ci vsc8584_macsec_flow_disable(phydev, flow); 99662306a36Sopenharmony_ci macsec_pn_wrapped(priv->secy, flow->tx_sa); 99762306a36Sopenharmony_ci return; 99862306a36Sopenharmony_ci } 99962306a36Sopenharmony_ci } 100062306a36Sopenharmony_ci} 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_civoid vsc8584_config_macsec_intr(struct phy_device *phydev) 100362306a36Sopenharmony_ci{ 100462306a36Sopenharmony_ci phy_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED_2); 100562306a36Sopenharmony_ci phy_write(phydev, MSCC_PHY_EXTENDED_INT, MSCC_PHY_EXTENDED_INT_MS_EGR); 100662306a36Sopenharmony_ci phy_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD); 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, MACSEC_EGR, MSCC_MS_AIC_CTRL, 0xf); 100962306a36Sopenharmony_ci vsc8584_macsec_phy_write(phydev, MACSEC_EGR, MSCC_MS_INTR_CTRL_STATUS, 101062306a36Sopenharmony_ci MSCC_MS_INTR_CTRL_STATUS_INTR_ENABLE(MACSEC_INTR_CTRL_STATUS_ROLLOVER)); 101162306a36Sopenharmony_ci} 1012