[][Add macsec HW offload backport from kernel 5.18]

[Description]
Add macsec HW offload backport from kernel 5.18.

[Release-log]
N/A

Change-Id: I5b143fe620ec4bcae4075d1d85db5e41c8d48717
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/5981730
diff --git a/target/linux/mediatek/patches-5.4/999-1758-08-v5.18-net-phy-mscc-macsec-support.patch b/target/linux/mediatek/patches-5.4/999-1758-08-v5.18-net-phy-mscc-macsec-support.patch
new file mode 100644
index 0000000..9c7ea17
--- /dev/null
+++ b/target/linux/mediatek/patches-5.4/999-1758-08-v5.18-net-phy-mscc-macsec-support.patch
@@ -0,0 +1,786 @@
+From 28c5107aa904ef9db6b023039d20b6b4c4181675 Mon Sep 17 00:00:00 2001
+From: Antoine Tenart <antoine.tenart@bootlin.com>
+Date: Mon, 13 Jan 2020 23:31:46 +0100
+Subject: net: phy: mscc: macsec support
+
+This patch adds MACsec offloading support to some Microsemi PHYs, to
+configure flows and transformations so that matched packets can be
+processed by the MACsec engine, either at egress, or at ingress.
+
+Signed-off-by: Antoine Tenart <antoine.tenart@bootlin.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/phy/Kconfig       |   3 +
+ drivers/net/phy/mscc.c        | 691 ++++++++++++++++++++++++++++++++++++++++++
+ drivers/net/phy/mscc_macsec.h |   4 +
+ 3 files changed, 698 insertions(+)
+
+diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
+index 2e016271e1268..ac82ff959b7c0 100644
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -437,6 +437,9 @@ config MICROCHIP_T1_PHY
+ 
+ config MICROSEMI_PHY
+ 	tristate "Microsemi PHYs"
++	depends on MACSEC || MACSEC=n
++	select CRYPTO_AES
++	select CRYPTO_ECB
+ 	---help---
+ 	  Currently supports VSC8514, VSC8530, VSC8531, VSC8540 and VSC8541 PHYs
+ 
+diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c
+index 8579a59a1336a..ccf17818570f9 100644
+--- a/drivers/net/phy/mscc.c
++++ b/drivers/net/phy/mscc.c
+@@ -18,6 +18,13 @@
+ #include <linux/netdevice.h>
+ #include <dt-bindings/net/mscc-phy-vsc8531.h>
+ 
++#include <linux/scatterlist.h>
++#include <crypto/skcipher.h>
++
++#if IS_ENABLED(CONFIG_MACSEC)
++#include <net/macsec.h>
++#endif
++
+ #include "mscc_macsec.h"
+ #include "mscc_mac.h"
+ #include "mscc_fc_buffer.h"
+@@ -436,6 +443,44 @@ static const struct vsc85xx_hw_stat vsc8584_hw_stats[] = {
+ 	},
+ };
+ 
++#if IS_ENABLED(CONFIG_MACSEC)
++struct macsec_flow {
++	struct list_head list;
++	enum mscc_macsec_destination_ports port;
++	enum macsec_bank bank;
++	u32 index;
++	int assoc_num;
++	bool has_transformation;
++
++	/* Highest takes precedence [0..15] */
++	u8 priority;
++
++	u8 key[MACSEC_KEYID_LEN];
++
++	union {
++		struct macsec_rx_sa *rx_sa;
++		struct macsec_tx_sa *tx_sa;
++	};
++
++	/* Matching */
++	struct {
++		u8 sci:1;
++		u8 tagged:1;
++		u8 untagged:1;
++		u8 etype:1;
++	} match;
++
++	u16 etype;
++
++	/* Action */
++	struct {
++		u8 bypass:1;
++		u8 drop:1;
++	} action;
++
++};
++#endif
++
+ struct vsc8531_private {
+ 	int rate_magic;
+ 	u16 supp_led_modes;
+@@ -449,6 +494,19 @@ struct vsc8531_private {
+ 	 * package.
+ 	 */
+ 	unsigned int base_addr;
++
++#if IS_ENABLED(CONFIG_MACSEC)
++	/* MACsec fields:
++	 * - One SecY per device (enforced at the s/w implementation level)
++	 * - macsec_flows: list of h/w flows
++	 * - ingr_flows: bitmap of ingress flows
++	 * - egr_flows: bitmap of egress flows
++	 */
++	struct macsec_secy *secy;
++	struct list_head macsec_flows;
++	unsigned long ingr_flows;
++	unsigned long egr_flows;
++#endif
+ };
+ 
+ #ifdef CONFIG_OF_MDIO
+@@ -1951,6 +2009,634 @@ static int vsc8584_macsec_init(struct phy_device *phydev)
+ 
+ 	return 0;
+ }
++
++static void vsc8584_macsec_flow(struct phy_device *phydev,
++				struct macsec_flow *flow)
++{
++	struct vsc8531_private *priv = phydev->priv;
++	enum macsec_bank bank = flow->bank;
++	u32 val, match = 0, mask = 0, action = 0, idx = flow->index;
++
++	if (flow->match.tagged)
++		match |= MSCC_MS_SAM_MISC_MATCH_TAGGED;
++	if (flow->match.untagged)
++		match |= MSCC_MS_SAM_MISC_MATCH_UNTAGGED;
++
++	if (bank == MACSEC_INGR && flow->assoc_num >= 0) {
++		match |= MSCC_MS_SAM_MISC_MATCH_AN(flow->assoc_num);
++		mask |= MSCC_MS_SAM_MASK_AN_MASK(0x3);
++	}
++
++	if (bank == MACSEC_INGR && flow->match.sci && flow->rx_sa->sc->sci) {
++		match |= MSCC_MS_SAM_MISC_MATCH_TCI(BIT(3));
++		mask |= MSCC_MS_SAM_MASK_TCI_MASK(BIT(3)) |
++			MSCC_MS_SAM_MASK_SCI_MASK;
++
++		vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_MATCH_SCI_LO(idx),
++					 lower_32_bits(flow->rx_sa->sc->sci));
++		vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_MATCH_SCI_HI(idx),
++					 upper_32_bits(flow->rx_sa->sc->sci));
++	}
++
++	if (flow->match.etype) {
++		mask |= MSCC_MS_SAM_MASK_MAC_ETYPE_MASK;
++
++		vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_MAC_SA_MATCH_HI(idx),
++					 MSCC_MS_SAM_MAC_SA_MATCH_HI_ETYPE(htons(flow->etype)));
++	}
++
++	match |= MSCC_MS_SAM_MISC_MATCH_PRIORITY(flow->priority);
++
++	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_MISC_MATCH(idx), match);
++	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_MASK(idx), mask);
++
++	/* Action for matching packets */
++	if (flow->action.drop)
++		action = MSCC_MS_FLOW_DROP;
++	else if (flow->action.bypass || flow->port == MSCC_MS_PORT_UNCONTROLLED)
++		action = MSCC_MS_FLOW_BYPASS;
++	else
++		action = (bank == MACSEC_INGR) ?
++			 MSCC_MS_FLOW_INGRESS : MSCC_MS_FLOW_EGRESS;
++
++	val = MSCC_MS_SAM_FLOW_CTRL_FLOW_TYPE(action) |
++	      MSCC_MS_SAM_FLOW_CTRL_DROP_ACTION(MSCC_MS_ACTION_DROP) |
++	      MSCC_MS_SAM_FLOW_CTRL_DEST_PORT(flow->port);
++
++	if (action == MSCC_MS_FLOW_BYPASS)
++		goto write_ctrl;
++
++	if (bank == MACSEC_INGR) {
++		if (priv->secy->replay_protect)
++			val |= MSCC_MS_SAM_FLOW_CTRL_REPLAY_PROTECT;
++		if (priv->secy->validate_frames == MACSEC_VALIDATE_STRICT)
++			val |= MSCC_MS_SAM_FLOW_CTRL_VALIDATE_FRAMES(MSCC_MS_VALIDATE_STRICT);
++		else if (priv->secy->validate_frames == MACSEC_VALIDATE_CHECK)
++			val |= MSCC_MS_SAM_FLOW_CTRL_VALIDATE_FRAMES(MSCC_MS_VALIDATE_CHECK);
++	} else if (bank == MACSEC_EGR) {
++		if (priv->secy->protect_frames)
++			val |= MSCC_MS_SAM_FLOW_CTRL_PROTECT_FRAME;
++		if (priv->secy->tx_sc.encrypt)
++			val |= MSCC_MS_SAM_FLOW_CTRL_CONF_PROTECT;
++		if (priv->secy->tx_sc.send_sci)
++			val |= MSCC_MS_SAM_FLOW_CTRL_INCLUDE_SCI;
++	}
++
++write_ctrl:
++	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_FLOW_CTRL(idx), val);
++}
++
++static struct macsec_flow *vsc8584_macsec_find_flow(struct macsec_context *ctx,
++						    enum macsec_bank bank)
++{
++	struct vsc8531_private *priv = ctx->phydev->priv;
++	struct macsec_flow *pos, *tmp;
++
++	list_for_each_entry_safe(pos, tmp, &priv->macsec_flows, list)
++		if (pos->assoc_num == ctx->sa.assoc_num && pos->bank == bank)
++			return pos;
++
++	return ERR_PTR(-ENOENT);
++}
++
++static void vsc8584_macsec_flow_enable(struct phy_device *phydev,
++				       struct macsec_flow *flow)
++{
++	enum macsec_bank bank = flow->bank;
++	u32 val, idx = flow->index;
++
++	if ((flow->bank == MACSEC_INGR && flow->rx_sa && !flow->rx_sa->active) ||
++	    (flow->bank == MACSEC_EGR && flow->tx_sa && !flow->tx_sa->active))
++		return;
++
++	/* Enable */
++	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_ENTRY_SET1, BIT(idx));
++
++	/* Set in-use */
++	val = vsc8584_macsec_phy_read(phydev, bank, MSCC_MS_SAM_FLOW_CTRL(idx));
++	val |= MSCC_MS_SAM_FLOW_CTRL_SA_IN_USE;
++	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_FLOW_CTRL(idx), val);
++}
++
++static void vsc8584_macsec_flow_disable(struct phy_device *phydev,
++					struct macsec_flow *flow)
++{
++	enum macsec_bank bank = flow->bank;
++	u32 val, idx = flow->index;
++
++	/* Disable */
++	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_ENTRY_CLEAR1, BIT(idx));
++
++	/* Clear in-use */
++	val = vsc8584_macsec_phy_read(phydev, bank, MSCC_MS_SAM_FLOW_CTRL(idx));
++	val &= ~MSCC_MS_SAM_FLOW_CTRL_SA_IN_USE;
++	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_FLOW_CTRL(idx), val);
++}
++
++static u32 vsc8584_macsec_flow_context_id(struct macsec_flow *flow)
++{
++	if (flow->bank == MACSEC_INGR)
++		return flow->index + MSCC_MS_MAX_FLOWS;
++
++	return flow->index;
++}
++
++/* Derive the AES key to get a key for the hash autentication */
++static int vsc8584_macsec_derive_key(const u8 key[MACSEC_KEYID_LEN],
++				     u16 key_len, u8 hkey[16])
++{
++	struct crypto_skcipher *tfm = crypto_alloc_skcipher("ecb(aes)", 0, 0);
++	struct skcipher_request *req = NULL;
++	struct scatterlist src, dst;
++	DECLARE_CRYPTO_WAIT(wait);
++	u32 input[4] = {0};
++	int ret;
++
++	if (IS_ERR(tfm))
++		return PTR_ERR(tfm);
++
++	req = skcipher_request_alloc(tfm, GFP_KERNEL);
++	if (!req) {
++		ret = -ENOMEM;
++		goto out;
++	}
++
++	skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |
++				      CRYPTO_TFM_REQ_MAY_SLEEP, crypto_req_done,
++				      &wait);
++	ret = crypto_skcipher_setkey(tfm, key, key_len);
++	if (ret < 0)
++		goto out;
++
++	sg_init_one(&src, input, 16);
++	sg_init_one(&dst, hkey, 16);
++	skcipher_request_set_crypt(req, &src, &dst, 16, NULL);
++
++	ret = crypto_wait_req(crypto_skcipher_encrypt(req), &wait);
++
++out:
++	skcipher_request_free(req);
++	crypto_free_skcipher(tfm);
++	return ret;
++}
++
++static int vsc8584_macsec_transformation(struct phy_device *phydev,
++					 struct macsec_flow *flow)
++{
++	struct vsc8531_private *priv = phydev->priv;
++	enum macsec_bank bank = flow->bank;
++	int i, ret, index = flow->index;
++	u32 rec = 0, control = 0;
++	u8 hkey[16];
++	sci_t sci;
++
++	ret = vsc8584_macsec_derive_key(flow->key, priv->secy->key_len, hkey);
++	if (ret)
++		return ret;
++
++	switch (priv->secy->key_len) {
++	case 16:
++		control |= CONTROL_CRYPTO_ALG(CTRYPTO_ALG_AES_CTR_128);
++		break;
++	case 32:
++		control |= CONTROL_CRYPTO_ALG(CTRYPTO_ALG_AES_CTR_256);
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	control |= (bank == MACSEC_EGR) ?
++		   (CONTROL_TYPE_EGRESS | CONTROL_AN(priv->secy->tx_sc.encoding_sa)) :
++		   (CONTROL_TYPE_INGRESS | CONTROL_SEQ_MASK);
++
++	control |= CONTROL_UPDATE_SEQ | CONTROL_ENCRYPT_AUTH | CONTROL_KEY_IN_CTX |
++		   CONTROL_IV0 | CONTROL_IV1 | CONTROL_IV_IN_SEQ |
++		   CONTROL_DIGEST_TYPE(0x2) | CONTROL_SEQ_TYPE(0x1) |
++		   CONTROL_AUTH_ALG(AUTH_ALG_AES_GHAS) | CONTROL_CONTEXT_ID;
++
++	/* Set the control word */
++	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_XFORM_REC(index, rec++),
++				 control);
++
++	/* Set the context ID. Must be unique. */
++	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_XFORM_REC(index, rec++),
++				 vsc8584_macsec_flow_context_id(flow));
++
++	/* Set the encryption/decryption key */
++	for (i = 0; i < priv->secy->key_len / sizeof(u32); i++)
++		vsc8584_macsec_phy_write(phydev, bank,
++					 MSCC_MS_XFORM_REC(index, rec++),
++					 ((u32 *)flow->key)[i]);
++
++	/* Set the authentication key */
++	for (i = 0; i < 4; i++)
++		vsc8584_macsec_phy_write(phydev, bank,
++					 MSCC_MS_XFORM_REC(index, rec++),
++					 ((u32 *)hkey)[i]);
++
++	/* Initial sequence number */
++	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_XFORM_REC(index, rec++),
++				 bank == MACSEC_INGR ?
++				 flow->rx_sa->next_pn : flow->tx_sa->next_pn);
++
++	if (bank == MACSEC_INGR)
++		/* Set the mask (replay window size) */
++		vsc8584_macsec_phy_write(phydev, bank,
++					 MSCC_MS_XFORM_REC(index, rec++),
++					 priv->secy->replay_window);
++
++	/* Set the input vectors */
++	sci = bank == MACSEC_INGR ? flow->rx_sa->sc->sci : priv->secy->sci;
++	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_XFORM_REC(index, rec++),
++				 lower_32_bits(sci));
++	vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_XFORM_REC(index, rec++),
++				 upper_32_bits(sci));
++
++	while (rec < 20)
++		vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_XFORM_REC(index, rec++),
++					 0);
++
++	flow->has_transformation = true;
++	return 0;
++}
++
++static struct macsec_flow *vsc8584_macsec_alloc_flow(struct vsc8531_private *priv,
++						     enum macsec_bank bank)
++{
++	unsigned long *bitmap = bank == MACSEC_INGR ?
++				&priv->ingr_flows : &priv->egr_flows;
++	struct macsec_flow *flow;
++	int index;
++
++	index = find_first_zero_bit(bitmap, MSCC_MS_MAX_FLOWS);
++
++	if (index == MSCC_MS_MAX_FLOWS)
++		return ERR_PTR(-ENOMEM);
++
++	flow = kzalloc(sizeof(*flow), GFP_KERNEL);
++	if (!flow)
++		return ERR_PTR(-ENOMEM);
++
++	set_bit(index, bitmap);
++	flow->index = index;
++	flow->bank = bank;
++	flow->priority = 8;
++	flow->assoc_num = -1;
++
++	list_add_tail(&flow->list, &priv->macsec_flows);
++	return flow;
++}
++
++static void vsc8584_macsec_free_flow(struct vsc8531_private *priv,
++				     struct macsec_flow *flow)
++{
++	unsigned long *bitmap = flow->bank == MACSEC_INGR ?
++				&priv->ingr_flows : &priv->egr_flows;
++
++	list_del(&flow->list);
++	clear_bit(flow->index, bitmap);
++	kfree(flow);
++}
++
++static int vsc8584_macsec_add_flow(struct phy_device *phydev,
++				   struct macsec_flow *flow, bool update)
++{
++	int ret;
++
++	flow->port = MSCC_MS_PORT_CONTROLLED;
++	vsc8584_macsec_flow(phydev, flow);
++
++	if (update)
++		return 0;
++
++	ret = vsc8584_macsec_transformation(phydev, flow);
++	if (ret) {
++		vsc8584_macsec_free_flow(phydev->priv, flow);
++		return ret;
++	}
++
++	return 0;
++}
++
++static int vsc8584_macsec_default_flows(struct phy_device *phydev)
++{
++	struct macsec_flow *flow;
++
++	/* Add a rule to let the MKA traffic go through, ingress */
++	flow = vsc8584_macsec_alloc_flow(phydev->priv, MACSEC_INGR);
++	if (IS_ERR(flow))
++		return PTR_ERR(flow);
++
++	flow->priority = 15;
++	flow->port = MSCC_MS_PORT_UNCONTROLLED;
++	flow->match.tagged = 1;
++	flow->match.untagged = 1;
++	flow->match.etype = 1;
++	flow->etype = ETH_P_PAE;
++	flow->action.bypass = 1;
++
++	vsc8584_macsec_flow(phydev, flow);
++	vsc8584_macsec_flow_enable(phydev, flow);
++
++	/* Add a rule to let the MKA traffic go through, egress */
++	flow = vsc8584_macsec_alloc_flow(phydev->priv, MACSEC_EGR);
++	if (IS_ERR(flow))
++		return PTR_ERR(flow);
++
++	flow->priority = 15;
++	flow->port = MSCC_MS_PORT_COMMON;
++	flow->match.untagged = 1;
++	flow->match.etype = 1;
++	flow->etype = ETH_P_PAE;
++	flow->action.bypass = 1;
++
++	vsc8584_macsec_flow(phydev, flow);
++	vsc8584_macsec_flow_enable(phydev, flow);
++
++	return 0;
++}
++
++static void vsc8584_macsec_del_flow(struct phy_device *phydev,
++				    struct macsec_flow *flow)
++{
++	vsc8584_macsec_flow_disable(phydev, flow);
++	vsc8584_macsec_free_flow(phydev->priv, flow);
++}
++
++static int __vsc8584_macsec_add_rxsa(struct macsec_context *ctx,
++				     struct macsec_flow *flow, bool update)
++{
++	struct phy_device *phydev = ctx->phydev;
++	struct vsc8531_private *priv = phydev->priv;
++
++	if (!flow) {
++		flow = vsc8584_macsec_alloc_flow(priv, MACSEC_INGR);
++		if (IS_ERR(flow))
++			return PTR_ERR(flow);
++
++		memcpy(flow->key, ctx->sa.key, priv->secy->key_len);
++	}
++
++	flow->assoc_num = ctx->sa.assoc_num;
++	flow->rx_sa = ctx->sa.rx_sa;
++
++	/* Always match tagged packets on ingress */
++	flow->match.tagged = 1;
++	flow->match.sci = 1;
++
++	if (priv->secy->validate_frames != MACSEC_VALIDATE_DISABLED)
++		flow->match.untagged = 1;
++
++	return vsc8584_macsec_add_flow(phydev, flow, update);
++}
++
++static int __vsc8584_macsec_add_txsa(struct macsec_context *ctx,
++				     struct macsec_flow *flow, bool update)
++{
++	struct phy_device *phydev = ctx->phydev;
++	struct vsc8531_private *priv = phydev->priv;
++
++	if (!flow) {
++		flow = vsc8584_macsec_alloc_flow(priv, MACSEC_EGR);
++		if (IS_ERR(flow))
++			return PTR_ERR(flow);
++
++		memcpy(flow->key, ctx->sa.key, priv->secy->key_len);
++	}
++
++	flow->assoc_num = ctx->sa.assoc_num;
++	flow->tx_sa = ctx->sa.tx_sa;
++
++	/* Always match untagged packets on egress */
++	flow->match.untagged = 1;
++
++	return vsc8584_macsec_add_flow(phydev, flow, update);
++}
++
++static int vsc8584_macsec_dev_open(struct macsec_context *ctx)
++{
++	struct vsc8531_private *priv = ctx->phydev->priv;
++	struct macsec_flow *flow, *tmp;
++
++	/* No operation to perform before the commit step */
++	if (ctx->prepare)
++		return 0;
++
++	list_for_each_entry_safe(flow, tmp, &priv->macsec_flows, list)
++		vsc8584_macsec_flow_enable(ctx->phydev, flow);
++
++	return 0;
++}
++
++static int vsc8584_macsec_dev_stop(struct macsec_context *ctx)
++{
++	struct vsc8531_private *priv = ctx->phydev->priv;
++	struct macsec_flow *flow, *tmp;
++
++	/* No operation to perform before the commit step */
++	if (ctx->prepare)
++		return 0;
++
++	list_for_each_entry_safe(flow, tmp, &priv->macsec_flows, list)
++		vsc8584_macsec_flow_disable(ctx->phydev, flow);
++
++	return 0;
++}
++
++static int vsc8584_macsec_add_secy(struct macsec_context *ctx)
++{
++	struct vsc8531_private *priv = ctx->phydev->priv;
++	struct macsec_secy *secy = ctx->secy;
++
++	if (ctx->prepare) {
++		if (priv->secy)
++			return -EEXIST;
++
++		return 0;
++	}
++
++	priv->secy = secy;
++
++	vsc8584_macsec_flow_default_action(ctx->phydev, MACSEC_EGR,
++					   secy->validate_frames != MACSEC_VALIDATE_DISABLED);
++	vsc8584_macsec_flow_default_action(ctx->phydev, MACSEC_INGR,
++					   secy->validate_frames != MACSEC_VALIDATE_DISABLED);
++
++	return vsc8584_macsec_default_flows(ctx->phydev);
++}
++
++static int vsc8584_macsec_del_secy(struct macsec_context *ctx)
++{
++	struct vsc8531_private *priv = ctx->phydev->priv;
++	struct macsec_flow *flow, *tmp;
++
++	/* No operation to perform before the commit step */
++	if (ctx->prepare)
++		return 0;
++
++	list_for_each_entry_safe(flow, tmp, &priv->macsec_flows, list)
++		vsc8584_macsec_del_flow(ctx->phydev, flow);
++
++	vsc8584_macsec_flow_default_action(ctx->phydev, MACSEC_EGR, false);
++	vsc8584_macsec_flow_default_action(ctx->phydev, MACSEC_INGR, false);
++
++	priv->secy = NULL;
++	return 0;
++}
++
++static int vsc8584_macsec_upd_secy(struct macsec_context *ctx)
++{
++	/* No operation to perform before the commit step */
++	if (ctx->prepare)
++		return 0;
++
++	vsc8584_macsec_del_secy(ctx);
++	return vsc8584_macsec_add_secy(ctx);
++}
++
++static int vsc8584_macsec_add_rxsc(struct macsec_context *ctx)
++{
++	/* Nothing to do */
++	return 0;
++}
++
++static int vsc8584_macsec_upd_rxsc(struct macsec_context *ctx)
++{
++	return -EOPNOTSUPP;
++}
++
++static int vsc8584_macsec_del_rxsc(struct macsec_context *ctx)
++{
++	struct vsc8531_private *priv = ctx->phydev->priv;
++	struct macsec_flow *flow, *tmp;
++
++	/* No operation to perform before the commit step */
++	if (ctx->prepare)
++		return 0;
++
++	list_for_each_entry_safe(flow, tmp, &priv->macsec_flows, list) {
++		if (flow->bank == MACSEC_INGR && flow->rx_sa &&
++		    flow->rx_sa->sc->sci == ctx->rx_sc->sci)
++			vsc8584_macsec_del_flow(ctx->phydev, flow);
++	}
++
++	return 0;
++}
++
++static int vsc8584_macsec_add_rxsa(struct macsec_context *ctx)
++{
++	struct macsec_flow *flow = NULL;
++
++	if (ctx->prepare)
++		return __vsc8584_macsec_add_rxsa(ctx, flow, false);
++
++	flow = vsc8584_macsec_find_flow(ctx, MACSEC_INGR);
++	if (IS_ERR(flow))
++		return PTR_ERR(flow);
++
++	vsc8584_macsec_flow_enable(ctx->phydev, flow);
++	return 0;
++}
++
++static int vsc8584_macsec_upd_rxsa(struct macsec_context *ctx)
++{
++	struct macsec_flow *flow;
++
++	flow = vsc8584_macsec_find_flow(ctx, MACSEC_INGR);
++	if (IS_ERR(flow))
++		return PTR_ERR(flow);
++
++	if (ctx->prepare) {
++		/* Make sure the flow is disabled before updating it */
++		vsc8584_macsec_flow_disable(ctx->phydev, flow);
++
++		return __vsc8584_macsec_add_rxsa(ctx, flow, true);
++	}
++
++	vsc8584_macsec_flow_enable(ctx->phydev, flow);
++	return 0;
++}
++
++static int vsc8584_macsec_del_rxsa(struct macsec_context *ctx)
++{
++	struct macsec_flow *flow;
++
++	flow = vsc8584_macsec_find_flow(ctx, MACSEC_INGR);
++
++	if (IS_ERR(flow))
++		return PTR_ERR(flow);
++	if (ctx->prepare)
++		return 0;
++
++	vsc8584_macsec_del_flow(ctx->phydev, flow);
++	return 0;
++}
++
++static int vsc8584_macsec_add_txsa(struct macsec_context *ctx)
++{
++	struct macsec_flow *flow = NULL;
++
++	if (ctx->prepare)
++		return __vsc8584_macsec_add_txsa(ctx, flow, false);
++
++	flow = vsc8584_macsec_find_flow(ctx, MACSEC_EGR);
++	if (IS_ERR(flow))
++		return PTR_ERR(flow);
++
++	vsc8584_macsec_flow_enable(ctx->phydev, flow);
++	return 0;
++}
++
++static int vsc8584_macsec_upd_txsa(struct macsec_context *ctx)
++{
++	struct macsec_flow *flow;
++
++	flow = vsc8584_macsec_find_flow(ctx, MACSEC_EGR);
++	if (IS_ERR(flow))
++		return PTR_ERR(flow);
++
++	if (ctx->prepare) {
++		/* Make sure the flow is disabled before updating it */
++		vsc8584_macsec_flow_disable(ctx->phydev, flow);
++
++		return __vsc8584_macsec_add_txsa(ctx, flow, true);
++	}
++
++	vsc8584_macsec_flow_enable(ctx->phydev, flow);
++	return 0;
++}
++
++static int vsc8584_macsec_del_txsa(struct macsec_context *ctx)
++{
++	struct macsec_flow *flow;
++
++	flow = vsc8584_macsec_find_flow(ctx, MACSEC_EGR);
++
++	if (IS_ERR(flow))
++		return PTR_ERR(flow);
++	if (ctx->prepare)
++		return 0;
++
++	vsc8584_macsec_del_flow(ctx->phydev, flow);
++	return 0;
++}
++
++static struct macsec_ops vsc8584_macsec_ops = {
++	.mdo_dev_open = vsc8584_macsec_dev_open,
++	.mdo_dev_stop = vsc8584_macsec_dev_stop,
++	.mdo_add_secy = vsc8584_macsec_add_secy,
++	.mdo_upd_secy = vsc8584_macsec_upd_secy,
++	.mdo_del_secy = vsc8584_macsec_del_secy,
++	.mdo_add_rxsc = vsc8584_macsec_add_rxsc,
++	.mdo_upd_rxsc = vsc8584_macsec_upd_rxsc,
++	.mdo_del_rxsc = vsc8584_macsec_del_rxsc,
++	.mdo_add_rxsa = vsc8584_macsec_add_rxsa,
++	.mdo_upd_rxsa = vsc8584_macsec_upd_rxsa,
++	.mdo_del_rxsa = vsc8584_macsec_del_rxsa,
++	.mdo_add_txsa = vsc8584_macsec_add_txsa,
++	.mdo_upd_txsa = vsc8584_macsec_upd_txsa,
++	.mdo_del_txsa = vsc8584_macsec_del_txsa,
++};
+ #endif /* CONFIG_MACSEC */
+ 
+ /* Check if one PHY has already done the init of the parts common to all PHYs
+@@ -2109,6 +2795,11 @@ static int vsc8584_config_init(struct phy_device *phydev)
+ 	case PHY_ID_VSC8575:
+ 	case PHY_ID_VSC8582:
+ 	case PHY_ID_VSC8584:
++		INIT_LIST_HEAD(&vsc8531->macsec_flows);
++		vsc8531->secy = NULL;
++
++		phydev->macsec_ops = &vsc8584_macsec_ops;
++
+ 		ret = vsc8584_macsec_init(phydev);
+ 		if (ret)
+ 			goto err;
+diff --git a/drivers/net/phy/mscc_macsec.h b/drivers/net/phy/mscc_macsec.h
+index 0d108da28dad2..9b5d0af91d204 100644
+--- a/drivers/net/phy/mscc_macsec.h
++++ b/drivers/net/phy/mscc_macsec.h
+@@ -8,6 +8,8 @@
+ #ifndef _MSCC_OCELOT_MACSEC_H_
+ #define _MSCC_OCELOT_MACSEC_H_
+ 
++#define MSCC_MS_MAX_FLOWS		16
++
+ #define CONTROL_TYPE_EGRESS		0x6
+ #define CONTROL_TYPE_INGRESS		0xf
+ #define CONTROL_IV0			BIT(5)
+@@ -59,6 +61,8 @@ enum mscc_macsec_validate_levels {
+ #define MSCC_MS_XFORM_REC(x, y)		(((x) << 5) + (y))
+ #define MSCC_MS_ENA_CFG			0x800
+ #define MSCC_MS_FC_CFG			0x804
++#define MSCC_MS_SAM_MAC_SA_MATCH_LO(x)	(0x1000 + ((x) << 4))
++#define MSCC_MS_SAM_MAC_SA_MATCH_HI(x)	(0x1001 + ((x) << 4))
+ #define MSCC_MS_SAM_MISC_MATCH(x)	(0x1004 + ((x) << 4))
+ #define MSCC_MS_SAM_MATCH_SCI_LO(x)	(0x1005 + ((x) << 4))
+ #define MSCC_MS_SAM_MATCH_SCI_HI(x)	(0x1006 + ((x) << 4))
+-- 
+cgit 1.2.3-1.el7
+