linux/drivers/net/phy/mscc/mscc_macsec.c
<<
>>
Prefs
   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[MACSEC_MAX_KEY_LEN],
 505                                     u16 key_len, u8 hkey[16])
 506{
 507        const u8 input[AES_BLOCK_SIZE] = {0};
 508        struct crypto_aes_ctx ctx;
 509        int ret;
 510
 511        ret = aes_expandkey(&ctx, key, key_len);
 512        if (ret)
 513                return ret;
 514
 515        aes_encrypt(&ctx, hkey, input);
 516        memzero_explicit(&ctx, sizeof(ctx));
 517        return 0;
 518}
 519
 520static int vsc8584_macsec_transformation(struct phy_device *phydev,
 521                                         struct macsec_flow *flow)
 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(flow->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 *)flow->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 int vsc8584_macsec_add_flow(struct phy_device *phydev,
 639                                   struct macsec_flow *flow, bool update)
 640{
 641        int ret;
 642
 643        flow->port = MSCC_MS_PORT_CONTROLLED;
 644        vsc8584_macsec_flow(phydev, flow);
 645
 646        if (update)
 647                return 0;
 648
 649        ret = vsc8584_macsec_transformation(phydev, flow);
 650        if (ret) {
 651                vsc8584_macsec_free_flow(phydev->priv, flow);
 652                return ret;
 653        }
 654
 655        return 0;
 656}
 657
 658static int vsc8584_macsec_default_flows(struct phy_device *phydev)
 659{
 660        struct macsec_flow *flow;
 661
 662        /* Add a rule to let the MKA traffic go through, ingress */
 663        flow = vsc8584_macsec_alloc_flow(phydev->priv, MACSEC_INGR);
 664        if (IS_ERR(flow))
 665                return PTR_ERR(flow);
 666
 667        flow->priority = 15;
 668        flow->port = MSCC_MS_PORT_UNCONTROLLED;
 669        flow->match.tagged = 1;
 670        flow->match.untagged = 1;
 671        flow->match.etype = 1;
 672        flow->etype = ETH_P_PAE;
 673        flow->action.bypass = 1;
 674
 675        vsc8584_macsec_flow(phydev, flow);
 676        vsc8584_macsec_flow_enable(phydev, flow);
 677
 678        /* Add a rule to let the MKA traffic go through, egress */
 679        flow = vsc8584_macsec_alloc_flow(phydev->priv, MACSEC_EGR);
 680        if (IS_ERR(flow))
 681                return PTR_ERR(flow);
 682
 683        flow->priority = 15;
 684        flow->port = MSCC_MS_PORT_COMMON;
 685        flow->match.untagged = 1;
 686        flow->match.etype = 1;
 687        flow->etype = ETH_P_PAE;
 688        flow->action.bypass = 1;
 689
 690        vsc8584_macsec_flow(phydev, flow);
 691        vsc8584_macsec_flow_enable(phydev, flow);
 692
 693        return 0;
 694}
 695
 696static void vsc8584_macsec_del_flow(struct phy_device *phydev,
 697                                    struct macsec_flow *flow)
 698{
 699        vsc8584_macsec_flow_disable(phydev, flow);
 700        vsc8584_macsec_free_flow(phydev->priv, flow);
 701}
 702
 703static int __vsc8584_macsec_add_rxsa(struct macsec_context *ctx,
 704                                     struct macsec_flow *flow, bool update)
 705{
 706        struct phy_device *phydev = ctx->phydev;
 707        struct vsc8531_private *priv = phydev->priv;
 708
 709        if (!flow) {
 710                flow = vsc8584_macsec_alloc_flow(priv, MACSEC_INGR);
 711                if (IS_ERR(flow))
 712                        return PTR_ERR(flow);
 713
 714                memcpy(flow->key, ctx->sa.key, priv->secy->key_len);
 715        }
 716
 717        flow->assoc_num = ctx->sa.assoc_num;
 718        flow->rx_sa = ctx->sa.rx_sa;
 719
 720        /* Always match tagged packets on ingress */
 721        flow->match.tagged = 1;
 722        flow->match.sci = 1;
 723
 724        if (priv->secy->validate_frames != MACSEC_VALIDATE_DISABLED)
 725                flow->match.untagged = 1;
 726
 727        return vsc8584_macsec_add_flow(phydev, flow, update);
 728}
 729
 730static int __vsc8584_macsec_add_txsa(struct macsec_context *ctx,
 731                                     struct macsec_flow *flow, bool update)
 732{
 733        struct phy_device *phydev = ctx->phydev;
 734        struct vsc8531_private *priv = phydev->priv;
 735
 736        if (!flow) {
 737                flow = vsc8584_macsec_alloc_flow(priv, MACSEC_EGR);
 738                if (IS_ERR(flow))
 739                        return PTR_ERR(flow);
 740
 741                memcpy(flow->key, ctx->sa.key, priv->secy->key_len);
 742        }
 743
 744        flow->assoc_num = ctx->sa.assoc_num;
 745        flow->tx_sa = ctx->sa.tx_sa;
 746
 747        /* Always match untagged packets on egress */
 748        flow->match.untagged = 1;
 749
 750        return vsc8584_macsec_add_flow(phydev, flow, update);
 751}
 752
 753static int vsc8584_macsec_dev_open(struct macsec_context *ctx)
 754{
 755        struct vsc8531_private *priv = ctx->phydev->priv;
 756        struct macsec_flow *flow, *tmp;
 757
 758        /* No operation to perform before the commit step */
 759        if (ctx->prepare)
 760                return 0;
 761
 762        list_for_each_entry_safe(flow, tmp, &priv->macsec_flows, list)
 763                vsc8584_macsec_flow_enable(ctx->phydev, flow);
 764
 765        return 0;
 766}
 767
 768static int vsc8584_macsec_dev_stop(struct macsec_context *ctx)
 769{
 770        struct vsc8531_private *priv = ctx->phydev->priv;
 771        struct macsec_flow *flow, *tmp;
 772
 773        /* No operation to perform before the commit step */
 774        if (ctx->prepare)
 775                return 0;
 776
 777        list_for_each_entry_safe(flow, tmp, &priv->macsec_flows, list)
 778                vsc8584_macsec_flow_disable(ctx->phydev, flow);
 779
 780        return 0;
 781}
 782
 783static int vsc8584_macsec_add_secy(struct macsec_context *ctx)
 784{
 785        struct vsc8531_private *priv = ctx->phydev->priv;
 786        struct macsec_secy *secy = ctx->secy;
 787
 788        if (ctx->prepare) {
 789                if (priv->secy)
 790                        return -EEXIST;
 791
 792                return 0;
 793        }
 794
 795        priv->secy = secy;
 796
 797        vsc8584_macsec_flow_default_action(ctx->phydev, MACSEC_EGR,
 798                                           secy->validate_frames != MACSEC_VALIDATE_DISABLED);
 799        vsc8584_macsec_flow_default_action(ctx->phydev, MACSEC_INGR,
 800                                           secy->validate_frames != MACSEC_VALIDATE_DISABLED);
 801
 802        return vsc8584_macsec_default_flows(ctx->phydev);
 803}
 804
 805static int vsc8584_macsec_del_secy(struct macsec_context *ctx)
 806{
 807        struct vsc8531_private *priv = ctx->phydev->priv;
 808        struct macsec_flow *flow, *tmp;
 809
 810        /* No operation to perform before the commit step */
 811        if (ctx->prepare)
 812                return 0;
 813
 814        list_for_each_entry_safe(flow, tmp, &priv->macsec_flows, list)
 815                vsc8584_macsec_del_flow(ctx->phydev, flow);
 816
 817        vsc8584_macsec_flow_default_action(ctx->phydev, MACSEC_EGR, false);
 818        vsc8584_macsec_flow_default_action(ctx->phydev, MACSEC_INGR, false);
 819
 820        priv->secy = NULL;
 821        return 0;
 822}
 823
 824static int vsc8584_macsec_upd_secy(struct macsec_context *ctx)
 825{
 826        /* No operation to perform before the commit step */
 827        if (ctx->prepare)
 828                return 0;
 829
 830        vsc8584_macsec_del_secy(ctx);
 831        return vsc8584_macsec_add_secy(ctx);
 832}
 833
 834static int vsc8584_macsec_add_rxsc(struct macsec_context *ctx)
 835{
 836        /* Nothing to do */
 837        return 0;
 838}
 839
 840static int vsc8584_macsec_upd_rxsc(struct macsec_context *ctx)
 841{
 842        return -EOPNOTSUPP;
 843}
 844
 845static int vsc8584_macsec_del_rxsc(struct macsec_context *ctx)
 846{
 847        struct vsc8531_private *priv = ctx->phydev->priv;
 848        struct macsec_flow *flow, *tmp;
 849
 850        /* No operation to perform before the commit step */
 851        if (ctx->prepare)
 852                return 0;
 853
 854        list_for_each_entry_safe(flow, tmp, &priv->macsec_flows, list) {
 855                if (flow->bank == MACSEC_INGR && flow->rx_sa &&
 856                    flow->rx_sa->sc->sci == ctx->rx_sc->sci)
 857                        vsc8584_macsec_del_flow(ctx->phydev, flow);
 858        }
 859
 860        return 0;
 861}
 862
 863static int vsc8584_macsec_add_rxsa(struct macsec_context *ctx)
 864{
 865        struct macsec_flow *flow = NULL;
 866
 867        if (ctx->prepare)
 868                return __vsc8584_macsec_add_rxsa(ctx, flow, false);
 869
 870        flow = vsc8584_macsec_find_flow(ctx, MACSEC_INGR);
 871        if (IS_ERR(flow))
 872                return PTR_ERR(flow);
 873
 874        vsc8584_macsec_flow_enable(ctx->phydev, flow);
 875        return 0;
 876}
 877
 878static int vsc8584_macsec_upd_rxsa(struct macsec_context *ctx)
 879{
 880        struct macsec_flow *flow;
 881
 882        flow = vsc8584_macsec_find_flow(ctx, MACSEC_INGR);
 883        if (IS_ERR(flow))
 884                return PTR_ERR(flow);
 885
 886        if (ctx->prepare) {
 887                /* Make sure the flow is disabled before updating it */
 888                vsc8584_macsec_flow_disable(ctx->phydev, flow);
 889
 890                return __vsc8584_macsec_add_rxsa(ctx, flow, true);
 891        }
 892
 893        vsc8584_macsec_flow_enable(ctx->phydev, flow);
 894        return 0;
 895}
 896
 897static int vsc8584_macsec_del_rxsa(struct macsec_context *ctx)
 898{
 899        struct macsec_flow *flow;
 900
 901        flow = vsc8584_macsec_find_flow(ctx, MACSEC_INGR);
 902
 903        if (IS_ERR(flow))
 904                return PTR_ERR(flow);
 905        if (ctx->prepare)
 906                return 0;
 907
 908        vsc8584_macsec_del_flow(ctx->phydev, flow);
 909        return 0;
 910}
 911
 912static int vsc8584_macsec_add_txsa(struct macsec_context *ctx)
 913{
 914        struct macsec_flow *flow = NULL;
 915
 916        if (ctx->prepare)
 917                return __vsc8584_macsec_add_txsa(ctx, flow, false);
 918
 919        flow = vsc8584_macsec_find_flow(ctx, MACSEC_EGR);
 920        if (IS_ERR(flow))
 921                return PTR_ERR(flow);
 922
 923        vsc8584_macsec_flow_enable(ctx->phydev, flow);
 924        return 0;
 925}
 926
 927static int vsc8584_macsec_upd_txsa(struct macsec_context *ctx)
 928{
 929        struct macsec_flow *flow;
 930
 931        flow = vsc8584_macsec_find_flow(ctx, MACSEC_EGR);
 932        if (IS_ERR(flow))
 933                return PTR_ERR(flow);
 934
 935        if (ctx->prepare) {
 936                /* Make sure the flow is disabled before updating it */
 937                vsc8584_macsec_flow_disable(ctx->phydev, flow);
 938
 939                return __vsc8584_macsec_add_txsa(ctx, flow, true);
 940        }
 941
 942        vsc8584_macsec_flow_enable(ctx->phydev, flow);
 943        return 0;
 944}
 945
 946static int vsc8584_macsec_del_txsa(struct macsec_context *ctx)
 947{
 948        struct macsec_flow *flow;
 949
 950        flow = vsc8584_macsec_find_flow(ctx, MACSEC_EGR);
 951
 952        if (IS_ERR(flow))
 953                return PTR_ERR(flow);
 954        if (ctx->prepare)
 955                return 0;
 956
 957        vsc8584_macsec_del_flow(ctx->phydev, flow);
 958        return 0;
 959}
 960
 961static const struct macsec_ops vsc8584_macsec_ops = {
 962        .mdo_dev_open = vsc8584_macsec_dev_open,
 963        .mdo_dev_stop = vsc8584_macsec_dev_stop,
 964        .mdo_add_secy = vsc8584_macsec_add_secy,
 965        .mdo_upd_secy = vsc8584_macsec_upd_secy,
 966        .mdo_del_secy = vsc8584_macsec_del_secy,
 967        .mdo_add_rxsc = vsc8584_macsec_add_rxsc,
 968        .mdo_upd_rxsc = vsc8584_macsec_upd_rxsc,
 969        .mdo_del_rxsc = vsc8584_macsec_del_rxsc,
 970        .mdo_add_rxsa = vsc8584_macsec_add_rxsa,
 971        .mdo_upd_rxsa = vsc8584_macsec_upd_rxsa,
 972        .mdo_del_rxsa = vsc8584_macsec_del_rxsa,
 973        .mdo_add_txsa = vsc8584_macsec_add_txsa,
 974        .mdo_upd_txsa = vsc8584_macsec_upd_txsa,
 975        .mdo_del_txsa = vsc8584_macsec_del_txsa,
 976};
 977
 978int vsc8584_macsec_init(struct phy_device *phydev)
 979{
 980        struct vsc8531_private *vsc8531 = phydev->priv;
 981
 982        switch (phydev->phy_id & phydev->drv->phy_id_mask) {
 983        case PHY_ID_VSC856X:
 984        case PHY_ID_VSC8582:
 985        case PHY_ID_VSC8584:
 986                INIT_LIST_HEAD(&vsc8531->macsec_flows);
 987                vsc8531->secy = NULL;
 988
 989                phydev->macsec_ops = &vsc8584_macsec_ops;
 990
 991                return __vsc8584_macsec_init(phydev);
 992        }
 993
 994        return 0;
 995}
 996
 997void vsc8584_handle_macsec_interrupt(struct phy_device *phydev)
 998{
 999        struct vsc8531_private *priv = phydev->priv;
1000        struct macsec_flow *flow, *tmp;
1001        u32 cause, rec;
1002
1003        /* Check MACsec PN rollover */
1004        cause = vsc8584_macsec_phy_read(phydev, MACSEC_EGR,
1005                                        MSCC_MS_INTR_CTRL_STATUS);
1006        cause &= MSCC_MS_INTR_CTRL_STATUS_INTR_CLR_STATUS_M;
1007        if (!(cause & MACSEC_INTR_CTRL_STATUS_ROLLOVER))
1008                return;
1009
1010        rec = 6 + priv->secy->key_len / sizeof(u32);
1011        list_for_each_entry_safe(flow, tmp, &priv->macsec_flows, list) {
1012                u32 val;
1013
1014                if (flow->bank != MACSEC_EGR || !flow->has_transformation)
1015                        continue;
1016
1017                val = vsc8584_macsec_phy_read(phydev, MACSEC_EGR,
1018                                              MSCC_MS_XFORM_REC(flow->index, rec));
1019                if (val == 0xffffffff) {
1020                        vsc8584_macsec_flow_disable(phydev, flow);
1021                        macsec_pn_wrapped(priv->secy, flow->tx_sa);
1022                        return;
1023                }
1024        }
1025}
1026
1027void vsc8584_config_macsec_intr(struct phy_device *phydev)
1028{
1029        phy_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED_2);
1030        phy_write(phydev, MSCC_PHY_EXTENDED_INT, MSCC_PHY_EXTENDED_INT_MS_EGR);
1031        phy_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
1032
1033        vsc8584_macsec_phy_write(phydev, MACSEC_EGR, MSCC_MS_AIC_CTRL, 0xf);
1034        vsc8584_macsec_phy_write(phydev, MACSEC_EGR, MSCC_MS_INTR_CTRL_STATUS,
1035                                 MSCC_MS_INTR_CTRL_STATUS_INTR_ENABLE(MACSEC_INTR_CTRL_STATUS_ROLLOVER));
1036}
1037