2019-01-23 16:00:32

by Antoine Tenart

[permalink] [raw]
Subject: [PATCH net-next 00/10] net: macsec: initial support for hardware offloading

Hello,

This series intends to add support for offloading MACsec transformations
in hardware enabled devices. The series is divided in two parts: the
first 7 patches add the infrastructure support to offload a MACsec
configuration to hardware drivers; and the last 3 patches introduce the
MACsec offloading support in the Microsemi Ocelot networking PHY, making
it the first driver to support the MACsec hardware offloading feature.

The series can also be found at:
https://github.com/atenart/linux/tree/net-next/macsec

If you think I'm missing anyone who would be interested in
participating to the discussion please feel free to Cc them and I'll add
them to the Cc list for the next iteration.

MACsec hardware offloading infrastructure
-----------------------------------------

Linux has a software implementation of the MACsec standard and so far no
hardware offloading feature was developed and submitted. Some hardware
engines can perform MACsec operations, such as the Intel ixgbe NIC and
the Microsemi Ocelot PHY (the one we use in this series). This means the
MACsec offloading infrastructure should support networking PHY and
Ethernet drivers. A preliminary email[1] was sent about this.

The main idea here is to re-use the logic and data structures of the
software MACsec implementation. This allows not to duplicate definitions
and structure storing the same kind of information. It also allows to
use a unified genlink interface for both MACsec implementations (so that
the same userspace tool, `ip macsec`, is used with the same arguments).
The MACsec offloading support cannot be disabled if an interface
supports it at the moment, but this could be implemented later on if
this is a need (we could think of something like
`ip macsec set macsec0 offloading off`).

The MACsec configuration is passed to device drivers supporting it
through macsec_hw_offload() which is called (indirectly) from the MACsec
genl helpers. This function calls the macsec() ops of PHY and Ethernet
drivers in two steps: a preparation one, and a commit one. The first
step is allowed to fail and should be used to check if a provided
configuration is compatible with the features provided by a MACsec
engine, while the second step is not allowed to fail and should only be
used to enable a given MACsec configuration. Two extra calls are made:
when a virtual MACsec interface is created and when it is deleted, so
that the hardware driver can stay in sync.

The Rx and TX handlers are modified to take in account the special case
were the MACsec transformation happens in the hardware, whether in a PHY
or in a MAC, as the packets seen by the networking stack on both the
physical and MACsec virtual interface are exactly the same. This leads
to some limitations: the hardware and software implementations can't be
used on the same physical interface, as the policies would be impossible
to fulfill (such as strict validation of the frames). Also only a single
virtual MACsec interface can be attached to a physical port supporting
hardware offloading as it would be impossible to guess onto which
interface a given packet should go (for ingress traffic).

Another limitation as of now is that the counters and statistics are not
reported back from the hardware to the software MACsec implementation.
This isn't an issue when using offloaded MACsec transformations, but it
should be added in the future so that the MACsec state can be reported
to the user (which would also improve the debug).

[1] https://www.spinics.net/lists/netdev/msg513047.html

Microsemi Ocelot PHY MACsec support
-----------------------------------

In order to add support for the MACsec offloading feature in the
Microsemi Ocelot driver, the __phy_read_page and __phy_write_page
helpers had to be exported. This is because the initialization of the
PHY is done while holding the MDIO bus lock, and we need to change the
page to configure the MACsec block.

The support itself is then added in two patches. The first one adds
support for configuring the MACsec block within the PHY, so that it is
up, running and available for future configuration, but is not doing any
modification on the traffic passing through the PHY. The second patch
implements the phy_driver macsec() helper in the Microsemi Ocelot PHY
driver, and introduce helpers to configure MACsec transformations and
flows to match specific packets.

Comments are of course welcomed. Thanks!
Antoine

Antoine Tenart (10):
net: introduce the MACSEC netdev feature
net: macsec: convert to SPDX
net: macsec: move some definitions in a dedicated header
net: macsec: introduce the netdev_macsec structure
net: phy: introduce a phy_driver macsec helper
net: introduce a net_device_ops macsec helper
net: macsec: hardware offloading infrastructure
net: phy: export __phy_read_page/__phy_write_page
net: phy: mscc: macsec initialization
net: phy: mscc: macsec support

drivers/net/macsec.c | 466 +++++++++------
drivers/net/phy/Kconfig | 2 +
drivers/net/phy/mscc.c | 960 +++++++++++++++++++++++++++++++
drivers/net/phy/mscc_fc_buffer.h | 64 +++
drivers/net/phy/mscc_mac.h | 159 +++++
drivers/net/phy/mscc_macsec.h | 258 +++++++++
drivers/net/phy/phy-core.c | 6 +-
drivers/net/phy/phy.c | 17 +
include/linux/netdev_features.h | 3 +
include/linux/netdevice.h | 8 +
include/linux/phy.h | 12 +
include/net/macsec.h | 223 +++++++
net/core/ethtool.c | 1 +
13 files changed, 1996 insertions(+), 183 deletions(-)
create mode 100644 drivers/net/phy/mscc_fc_buffer.h
create mode 100644 drivers/net/phy/mscc_mac.h
create mode 100644 drivers/net/phy/mscc_macsec.h
create mode 100644 include/net/macsec.h

--
2.20.1



2019-01-23 16:00:50

by Antoine Tenart

[permalink] [raw]
Subject: [PATCH net-next 01/10] net: introduce the MACSEC netdev feature

This patch introduce a new netdev feature, which will be used by drivers
to state they can perform MACsec transformations in hardware.

Signed-off-by: Antoine Tenart <[email protected]>
---
include/linux/netdev_features.h | 3 +++
net/core/ethtool.c | 1 +
2 files changed, 4 insertions(+)

diff --git a/include/linux/netdev_features.h b/include/linux/netdev_features.h
index 2b2a6dce1630..f278da0f03cd 100644
--- a/include/linux/netdev_features.h
+++ b/include/linux/netdev_features.h
@@ -84,6 +84,8 @@ enum {
NETIF_F_GRO_HW_BIT, /* Hardware Generic receive offload */
NETIF_F_HW_TLS_RECORD_BIT, /* Offload TLS record */

+ NETIF_F_HW_MACSEC_BIT, /* Offload MACsec operations */
+
/*
* Add your fresh new feature above and remember to update
* netdev_features_strings[] in net/core/ethtool.c and maybe
@@ -153,6 +155,7 @@ enum {
#define NETIF_F_GSO_UDP_L4 __NETIF_F(GSO_UDP_L4)
#define NETIF_F_HW_TLS_TX __NETIF_F(HW_TLS_TX)
#define NETIF_F_HW_TLS_RX __NETIF_F(HW_TLS_RX)
+#define NETIF_F_HW_MACSEC __NETIF_F(HW_MACSEC)

#define for_each_netdev_feature(mask_addr, bit) \
for_each_set_bit(bit, (unsigned long *)mask_addr, NETDEV_FEATURE_COUNT)
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 158264f7cfaf..c43f281db758 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -113,6 +113,7 @@ static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN]
[NETIF_F_HW_TLS_RECORD_BIT] = "tls-hw-record",
[NETIF_F_HW_TLS_TX_BIT] = "tls-hw-tx-offload",
[NETIF_F_HW_TLS_RX_BIT] = "tls-hw-rx-offload",
+ [NETIF_F_HW_MACSEC_BIT] = "macsec-hw-offload",
};

static const char
--
2.20.1


2019-01-23 16:01:07

by Antoine Tenart

[permalink] [raw]
Subject: [PATCH net-next 05/10] net: phy: introduce a phy_driver macsec helper

This patch introduces a phy_driver MACsec helper to allow PHYs to
implement a MACsec offloading solution. The phy_driver MACsec helper is
called through a wrapper, phy_macsec, to perform this call while holding
the phydev lock.

Signed-off-by: Antoine Tenart <[email protected]>
---
drivers/net/phy/phy.c | 17 +++++++++++++++++
include/linux/phy.h | 9 +++++++++
2 files changed, 26 insertions(+)

diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 631ed33fe9d9..6b37bb845ce9 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -1095,6 +1095,23 @@ int phy_get_eee_err(struct phy_device *phydev)
}
EXPORT_SYMBOL(phy_get_eee_err);

+int phy_macsec(struct phy_device *phydev, struct netdev_macsec *macsec)
+{
+ int ret = -EOPNOTSUPP;
+
+ if (!phydev->drv)
+ return -EIO;
+
+ mutex_lock(&phydev->lock);
+
+ if (phydev->drv->macsec)
+ ret = phydev->drv->macsec(phydev, macsec);
+
+ mutex_unlock(&phydev->lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(phy_macsec);
+
/**
* phy_ethtool_get_eee - get EEE supported and status
* @phydev: target phy_device struct
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 1f3873a2ff29..21839f352e7c 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -27,6 +27,10 @@
#include <linux/workqueue.h>
#include <linux/mod_devicetable.h>

+#ifdef CONFIG_MACSEC
+#include <net/macsec.h>
+#endif
+
#include <linux/atomic.h>

#define PHY_DEFAULT_FEATURES (SUPPORTED_Autoneg | \
@@ -630,6 +634,10 @@ struct phy_driver {
struct ethtool_tunable *tuna,
const void *data);
int (*set_loopback)(struct phy_device *dev, bool enable);
+
+#ifdef CONFIG_MACSEC
+ int (*macsec)(struct phy_device *dev, struct netdev_macsec *macsec);
+#endif
};
#define to_phy_driver(d) container_of(to_mdio_common_driver(d), \
struct phy_driver, mdiodrv)
@@ -1072,6 +1080,7 @@ int phy_unregister_fixup_for_uid(u32 phy_uid, u32 phy_uid_mask);

int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable);
int phy_get_eee_err(struct phy_device *phydev);
+int phy_macsec(struct phy_device *phydev, struct netdev_macsec *macsec);
int phy_ethtool_set_eee(struct phy_device *phydev, struct ethtool_eee *data);
int phy_ethtool_get_eee(struct phy_device *phydev, struct ethtool_eee *data);
int phy_ethtool_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol);
--
2.20.1


2019-01-23 16:01:16

by Antoine Tenart

[permalink] [raw]
Subject: [PATCH net-next 09/10] net: phy: mscc: macsec initialization

This patch adds support for initializing the MACsec engine found within
the Microsemi Ocelot PHY. The engine is initialized in a passthrough
mode and does not modify any incoming or outgoing packet. But thanks to
this it now can be configured to perform MACsec transformations on
packets, which will be supported by a future patch.

The MACsec read and write functions are wrapped into two versions: one
called during the init phase, and the other one later on. This is
because the init functions in the Microsemi Ocelot PHY driver are called
while the MDIO bus lock is taken.

Signed-off-by: Antoine Tenart <[email protected]>
---
drivers/net/phy/mscc.c | 401 +++++++++++++++++++++++++++++++
drivers/net/phy/mscc_fc_buffer.h | 64 +++++
drivers/net/phy/mscc_mac.h | 159 ++++++++++++
drivers/net/phy/mscc_macsec.h | 256 ++++++++++++++++++++
4 files changed, 880 insertions(+)
create mode 100644 drivers/net/phy/mscc_fc_buffer.h
create mode 100644 drivers/net/phy/mscc_mac.h
create mode 100644 drivers/net/phy/mscc_macsec.h

diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c
index db50efb30df5..f82d7632fb4a 100644
--- a/drivers/net/phy/mscc.c
+++ b/drivers/net/phy/mscc.c
@@ -18,6 +18,10 @@
#include <linux/netdevice.h>
#include <dt-bindings/net/mscc-phy-vsc8531.h>

+#include "mscc_macsec.h"
+#include "mscc_mac.h"
+#include "mscc_fc_buffer.h"
+
enum rgmii_rx_clock_delay {
RGMII_RX_CLK_DELAY_0_2_NS = 0,
RGMII_RX_CLK_DELAY_0_8_NS = 1,
@@ -85,12 +89,33 @@ enum rgmii_rx_clock_delay {
#define LED_MODE_SEL_MASK(x) (GENMASK(3, 0) << LED_MODE_SEL_POS(x))
#define LED_MODE_SEL(x, mode) (((mode) << LED_MODE_SEL_POS(x)) & LED_MODE_SEL_MASK(x))

+#define MSCC_EXT_PAGE_MACSEC_17 17
+#define MSCC_EXT_PAGE_MACSEC_18 18
+
+#define MSCC_EXT_PAGE_MACSEC_19 19
+#define MSCC_PHY_MACSEC_19_REG_ADDR(x) (x)
+#define MSCC_PHY_MACSEC_19_TARGET(x) ((x) << 12)
+#define MSCC_PHY_MACSEC_19_READ BIT(14)
+#define MSCC_PHY_MACSEC_19_CMD BIT(15)
+
+#define MSCC_EXT_PAGE_MACSEC_20 20
+#define MSCC_PHY_MACSEC_20_TARGET(x) (x)
+enum macsec_bank {
+ FC_BUFFER = 0x04,
+ HOST_MAC = 0x05,
+ LINE_MAC = 0x06,
+ IP_1588 = 0x0e,
+ MACSEC_INGR = 0x38,
+ MACSEC_EGR = 0x3c,
+};
+
#define MSCC_EXT_PAGE_ACCESS 31
#define MSCC_PHY_PAGE_STANDARD 0x0000 /* Standard registers */
#define MSCC_PHY_PAGE_EXTENDED 0x0001 /* Extended registers */
#define MSCC_PHY_PAGE_EXTENDED_2 0x0002 /* Extended reg - page 2 */
#define MSCC_PHY_PAGE_EXTENDED_3 0x0003 /* Extended reg - page 3 */
#define MSCC_PHY_PAGE_EXTENDED_4 0x0004 /* Extended reg - page 4 */
+#define MSCC_PHY_PAGE_MACSEC MSCC_PHY_PAGE_EXTENDED_4
/* Extended reg - GPIO; this is a bank of registers that are shared for all PHYs
* in the same package.
*/
@@ -1538,6 +1563,377 @@ static int vsc8584_config_pre_init(struct phy_device *phydev)
return ret;
}

+static u32 __vsc8584_macsec_phy_read(struct phy_device *phydev,
+ enum macsec_bank bank, u32 reg, bool init)
+{
+ u32 val, val_l = 0, val_h = 0;
+ unsigned long deadline;
+ int rc;
+
+ if (!init) {
+ rc = phy_select_page(phydev, MSCC_PHY_PAGE_MACSEC);
+ if (rc < 0)
+ goto failed;
+ } else {
+ __phy_write_page(phydev, MSCC_PHY_PAGE_MACSEC);
+ }
+
+ __phy_write(phydev, MSCC_EXT_PAGE_MACSEC_20,
+ MSCC_PHY_MACSEC_20_TARGET(bank >> 2));
+
+ if (bank >> 2 == 0x1)
+ /* non-MACsec access */
+ bank &= 0x3;
+ else
+ bank = 0;
+
+ __phy_write(phydev, MSCC_EXT_PAGE_MACSEC_19,
+ MSCC_PHY_MACSEC_19_CMD | MSCC_PHY_MACSEC_19_READ |
+ MSCC_PHY_MACSEC_19_REG_ADDR(reg) |
+ MSCC_PHY_MACSEC_19_TARGET(bank));
+
+ deadline = jiffies + msecs_to_jiffies(PROC_CMD_NCOMPLETED_TIMEOUT_MS);
+ do {
+ val = __phy_read(phydev, MSCC_EXT_PAGE_MACSEC_19);
+ } while (time_before(jiffies, deadline) && !(val & MSCC_PHY_MACSEC_19_CMD));
+
+ val_l = __phy_read(phydev, MSCC_EXT_PAGE_MACSEC_17);
+ val_h = __phy_read(phydev, MSCC_EXT_PAGE_MACSEC_18);
+
+ if (!init) {
+failed:
+ phy_restore_page(phydev, rc, rc);
+ } else {
+ __phy_write_page(phydev, MSCC_PHY_PAGE_STANDARD);
+ }
+
+ return (val_h << 16) | val_l;
+}
+
+static u32 vsc8584_macsec_init_phy_read(struct phy_device *phydev,
+ enum macsec_bank bank, u32 reg)
+{
+ return __vsc8584_macsec_phy_read(phydev, bank, reg, true);
+}
+
+static u32 vsc8584_macsec_phy_read(struct phy_device *phydev,
+ enum macsec_bank bank, u32 reg)
+{
+ return __vsc8584_macsec_phy_read(phydev, bank, reg, false);
+}
+
+static void __vsc8584_macsec_phy_write(struct phy_device *phydev,
+ enum macsec_bank bank, u32 reg, u32 val,
+ bool init)
+{
+ unsigned long deadline;
+ int rc;
+
+ if (!init) {
+ rc = phy_select_page(phydev, MSCC_PHY_PAGE_MACSEC);
+ if (rc < 0)
+ goto failed;
+ } else {
+ __phy_write_page(phydev, MSCC_PHY_PAGE_MACSEC);
+ }
+
+ __phy_write(phydev, MSCC_EXT_PAGE_MACSEC_20,
+ MSCC_PHY_MACSEC_20_TARGET(bank >> 2));
+
+ if ((bank >> 2 == 0x1) || (bank >> 2 == 0x3))
+ bank &= 0x3;
+ else
+ /* MACsec access */
+ bank = 0;
+
+ __phy_write(phydev, MSCC_EXT_PAGE_MACSEC_17, (u16)val);
+ __phy_write(phydev, MSCC_EXT_PAGE_MACSEC_18, (u16)(val >> 16));
+
+ __phy_write(phydev, MSCC_EXT_PAGE_MACSEC_19,
+ MSCC_PHY_MACSEC_19_CMD | MSCC_PHY_MACSEC_19_REG_ADDR(reg) |
+ MSCC_PHY_MACSEC_19_TARGET(bank));
+
+ deadline = jiffies + msecs_to_jiffies(PROC_CMD_NCOMPLETED_TIMEOUT_MS);
+ do {
+ val = __phy_read(phydev, MSCC_EXT_PAGE_MACSEC_19);
+ } while (time_before(jiffies, deadline) && !(val & MSCC_PHY_MACSEC_19_CMD));
+
+ if (!init) {
+failed:
+ phy_restore_page(phydev, rc, rc);
+ } else {
+ __phy_write_page(phydev, MSCC_PHY_PAGE_STANDARD);
+ }
+}
+
+static void vsc8584_macsec_init_phy_write(struct phy_device *phydev,
+ enum macsec_bank bank, u32 reg,
+ u32 val)
+{
+ return __vsc8584_macsec_phy_write(phydev, bank, reg, val, true);
+}
+
+static void vsc8584_macsec_phy_write(struct phy_device *phydev,
+ enum macsec_bank bank, u32 reg, u32 val)
+{
+ return __vsc8584_macsec_phy_write(phydev, bank, reg, val, false);
+}
+
+static void vsc8584_macsec_classification(struct phy_device *phydev,
+ enum macsec_bank bank)
+{
+ /* enable VLAN tag parsing */
+ vsc8584_macsec_init_phy_write(phydev, bank, MSCC_MS_SAM_CP_TAG,
+ MSCC_MS_SAM_CP_TAG_PARSE_STAG |
+ MSCC_MS_SAM_CP_TAG_PARSE_QTAG |
+ MSCC_MS_SAM_CP_TAG_PARSE_QINQ);
+}
+
+static void vsc8584_macsec_flow_default_action(struct phy_device *phydev,
+ enum macsec_bank bank)
+{
+ u32 port = (bank == MACSEC_INGR) ?
+ MSCC_MS_PORT_CONTROLLED : MSCC_MS_PORT_COMMON;
+
+ vsc8584_macsec_init_phy_write(phydev, bank, MSCC_MS_SAM_NM_FLOW_NCP,
+ /* MACsec untagged */
+ MSCC_MS_SAM_NM_FLOW_NCP_UNTAGGED_DROP_ACTION(MSCC_MS_ACTION_DROP) |
+ MSCC_MS_SAM_NM_FLOW_NCP_UNTAGGED_DEST_PORT(port) |
+ /* MACsec tagged */
+ MSCC_MS_SAM_NM_FLOW_NCP_TAGGED_DROP_ACTION(MSCC_MS_ACTION_DROP) |
+ MSCC_MS_SAM_NM_FLOW_NCP_TAGGED_DEST_PORT(port) |
+ /* Bad tag */
+ MSCC_MS_SAM_NM_FLOW_NCP_BADTAG_DROP_ACTION(MSCC_MS_ACTION_DROP) |
+ MSCC_MS_SAM_NM_FLOW_NCP_BADTAG_DEST_PORT(port) |
+ /* Kay tag */
+ MSCC_MS_SAM_NM_FLOW_NCP_KAY_DROP_ACTION(MSCC_MS_ACTION_DROP) |
+ MSCC_MS_SAM_NM_FLOW_NCP_KAY_DEST_PORT(port));
+ vsc8584_macsec_init_phy_write(phydev, bank, MSCC_MS_SAM_NM_FLOW_CP,
+ /* MACsec untagged */
+ MSCC_MS_SAM_NM_FLOW_CP_UNTAGGED_DROP_ACTION(MSCC_MS_ACTION_DROP) |
+ MSCC_MS_SAM_NM_FLOW_CP_UNTAGGED_DEST_PORT(port) |
+ /* MACsec tagged */
+ MSCC_MS_SAM_NM_FLOW_CP_TAGGED_DROP_ACTION(MSCC_MS_ACTION_DROP) |
+ MSCC_MS_SAM_NM_FLOW_CP_TAGGED_DEST_PORT(port) |
+ /* Bad tag */
+ MSCC_MS_SAM_NM_FLOW_CP_BADTAG_DROP_ACTION(MSCC_MS_ACTION_DROP) |
+ MSCC_MS_SAM_NM_FLOW_CP_BADTAG_DEST_PORT(port) |
+ /* Kay tag */
+ MSCC_MS_SAM_NM_FLOW_CP_KAY_DROP_ACTION(MSCC_MS_ACTION_DROP) |
+ MSCC_MS_SAM_NM_FLOW_CP_KAY_DEST_PORT(port));
+}
+
+static void vsc8584_macsec_integrity_checks(struct phy_device *phydev,
+ enum macsec_bank bank)
+{
+ u32 val;
+
+ if (bank != MACSEC_INGR)
+ return;
+
+ /* Set default rules to pass unmatched frames */
+ val = vsc8584_macsec_init_phy_read(phydev, bank,
+ MSCC_MS_PARAMS2_IG_CC_CONTROL);
+ val |= MSCC_MS_PARAMS2_IG_CC_CONTROL_NON_MATCH_CTRL_ACT |
+ MSCC_MS_PARAMS2_IG_CC_CONTROL_NON_MATCH_ACT;
+ vsc8584_macsec_init_phy_write(phydev, bank, MSCC_MS_PARAMS2_IG_CC_CONTROL,
+ val);
+
+ vsc8584_macsec_init_phy_write(phydev, bank, MSCC_MS_PARAMS2_IG_CP_TAG,
+ MSCC_MS_PARAMS2_IG_CP_TAG_PARSE_STAG |
+ MSCC_MS_PARAMS2_IG_CP_TAG_PARSE_QTAG |
+ MSCC_MS_PARAMS2_IG_CP_TAG_PARSE_QINQ);
+}
+
+static void vsc8584_macsec_block_init(struct phy_device *phydev,
+ enum macsec_bank bank)
+{
+ u32 val;
+ int i;
+
+ vsc8584_macsec_init_phy_write(phydev, bank, MSCC_MS_ENA_CFG,
+ MSCC_MS_ENA_CFG_SW_RST |
+ MSCC_MS_ENA_CFG_MACSEC_BYPASS_ENA);
+
+ /* Set the MACsec block out of s/w reset and enable clocks */
+ vsc8584_macsec_init_phy_write(phydev, bank, MSCC_MS_ENA_CFG,
+ MSCC_MS_ENA_CFG_CLK_ENA);
+
+ vsc8584_macsec_init_phy_write(phydev, bank, MSCC_MS_STATUS_CONTEXT_CTRL,
+ bank == MACSEC_INGR ? 0xe5880214 : 0xe5880218);
+ vsc8584_macsec_init_phy_write(phydev, bank, MSCC_MS_MISC_CONTROL,
+ MSCC_MS_MISC_CONTROL_MC_LATENCY_FIX(bank == MACSEC_INGR ? 57 : 40) |
+ MSCC_MS_MISC_CONTROL_XFORM_REC_SIZE(bank == MACSEC_INGR ? 1 : 2));
+
+ /* Clear the counters */
+ val = vsc8584_macsec_init_phy_read(phydev, bank, MSCC_MS_COUNT_CONTROL);
+ val |= MSCC_MS_COUNT_CONTROL_AUTO_CNTR_RESET;
+ vsc8584_macsec_init_phy_write(phydev, bank, MSCC_MS_COUNT_CONTROL, val);
+
+ /* Enable octet increment mode */
+ vsc8584_macsec_init_phy_write(phydev, bank, MSCC_MS_PP_CTRL,
+ MSCC_MS_PP_CTRL_MACSEC_OCTET_INCR_MODE);
+
+ vsc8584_macsec_init_phy_write(phydev, bank, MSCC_MS_BLOCK_CTX_UPDATE, 0x3);
+
+ val = vsc8584_macsec_init_phy_read(phydev, bank, MSCC_MS_COUNT_CONTROL);
+ val |= MSCC_MS_COUNT_CONTROL_RESET_ALL;
+ vsc8584_macsec_init_phy_write(phydev, bank, MSCC_MS_COUNT_CONTROL, val);
+
+ /* Set the MTU */
+ vsc8584_macsec_init_phy_write(phydev, bank, MSCC_MS_NON_VLAN_MTU_CHECK,
+ MSCC_MS_NON_VLAN_MTU_CHECK_NV_MTU_COMPARE(32761) |
+ MSCC_MS_NON_VLAN_MTU_CHECK_NV_MTU_COMP_DROP);
+
+ for (i = 0; i < 8; i++)
+ vsc8584_macsec_init_phy_write(phydev, bank, MSCC_MS_VLAN_MTU_CHECK(i),
+ MSCC_MS_VLAN_MTU_CHECK_MTU_COMPARE(32761) |
+ MSCC_MS_VLAN_MTU_CHECK_MTU_COMP_DROP);
+
+ if (bank == MACSEC_EGR) {
+ val = vsc8584_macsec_init_phy_read(phydev, bank, MSCC_MS_INTR_CTRL_STATUS);
+ val &= ~MSCC_MS_INTR_CTRL_STATUS_INTR_ENABLE_M;
+ vsc8584_macsec_init_phy_write(phydev, bank, MSCC_MS_INTR_CTRL_STATUS, val);
+
+ vsc8584_macsec_init_phy_write(phydev, bank, MSCC_MS_FC_CFG,
+ MSCC_MS_FC_CFG_FCBUF_ENA |
+ MSCC_MS_FC_CFG_LOW_THRESH(0x1) |
+ MSCC_MS_FC_CFG_HIGH_THRESH(0x4) |
+ MSCC_MS_FC_CFG_LOW_BYTES_VAL(0x4) |
+ MSCC_MS_FC_CFG_HIGH_BYTES_VAL(0x6));
+ }
+
+ vsc8584_macsec_classification(phydev, bank);
+ vsc8584_macsec_flow_default_action(phydev, bank);
+ vsc8584_macsec_integrity_checks(phydev, bank);
+
+ /* Enable the MACsec block */
+ vsc8584_macsec_init_phy_write(phydev, bank, MSCC_MS_ENA_CFG,
+ MSCC_MS_ENA_CFG_CLK_ENA |
+ MSCC_MS_ENA_CFG_MACSEC_ENA |
+ MSCC_MS_ENA_CFG_MACSEC_SPEED_MODE(0x5));
+}
+
+static void vsc8584_macsec_mac_init(struct phy_device *phydev,
+ enum macsec_bank bank)
+{
+ u32 val;
+ int i;
+
+ /* Clear host & line stats */
+ for (i = 0; i < 36; i++)
+ vsc8584_macsec_init_phy_write(phydev, bank, 0x1c + i, 0);
+
+ val = vsc8584_macsec_init_phy_read(phydev, bank,
+ MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL);
+ val &= ~MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL_PAUSE_MODE_M;
+ val |= MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL_PAUSE_MODE(2) |
+ MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL_PAUSE_VALUE(0xffff);
+ vsc8584_macsec_init_phy_write(phydev, bank,
+ MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL, val);
+
+ val = vsc8584_macsec_init_phy_read(phydev, bank,
+ MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL_2);
+ val |= 0xffff;
+ vsc8584_macsec_init_phy_write(phydev, bank,
+ MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL_2, val);
+
+ val = vsc8584_macsec_init_phy_read(phydev, bank,
+ MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL);
+ if (bank == HOST_MAC)
+ val |= MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL_PAUSE_TIMER_ENA |
+ MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL_PAUSE_FRAME_DROP_ENA;
+ else
+ val |= MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL_PAUSE_REACT_ENA |
+ MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL_PAUSE_FRAME_DROP_ENA |
+ MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL_PAUSE_MODE |
+ MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL_EARLY_PAUSE_DETECT_ENA;
+ vsc8584_macsec_init_phy_write(phydev, bank,
+ MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL, val);
+
+ vsc8584_macsec_init_phy_write(phydev, bank, MSCC_MAC_CFG_PKTINF_CFG,
+ MSCC_MAC_CFG_PKTINF_CFG_STRIP_FCS_ENA |
+ MSCC_MAC_CFG_PKTINF_CFG_INSERT_FCS_ENA |
+ MSCC_MAC_CFG_PKTINF_CFG_LPI_RELAY_ENA |
+ MSCC_MAC_CFG_PKTINF_CFG_STRIP_PREAMBLE_ENA |
+ MSCC_MAC_CFG_PKTINF_CFG_INSERT_PREAMBLE_ENA |
+ (bank == HOST_MAC ?
+ MSCC_MAC_CFG_PKTINF_CFG_ENABLE_TX_PADDING : 0));
+
+ val = vsc8584_macsec_init_phy_read(phydev, bank, MSCC_MAC_CFG_MODE_CFG);
+ val &= ~MSCC_MAC_CFG_MODE_CFG_DISABLE_DIC;
+ vsc8584_macsec_init_phy_write(phydev, bank, MSCC_MAC_CFG_MODE_CFG, val);
+
+ val = vsc8584_macsec_init_phy_read(phydev, bank, MSCC_MAC_CFG_MAXLEN_CFG);
+ val &= ~MSCC_MAC_CFG_MAXLEN_CFG_MAX_LEN_M;
+ val |= MSCC_MAC_CFG_MAXLEN_CFG_MAX_LEN(10240);
+ vsc8584_macsec_init_phy_write(phydev, bank, MSCC_MAC_CFG_MAXLEN_CFG, val);
+
+ vsc8584_macsec_init_phy_write(phydev, bank, MSCC_MAC_CFG_ADV_CHK_CFG,
+ MSCC_MAC_CFG_ADV_CHK_CFG_SFD_CHK_ENA |
+ MSCC_MAC_CFG_ADV_CHK_CFG_PRM_CHK_ENA |
+ MSCC_MAC_CFG_ADV_CHK_CFG_OOR_ERR_ENA |
+ MSCC_MAC_CFG_ADV_CHK_CFG_INR_ERR_ENA);
+
+ val = vsc8584_macsec_init_phy_read(phydev, bank, MSCC_MAC_CFG_LFS_CFG);
+ val &= ~MSCC_MAC_CFG_LFS_CFG_LFS_MODE_ENA;
+ vsc8584_macsec_init_phy_write(phydev, bank, MSCC_MAC_CFG_LFS_CFG, val);
+
+ vsc8584_macsec_init_phy_write(phydev, bank, MSCC_MAC_CFG_ENA_CFG,
+ MSCC_MAC_CFG_ENA_CFG_RX_CLK_ENA |
+ MSCC_MAC_CFG_ENA_CFG_TX_CLK_ENA |
+ MSCC_MAC_CFG_ENA_CFG_RX_ENA |
+ MSCC_MAC_CFG_ENA_CFG_TX_ENA);
+}
+
+/* Must be called with mdio_lock taken */
+static int vsc8584_macsec_init(struct phy_device *phydev)
+{
+ u32 val;
+
+ vsc8584_macsec_block_init(phydev, MACSEC_INGR);
+ vsc8584_macsec_block_init(phydev, MACSEC_EGR);
+ vsc8584_macsec_mac_init(phydev, HOST_MAC);
+ vsc8584_macsec_mac_init(phydev, LINE_MAC);
+
+ vsc8584_macsec_init_phy_write(phydev, FC_BUFFER,
+ MSCC_FCBUF_FC_READ_THRESH_CFG,
+ MSCC_FCBUF_FC_READ_THRESH_CFG_TX_THRESH(4) |
+ MSCC_FCBUF_FC_READ_THRESH_CFG_RX_THRESH(5));
+
+ val = vsc8584_macsec_init_phy_read(phydev, FC_BUFFER, MSCC_FCBUF_MODE_CFG);
+ val |= MSCC_FCBUF_MODE_CFG_PAUSE_GEN_ENA |
+ MSCC_FCBUF_MODE_CFG_RX_PPM_RATE_ADAPT_ENA |
+ MSCC_FCBUF_MODE_CFG_TX_PPM_RATE_ADAPT_ENA;
+ vsc8584_macsec_init_phy_write(phydev, FC_BUFFER, MSCC_FCBUF_MODE_CFG, val);
+
+ vsc8584_macsec_init_phy_write(phydev, FC_BUFFER, MSCC_FCBUF_PPM_RATE_ADAPT_THRESH_CFG,
+ MSCC_FCBUF_PPM_RATE_ADAPT_THRESH_CFG_TX_THRESH(8) |
+ MSCC_FCBUF_PPM_RATE_ADAPT_THRESH_CFG_TX_OFFSET(9));
+
+ val = vsc8584_macsec_init_phy_read(phydev, FC_BUFFER,
+ MSCC_FCBUF_TX_DATA_QUEUE_CFG);
+ val &= ~(MSCC_FCBUF_TX_DATA_QUEUE_CFG_START_M |
+ MSCC_FCBUF_TX_DATA_QUEUE_CFG_END_M);
+ val |= MSCC_FCBUF_TX_DATA_QUEUE_CFG_START(0) |
+ MSCC_FCBUF_TX_DATA_QUEUE_CFG_END(5119);
+ vsc8584_macsec_init_phy_write(phydev, FC_BUFFER,
+ MSCC_FCBUF_TX_DATA_QUEUE_CFG, val);
+
+ val = vsc8584_macsec_init_phy_read(phydev, FC_BUFFER, MSCC_FCBUF_ENA_CFG);
+ val |= MSCC_FCBUF_ENA_CFG_TX_ENA | MSCC_FCBUF_ENA_CFG_RX_ENA;
+ vsc8584_macsec_init_phy_write(phydev, FC_BUFFER, MSCC_FCBUF_ENA_CFG, val);
+
+ val = vsc8584_macsec_init_phy_read(phydev, IP_1588,
+ MSCC_PROC_0_IP_1588_TOP_CFG_STAT_MODE_CTL);
+ val &= ~MSCC_PROC_0_IP_1588_TOP_CFG_STAT_MODE_CTL_PROTOCOL_MODE_M;
+ val |= MSCC_PROC_0_IP_1588_TOP_CFG_STAT_MODE_CTL_PROTOCOL_MODE(4);
+ vsc8584_macsec_init_phy_write(phydev, IP_1588,
+ MSCC_PROC_0_IP_1588_TOP_CFG_STAT_MODE_CTL, val);
+
+ return 0;
+}
+
/* Check if one PHY has already done the init of the parts common to all PHYs
* in the Quad PHY package.
*/
@@ -1667,6 +2063,11 @@ static int vsc8584_config_init(struct phy_device *phydev)
if (ret)
goto err;

+ /* MACsec */
+ ret = vsc8584_macsec_init(phydev);
+ if (ret)
+ goto err;
+
mutex_unlock(&phydev->mdio.bus->mdio_lock);

phy_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD);
diff --git a/drivers/net/phy/mscc_fc_buffer.h b/drivers/net/phy/mscc_fc_buffer.h
new file mode 100644
index 000000000000..7e9c0e877895
--- /dev/null
+++ b/drivers/net/phy/mscc_fc_buffer.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
+/*
+ * Microsemi Ocelot Switch driver
+ *
+ * Copyright (C) 2019 Microsemi Corporation
+ */
+
+#ifndef _MSCC_OCELOT_FC_BUFFER_H_
+#define _MSCC_OCELOT_FC_BUFFER_H_
+
+#define MSCC_FCBUF_ENA_CFG 0x00
+#define MSCC_FCBUF_MODE_CFG 0x01
+#define MSCC_FCBUF_PPM_RATE_ADAPT_THRESH_CFG 0x02
+#define MSCC_FCBUF_TX_CTRL_QUEUE_CFG 0x03
+#define MSCC_FCBUF_TX_DATA_QUEUE_CFG 0x04
+#define MSCC_FCBUF_RX_DATA_QUEUE_CFG 0x05
+#define MSCC_FCBUF_TX_BUFF_XON_XOFF_THRESH_CFG 0x06
+#define MSCC_FCBUF_FC_READ_THRESH_CFG 0x07
+#define MSCC_FCBUF_TX_FRM_GAP_COMP 0x08
+
+#define MSCC_FCBUF_ENA_CFG_TX_ENA BIT(0)
+#define MSCC_FCBUF_ENA_CFG_RX_ENA BIT(4)
+
+#define MSCC_FCBUF_MODE_CFG_DROP_BEHAVIOUR BIT(4)
+#define MSCC_FCBUF_MODE_CFG_PAUSE_REACT_ENA BIT(8)
+#define MSCC_FCBUF_MODE_CFG_RX_PPM_RATE_ADAPT_ENA BIT(12)
+#define MSCC_FCBUF_MODE_CFG_TX_PPM_RATE_ADAPT_ENA BIT(16)
+#define MSCC_FCBUF_MODE_CFG_TX_CTRL_QUEUE_ENA BIT(20)
+#define MSCC_FCBUF_MODE_CFG_PAUSE_GEN_ENA BIT(24)
+#define MSCC_FCBUF_MODE_CFG_INCLUDE_PAUSE_RCVD_IN_PAUSE_GEN BIT(28)
+
+#define MSCC_FCBUF_PPM_RATE_ADAPT_THRESH_CFG_TX_THRESH(x) (x)
+#define MSCC_FCBUF_PPM_RATE_ADAPT_THRESH_CFG_TX_THRESH_M GENMASK(15, 0)
+#define MSCC_FCBUF_PPM_RATE_ADAPT_THRESH_CFG_TX_OFFSET(x) ((x) << 16)
+#define MSCC_FCBUF_PPM_RATE_ADAPT_THRESH_CFG_TX_OFFSET_M GENMASK(19, 16)
+#define MSCC_FCBUF_PPM_RATE_ADAPT_THRESH_CFG_RX_THRESH(x) ((x) << 20)
+#define MSCC_FCBUF_PPM_RATE_ADAPT_THRESH_CFG_RX_THRESH_M GENMASK(31, 20)
+
+#define MSCC_FCBUF_TX_CTRL_QUEUE_CFG_START(x) (x)
+#define MSCC_FCBUF_TX_CTRL_QUEUE_CFG_START_M GENMASK(15, 0)
+#define MSCC_FCBUF_TX_CTRL_QUEUE_CFG_END(x) ((x) << 16)
+#define MSCC_FCBUF_TX_CTRL_QUEUE_CFG_END_M GENMASK(31, 16)
+
+#define MSCC_FCBUF_TX_DATA_QUEUE_CFG_START(x) (x)
+#define MSCC_FCBUF_TX_DATA_QUEUE_CFG_START_M GENMASK(15, 0)
+#define MSCC_FCBUF_TX_DATA_QUEUE_CFG_END(x) ((x) << 16)
+#define MSCC_FCBUF_TX_DATA_QUEUE_CFG_END_M GENMASK(31, 16)
+
+#define MSCC_FCBUF_RX_DATA_QUEUE_CFG_START(x) (x)
+#define MSCC_FCBUF_RX_DATA_QUEUE_CFG_START_M GENMASK(15, 0)
+#define MSCC_FCBUF_RX_DATA_QUEUE_CFG_END(x) ((x) << 16)
+#define MSCC_FCBUF_RX_DATA_QUEUE_CFG_END_M GENMASK(31, 16)
+
+#define MSCC_FCBUF_TX_BUFF_XON_XOFF_THRESH_CFG_XOFF_THRESH(x) (x)
+#define MSCC_FCBUF_TX_BUFF_XON_XOFF_THRESH_CFG_XOFF_THRESH_M GENMASK(15, 0)
+#define MSCC_FCBUF_TX_BUFF_XON_XOFF_THRESH_CFG_XON_THRESH(x) ((x) << 16)
+#define MSCC_FCBUF_TX_BUFF_XON_XOFF_THRESH_CFG_XON_THRESH_M GENMASK(31, 16)
+
+#define MSCC_FCBUF_FC_READ_THRESH_CFG_TX_THRESH(x) (x)
+#define MSCC_FCBUF_FC_READ_THRESH_CFG_TX_THRESH_M GENMASK(15, 0)
+#define MSCC_FCBUF_FC_READ_THRESH_CFG_RX_THRESH(x) ((x) << 16)
+#define MSCC_FCBUF_FC_READ_THRESH_CFG_RX_THRESH_M GENMASK(31, 16)
+
+#endif
diff --git a/drivers/net/phy/mscc_mac.h b/drivers/net/phy/mscc_mac.h
new file mode 100644
index 000000000000..9420ee5175a6
--- /dev/null
+++ b/drivers/net/phy/mscc_mac.h
@@ -0,0 +1,159 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
+/*
+ * Microsemi Ocelot Switch driver
+ *
+ * Copyright (c) 2017 Microsemi Corporation
+ */
+
+#ifndef _MSCC_OCELOT_LINE_MAC_H_
+#define _MSCC_OCELOT_LINE_MAC_H_
+
+#define MSCC_MAC_CFG_ENA_CFG 0x00
+#define MSCC_MAC_CFG_MODE_CFG 0x01
+#define MSCC_MAC_CFG_MAXLEN_CFG 0x02
+#define MSCC_MAC_CFG_NUM_TAGS_CFG 0x03
+#define MSCC_MAC_CFG_TAGS_CFG 0x04
+#define MSCC_MAC_CFG_ADV_CHK_CFG 0x07
+#define MSCC_MAC_CFG_LFS_CFG 0x08
+#define MSCC_MAC_CFG_LB_CFG 0x09
+#define MSCC_MAC_CFG_PKTINF_CFG 0x0a
+#define MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL 0x0b
+#define MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL_2 0x0c
+#define MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL 0x0d
+#define MSCC_MAC_PAUSE_CFG_STATE 0x0e
+#define MSCC_MAC_PAUSE_CFG_MAC_ADDRESS_LSB 0x0f
+#define MSCC_MAC_PAUSE_CFG_MAC_ADDRESS_MSB 0x10
+#define MSCC_MAC_STATUS_RX_LANE_STICKY_0 0x11
+#define MSCC_MAC_STATUS_RX_LANE_STICKY_1 0x12
+#define MSCC_MAC_STATUS_TX_MONITOR_STICKY 0x13
+#define MSCC_MAC_STATUS_TX_MONITOR_STICKY_MASK 0x14
+#define MSCC_MAC_STATUS_STICKY 0x15
+#define MSCC_MAC_STATUS_STICKY_MASK 0x16
+#define MSCC_MAC_STATS_32BIT_RX_HIH_CKSM_ERR_CNT 0x17
+#define MSCC_MAC_STATS_32BIT_RX_XGMII_PROT_ERR_CNT 0x18
+#define MSCC_MAC_STATS_32BIT_RX_SYMBOL_ERR_CNT 0x19
+#define MSCC_MAC_STATS_32BIT_RX_PAUSE_CNT 0x1a
+#define MSCC_MAC_STATS_32BIT_RX_UNSUP_OPCODE_CNT 0x1b
+#define MSCC_MAC_STATS_32BIT_RX_UC_CNT 0x1c
+#define MSCC_MAC_STATS_32BIT_RX_MC_CNT 0x1d
+#define MSCC_MAC_STATS_32BIT_RX_BC_CNT 0x1e
+#define MSCC_MAC_STATS_32BIT_RX_CRC_ERR_CNT 0x1f
+#define MSCC_MAC_STATS_32BIT_RX_UNDERSIZE_CNT 0x20
+#define MSCC_MAC_STATS_32BIT_RX_FRAGMENTS_CNT 0x21
+#define MSCC_MAC_STATS_32BIT_RX_IN_RANGE_LEN_ERR_CNT 0x22
+#define MSCC_MAC_STATS_32BIT_RX_OUT_OF_RANGE_LEN_ERR_CNT 0x23
+#define MSCC_MAC_STATS_32BIT_RX_OVERSIZE_CNT 0x24
+#define MSCC_MAC_STATS_32BIT_RX_JABBERS_CNT 0x25
+#define MSCC_MAC_STATS_32BIT_RX_SIZE64_CNT 0x26
+#define MSCC_MAC_STATS_32BIT_RX_SIZE65TO127_CNT 0x27
+#define MSCC_MAC_STATS_32BIT_RX_SIZE128TO255_CNT 0x28
+#define MSCC_MAC_STATS_32BIT_RX_SIZE256TO511_CNT 0x29
+#define MSCC_MAC_STATS_32BIT_RX_SIZE512TO1023_CNT 0x2a
+#define MSCC_MAC_STATS_32BIT_RX_SIZE1024TO1518_CNT 0x2b
+#define MSCC_MAC_STATS_32BIT_RX_SIZE1519TOMAX_CNT 0x2c
+#define MSCC_MAC_STATS_32BIT_RX_IPG_SHRINK_CNT 0x2d
+#define MSCC_MAC_STATS_32BIT_TX_PAUSE_CNT 0x2e
+#define MSCC_MAC_STATS_32BIT_TX_UC_CNT 0x2f
+#define MSCC_MAC_STATS_32BIT_TX_MC_CNT 0x30
+#define MSCC_MAC_STATS_32BIT_TX_BC_CNT 0x31
+#define MSCC_MAC_STATS_32BIT_TX_SIZE64_CNT 0x32
+#define MSCC_MAC_STATS_32BIT_TX_SIZE65TO127_CNT 0x33
+#define MSCC_MAC_STATS_32BIT_TX_SIZE128TO255_CNT 0x34
+#define MSCC_MAC_STATS_32BIT_TX_SIZE256TO511_CNT 0x35
+#define MSCC_MAC_STATS_32BIT_TX_SIZE512TO1023_CNT 0x36
+#define MSCC_MAC_STATS_32BIT_TX_SIZE1024TO1518_CNT 0x37
+#define MSCC_MAC_STATS_32BIT_TX_SIZE1519TOMAX_CNT 0x38
+#define MSCC_MAC_STATS_40BIT_RX_BAD_BYTES_CNT 0x39
+#define MSCC_MAC_STATS_40BIT_RX_BAD_BYTES_MSB_CNT 0x3a
+#define MSCC_MAC_STATS_40BIT_RX_OK_BYTES_CNT 0x3b
+#define MSCC_MAC_STATS_40BIT_RX_OK_BYTES_MSB_CNT 0x3c
+#define MSCC_MAC_STATS_40BIT_RX_IN_BYTES_CNT 0x3d
+#define MSCC_MAC_STATS_40BIT_RX_IN_BYTES_MSB_CNT 0x3e
+#define MSCC_MAC_STATS_40BIT_TX_OK_BYTES_CNT 0x3f
+#define MSCC_MAC_STATS_40BIT_TX_OK_BYTES_MSB_CNT 0x40
+#define MSCC_MAC_STATS_40BIT_TX_OUT_BYTES_CNT 0x41
+#define MSCC_MAC_STATS_40BIT_TX_OUT_BYTES_MSB_CNT 0x42
+
+#define MSCC_MAC_CFG_ENA_CFG_RX_CLK_ENA BIT(0)
+#define MSCC_MAC_CFG_ENA_CFG_TX_CLK_ENA BIT(4)
+#define MSCC_MAC_CFG_ENA_CFG_RX_SW_RST BIT(8)
+#define MSCC_MAC_CFG_ENA_CFG_TX_SW_RST BIT(12)
+#define MSCC_MAC_CFG_ENA_CFG_RX_ENA BIT(16)
+#define MSCC_MAC_CFG_ENA_CFG_TX_ENA BIT(20)
+
+#define MSCC_MAC_CFG_MODE_CFG_FORCE_CW_UPDATE_INTERVAL(x) ((x) << 20)
+#define MSCC_MAC_CFG_MODE_CFG_FORCE_CW_UPDATE_INTERVAL_M GENMASK(29, 20)
+#define MSCC_MAC_CFG_MODE_CFG_FORCE_CW_UPDATE BIT(16)
+#define MSCC_MAC_CFG_MODE_CFG_TUNNEL_PAUSE_FRAMES BIT(14)
+#define MSCC_MAC_CFG_MODE_CFG_MAC_PREAMBLE_CFG(x) ((x) << 10)
+#define MSCC_MAC_CFG_MODE_CFG_MAC_PREAMBLE_CFG_M GENMASK(12, 10)
+#define MSCC_MAC_CFG_MODE_CFG_MAC_IPG_CFG BIT(6)
+#define MSCC_MAC_CFG_MODE_CFG_XGMII_GEN_MODE_ENA BIT(4)
+#define MSCC_MAC_CFG_MODE_CFG_HIH_CRC_CHECK BIT(2)
+#define MSCC_MAC_CFG_MODE_CFG_UNDERSIZED_FRAME_DROP_DIS BIT(1)
+#define MSCC_MAC_CFG_MODE_CFG_DISABLE_DIC BIT(0)
+
+#define MSCC_MAC_CFG_MAXLEN_CFG_MAX_LEN_TAG_CHK BIT(16)
+#define MSCC_MAC_CFG_MAXLEN_CFG_MAX_LEN(x) (x)
+#define MSCC_MAC_CFG_MAXLEN_CFG_MAX_LEN_M GENMASK(15, 0)
+
+#define MSCC_MAC_CFG_TAGS_CFG_RSZ 0x4
+#define MSCC_MAC_CFG_TAGS_CFG_TAG_ID(x) ((x) << 16)
+#define MSCC_MAC_CFG_TAGS_CFG_TAG_ID_M GENMASK(31, 16)
+#define MSCC_MAC_CFG_TAGS_CFG_TAG_ENA BIT(4)
+
+#define MSCC_MAC_CFG_ADV_CHK_CFG_EXT_EOP_CHK_ENA BIT(24)
+#define MSCC_MAC_CFG_ADV_CHK_CFG_EXT_SOP_CHK_ENA BIT(20)
+#define MSCC_MAC_CFG_ADV_CHK_CFG_SFD_CHK_ENA BIT(16)
+#define MSCC_MAC_CFG_ADV_CHK_CFG_PRM_SHK_CHK_DIS BIT(12)
+#define MSCC_MAC_CFG_ADV_CHK_CFG_PRM_CHK_ENA BIT(8)
+#define MSCC_MAC_CFG_ADV_CHK_CFG_OOR_ERR_ENA BIT(4)
+#define MSCC_MAC_CFG_ADV_CHK_CFG_INR_ERR_ENA BIT(0)
+
+#define MSCC_MAC_CFG_LFS_CFG_LFS_INH_TX BIT(8)
+#define MSCC_MAC_CFG_LFS_CFG_LFS_DIS_TX BIT(4)
+#define MSCC_MAC_CFG_LFS_CFG_LFS_UNIDIR_ENA BIT(3)
+#define MSCC_MAC_CFG_LFS_CFG_USE_LEADING_EDGE_DETECT BIT(2)
+#define MSCC_MAC_CFG_LFS_CFG_SPURIOUS_Q_DIS BIT(1)
+#define MSCC_MAC_CFG_LFS_CFG_LFS_MODE_ENA BIT(0)
+
+#define MSCC_MAC_CFG_LB_CFG_XGMII_HOST_LB_ENA BIT(4)
+#define MSCC_MAC_CFG_LB_CFG_XGMII_PHY_LB_ENA BIT(0)
+
+#define MSCC_MAC_CFG_PKTINF_CFG_STRIP_FCS_ENA BIT(0)
+#define MSCC_MAC_CFG_PKTINF_CFG_INSERT_FCS_ENA BIT(4)
+#define MSCC_MAC_CFG_PKTINF_CFG_STRIP_PREAMBLE_ENA BIT(8)
+#define MSCC_MAC_CFG_PKTINF_CFG_INSERT_PREAMBLE_ENA BIT(12)
+#define MSCC_MAC_CFG_PKTINF_CFG_LPI_RELAY_ENA BIT(16)
+#define MSCC_MAC_CFG_PKTINF_CFG_LF_RELAY_ENA BIT(20)
+#define MSCC_MAC_CFG_PKTINF_CFG_RF_RELAY_ENA BIT(24)
+#define MSCC_MAC_CFG_PKTINF_CFG_ENABLE_TX_PADDING BIT(25)
+#define MSCC_MAC_CFG_PKTINF_CFG_ENABLE_RX_PADDING BIT(26)
+#define MSCC_MAC_CFG_PKTINF_CFG_ENABLE_4BYTE_PREAMBLE BIT(27)
+#define MSCC_MAC_CFG_PKTINF_CFG_MACSEC_BYPASS_NUM_PTP_STALL_CLKS(x) ((x) << 28)
+#define MSCC_MAC_CFG_PKTINF_CFG_MACSEC_BYPASS_NUM_PTP_STALL_CLKS_M GENMASK(30, 28)
+
+#define MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL_PAUSE_VALUE(x) ((x) << 16)
+#define MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL_PAUSE_VALUE_M GENMASK(31, 16)
+#define MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL_WAIT_FOR_LPI_LOW BIT(12)
+#define MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL_USE_PAUSE_STALL_ENA BIT(8)
+#define MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL_PAUSE_REPL_MODE BIT(4)
+#define MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL_PAUSE_FRC_FRAME BIT(2)
+#define MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL_PAUSE_MODE(x) (x)
+#define MSCC_MAC_PAUSE_CFG_TX_FRAME_CTRL_PAUSE_MODE_M GENMASK(1, 0)
+
+#define MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL_EARLY_PAUSE_DETECT_ENA BIT(16)
+#define MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL_PRE_CRC_MODE BIT(20)
+#define MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL_PAUSE_TIMER_ENA BIT(12)
+#define MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL_PAUSE_REACT_ENA BIT(8)
+#define MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL_PAUSE_FRAME_DROP_ENA BIT(4)
+#define MSCC_MAC_PAUSE_CFG_RX_FRAME_CTRL_PAUSE_MODE BIT(0)
+
+#define MSCC_MAC_PAUSE_CFG_STATE_PAUSE_STATE BIT(0)
+#define MSCC_MAC_PAUSE_CFG_STATE_MAC_TX_PAUSE_GEN BIT(4)
+
+#define MSCC_PROC_0_IP_1588_TOP_CFG_STAT_MODE_CTL 0x2
+#define MSCC_PROC_0_IP_1588_TOP_CFG_STAT_MODE_CTL_PROTOCOL_MODE(x) (x)
+#define MSCC_PROC_0_IP_1588_TOP_CFG_STAT_MODE_CTL_PROTOCOL_MODE_M GENMASK(2, 0)
+
+#endif /* _MSCC_OCELOT_LINE_MAC_H_ */
diff --git a/drivers/net/phy/mscc_macsec.h b/drivers/net/phy/mscc_macsec.h
new file mode 100644
index 000000000000..52902669e8ca
--- /dev/null
+++ b/drivers/net/phy/mscc_macsec.h
@@ -0,0 +1,256 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
+/*
+ * Microsemi Ocelot Switch driver
+ *
+ * Copyright (c) 2018 Microsemi Corporation
+ */
+
+#ifndef _MSCC_OCELOT_MACSEC_H_
+#define _MSCC_OCELOT_MACSEC_H_
+
+#define CONTROL_TYPE_EGRESS 0x6
+#define CONTROL_TYPE_INGRESS 0xf
+#define CONTROL_IV0 BIT(5)
+#define CONTROL_IV1 BIT(6)
+#define CONTROL_IV2 BIT(7)
+#define CONTROL_UPDATE_SEQ BIT(13)
+#define CONTROL_IV_IN_SEQ BIT(14)
+#define CONTROL_ENCRYPT_AUTH BIT(15)
+#define CONTROL_KEY_IN_CTX BIT(16)
+#define CONTROL_CRYPTO_ALG(x) ((x) << 17)
+#define CTRYPTO_ALG_AES_CTR_128 0x5
+#define CTRYPTO_ALG_AES_CTR_192 0x6
+#define CTRYPTO_ALG_AES_CTR_256 0x7
+#define CONTROL_DIGEST_TYPE(x) ((x) << 21)
+#define CONTROL_AUTH_ALG(x) ((x) << 23)
+#define AUTH_ALG_AES_GHAS 0x4
+#define CONTROL_AN(x) ((x) << 26)
+#define CONTROL_SEQ_TYPE(x) ((x) << 28)
+#define CONTROL_SEQ_MASK BIT(30)
+#define CONTROL_CONTEXT_ID BIT(31)
+
+enum mscc_macsec_destination_ports {
+ MSCC_MS_PORT_COMMON = 0,
+ MSCC_MS_PORT_RSVD = 1,
+ MSCC_MS_PORT_CONTROLLED = 2,
+ MSCC_MS_PORT_UNCONTROLLED = 3,
+};
+
+enum mscc_macsec_drop_actions {
+ MSCC_MS_ACTION_BYPASS_CRC = 0,
+ MSCC_MS_ACTION_BYPASS_BAD = 1,
+ MSCC_MS_ACTION_DROP = 2,
+ MSCC_MS_ACTION_BYPASS = 3,
+};
+
+enum mscc_macsec_flow_types {
+ MSCC_MS_FLOW_BYPASS = 0,
+ MSCC_MS_FLOW_DROP = 1,
+ MSCC_MS_FLOW_INGRESS = 2,
+ MSCC_MS_FLOW_EGRESS = 3,
+};
+
+enum mscc_macsec_validate_levels {
+ MSCC_MS_VALIDATE_DISABLED = 0,
+ MSCC_MS_VALIDATE_CHECK = 1,
+ MSCC_MS_VALIDATE_STRICT = 2,
+};
+
+#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_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))
+#define MSCC_MS_SAM_MASK(x) (0x1007 + ((x) << 4))
+#define MSCC_MS_SAM_ENTRY_SET1 0x1808
+#define MSCC_MS_SAM_ENTRY_CLEAR1 0x180c
+#define MSCC_MS_SAM_FLOW_CTRL(x) (0x1c00 + (x))
+#define MSCC_MS_SAM_CP_TAG 0x1e40
+#define MSCC_MS_SAM_NM_FLOW_NCP 0x1e51
+#define MSCC_MS_SAM_NM_FLOW_CP 0x1e52
+#define MSCC_MS_MISC_CONTROL 0x1e5f
+#define MSCC_MS_COUNT_CONTROL 0x3204
+#define MSCC_MS_PARAMS2_IG_CC_CONTROL 0x3a10
+#define MSCC_MS_PARAMS2_IG_CP_TAG 0x3a14
+#define MSCC_MS_VLAN_MTU_CHECK(x) (0x3c40 + (x))
+#define MSCC_MS_NON_VLAN_MTU_CHECK 0x3c48
+#define MSCC_MS_PP_CTRL 0x3c4b
+#define MSCC_MS_STATUS_CONTEXT_CTRL 0x3d02
+#define MSCC_MS_INTR_CTRL_STATUS 0x3d04
+#define MSCC_MS_BLOCK_CTX_UPDATE 0x3d0c
+
+/* MACSEC_ENA_CFG */
+#define MSCC_MS_ENA_CFG_CLK_ENA BIT(0)
+#define MSCC_MS_ENA_CFG_SW_RST BIT(1)
+#define MSCC_MS_ENA_CFG_MACSEC_BYPASS_ENA BIT(8)
+#define MSCC_MS_ENA_CFG_MACSEC_ENA BIT(9)
+#define MSCC_MS_ENA_CFG_MACSEC_SPEED_MODE(x) ((x) << 10)
+#define MSCC_MS_ENA_CFG_MACSEC_SPEED_MODE_M GENMASK(12, 10)
+
+/* MACSEC_FC_CFG */
+#define MSCC_MS_FC_CFG_FCBUF_ENA BIT(0)
+#define MSCC_MS_FC_CFG_USE_PKT_EXPANSION_INDICATION BIT(1)
+#define MSCC_MS_FC_CFG_LOW_THRESH(x) ((x) << 4)
+#define MSCC_MS_FC_CFG_LOW_THRESH_M GENMASK(7, 4)
+#define MSCC_MS_FC_CFG_HIGH_THRESH(x) ((x) << 8)
+#define MSCC_MS_FC_CFG_HIGH_THRESH_M GENMASK(11, 8)
+#define MSCC_MS_FC_CFG_LOW_BYTES_VAL(x) ((x) << 12)
+#define MSCC_MS_FC_CFG_LOW_BYTES_VAL_M GENMASK(14, 12)
+#define MSCC_MS_FC_CFG_HIGH_BYTES_VAL(x) ((x) << 16)
+#define MSCC_MS_FC_CFG_HIGH_BYTES_VAL_M GENMASK(18, 16)
+
+/* MACSEC_SAM_MISC_MATCH */
+#define MSCC_MS_SAM_MISC_MATCH_VLAN_VALID BIT(0)
+#define MSCC_MS_SAM_MISC_MATCH_QINQ_FOUND BIT(1)
+#define MSCC_MS_SAM_MISC_MATCH_STAG_VALID BIT(2)
+#define MSCC_MS_SAM_MISC_MATCH_QTAG_VALID BIT(3)
+#define MSCC_MS_SAM_MISC_MATCH_VLAN_UP(x) ((x) << 4)
+#define MSCC_MS_SAM_MISC_MATCH_VLAN_UP_M GENMASK(6, 4)
+#define MSCC_MS_SAM_MISC_MATCH_CONTROL_PACKET BIT(7)
+#define MSCC_MS_SAM_MISC_MATCH_UNTAGGED BIT(8)
+#define MSCC_MS_SAM_MISC_MATCH_TAGGED BIT(9)
+#define MSCC_MS_SAM_MISC_MATCH_BAD_TAG BIT(10)
+#define MSCC_MS_SAM_MISC_MATCH_KAY_TAG BIT(11)
+#define MSCC_MS_SAM_MISC_MATCH_SOURCE_PORT(x) ((x) << 12)
+#define MSCC_MS_SAM_MISC_MATCH_SOURCE_PORT_M GENMASK(13, 12)
+#define MSCC_MS_SAM_MISC_MATCH_MATCH_PRIORITY(x) ((x) << 16)
+#define MSCC_MS_SAM_MISC_MATCH_MATCH_PRIORITY_M GENMASK(19, 16)
+#define MSCC_MS_SAM_MISC_MATCH_AN(x) ((x) << 24)
+#define MSCC_MS_SAM_MISC_MATCH_TCI(x) ((x) << 26)
+
+/* MACSEC_SAM_MASK */
+#define MSCC_MS_SAM_MASK_MAC_SA_MASK(x) (x)
+#define MSCC_MS_SAM_MASK_MAC_SA_MASK_M GENMASK(5, 0)
+#define MSCC_MS_SAM_MASK_MAC_DA_MASK(x) ((x) << 6)
+#define MSCC_MS_SAM_MASK_MAC_DA_MASK_M GENMASK(11, 6)
+#define MSCC_MS_SAM_MASK_MAC_ETYPE_MASK BIT(12)
+#define MSCC_MS_SAM_MASK_VLAN_VLD_MASK BIT(13)
+#define MSCC_MS_SAM_MASK_QINQ_FOUND_MASK BIT(14)
+#define MSCC_MS_SAM_MASK_STAG_VLD_MASK BIT(15)
+#define MSCC_MS_SAM_MASK_QTAG_VLD_MASK BIT(16)
+#define MSCC_MS_SAM_MASK_VLAN_UP_MASK BIT(17)
+#define MSCC_MS_SAM_MASK_VLAN_ID_MASK BIT(18)
+#define MSCC_MS_SAM_MASK_SOURCE_PORT_MASK BIT(19)
+#define MSCC_MS_SAM_MASK_CTL_PACKET_MASK BIT(20)
+#define MSCC_MS_SAM_MASK_VLAN_UP_INNER_MASK BIT(21)
+#define MSCC_MS_SAM_MASK_VLAN_ID_INNER_MASK BIT(22)
+#define MSCC_MS_SAM_MASK_SCI_MASK BIT(23)
+#define MSCC_MS_SAM_MASK_AN_MASK(x) ((x) << 24)
+#define MSCC_MS_SAM_MASK_TCI_MASK(x) ((x) << 26)
+
+/* MACSEC_SAM_FLOW_CTRL_EGR */
+#define MSCC_MS_SAM_FLOW_CTRL_FLOW_TYPE(x) (x)
+#define MSCC_MS_SAM_FLOW_CTRL_FLOW_TYPE_M GENMASK(1, 0)
+#define MSCC_MS_SAM_FLOW_CTRL_DEST_PORT(x) ((x) << 2)
+#define MSCC_MS_SAM_FLOW_CTRL_DEST_PORT_M GENMASK(3, 2)
+#define MSCC_MS_SAM_FLOW_CTRL_RESV_4 BIT(4)
+#define MSCC_MS_SAM_FLOW_CTRL_FLOW_CRYPT_AUTH BIT(5)
+#define MSCC_MS_SAM_FLOW_CTRL_DROP_ACTION(x) ((x) << 6)
+#define MSCC_MS_SAM_FLOW_CTRL_DROP_ACTION_M GENMASK(7, 6)
+#define MSCC_MS_SAM_FLOW_CTRL_RESV_15_TO_8(x) ((x) << 8)
+#define MSCC_MS_SAM_FLOW_CTRL_RESV_15_TO_8_M GENMASK(15, 8)
+#define MSCC_MS_SAM_FLOW_CTRL_PROTECT_FRAME BIT(16)
+#define MSCC_MS_SAM_FLOW_CTRL_REPLAY_PROTECT BIT(16)
+#define MSCC_MS_SAM_FLOW_CTRL_SA_IN_USE BIT(17)
+#define MSCC_MS_SAM_FLOW_CTRL_INCLUDE_SCI BIT(18)
+#define MSCC_MS_SAM_FLOW_CTRL_USE_ES BIT(19)
+#define MSCC_MS_SAM_FLOW_CTRL_USE_SCB BIT(20)
+#define MSCC_MS_SAM_FLOW_CTRL_VALIDATE_FRAMES(x) ((x) << 19)
+#define MSCC_MS_SAM_FLOW_CTRL_TAG_BYPASS_SIZE(x) ((x) << 21)
+#define MSCC_MS_SAM_FLOW_CTRL_TAG_BYPASS_SIZE_M GENMASK(22, 21)
+#define MSCC_MS_SAM_FLOW_CTRL_RESV_23 BIT(23)
+#define MSCC_MS_SAM_FLOW_CTRL_CONFIDENTIALITY_OFFSET(x) ((x) << 24)
+#define MSCC_MS_SAM_FLOW_CTRL_CONFIDENTIALITY_OFFSET_M GENMASK(30, 24)
+#define MSCC_MS_SAM_FLOW_CTRL_CONF_PROTECT BIT(31)
+
+/* MACSEC_SAM_CP_TAG */
+#define MSCC_MS_SAM_CP_TAG_MAP_TBL(x) (x)
+#define MSCC_MS_SAM_CP_TAG_MAP_TBL_M GENMASK(23, 0)
+#define MSCC_MS_SAM_CP_TAG_DEF_UP(x) ((x) << 24)
+#define MSCC_MS_SAM_CP_TAG_DEF_UP_M GENMASK(26, 24)
+#define MSCC_MS_SAM_CP_TAG_STAG_UP_EN BIT(27)
+#define MSCC_MS_SAM_CP_TAG_QTAG_UP_EN BIT(28)
+#define MSCC_MS_SAM_CP_TAG_PARSE_QINQ BIT(29)
+#define MSCC_MS_SAM_CP_TAG_PARSE_STAG BIT(30)
+#define MSCC_MS_SAM_CP_TAG_PARSE_QTAG BIT(31)
+
+/* MACSEC_SAM_NM_FLOW_NCP */
+#define MSCC_MS_SAM_NM_FLOW_NCP_UNTAGGED_FLOW_TYPE(x) (x)
+#define MSCC_MS_SAM_NM_FLOW_NCP_UNTAGGED_DEST_PORT(x) ((x) << 2)
+#define MSCC_MS_SAM_NM_FLOW_NCP_UNTAGGED_DROP_ACTION(x) ((x) << 6)
+#define MSCC_MS_SAM_NM_FLOW_NCP_TAGGED_FLOW_TYPE(x) ((x) << 8)
+#define MSCC_MS_SAM_NM_FLOW_NCP_TAGGED_DEST_PORT(x) ((x) << 10)
+#define MSCC_MS_SAM_NM_FLOW_NCP_TAGGED_DROP_ACTION(x) ((x) << 14)
+#define MSCC_MS_SAM_NM_FLOW_NCP_BADTAG_FLOW_TYPE(x) ((x) << 16)
+#define MSCC_MS_SAM_NM_FLOW_NCP_BADTAG_DEST_PORT(x) ((x) << 18)
+#define MSCC_MS_SAM_NM_FLOW_NCP_BADTAG_DROP_ACTION(x) ((x) << 22)
+#define MSCC_MS_SAM_NM_FLOW_NCP_KAY_FLOW_TYPE(x) ((x) << 24)
+#define MSCC_MS_SAM_NM_FLOW_NCP_KAY_DEST_PORT(x) ((x) << 26)
+#define MSCC_MS_SAM_NM_FLOW_NCP_KAY_DROP_ACTION(x) ((x) << 30)
+
+/* MACSEC_SAM_NM_FLOW_CP */
+#define MSCC_MS_SAM_NM_FLOW_CP_UNTAGGED_FLOW_TYPE(x) (x)
+#define MSCC_MS_SAM_NM_FLOW_CP_UNTAGGED_DEST_PORT(x) ((x) << 2)
+#define MSCC_MS_SAM_NM_FLOW_CP_UNTAGGED_DROP_ACTION(x) ((x) << 6)
+#define MSCC_MS_SAM_NM_FLOW_CP_TAGGED_FLOW_TYPE(x) ((x) << 8)
+#define MSCC_MS_SAM_NM_FLOW_CP_TAGGED_DEST_PORT(x) ((x) << 10)
+#define MSCC_MS_SAM_NM_FLOW_CP_TAGGED_DROP_ACTION(x) ((x) << 14)
+#define MSCC_MS_SAM_NM_FLOW_CP_BADTAG_FLOW_TYPE(x) ((x) << 16)
+#define MSCC_MS_SAM_NM_FLOW_CP_BADTAG_DEST_PORT(x) ((x) << 18)
+#define MSCC_MS_SAM_NM_FLOW_CP_BADTAG_DROP_ACTION(x) ((x) << 22)
+#define MSCC_MS_SAM_NM_FLOW_CP_KAY_FLOW_TYPE(x) ((x) << 24)
+#define MSCC_MS_SAM_NM_FLOW_CP_KAY_DEST_PORT(x) ((x) << 26)
+#define MSCC_MS_SAM_NM_FLOW_CP_KAY_DROP_ACTION(x) ((x) << 30)
+
+/* MACSEC_MISC_CONTROL */
+#define MSCC_MS_MISC_CONTROL_MC_LATENCY_FIX(x) (x)
+#define MSCC_MS_MISC_CONTROL_MC_LATENCY_FIX_M GENMASK(5, 0)
+#define MSCC_MS_MISC_CONTROL_STATIC_BYPASS BIT(8)
+#define MSCC_MS_MISC_CONTROL_NM_MACSEC_EN BIT(9)
+#define MSCC_MS_MISC_CONTROL_VALIDATE_FRAMES(x) ((x) << 10)
+#define MSCC_MS_MISC_CONTROL_VALIDATE_FRAMES_M GENMASK(11, 10)
+#define MSCC_MS_MISC_CONTROL_XFORM_REC_SIZE(x) ((x) << 24)
+#define MSCC_MS_MISC_CONTROL_XFORM_REC_SIZE_M GENMASK(25, 24)
+
+/* MACSEC_COUNT_CONTROL */
+#define MSCC_MS_COUNT_CONTROL_RESET_ALL BIT(0)
+#define MSCC_MS_COUNT_CONTROL_DEBUG_ACCESS BIT(1)
+#define MSCC_MS_COUNT_CONTROL_SATURATE_CNTRS BIT(2)
+#define MSCC_MS_COUNT_CONTROL_AUTO_CNTR_RESET BIT(3)
+
+/* MACSEC_PARAMS2_IG_CC_CONTROL */
+#define MSCC_MS_PARAMS2_IG_CC_CONTROL_NON_MATCH_CTRL_ACT BIT(14)
+#define MSCC_MS_PARAMS2_IG_CC_CONTROL_NON_MATCH_ACT BIT(15)
+
+/* MACSEC_PARAMS2_IG_CP_TAG */
+#define MSCC_MS_PARAMS2_IG_CP_TAG_MAP_TBL(x) (x)
+#define MSCC_MS_PARAMS2_IG_CP_TAG_MAP_TBL_M GENMASK(23, 0)
+#define MSCC_MS_PARAMS2_IG_CP_TAG_DEF_UP(x) ((x) << 24)
+#define MSCC_MS_PARAMS2_IG_CP_TAG_DEF_UP_M GENMASK(26, 24)
+#define MSCC_MS_PARAMS2_IG_CP_TAG_STAG_UP_EN BIT(27)
+#define MSCC_MS_PARAMS2_IG_CP_TAG_QTAG_UP_EN BIT(28)
+#define MSCC_MS_PARAMS2_IG_CP_TAG_PARSE_QINQ BIT(29)
+#define MSCC_MS_PARAMS2_IG_CP_TAG_PARSE_STAG BIT(30)
+#define MSCC_MS_PARAMS2_IG_CP_TAG_PARSE_QTAG BIT(31)
+
+/* MACSEC_VLAN_MTU_CHECK */
+#define MSCC_MS_VLAN_MTU_CHECK_MTU_COMPARE(x) (x)
+#define MSCC_MS_VLAN_MTU_CHECK_MTU_COMPARE_M GENMASK(14, 0)
+#define MSCC_MS_VLAN_MTU_CHECK_MTU_COMP_DROP BIT(15)
+
+/* MACSEC_NON_VLAN_MTU_CHECK */
+#define MSCC_MS_NON_VLAN_MTU_CHECK_NV_MTU_COMPARE(x) (x)
+#define MSCC_MS_NON_VLAN_MTU_CHECK_NV_MTU_COMPARE_M GENMASK(14, 0)
+#define MSCC_MS_NON_VLAN_MTU_CHECK_NV_MTU_COMP_DROP BIT(15)
+
+/* MACSEC_PP_CTRL */
+#define MSCC_MS_PP_CTRL_MACSEC_OCTET_INCR_MODE BIT(0)
+
+/* MACSEC_INTR_CTRL_STATUS */
+#define MSCC_MS_INTR_CTRL_STATUS_INTR_CLR_STATUS(x) (x)
+#define MSCC_MS_INTR_CTRL_STATUS_INTR_CLR_STATUS_M GENMASK(15, 0)
+#define MSCC_MS_INTR_CTRL_STATUS_INTR_ENABLE(x) ((x) << 16)
+#define MSCC_MS_INTR_CTRL_STATUS_INTR_ENABLE_M GENMASK(31, 16)
+
+#endif
--
2.20.1


2019-01-23 16:01:28

by Antoine Tenart

[permalink] [raw]
Subject: [PATCH net-next 10/10] net: phy: mscc: macsec support

This patch adds MACsec support to the Microsemi Ocelot PHY, to configure
flows and transformations so that matched packets can be processed by
the MACsec engine, either at egress, or at ingress. This addition allows
a user to create an hardware accelerated virtual MACsec interface on a
port using a Microsemi Ocelot PHY.

Signed-off-by: Antoine Tenart <[email protected]>
---
drivers/net/phy/Kconfig | 2 +
drivers/net/phy/mscc.c | 559 ++++++++++++++++++++++++++++++++++
drivers/net/phy/mscc_macsec.h | 2 +
3 files changed, 563 insertions(+)

diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 3d187cd50eb0..995b9fa697ba 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -381,6 +381,8 @@ config MICROCHIP_T1_PHY

config MICROSEMI_PHY
tristate "Microsemi PHYs"
+ select CRYPTO_AES
+ select CRYPTO_ECB
---help---
Currently supports VSC8530, VSC8531, VSC8540 and VSC8541 PHYs

diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c
index f82d7632fb4a..89614e6b169d 100644
--- a/drivers/net/phy/mscc.c
+++ b/drivers/net/phy/mscc.c
@@ -18,6 +18,9 @@
#include <linux/netdevice.h>
#include <dt-bindings/net/mscc-phy-vsc8531.h>

+#include <linux/scatterlist.h>
+#include <crypto/skcipher.h>
+
#include "mscc_macsec.h"
#include "mscc_mac.h"
#include "mscc_fc_buffer.h"
@@ -390,6 +393,29 @@ static const struct vsc85xx_hw_stat vsc8584_hw_stats[] = {
},
};

+struct macsec_flow {
+ struct list_head list;
+ enum macsec_bank bank;
+ u32 index;
+ unsigned char assoc_num;
+
+ u8 key[MACSEC_KEYID_LEN];
+
+ union {
+ const struct macsec_rx_sa *rx_sa;
+ const struct macsec_tx_sa *tx_sa;
+ };
+
+ /* Matching */
+ bool tagged;
+ bool untagged;
+ bool control;
+ /* Action */
+ bool bypass;
+ bool drop;
+
+};
+
struct vsc8531_private {
int rate_magic;
u16 supp_led_modes;
@@ -403,6 +429,17 @@ struct vsc8531_private {
* package.
*/
unsigned int base_addr;
+
+ /* 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
+ */
+ const struct macsec_secy *secy;
+ struct list_head macsec_flows;
+ unsigned long ingr_flows;
+ unsigned long egr_flows;
};

#ifdef CONFIG_OF_MDIO
@@ -1934,6 +1971,524 @@ 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->control) {
+ match |= MSCC_MS_SAM_MISC_MATCH_CONTROL_PACKET;
+ mask |= MSCC_MS_SAM_MASK_CTL_PACKET_MASK;
+ }
+ if (flow->tagged)
+ match |= MSCC_MS_SAM_MISC_MATCH_TAGGED;
+ if (flow->untagged)
+ match |= MSCC_MS_SAM_MISC_MATCH_UNTAGGED;
+
+ if (bank == MACSEC_INGR) {
+ match |= MSCC_MS_SAM_MISC_MATCH_AN(flow->index);
+ mask |= MSCC_MS_SAM_MASK_AN_MASK(0x3);
+ }
+
+ /* If an SCI is present, the SC bit must be set */
+ if (bank == MACSEC_INGR && 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));
+ }
+
+ 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->bypass)
+ action = MSCC_MS_FLOW_BYPASS;
+ else if (flow->drop)
+ action = MSCC_MS_FLOW_DROP;
+ 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(MSCC_MS_PORT_CONTROLLED);
+
+ 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;
+ }
+
+ vsc8584_macsec_phy_write(phydev, bank, MSCC_MS_SAM_FLOW_CTRL(idx), val);
+}
+
+static enum macsec_bank vsc8584_macsec_command_to_bank(enum netdev_macsec_command command)
+{
+ switch (command) {
+ case MACSEC_ADD_RXSA:
+ case MACSEC_UPD_RXSA:
+ case MACSEC_DEL_RXSA:
+ return MACSEC_INGR;
+ case MACSEC_ADD_TXSA:
+ case MACSEC_UPD_TXSA:
+ case MACSEC_DEL_TXSA:
+ return MACSEC_EGR;
+ default:
+ return -EINVAL;
+ }
+}
+
+static struct macsec_flow *vsc8584_macsec_find_flow(struct vsc8531_private *priv,
+ enum macsec_bank bank,
+ struct netdev_macsec *macsec)
+{
+ struct macsec_flow *pos, *tmp;
+ sci_t flow_sci, sci = bank == MACSEC_INGR ?
+ macsec->sa.rx_sa->sc->sci : priv->secy->sci;
+
+ list_for_each_entry_safe(pos, tmp, &priv->macsec_flows, list) {
+ flow_sci = pos->bank == MACSEC_INGR ?
+ pos->rx_sa->sc->sci : priv->secy->sci;
+ if (pos->assoc_num == macsec->sa.assoc_num && flow_sci == sci &&
+ pos->bank == vsc8584_macsec_command_to_bank(macsec->command))
+ 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;
+ bool active = (flow->bank == MACSEC_INGR) ?
+ flow->rx_sa->active : flow->tx_sa->active;
+
+ if (!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)
+{
+ u32 rec = 0, control = 0, index = flow->index;
+ struct vsc8531_private *priv = phydev->priv;
+ enum macsec_bank bank = flow->bank;
+ u8 hkey[16];
+ int i, ret;
+ 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);
+ return 0;
+}
+
+static struct macsec_flow *vsc8584_macsec_alloc_flow(struct vsc8531_private *priv,
+ enum macsec_bank bank)
+{
+ struct macsec_flow *flow;
+ unsigned long *bitmap;
+ int index;
+
+ bitmap = bank == MACSEC_INGR ? &priv->ingr_flows : &priv->egr_flows;
+ 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;
+
+ 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,
+ enum netdev_macsec_command command,
+ struct macsec_flow *flow)
+{
+ int ret;
+
+ vsc8584_macsec_flow(phydev, flow);
+
+ if (command == MACSEC_UPD_RXSA || command == MACSEC_UPD_TXSA)
+ return 0;
+
+ ret = vsc8584_macsec_transformation(phydev, flow);
+ if (ret) {
+ vsc8584_macsec_free_flow(phydev->priv, flow);
+ return ret;
+ }
+
+ 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 phy_device *phydev,
+ struct netdev_macsec *macsec,
+ struct macsec_flow *flow)
+{
+ struct vsc8531_private *priv = phydev->priv;
+
+ if (!flow) {
+ flow = vsc8584_macsec_alloc_flow(phydev->priv, MACSEC_INGR);
+ if (IS_ERR(flow))
+ return PTR_ERR(flow);
+
+ memcpy(flow->key, macsec->sa.key, priv->secy->key_len);
+ }
+
+ flow->assoc_num = macsec->sa.assoc_num;
+ flow->rx_sa = macsec->sa.rx_sa;
+
+ /* Always match tagged packets on ingress */
+ flow->tagged = true;
+
+ if (priv->secy->validate_frames != MACSEC_VALIDATE_DISABLED)
+ flow->untagged = true;
+
+ return vsc8584_macsec_add_flow(phydev, macsec->command, flow);
+}
+
+static int vsc8584_macsec_add_txsa(struct phy_device *phydev,
+ struct netdev_macsec *macsec,
+ struct macsec_flow *flow)
+{
+ struct vsc8531_private *priv = phydev->priv;
+
+ if (!flow) {
+ flow = vsc8584_macsec_alloc_flow(phydev->priv, MACSEC_EGR);
+ if (IS_ERR(flow))
+ return PTR_ERR(flow);
+
+ memcpy(flow->key, macsec->sa.key, priv->secy->key_len);
+ }
+
+ flow->assoc_num = macsec->sa.assoc_num;
+ flow->tx_sa = macsec->sa.tx_sa;
+
+ /* Always match untagged packets on egress */
+ flow->untagged = true;
+
+ return vsc8584_macsec_add_flow(phydev, macsec->command, flow);
+}
+
+/* This function should ensure vsc8584_macsec_commit() will run successfully */
+static int vsc8584_macsec_prepare(struct phy_device *phydev,
+ struct netdev_macsec *macsec)
+{
+ struct vsc8531_private *priv = phydev->priv;
+ struct macsec_flow *flow = NULL;
+
+ if (macsec->command != MACSEC_ADD_SECY && !priv->secy)
+ return -EINVAL;
+
+ switch (macsec->command) {
+ case MACSEC_ADD_SECY:
+ if (priv->secy)
+ return -EEXIST;
+ return 0;
+ case MACSEC_UPD_RXSA:
+ flow = vsc8584_macsec_find_flow(phydev->priv, MACSEC_INGR,
+ macsec);
+ if (IS_ERR(flow))
+ return -ENOENT;
+
+ /* Make sure the flow is disabled before updating it */
+ vsc8584_macsec_flow_disable(phydev, flow);
+
+ /* Fall-through */
+ case MACSEC_ADD_RXSA:
+ return vsc8584_macsec_add_rxsa(phydev, macsec, flow);
+ case MACSEC_UPD_TXSA:
+ flow = vsc8584_macsec_find_flow(phydev->priv, MACSEC_EGR,
+ macsec);
+ if (IS_ERR(flow))
+ return -ENOENT;
+
+ /* Make sure the flow is disabled before updating it */
+ vsc8584_macsec_flow_disable(phydev, flow);
+
+ /* Fall-through */
+ case MACSEC_ADD_TXSA:
+ return vsc8584_macsec_add_txsa(phydev, macsec, flow);
+ case MACSEC_DEL_RXSA:
+ flow = vsc8584_macsec_find_flow(phydev->priv, MACSEC_INGR,
+ macsec);
+ if (IS_ERR(flow))
+ return -ENOENT;
+ return 0;
+ case MACSEC_DEL_TXSA:
+ flow = vsc8584_macsec_find_flow(phydev->priv, MACSEC_EGR,
+ macsec);
+ if (IS_ERR(flow))
+ return -ENOENT;
+ return 0;
+ /* Handled entirely in the commit phase */
+ case MACSEC_DEL_SECY:
+ case MACSEC_DEL_RXSC:
+ case MACSEC_DEV_OPEN:
+ case MACSEC_DEV_STOP:
+ return 0;
+ default:
+ break;
+ }
+
+ return -EOPNOTSUPP;
+}
+
+/* This function should not fail */
+static int vsc8584_macsec_commit(struct phy_device *phydev,
+ struct netdev_macsec *macsec)
+{
+ struct vsc8531_private *priv = phydev->priv;
+ struct macsec_flow *flow, *tmp;
+
+ switch (macsec->command) {
+ case MACSEC_ADD_SECY:
+ priv->secy = macsec->secy;
+ break;
+ case MACSEC_DEL_SECY:
+ list_for_each_entry_safe(flow, tmp, &priv->macsec_flows, list)
+ vsc8584_macsec_del_flow(phydev, flow);
+
+ priv->secy = NULL;
+ break;
+ case MACSEC_DEL_RXSC:
+ list_for_each_entry_safe(flow, tmp, &priv->macsec_flows, list) {
+ if (flow->bank == MACSEC_INGR &&
+ flow->rx_sa->sc->sci == macsec->rx_sc->sci)
+ vsc8584_macsec_del_flow(phydev, flow);
+ }
+ break;
+ case MACSEC_ADD_RXSA:
+ case MACSEC_UPD_RXSA:
+ flow = vsc8584_macsec_find_flow(phydev->priv, MACSEC_INGR,
+ macsec);
+ if (IS_ERR(flow))
+ return PTR_ERR(flow);
+ vsc8584_macsec_flow_enable(phydev, flow);
+ break;
+ case MACSEC_ADD_TXSA:
+ case MACSEC_UPD_TXSA:
+ flow = vsc8584_macsec_find_flow(phydev->priv, MACSEC_EGR,
+ macsec);
+ if (IS_ERR(flow))
+ return PTR_ERR(flow);
+ vsc8584_macsec_flow_enable(phydev, flow);
+ break;
+ case MACSEC_DEL_RXSA:
+ flow = vsc8584_macsec_find_flow(phydev->priv, MACSEC_INGR,
+ macsec);
+ if (IS_ERR(flow))
+ return PTR_ERR(flow);
+ vsc8584_macsec_del_flow(phydev, flow);
+ break;
+ case MACSEC_DEL_TXSA:
+ flow = vsc8584_macsec_find_flow(phydev->priv, MACSEC_EGR,
+ macsec);
+ if (IS_ERR(flow))
+ return PTR_ERR(flow);
+ vsc8584_macsec_del_flow(phydev, flow);
+ break;
+ case MACSEC_DEV_OPEN:
+ list_for_each_entry_safe(flow, tmp, &priv->macsec_flows, list)
+ vsc8584_macsec_flow_enable(phydev, flow);
+ break;
+ case MACSEC_DEV_STOP:
+ list_for_each_entry_safe(flow, tmp, &priv->macsec_flows, list)
+ vsc8584_macsec_flow_disable(phydev, flow);
+ break;
+ default:
+ /* Nothing to be done */
+ break;
+ }
+
+ return 0;
+}
+
+static int vsc8584_macsec(struct phy_device *phydev,
+ struct netdev_macsec *macsec)
+{
+ if (macsec->prepare)
+ return vsc8584_macsec_prepare(phydev, macsec);
+
+ return vsc8584_macsec_commit(phydev, macsec);
+}
+
/* Check if one PHY has already done the init of the parts common to all PHYs
* in the Quad PHY package.
*/
@@ -2064,6 +2619,9 @@ static int vsc8584_config_init(struct phy_device *phydev)
goto err;

/* MACsec */
+ INIT_LIST_HEAD(&vsc8531->macsec_flows);
+ vsc8531->secy = NULL;
+
ret = vsc8584_macsec_init(phydev);
if (ret)
goto err;
@@ -2428,6 +2986,7 @@ static struct phy_driver vsc85xx_driver[] = {
.get_sset_count = &vsc85xx_get_sset_count,
.get_strings = &vsc85xx_get_strings,
.get_stats = &vsc85xx_get_stats,
+ .macsec = &vsc8584_macsec,
}

};
diff --git a/drivers/net/phy/mscc_macsec.h b/drivers/net/phy/mscc_macsec.h
index 52902669e8ca..cf12d7967133 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)
--
2.20.1


2019-01-23 16:01:38

by Antoine Tenart

[permalink] [raw]
Subject: [PATCH net-next 08/10] net: phy: export __phy_read_page/__phy_write_page

This patch exports the __phy_read_page and __phy_write_page helpers, to
allow reading and setting the current page when a function already holds
the MDIO lock.

This is something the Microsemi PHY driver does during its
initialization because parts of its registers and engines are shared
between ports. With the upcoming MACsec offloading support in this PHY,
we'll need to configure the MACsec engine and to do so changing pages is
required.

Signed-off-by: Antoine Tenart <[email protected]>
---
drivers/net/phy/phy-core.c | 6 ++++--
include/linux/phy.h | 3 +++
2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/net/phy/phy-core.c b/drivers/net/phy/phy-core.c
index 909b3344babf..be0c65b6e2da 100644
--- a/drivers/net/phy/phy-core.c
+++ b/drivers/net/phy/phy-core.c
@@ -538,15 +538,17 @@ int phy_modify(struct phy_device *phydev, u32 regnum, u16 mask, u16 set)
}
EXPORT_SYMBOL_GPL(phy_modify);

-static int __phy_read_page(struct phy_device *phydev)
+int __phy_read_page(struct phy_device *phydev)
{
return phydev->drv->read_page(phydev);
}
+EXPORT_SYMBOL_GPL(__phy_read_page);

-static int __phy_write_page(struct phy_device *phydev, int page)
+int __phy_write_page(struct phy_device *phydev, int page)
{
return phydev->drv->write_page(phydev, page);
}
+EXPORT_SYMBOL_GPL(__phy_write_page);

/**
* phy_save_page() - take the bus lock and save the current page
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 21839f352e7c..5f17080bc697 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -766,6 +766,9 @@ static inline int __phy_write(struct phy_device *phydev, u32 regnum, u16 val)
val);
}

+int __phy_read_page(struct phy_device *phydev);
+int __phy_write_page(struct phy_device *phydev, int page);
+
int __phy_modify(struct phy_device *phydev, u32 regnum, u16 mask, u16 set);
int phy_modify(struct phy_device *phydev, u32 regnum, u16 mask, u16 set);

--
2.20.1


2019-01-23 16:01:49

by Antoine Tenart

[permalink] [raw]
Subject: [PATCH net-next 06/10] net: introduce a net_device_ops macsec helper

This patch introduces a net_device_ops MACsec helper to allow net device
drivers to implement a MACsec offloading solution.

Signed-off-by: Antoine Tenart <[email protected]>
---
include/linux/netdevice.h | 8 ++++++++
1 file changed, 8 insertions(+)

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index e675ef97a426..ee2f40dca515 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -53,6 +53,10 @@
#include <uapi/linux/pkt_cls.h>
#include <linux/hashtable.h>

+#ifdef CONFIG_MACSEC
+#include <net/macsec.h>
+#endif
+
struct netpoll_info;
struct device;
struct phy_device;
@@ -1441,6 +1445,10 @@ struct net_device_ops {
u32 flags);
int (*ndo_xsk_async_xmit)(struct net_device *dev,
u32 queue_id);
+#ifdef CONFIG_MACSEC
+ int (*ndo_macsec)(struct net_device *dev,
+ struct netdev_macsec *macsec);
+#endif
};

/**
--
2.20.1


2019-01-23 16:02:08

by Antoine Tenart

[permalink] [raw]
Subject: [PATCH net-next 04/10] net: macsec: introduce the netdev_macsec structure

This patch introduces the netdev_macsec structure. It will be used
in the kernel to exchange information between the common MACsec
implementation (macsec.c) and the MACsec hardware offloading
implementations. This structure contains a command (struct
netdev_macsec_command) and pointers to MACsec specific structures which
contain the actual MACsec configuration.

Signed-off-by: Antoine Tenart <[email protected]>
---
include/net/macsec.h | 45 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 45 insertions(+)

diff --git a/include/net/macsec.h b/include/net/macsec.h
index 15ff331dd670..1e4d37c190ed 100644
--- a/include/net/macsec.h
+++ b/include/net/macsec.h
@@ -175,4 +175,49 @@ struct macsec_secy {
struct macsec_rx_sc __rcu *rx_sc;
};

+enum netdev_macsec_command {
+ /* Device wide */
+ MACSEC_DEV_OPEN,
+ MACSEC_DEV_STOP,
+
+ /* SecY */
+ MACSEC_ADD_SECY,
+ MACSEC_UPD_SECY,
+ MACSEC_DEL_SECY,
+
+ /* Security channels */
+ MACSEC_ADD_RXSC,
+ MACSEC_UPD_RXSC,
+ MACSEC_DEL_RXSC,
+
+ /* Security associations */
+ MACSEC_ADD_RXSA,
+ MACSEC_UPD_RXSA,
+ MACSEC_DEL_RXSA,
+ MACSEC_ADD_TXSA,
+ MACSEC_UPD_TXSA,
+ MACSEC_DEL_TXSA,
+};
+
+struct netdev_macsec {
+ enum netdev_macsec_command command;
+ u8 prepare:1;
+
+ union {
+ /* MACSEC_*_SECY */
+ const struct macsec_secy *secy;
+ /* MACSEC_*_RXSC */
+ const struct macsec_rx_sc *rx_sc;
+ /* MACSEC_*_RXSA/TXSA */
+ struct {
+ unsigned char assoc_num;
+ u8 key[MACSEC_KEYID_LEN];
+ union {
+ const struct macsec_rx_sa *rx_sa;
+ const struct macsec_tx_sa *tx_sa;
+ };
+ } sa;
+ };
+};
+
#endif /* _NET_MACSEC_H_ */
--
2.20.1


2019-01-23 16:02:16

by Antoine Tenart

[permalink] [raw]
Subject: [PATCH net-next 02/10] net: macsec: convert to SPDX

This cosmetic patch converts the macsec implementation license header to
the now recommended format, SPDX.

Signed-off-by: Antoine Tenart <[email protected]>
---
drivers/net/macsec.c | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
index 64a982563d59..56e354305f76 100644
--- a/drivers/net/macsec.c
+++ b/drivers/net/macsec.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* drivers/net/macsec.c - MACsec device
*
* Copyright (c) 2015 Sabrina Dubroca <[email protected]>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/

#include <linux/types.h>
--
2.20.1


2019-01-23 16:02:30

by Antoine Tenart

[permalink] [raw]
Subject: [PATCH net-next 07/10] net: macsec: hardware offloading infrastructure

This patch introduces the MACsec hardware offloading infrastructure.

The main idea here is to re-use the logic and data structures of the
software MACsec implementation. This allows not to duplicate definitions
and structure storing the same kind of information. It also allows to
use a unified genlink interface for both MACsec implementations (so that
the same userspace tool, `ip macsec`, is used with the same arguments).
The MACsec offloading support cannot be disabled if an interface
supports it at the moment.

The MACsec configuration is passed to device drivers supporting it
through macsec_hw_offload() which is called (indirectly) from the MACsec
genl helpers. This function calls the macsec() ops of PHY and Ethernet
drivers in two steps: a preparation one, and a commit one. The first
step is allowed to fail and should be used to check if a provided
configuration is compatible with the features provided by a MACsec
engine, while the second step is not allowed to fail and should only be
used to enable a given MACsec configuration. Two extra calls are made:
when a virtual MACsec interface is created and when it is deleted, so
that the hardware driver can stay in sync.

The Rx and TX handlers are modified to take in account the special case
were the MACsec transformation happens in the hardware, whether in a PHY
or in a MAC, as the packets seen by the networking stack on both the
physical and MACsec virtual interface are exactly the same. This leads
to some limitations: the hardware and software implementations can't be
used on the same physical interface, as the policies would be impossible
to fulfill (such as strict validation of the frames). Also only a single
virtual MACsec interface can be attached to a physical port supporting
hardware offloading as it would be impossible to guess onto which
interface a given packet should go (for ingress traffic).

Another limitation as of now is that the counters and statistics are not
reported back from the hardware to the software MACsec implementation.
This isn't an issue when using offloaded MACsec transformations, but it
should be added in the future so that the MACsec state can be reported
to the user (which would also improve the debug).

Signed-off-by: Antoine Tenart <[email protected]>
---
drivers/net/macsec.c | 296 +++++++++++++++++++++++++++++++++++++++++--
1 file changed, 283 insertions(+), 13 deletions(-)

diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
index c3a138dd4386..3dfcc92cf83c 100644
--- a/drivers/net/macsec.c
+++ b/drivers/net/macsec.c
@@ -16,6 +16,7 @@
#include <net/genetlink.h>
#include <net/sock.h>
#include <net/gro_cells.h>
+#include <linux/phy.h>

#include <net/macsec.h>
#include <uapi/linux/if_macsec.h>
@@ -319,6 +320,25 @@ static void macsec_set_shortlen(struct macsec_eth_header *h, size_t data_len)
h->short_length = data_len;
}

+/* Checks if underlying layers implement MACsec offloading functions */
+static inline bool macsec_hw_offload_capable(struct macsec_dev *dev)
+{
+ struct phy_device *phydev;
+
+ if (!dev || !dev->real_dev)
+ return false;
+
+ phydev = dev->real_dev->phydev;
+
+ if (phydev && phydev->drv && phydev->drv->macsec)
+ return true;
+ if (dev->real_dev->features & NETIF_F_HW_MACSEC &&
+ dev->real_dev->netdev_ops->ndo_macsec)
+ return true;
+
+ return false;
+}
+
/* validate MACsec packet according to IEEE 802.1AE-2006 9.12 */
static bool macsec_validate_skb(struct sk_buff *skb, u16 icv_len)
{
@@ -867,8 +887,10 @@ static struct macsec_rx_sc *find_rx_sc_rtnl(struct macsec_secy *secy, sci_t sci)
return NULL;
}

-static void handle_not_macsec(struct sk_buff *skb)
+static enum rx_handler_result handle_not_macsec(struct sk_buff *skb)
{
+ /* Deliver to the uncontrolled port by default */
+ enum rx_handler_result ret = RX_HANDLER_PASS;
struct macsec_rxh_data *rxd;
struct macsec_dev *macsec;

@@ -883,7 +905,8 @@ static void handle_not_macsec(struct sk_buff *skb)
struct sk_buff *nskb;
struct pcpu_secy_stats *secy_stats = this_cpu_ptr(macsec->stats);

- if (macsec->secy.validate_frames == MACSEC_VALIDATE_STRICT) {
+ if (!macsec_hw_offload_capable(macsec) &&
+ macsec->secy.validate_frames == MACSEC_VALIDATE_STRICT) {
u64_stats_update_begin(&secy_stats->syncp);
secy_stats->stats.InPktsNoTag++;
u64_stats_update_end(&secy_stats->syncp);
@@ -902,9 +925,17 @@ static void handle_not_macsec(struct sk_buff *skb)
secy_stats->stats.InPktsUntagged++;
u64_stats_update_end(&secy_stats->syncp);
}
+
+ if (netif_running(macsec->secy.netdev) &&
+ macsec_hw_offload_capable(macsec)) {
+ ret = RX_HANDLER_EXACT;
+ goto out;
+ }
}

+out:
rcu_read_unlock();
+ return ret;
}

static rx_handler_result_t macsec_handle_frame(struct sk_buff **pskb)
@@ -929,12 +960,8 @@ static rx_handler_result_t macsec_handle_frame(struct sk_buff **pskb)
goto drop_direct;

hdr = macsec_ethhdr(skb);
- if (hdr->eth.h_proto != htons(ETH_P_MACSEC)) {
- handle_not_macsec(skb);
-
- /* and deliver to the uncontrolled port */
- return RX_HANDLER_PASS;
- }
+ if (hdr->eth.h_proto != htons(ETH_P_MACSEC))
+ return handle_not_macsec(skb);

skb = skb_unshare(skb, GFP_ATOMIC);
if (!skb) {
@@ -1440,6 +1467,137 @@ static const struct nla_policy macsec_genl_sa_policy[NUM_MACSEC_SA_ATTR] = {
.len = MACSEC_MAX_KEY_LEN, },
};

+static int macsec_hw_offload(struct net_device *net,
+ struct netdev_macsec *macsec)
+{
+ struct macsec_dev *dev = netdev_priv(net);
+ int ret;
+
+ /* Phase I: prepare. The drive should fail here if there are going to be
+ * issues in the commit phase.
+ *
+ * If supported the PHY implementation is called, otherwise the MAC one
+ * is used.
+ *
+ * Phase II: commit. This step cannot fail.
+ */
+ macsec->prepare = true;
+
+ if (dev->real_dev->phydev) {
+ ret = phy_macsec(dev->real_dev->phydev, macsec);
+ if (ret == -EOPNOTSUPP)
+ goto try_netdev_macsec;
+ if (ret)
+ return ret;
+
+ macsec->prepare = false;
+ ret = phy_macsec(dev->real_dev->phydev, macsec);
+ if (unlikely(ret))
+ goto offload_failed;
+
+ return 0;
+ }
+
+try_netdev_macsec:
+ if (dev->real_dev->netdev_ops->ndo_macsec) {
+ ret = dev->real_dev->netdev_ops->ndo_macsec(net, macsec);
+ if (ret)
+ return ret;
+
+ macsec->prepare = false;
+ ret = dev->real_dev->netdev_ops->ndo_macsec(net, macsec);
+ if (unlikely(ret))
+ goto offload_failed;
+ }
+
+ return 0;
+
+offload_failed:
+ /* This should never happen: commit is not allowed to fail */
+ WARN(1, "MACsec offloading commit failed (%d)\n", ret);
+ return ret;
+}
+
+static int macsec_hw_offload_secy(struct net_device *net,
+ enum netdev_macsec_command command,
+ struct macsec_secy *secy)
+{
+ struct macsec_dev *dev = netdev_priv(net);
+ struct netdev_macsec macsec;
+
+ if (!macsec_hw_offload_capable(dev))
+ return 0;
+
+ memset(&macsec, 0, sizeof(macsec));
+ macsec.command = command;
+ macsec.secy = secy;
+
+ return macsec_hw_offload(net, &macsec);
+}
+
+static int macsec_hw_offload_rxsc(struct net_device *net,
+ enum netdev_macsec_command command,
+ struct macsec_rx_sc *rx_sc)
+{
+ struct macsec_dev *dev = netdev_priv(net);
+ struct netdev_macsec macsec;
+
+ if (!macsec_hw_offload_capable(dev))
+ return 0;
+
+ memset(&macsec, 0, sizeof(macsec));
+ macsec.command = command;
+ macsec.rx_sc = rx_sc;
+
+ return macsec_hw_offload(net, &macsec);
+}
+
+static int macsec_hw_offload_rxsa(struct net_device *net,
+ enum netdev_macsec_command command,
+ struct macsec_rx_sa *rx_sa,
+ unsigned char assoc_num, u8 *key)
+{
+ struct macsec_secy *secy = &macsec_priv(net)->secy;
+ struct macsec_dev *dev = netdev_priv(net);
+ struct netdev_macsec macsec;
+
+ if (!macsec_hw_offload_capable(dev))
+ return 0;
+
+ memset(&macsec, 0, sizeof(macsec));
+ macsec.command = command;
+ macsec.sa.assoc_num = assoc_num;
+ macsec.sa.rx_sa = rx_sa;
+
+ if (key)
+ memcpy(macsec.sa.key, key, secy->key_len);
+
+ return macsec_hw_offload(net, &macsec);
+}
+
+static int macsec_hw_offload_txsa(struct net_device *net,
+ enum netdev_macsec_command command,
+ struct macsec_tx_sa *tx_sa,
+ unsigned char assoc_num, u8 *key)
+{
+ struct macsec_secy *secy = &macsec_priv(net)->secy;
+ struct macsec_dev *dev = netdev_priv(net);
+ struct netdev_macsec macsec;
+
+ if (!macsec_hw_offload_capable(dev))
+ return 0;
+
+ memset(&macsec, 0, sizeof(macsec));
+ macsec.command = command;
+ macsec.sa.assoc_num = assoc_num;
+ macsec.sa.tx_sa = tx_sa;
+
+ if (key)
+ memcpy(macsec.sa.key, key, secy->key_len);
+
+ return macsec_hw_offload(net, &macsec);
+}
+
static int parse_sa_config(struct nlattr **attrs, struct nlattr **tb_sa)
{
if (!attrs[MACSEC_ATTR_SA_CONFIG])
@@ -1561,6 +1719,15 @@ static int macsec_add_rxsa(struct sk_buff *skb, struct genl_info *info)

nla_memcpy(rx_sa->key.id, tb_sa[MACSEC_SA_ATTR_KEYID], MACSEC_KEYID_LEN);
rx_sa->sc = rx_sc;
+
+ err = macsec_hw_offload_rxsa(dev, MACSEC_ADD_RXSA, rx_sa, assoc_num,
+ nla_data(tb_sa[MACSEC_SA_ATTR_KEY]));
+ if (err) {
+ kfree(rx_sa);
+ rtnl_unlock();
+ return err;
+ }
+
rcu_assign_pointer(rx_sc->sa[assoc_num], rx_sa);

rtnl_unlock();
@@ -1717,6 +1884,15 @@ static int macsec_add_txsa(struct sk_buff *skb, struct genl_info *info)
if (assoc_num == tx_sc->encoding_sa && tx_sa->active)
secy->operational = true;

+ err = macsec_hw_offload_txsa(dev, MACSEC_ADD_TXSA, tx_sa, assoc_num,
+ nla_data(tb_sa[MACSEC_SA_ATTR_KEY]));
+ if (err) {
+ secy->operational = false;
+ kfree(tx_sa);
+ rtnl_unlock();
+ return err;
+ }
+
rcu_assign_pointer(tx_sc->sa[assoc_num], tx_sa);

rtnl_unlock();
@@ -1734,6 +1910,7 @@ static int macsec_del_rxsa(struct sk_buff *skb, struct genl_info *info)
u8 assoc_num;
struct nlattr *tb_rxsc[MACSEC_RXSC_ATTR_MAX + 1];
struct nlattr *tb_sa[MACSEC_SA_ATTR_MAX + 1];
+ int ret;

if (!attrs[MACSEC_ATTR_IFINDEX])
return -EINVAL;
@@ -1757,6 +1934,13 @@ static int macsec_del_rxsa(struct sk_buff *skb, struct genl_info *info)
return -EBUSY;
}

+ ret = macsec_hw_offload_rxsa(dev, MACSEC_DEL_RXSA, rx_sa, assoc_num,
+ NULL);
+ if (ret) {
+ rtnl_unlock();
+ return ret;
+ }
+
RCU_INIT_POINTER(rx_sc->sa[assoc_num], NULL);
clear_rx_sa(rx_sa);

@@ -1773,6 +1957,7 @@ static int macsec_del_rxsc(struct sk_buff *skb, struct genl_info *info)
struct macsec_rx_sc *rx_sc;
sci_t sci;
struct nlattr *tb_rxsc[MACSEC_RXSC_ATTR_MAX + 1];
+ int ret;

if (!attrs[MACSEC_ATTR_IFINDEX])
return -EINVAL;
@@ -1799,6 +1984,15 @@ static int macsec_del_rxsc(struct sk_buff *skb, struct genl_info *info)
return -ENODEV;
}

+ ret = macsec_hw_offload_rxsc(dev, MACSEC_DEL_RXSC, rx_sc);
+ if (ret) {
+ /* Revert del_rx_sc() */
+ if (rx_sc->active)
+ secy->n_rx_sc++;
+ rtnl_unlock();
+ return ret;
+ }
+
free_rx_sc(rx_sc);
rtnl_unlock();

@@ -1814,6 +2008,7 @@ static int macsec_del_txsa(struct sk_buff *skb, struct genl_info *info)
struct macsec_tx_sa *tx_sa;
u8 assoc_num;
struct nlattr *tb_sa[MACSEC_SA_ATTR_MAX + 1];
+ int ret;

if (!attrs[MACSEC_ATTR_IFINDEX])
return -EINVAL;
@@ -1834,6 +2029,13 @@ static int macsec_del_txsa(struct sk_buff *skb, struct genl_info *info)
return -EBUSY;
}

+ ret = macsec_hw_offload_txsa(dev, MACSEC_DEL_TXSA, tx_sa, assoc_num,
+ NULL);
+ if (ret) {
+ rtnl_unlock();
+ return ret;
+ }
+
RCU_INIT_POINTER(tx_sc->sa[assoc_num], NULL);
clear_tx_sa(tx_sa);

@@ -1872,6 +2074,7 @@ static int macsec_upd_txsa(struct sk_buff *skb, struct genl_info *info)
struct macsec_tx_sa *tx_sa;
u8 assoc_num;
struct nlattr *tb_sa[MACSEC_SA_ATTR_MAX + 1];
+ int ret;

if (!attrs[MACSEC_ATTR_IFINDEX])
return -EINVAL;
@@ -1902,9 +2105,16 @@ static int macsec_upd_txsa(struct sk_buff *skb, struct genl_info *info)
if (assoc_num == tx_sc->encoding_sa)
secy->operational = tx_sa->active;

+ ret = macsec_hw_offload_txsa(dev, MACSEC_UPD_TXSA, tx_sa, assoc_num,
+ NULL);
+ if (ret) {
+ tx_sa->active = !tx_sa->active;
+ secy->operational = tx_sa->active;
+ }
+
rtnl_unlock();

- return 0;
+ return ret;
}

static int macsec_upd_rxsa(struct sk_buff *skb, struct genl_info *info)
@@ -1917,6 +2127,7 @@ static int macsec_upd_rxsa(struct sk_buff *skb, struct genl_info *info)
u8 assoc_num;
struct nlattr *tb_rxsc[MACSEC_RXSC_ATTR_MAX + 1];
struct nlattr *tb_sa[MACSEC_SA_ATTR_MAX + 1];
+ int ret;

if (!attrs[MACSEC_ATTR_IFINDEX])
return -EINVAL;
@@ -1947,8 +2158,13 @@ static int macsec_upd_rxsa(struct sk_buff *skb, struct genl_info *info)
if (tb_sa[MACSEC_SA_ATTR_ACTIVE])
rx_sa->active = nla_get_u8(tb_sa[MACSEC_SA_ATTR_ACTIVE]);

+ ret = macsec_hw_offload_rxsa(dev, MACSEC_UPD_RXSA, rx_sa, assoc_num,
+ NULL);
+ if (ret)
+ rx_sa->active = !rx_sa->active;
+
rtnl_unlock();
- return 0;
+ return ret;
}

static int macsec_upd_rxsc(struct sk_buff *skb, struct genl_info *info)
@@ -2545,11 +2761,15 @@ static netdev_tx_t macsec_start_xmit(struct sk_buff *skb,
{
struct macsec_dev *macsec = netdev_priv(dev);
struct macsec_secy *secy = &macsec->secy;
+ struct macsec_tx_sc *tx_sc = &secy->tx_sc;
struct pcpu_secy_stats *secy_stats;
+ struct macsec_tx_sa *tx_sa;
int ret, len;

+ tx_sa = macsec_txsa_get(tx_sc->sa[tx_sc->encoding_sa]);
+
/* 10.5 */
- if (!secy->protect_frames) {
+ if (!secy->protect_frames || macsec_hw_offload_capable(macsec)) {
secy_stats = this_cpu_ptr(macsec->stats);
u64_stats_update_begin(&secy_stats->syncp);
secy_stats->stats.OutPktsUntagged++;
@@ -2662,6 +2882,15 @@ static int macsec_dev_open(struct net_device *dev)
goto clear_allmulti;
}

+ if (macsec_hw_offload_capable(macsec)) {
+ struct netdev_macsec ms;
+
+ memset(&ms, 0, sizeof(ms));
+ ms.command = MACSEC_DEV_OPEN;
+
+ macsec_hw_offload(dev, &ms);
+ }
+
if (netif_carrier_ok(real_dev))
netif_carrier_on(dev);

@@ -2682,6 +2911,15 @@ static int macsec_dev_stop(struct net_device *dev)

netif_carrier_off(dev);

+ if (macsec_hw_offload_capable(macsec)) {
+ struct netdev_macsec ms;
+
+ memset(&ms, 0, sizeof(ms));
+ ms.command = MACSEC_DEV_STOP;
+
+ macsec_hw_offload(dev, &ms);
+ }
+
dev_mc_unsync(real_dev, dev);
dev_uc_unsync(real_dev, dev);

@@ -2921,6 +3159,9 @@ static int macsec_changelink(struct net_device *dev, struct nlattr *tb[],
struct nlattr *data[],
struct netlink_ext_ack *extack)
{
+ struct macsec_dev *macsec = macsec_priv(dev);
+ int ret;
+
if (!data)
return 0;

@@ -2930,7 +3171,11 @@ static int macsec_changelink(struct net_device *dev, struct nlattr *tb[],
data[IFLA_MACSEC_PORT])
return -EINVAL;

- return macsec_changelink_common(dev, data);
+ ret = macsec_changelink_common(dev, data);
+ if (ret)
+ return ret;
+
+ return macsec_hw_offload_secy(dev, MACSEC_UPD_SECY, &macsec->secy);
}

static void macsec_del_dev(struct macsec_dev *macsec)
@@ -2973,6 +3218,7 @@ static void macsec_dellink(struct net_device *dev, struct list_head *head)
struct net_device *real_dev = macsec->real_dev;
struct macsec_rxh_data *rxd = macsec_data_rtnl(real_dev);

+ macsec_hw_offload_secy(dev, MACSEC_DEL_SECY, &macsec->secy);
macsec_common_dellink(dev, head);

if (list_empty(&rxd->secys)) {
@@ -3068,7 +3314,8 @@ static int macsec_newlink(struct net *net, struct net_device *dev,
struct netlink_ext_ack *extack)
{
struct macsec_dev *macsec = macsec_priv(dev);
- struct net_device *real_dev;
+ struct net_device *real_dev, *loop_dev;
+ struct net *loop_net;
int err;
sci_t sci;
u8 icv_len = DEFAULT_ICV_LEN;
@@ -3080,6 +3327,25 @@ static int macsec_newlink(struct net *net, struct net_device *dev,
if (!real_dev)
return -ENODEV;

+ for_each_net(loop_net) {
+ for_each_netdev(loop_net, loop_dev) {
+ struct macsec_dev *priv;
+
+ if (!netif_is_macsec(loop_dev))
+ continue;
+
+ priv = macsec_priv(loop_dev);
+
+ /* A limitation of the MACsec h/w offloading is only a
+ * single MACsec interface can be created for a given
+ * real interface.
+ */
+ if (macsec_hw_offload_capable(priv) &&
+ priv->real_dev == real_dev)
+ return -EBUSY;
+ }
+ }
+
dev->priv_flags |= IFF_MACSEC;

macsec->real_dev = real_dev;
@@ -3137,6 +3403,10 @@ static int macsec_newlink(struct net *net, struct net_device *dev,
if (err < 0)
goto del_dev;

+ err = macsec_hw_offload_secy(dev, MACSEC_ADD_SECY, &macsec->secy);
+ if (err)
+ goto del_dev;
+
netif_stacked_transfer_operstate(real_dev, dev);
linkwatch_fire_event(dev);

--
2.20.1


2019-01-23 16:03:57

by Antoine Tenart

[permalink] [raw]
Subject: [PATCH net-next 03/10] net: macsec: move some definitions in a dedicated header

This patch moves some structure, type and identifier definitions into a
MACsec specific header. This patch does not modify how the MACsec code
is running and only move things around. This is a preparation for the
future MACsec hardware offloading support, which will re-use those
definitions outside macsec.c.

Signed-off-by: Antoine Tenart <[email protected]>
---
drivers/net/macsec.c | 164 +--------------------------------------
include/net/macsec.h | 178 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 179 insertions(+), 163 deletions(-)
create mode 100644 include/net/macsec.h

diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
index 56e354305f76..c3a138dd4386 100644
--- a/drivers/net/macsec.c
+++ b/drivers/net/macsec.c
@@ -17,10 +17,9 @@
#include <net/sock.h>
#include <net/gro_cells.h>

+#include <net/macsec.h>
#include <uapi/linux/if_macsec.h>

-typedef u64 __bitwise sci_t;
-
#define MACSEC_SCI_LEN 8

/* SecTAG length = macsec_eth_header without the optional SCI */
@@ -58,8 +57,6 @@ struct macsec_eth_header {
#define GCM_AES_IV_LEN 12
#define DEFAULT_ICV_LEN 16

-#define MACSEC_NUM_AN 4 /* 2 bits for the association number */
-
#define for_each_rxsc(secy, sc) \
for (sc = rcu_dereference_bh(secy->rx_sc); \
sc; \
@@ -77,49 +74,6 @@ struct gcm_iv {
__be32 pn;
};

-/**
- * struct macsec_key - SA key
- * @id: user-provided key identifier
- * @tfm: crypto struct, key storage
- */
-struct macsec_key {
- u8 id[MACSEC_KEYID_LEN];
- struct crypto_aead *tfm;
-};
-
-struct macsec_rx_sc_stats {
- __u64 InOctetsValidated;
- __u64 InOctetsDecrypted;
- __u64 InPktsUnchecked;
- __u64 InPktsDelayed;
- __u64 InPktsOK;
- __u64 InPktsInvalid;
- __u64 InPktsLate;
- __u64 InPktsNotValid;
- __u64 InPktsNotUsingSA;
- __u64 InPktsUnusedSA;
-};
-
-struct macsec_rx_sa_stats {
- __u32 InPktsOK;
- __u32 InPktsInvalid;
- __u32 InPktsNotValid;
- __u32 InPktsNotUsingSA;
- __u32 InPktsUnusedSA;
-};
-
-struct macsec_tx_sa_stats {
- __u32 OutPktsProtected;
- __u32 OutPktsEncrypted;
-};
-
-struct macsec_tx_sc_stats {
- __u64 OutPktsProtected;
- __u64 OutPktsEncrypted;
- __u64 OutOctetsProtected;
- __u64 OutOctetsEncrypted;
-};
-
struct macsec_dev_stats {
__u64 OutPktsUntagged;
__u64 InPktsUntagged;
@@ -131,124 +85,8 @@ struct macsec_dev_stats {
__u64 InPktsOverrun;
};

-/**
- * struct macsec_rx_sa - receive secure association
- * @active:
- * @next_pn: packet number expected for the next packet
- * @lock: protects next_pn manipulations
- * @key: key structure
- * @stats: per-SA stats
- */
-struct macsec_rx_sa {
- struct macsec_key key;
- spinlock_t lock;
- u32 next_pn;
- refcount_t refcnt;
- bool active;
- struct macsec_rx_sa_stats __percpu *stats;
- struct macsec_rx_sc *sc;
- struct rcu_head rcu;
-};
-
-struct pcpu_rx_sc_stats {
- struct macsec_rx_sc_stats stats;
- struct u64_stats_sync syncp;
-};
-
-/**
- * struct macsec_rx_sc - receive secure channel
- * @sci: secure channel identifier for this SC
- * @active: channel is active
- * @sa: array of secure associations
- * @stats: per-SC stats
- */
-struct macsec_rx_sc {
- struct macsec_rx_sc __rcu *next;
- sci_t sci;
- bool active;
- struct macsec_rx_sa __rcu *sa[MACSEC_NUM_AN];
- struct pcpu_rx_sc_stats __percpu *stats;
- refcount_t refcnt;
- struct rcu_head rcu_head;
-};
-
-/**
- * struct macsec_tx_sa - transmit secure association
- * @active:
- * @next_pn: packet number to use for the next packet
- * @lock: protects next_pn manipulations
- * @key: key structure
- * @stats: per-SA stats
- */
-struct macsec_tx_sa {
- struct macsec_key key;
- spinlock_t lock;
- u32 next_pn;
- refcount_t refcnt;
- bool active;
- struct macsec_tx_sa_stats __percpu *stats;
- struct rcu_head rcu;
-};
-
-struct pcpu_tx_sc_stats {
- struct macsec_tx_sc_stats stats;
- struct u64_stats_sync syncp;
-};
-
-/**
- * struct macsec_tx_sc - transmit secure channel
- * @active:
- * @encoding_sa: association number of the SA currently in use
- * @encrypt: encrypt packets on transmit, or authenticate only
- * @send_sci: always include the SCI in the SecTAG
- * @end_station:
- * @scb: single copy broadcast flag
- * @sa: array of secure associations
- * @stats: stats for this TXSC
- */
-struct macsec_tx_sc {
- bool active;
- u8 encoding_sa;
- bool encrypt;
- bool send_sci;
- bool end_station;
- bool scb;
- struct macsec_tx_sa __rcu *sa[MACSEC_NUM_AN];
- struct pcpu_tx_sc_stats __percpu *stats;
-};
-
#define MACSEC_VALIDATE_DEFAULT MACSEC_VALIDATE_STRICT

-/**
- * struct macsec_secy - MACsec Security Entity
- * @netdev: netdevice for this SecY
- * @n_rx_sc: number of receive secure channels configured on this SecY
- * @sci: secure channel identifier used for tx
- * @key_len: length of keys used by the cipher suite
- * @icv_len: length of ICV used by the cipher suite
- * @validate_frames: validation mode
- * @operational: MAC_Operational flag
- * @protect_frames: enable protection for this SecY
- * @replay_protect: enable packet number checks on receive
- * @replay_window: size of the replay window
- * @tx_sc: transmit secure channel
- * @rx_sc: linked list of receive secure channels
- */
-struct macsec_secy {
- struct net_device *netdev;
- unsigned int n_rx_sc;
- sci_t sci;
- u16 key_len;
- u16 icv_len;
- enum macsec_validation_type validate_frames;
- bool operational;
- bool protect_frames;
- bool replay_protect;
- u32 replay_window;
- struct macsec_tx_sc tx_sc;
- struct macsec_rx_sc __rcu *rx_sc;
-};
-
struct pcpu_secy_stats {
struct macsec_dev_stats stats;
struct u64_stats_sync syncp;
diff --git a/include/net/macsec.h b/include/net/macsec.h
new file mode 100644
index 000000000000..15ff331dd670
--- /dev/null
+++ b/include/net/macsec.h
@@ -0,0 +1,178 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * MACsec netdev header, used for h/w accelerated implementations.
+ *
+ * Copyright (c) 2015 Sabrina Dubroca <[email protected]>
+ */
+#ifndef _NET_MACSEC_H_
+#define _NET_MACSEC_H_
+
+#include <linux/u64_stats_sync.h>
+#include <uapi/linux/if_link.h>
+#include <uapi/linux/if_macsec.h>
+
+typedef u64 __bitwise sci_t;
+
+#define MACSEC_NUM_AN 4 /* 2 bits for the association number */
+
+/**
+ * struct macsec_key - SA key
+ * @id: user-provided key identifier
+ * @tfm: crypto struct, key storage
+ */
+struct macsec_key {
+ u8 id[MACSEC_KEYID_LEN];
+ struct crypto_aead *tfm;
+};
+
+struct macsec_rx_sc_stats {
+ __u64 InOctetsValidated;
+ __u64 InOctetsDecrypted;
+ __u64 InPktsUnchecked;
+ __u64 InPktsDelayed;
+ __u64 InPktsOK;
+ __u64 InPktsInvalid;
+ __u64 InPktsLate;
+ __u64 InPktsNotValid;
+ __u64 InPktsNotUsingSA;
+ __u64 InPktsUnusedSA;
+};
+
+struct macsec_rx_sa_stats {
+ __u32 InPktsOK;
+ __u32 InPktsInvalid;
+ __u32 InPktsNotValid;
+ __u32 InPktsNotUsingSA;
+ __u32 InPktsUnusedSA;
+};
+
+struct macsec_tx_sa_stats {
+ __u32 OutPktsProtected;
+ __u32 OutPktsEncrypted;
+};
+
+struct macsec_tx_sc_stats {
+ __u64 OutPktsProtected;
+ __u64 OutPktsEncrypted;
+ __u64 OutOctetsProtected;
+ __u64 OutOctetsEncrypted;
+};
+
+/**
+ * struct macsec_rx_sa - receive secure association
+ * @active:
+ * @next_pn: packet number expected for the next packet
+ * @lock: protects next_pn manipulations
+ * @key: key structure
+ * @stats: per-SA stats
+ */
+struct macsec_rx_sa {
+ struct macsec_key key;
+ spinlock_t lock;
+ u32 next_pn;
+ refcount_t refcnt;
+ bool active;
+ struct macsec_rx_sa_stats __percpu *stats;
+ struct macsec_rx_sc *sc;
+ struct rcu_head rcu;
+};
+
+struct pcpu_rx_sc_stats {
+ struct macsec_rx_sc_stats stats;
+ struct u64_stats_sync syncp;
+};
+
+struct pcpu_tx_sc_stats {
+ struct macsec_tx_sc_stats stats;
+ struct u64_stats_sync syncp;
+};
+
+/**
+ * struct macsec_rx_sc - receive secure channel
+ * @sci: secure channel identifier for this SC
+ * @active: channel is active
+ * @sa: array of secure associations
+ * @stats: per-SC stats
+ */
+struct macsec_rx_sc {
+ struct macsec_rx_sc __rcu *next;
+ sci_t sci;
+ bool active;
+ struct macsec_rx_sa __rcu *sa[MACSEC_NUM_AN];
+ struct pcpu_rx_sc_stats __percpu *stats;
+ refcount_t refcnt;
+ struct rcu_head rcu_head;
+};
+
+/**
+ * struct macsec_tx_sa - transmit secure association
+ * @active:
+ * @next_pn: packet number to use for the next packet
+ * @lock: protects next_pn manipulations
+ * @key: key structure
+ * @stats: per-SA stats
+ */
+struct macsec_tx_sa {
+ struct macsec_key key;
+ spinlock_t lock;
+ u32 next_pn;
+ refcount_t refcnt;
+ bool active;
+ bool offloaded;
+ struct macsec_tx_sa_stats __percpu *stats;
+ struct rcu_head rcu;
+};
+
+/**
+ * struct macsec_tx_sc - transmit secure channel
+ * @active:
+ * @encoding_sa: association number of the SA currently in use
+ * @encrypt: encrypt packets on transmit, or authenticate only
+ * @send_sci: always include the SCI in the SecTAG
+ * @end_station:
+ * @scb: single copy broadcast flag
+ * @sa: array of secure associations
+ * @stats: stats for this TXSC
+ */
+struct macsec_tx_sc {
+ bool active;
+ u8 encoding_sa;
+ bool encrypt;
+ bool send_sci;
+ bool end_station;
+ bool scb;
+ struct macsec_tx_sa __rcu *sa[MACSEC_NUM_AN];
+ struct pcpu_tx_sc_stats __percpu *stats;
+};
+
+/**
+ * struct macsec_secy - MACsec Security Entity
+ * @netdev: netdevice for this SecY
+ * @n_rx_sc: number of receive secure channels configured on this SecY
+ * @sci: secure channel identifier used for tx
+ * @key_len: length of keys used by the cipher suite
+ * @icv_len: length of ICV used by the cipher suite
+ * @validate_frames: validation mode
+ * @operational: MAC_Operational flag
+ * @protect_frames: enable protection for this SecY
+ * @replay_protect: enable packet number checks on receive
+ * @replay_window: size of the replay window
+ * @tx_sc: transmit secure channel
+ * @rx_sc: linked list of receive secure channels
+ */
+struct macsec_secy {
+ struct net_device *netdev;
+ unsigned int n_rx_sc;
+ sci_t sci;
+ u16 key_len;
+ u16 icv_len;
+ enum macsec_validation_type validate_frames;
+ bool operational;
+ bool protect_frames;
+ bool replay_protect;
+ u32 replay_window;
+ struct macsec_tx_sc tx_sc;
+ struct macsec_rx_sc __rcu *rx_sc;
+};
+
+#endif /* _NET_MACSEC_H_ */
--
2.20.1


2019-01-23 17:05:03

by Andrew Lunn

[permalink] [raw]
Subject: Re: [PATCH net-next 02/10] net: macsec: convert to SPDX

On Wed, Jan 23, 2019 at 04:56:30PM +0100, Antoine Tenart wrote:
> This cosmetic patch converts the macsec implementation license header to
> the now recommended format, SPDX.
>
> Signed-off-by: Antoine Tenart <[email protected]>
> ---
> drivers/net/macsec.c | 6 +-----
> 1 file changed, 1 insertion(+), 5 deletions(-)
>
> diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
> index 64a982563d59..56e354305f76 100644
> --- a/drivers/net/macsec.c
> +++ b/drivers/net/macsec.c
> @@ -1,12 +1,8 @@
> +// SPDX-License-Identifier: GPL-2.0+
> /*
> * drivers/net/macsec.c - MACsec device
> *
> * Copyright (c) 2015 Sabrina Dubroca <[email protected]>
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License as published by
> - * the Free Software Foundation; either version 2 of the License, or
> - * (at your option) any later version.
> */
>
> #include <linux/types.h>

Hi Antoine

linux$ tail -4 drivers/net/macsec.c
MODULE_ALIAS_GENL_FAMILY("macsec");

MODULE_DESCRIPTION("MACsec IEEE 802.1AE");
MODULE_LICENSE("GPL v2");

The license text and the MODULE_LICENSE() don't agree with each other.
It would be good to fix this as well.

Thanks
Andrew

2019-01-23 17:10:35

by Andrew Lunn

[permalink] [raw]
Subject: Re: [PATCH net-next 05/10] net: phy: introduce a phy_driver macsec helper

> +int phy_macsec(struct phy_device *phydev, struct netdev_macsec *macsec)
> +{
> + int ret = -EOPNOTSUPP;
> +
> + if (!phydev->drv)
> + return -EIO;
> +
> + mutex_lock(&phydev->lock);
> +
> + if (phydev->drv->macsec)
> + ret = phydev->drv->macsec(phydev, macsec);
> +
> + mutex_unlock(&phydev->lock);
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(phy_macsec);
> +

> @@ -630,6 +634,10 @@ struct phy_driver {
> struct ethtool_tunable *tuna,
> const void *data);
> int (*set_loopback)(struct phy_device *dev, bool enable);
> +
> +#ifdef CONFIG_MACSEC
> + int (*macsec)(struct phy_device *dev, struct netdev_macsec *macsec);
> +#endif

Hi Antoine

So the member only exists if CONFIG_MACSEC is defined. So i think you
need similar protection in phy_macsec() or you are going to try to
access a member which sometimes does not exist.

Andrew

2019-01-23 20:12:16

by Florian Fainelli

[permalink] [raw]
Subject: Re: [PATCH net-next 03/10] net: macsec: move some definitions in a dedicated header

On 1/23/19 7:56 AM, Antoine Tenart wrote:
> This patch moves some structure, type and identifier definitions into a
> MACsec specific header. This patch does not modify how the MACsec code
> is running and only move things around. This is a preparation for the
> future MACsec hardware offloading support, which will re-use those
> definitions outside macsec.c.
>
> Signed-off-by: Antoine Tenart <[email protected]>
> ---
> drivers/net/macsec.c | 164 +--------------------------------------
> include/net/macsec.h | 178 +++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 179 insertions(+), 163 deletions(-)
> create mode 100644 include/net/macsec.h
>
> diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
> index 56e354305f76..c3a138dd4386 100644
> --- a/drivers/net/macsec.c
> +++ b/drivers/net/macsec.c
> @@ -17,10 +17,9 @@
> #include <net/sock.h>
> #include <net/gro_cells.h>
>
> +#include <net/macsec.h>
> #include <uapi/linux/if_macsec.h>

I would probably go with include/linux/if_macsec.h and have
uapi/linux/if_macsec.h include that file directly. This would be
consistent with other types of network interfaces: bridge, vlan etc.
--
Florian

2019-01-23 20:16:48

by Florian Fainelli

[permalink] [raw]
Subject: Re: [PATCH net-next 06/10] net: introduce a net_device_ops macsec helper

On 1/23/19 7:56 AM, Antoine Tenart wrote:
> This patch introduces a net_device_ops MACsec helper to allow net device
> drivers to implement a MACsec offloading solution.
>
> Signed-off-by: Antoine Tenart <[email protected]>
> ---
> include/linux/netdevice.h | 8 ++++++++
> 1 file changed, 8 insertions(+)
>
> diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
> index e675ef97a426..ee2f40dca515 100644
> --- a/include/linux/netdevice.h
> +++ b/include/linux/netdevice.h
> @@ -53,6 +53,10 @@
> #include <uapi/linux/pkt_cls.h>
> #include <linux/hashtable.h>
>
> +#ifdef CONFIG_MACSEC
> +#include <net/macsec.h>
> +#endif

You can provide a forward declaration for struct netdev_macsec and not
have to include that header file.

> +
> struct netpoll_info;
> struct device;
> struct phy_device;
> @@ -1441,6 +1445,10 @@ struct net_device_ops {
> u32 flags);
> int (*ndo_xsk_async_xmit)(struct net_device *dev,
> u32 queue_id);
> +#ifdef CONFIG_MACSEC
> + int (*ndo_macsec)(struct net_device *dev,
> + struct netdev_macsec *macsec);

You would really want to define an API which is more oriented towards
configuring/deconfiguring a MACsec association here, e.g.: similar to
what the IPsec offload ndos offer.

It is not clear to me whether after your patch series we still need to
create a macsec virtual device, and that gets offloaded onto its real
device/PHY device, or if we don't need that all?
--
Florian

2019-01-24 01:02:47

by David Miller

[permalink] [raw]
Subject: Re: [PATCH net-next 03/10] net: macsec: move some definitions in a dedicated header

From: Florian Fainelli <[email protected]>
Date: Wed, 23 Jan 2019 12:11:37 -0800

> On 1/23/19 7:56 AM, Antoine Tenart wrote:
>> This patch moves some structure, type and identifier definitions into a
>> MACsec specific header. This patch does not modify how the MACsec code
>> is running and only move things around. This is a preparation for the
>> future MACsec hardware offloading support, which will re-use those
>> definitions outside macsec.c.
>>
>> Signed-off-by: Antoine Tenart <[email protected]>
>> ---
>> drivers/net/macsec.c | 164 +--------------------------------------
>> include/net/macsec.h | 178 +++++++++++++++++++++++++++++++++++++++++++
>> 2 files changed, 179 insertions(+), 163 deletions(-)
>> create mode 100644 include/net/macsec.h
>>
>> diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
>> index 56e354305f76..c3a138dd4386 100644
>> --- a/drivers/net/macsec.c
>> +++ b/drivers/net/macsec.c
>> @@ -17,10 +17,9 @@
>> #include <net/sock.h>
>> #include <net/gro_cells.h>
>>
>> +#include <net/macsec.h>
>> #include <uapi/linux/if_macsec.h>
>
> I would probably go with include/linux/if_macsec.h and have
> uapi/linux/if_macsec.h include that file directly. This would be
> consistent with other types of network interfaces: bridge, vlan etc.

Agreed.

2019-01-24 08:57:25

by Antoine Tenart

[permalink] [raw]
Subject: Re: [PATCH net-next 02/10] net: macsec: convert to SPDX

Hi Andrew,

On Wed, Jan 23, 2019 at 06:03:06PM +0100, Andrew Lunn wrote:
> On Wed, Jan 23, 2019 at 04:56:30PM +0100, Antoine Tenart wrote:
> > This cosmetic patch converts the macsec implementation license header to
> > the now recommended format, SPDX.
> >
> > Signed-off-by: Antoine Tenart <[email protected]>
> > ---
> > drivers/net/macsec.c | 6 +-----
> > 1 file changed, 1 insertion(+), 5 deletions(-)
> >
> > diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
> > index 64a982563d59..56e354305f76 100644
> > --- a/drivers/net/macsec.c
> > +++ b/drivers/net/macsec.c
> > @@ -1,12 +1,8 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > /*
> > * drivers/net/macsec.c - MACsec device
> > *
> > * Copyright (c) 2015 Sabrina Dubroca <[email protected]>
> > - *
> > - * This program is free software; you can redistribute it and/or modify
> > - * it under the terms of the GNU General Public License as published by
> > - * the Free Software Foundation; either version 2 of the License, or
> > - * (at your option) any later version.
> > */
> >
> > #include <linux/types.h>
>
> linux$ tail -4 drivers/net/macsec.c
> MODULE_ALIAS_GENL_FAMILY("macsec");
>
> MODULE_DESCRIPTION("MACsec IEEE 802.1AE");
> MODULE_LICENSE("GPL v2");
>
> The license text and the MODULE_LICENSE() don't agree with each other.
> It would be good to fix this as well.

That's right, I'll fix it in v2. In such cases, the license text takes
precedence over the MODULE_LICENSE() definition ?

Thanks!
Antoine

--
Antoine T?nart, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

2019-01-24 08:57:26

by Antoine Tenart

[permalink] [raw]
Subject: Re: [PATCH net-next 05/10] net: phy: introduce a phy_driver macsec helper

Hi Andrew,

On Wed, Jan 23, 2019 at 06:08:16PM +0100, Andrew Lunn wrote:
> > +int phy_macsec(struct phy_device *phydev, struct netdev_macsec *macsec)
> > +{
> > + int ret = -EOPNOTSUPP;
> > +
> > + if (!phydev->drv)
> > + return -EIO;
> > +
> > + mutex_lock(&phydev->lock);
> > +
> > + if (phydev->drv->macsec)
> > + ret = phydev->drv->macsec(phydev, macsec);
> > +
> > + mutex_unlock(&phydev->lock);
> > + return ret;
> > +}
> > +EXPORT_SYMBOL_GPL(phy_macsec);
> > +
>
> > @@ -630,6 +634,10 @@ struct phy_driver {
> > struct ethtool_tunable *tuna,
> > const void *data);
> > int (*set_loopback)(struct phy_device *dev, bool enable);
> > +
> > +#ifdef CONFIG_MACSEC
> > + int (*macsec)(struct phy_device *dev, struct netdev_macsec *macsec);
> > +#endif
>
>
> So the member only exists if CONFIG_MACSEC is defined. So i think you
> need similar protection in phy_macsec() or you are going to try to
> access a member which sometimes does not exist.

Right, I'll fix that and protect the phy_macsec definition within an
'#ifdef CONFIG_MACSEC'.

Thanks!
Antoine

--
Antoine T?nart, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

2019-01-24 08:59:04

by Antoine Tenart

[permalink] [raw]
Subject: Re: [PATCH net-next 03/10] net: macsec: move some definitions in a dedicated header

Hi Florian,

On Wed, Jan 23, 2019 at 12:11:37PM -0800, Florian Fainelli wrote:
> On 1/23/19 7:56 AM, Antoine Tenart wrote:
> > This patch moves some structure, type and identifier definitions into a
> > MACsec specific header. This patch does not modify how the MACsec code
> > is running and only move things around. This is a preparation for the
> > future MACsec hardware offloading support, which will re-use those
> > definitions outside macsec.c.
> >
> > Signed-off-by: Antoine Tenart <[email protected]>
> > ---
> > drivers/net/macsec.c | 164 +--------------------------------------
> > include/net/macsec.h | 178 +++++++++++++++++++++++++++++++++++++++++++
> > 2 files changed, 179 insertions(+), 163 deletions(-)
> > create mode 100644 include/net/macsec.h
> >
> > diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
> > index 56e354305f76..c3a138dd4386 100644
> > --- a/drivers/net/macsec.c
> > +++ b/drivers/net/macsec.c
> > @@ -17,10 +17,9 @@
> > #include <net/sock.h>
> > #include <net/gro_cells.h>
> >
> > +#include <net/macsec.h>
> > #include <uapi/linux/if_macsec.h>
>
> I would probably go with include/linux/if_macsec.h and have
> uapi/linux/if_macsec.h include that file directly. This would be
> consistent with other types of network interfaces: bridge, vlan etc.

It's always a good idea to stay consistent with what's already done.
I'll update in v2.

Thanks!
Antoine

--
Antoine T?nart, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

2019-01-24 09:24:30

by Antoine Tenart

[permalink] [raw]
Subject: Re: [PATCH net-next 06/10] net: introduce a net_device_ops macsec helper

Hi Florian,

On Wed, Jan 23, 2019 at 12:16:08PM -0800, Florian Fainelli wrote:
> On 1/23/19 7:56 AM, Antoine Tenart wrote:
> > This patch introduces a net_device_ops MACsec helper to allow net device
> > drivers to implement a MACsec offloading solution.
> >
> > Signed-off-by: Antoine Tenart <[email protected]>
> > ---
> > include/linux/netdevice.h | 8 ++++++++
> > 1 file changed, 8 insertions(+)
> >
> > diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
> > index e675ef97a426..ee2f40dca515 100644
> > --- a/include/linux/netdevice.h
> > +++ b/include/linux/netdevice.h
> > @@ -53,6 +53,10 @@
> > #include <uapi/linux/pkt_cls.h>
> > #include <linux/hashtable.h>
> >
> > +#ifdef CONFIG_MACSEC
> > +#include <net/macsec.h>
> > +#endif
>
> You can provide a forward declaration for struct netdev_macsec and not
> have to include that header file.

OK.

> > +
> > struct netpoll_info;
> > struct device;
> > struct phy_device;
> > @@ -1441,6 +1445,10 @@ struct net_device_ops {
> > u32 flags);
> > int (*ndo_xsk_async_xmit)(struct net_device *dev,
> > u32 queue_id);
> > +#ifdef CONFIG_MACSEC
> > + int (*ndo_macsec)(struct net_device *dev,
> > + struct netdev_macsec *macsec);
>
> You would really want to define an API which is more oriented towards
> configuring/deconfiguring a MACsec association here, e.g.: similar to
> what the IPsec offload ndos offer.

This means mostly moving from a single function using a command field to
multiple specialized functions to add/remove each element of MACsec
configuration.

I don't have strong opinion on the single helper vs a structure
containing pointers to specialized ones, but out of curiosity what's the
benefit of such a move? Future additions and maintainability?

> It is not clear to me whether after your patch series we still need to
> create a macsec virtual device, and that gets offloaded onto its real
> device/PHY device, or if we don't need that all?

After this series, we will still need the virtual MACsec interface. When
using hardware offloading this interface isn't doing much, but it's the
interface used to configure all the MACsec connexions.

This is because, and that's specific to MACsec (vs IPsec), a software
implementation is already supported and it's using a virtual interface
to perform all the MACsec related operations (vs hooks in the Rx/Tx
paths). I really wanted to avoid having two interfaces and ways of
configuring MACsec depending on if the offloading is used.

This should also allow in the future to disable at run-time the
offloading on a given interface, and to still have MACsec working in
software (or the opposite, with extra work). For this to work, the
virtual interface still has to provide an Rx and a Tx functions so that
programs can bind onto the same interface, regardless of if the
offloading is enabled.

Thanks!
Antoine

--
Antoine T?nart, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

2019-01-24 13:12:04

by Andrew Lunn

[permalink] [raw]
Subject: Re: [PATCH net-next 02/10] net: macsec: convert to SPDX

> That's right, I'll fix it in v2. In such cases, the license text takes
> precedence over the MODULE_LICENSE() definition ?

Hi Antoine

IANAL

I've also not seen any real discussion about this. But when i recently
proposed patches to cleanup similar issues in drivers/net/phy, i gave
the license text precedence, since it is a lot easier for a human to
understand, and it is likely a human made the error....


Andrew

2019-01-24 13:30:13

by Antoine Tenart

[permalink] [raw]
Subject: Re: [PATCH net-next 02/10] net: macsec: convert to SPDX

Hi Andrew,

On Thu, Jan 24, 2019 at 02:11:18PM +0100, Andrew Lunn wrote:
> > That's right, I'll fix it in v2. In such cases, the license text takes
> > precedence over the MODULE_LICENSE() definition ?
>
> I've also not seen any real discussion about this. But when i recently
> proposed patches to cleanup similar issues in drivers/net/phy, i gave
> the license text precedence, since it is a lot easier for a human to
> understand, and it is likely a human made the error....

I would go for this as well, it seems logical for MODULE_LICENSE() to
only be an identifier of what the license described in the license text
is.

Thanks!
Antoine

--
Antoine T?nart, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

2019-01-24 14:59:45

by Igor Russkikh

[permalink] [raw]
Subject: Re: [PATCH net-next 06/10] net: introduce a net_device_ops macsec helper


Hi Antoine,

Its great to see macsec hw offload infrastructure happening!

> @@ -1441,6 +1445,10 @@ struct net_device_ops {
> u32 flags);
> int (*ndo_xsk_async_xmit)(struct net_device *dev,
> u32 queue_id);
> +#ifdef CONFIG_MACSEC
> + int (*ndo_macsec)(struct net_device *dev,
> + struct netdev_macsec *macsec);
> +#endif
> };

Most of ndo's are named by action verbs. This ndo is abit misleading, reader
may have difficulties understanding what

+ if (phydev->drv->macsec)
+ ret = phydev->drv->macsec(phydev, macsec);

is actually doing.

May be it'd be better renaming to at least ndo_do_macsec(), or ndo_setup_macsec()
?

Similar comment is for

+struct netdev_macsec {

It reads like a macsec device context, but it is a macsec configuration command.

Regards,
Igor

2019-01-24 15:08:35

by Antoine Tenart

[permalink] [raw]
Subject: Re: [PATCH net-next 06/10] net: introduce a net_device_ops macsec helper

Hi Igor,

On Thu, Jan 24, 2019 at 02:58:45PM +0000, Igor Russkikh wrote:
>
> Its great to see macsec hw offload infrastructure happening!
>
> > @@ -1441,6 +1445,10 @@ struct net_device_ops {
> > u32 flags);
> > int (*ndo_xsk_async_xmit)(struct net_device *dev,
> > u32 queue_id);
> > +#ifdef CONFIG_MACSEC
> > + int (*ndo_macsec)(struct net_device *dev,
> > + struct netdev_macsec *macsec);
> > +#endif
> > };
>
> Most of ndo's are named by action verbs. This ndo is abit misleading, reader
> may have difficulties understanding what
>
> + if (phydev->drv->macsec)
> + ret = phydev->drv->macsec(phydev, macsec);
>
> is actually doing.
>
> May be it'd be better renaming to at least ndo_do_macsec(), or ndo_setup_macsec()
> ?
>
> Similar comment is for
>
> +struct netdev_macsec {
>
> It reads like a macsec device context, but it is a macsec configuration command.

OK, I'll rename the functions so that they contain a verb.

Thanks!
Antoine

--
Antoine T?nart, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

2019-01-31 09:32:58

by Antoine Tenart

[permalink] [raw]
Subject: Re: [PATCH net-next 06/10] net: introduce a net_device_ops macsec helper

Hi,

On Thu, Jan 24, 2019 at 10:23:49AM +0100, Antoine Tenart wrote:
> On Wed, Jan 23, 2019 at 12:16:08PM -0800, Florian Fainelli wrote:
> > On 1/23/19 7:56 AM, Antoine Tenart wrote:
> > > @@ -1441,6 +1445,10 @@ struct net_device_ops {
> > > u32 flags);
> > > int (*ndo_xsk_async_xmit)(struct net_device *dev,
> > > u32 queue_id);
> > > +#ifdef CONFIG_MACSEC
> > > + int (*ndo_macsec)(struct net_device *dev,
> > > + struct netdev_macsec *macsec);
> >
> > You would really want to define an API which is more oriented towards
> > configuring/deconfiguring a MACsec association here, e.g.: similar to
> > what the IPsec offload ndos offer.
>
> This means mostly moving from a single function using a command field to
> multiple specialized functions to add/remove each element of MACsec
> configuration.
>
> I don't have strong opinion on the single helper vs a structure
> containing pointers to specialized ones, but out of curiosity what's the
> benefit of such a move? Future additions and maintainability?
>
> > It is not clear to me whether after your patch series we still need to
> > create a macsec virtual device, and that gets offloaded onto its real
> > device/PHY device, or if we don't need that all?
>
> After this series, we will still need the virtual MACsec interface. When
> using hardware offloading this interface isn't doing much, but it's the
> interface used to configure all the MACsec connexions.
>
> This is because, and that's specific to MACsec (vs IPsec), a software
> implementation is already supported and it's using a virtual interface
> to perform all the MACsec related operations (vs hooks in the Rx/Tx
> paths). I really wanted to avoid having two interfaces and ways of
> configuring MACsec depending on if the offloading is used.
>
> This should also allow in the future to disable at run-time the
> offloading on a given interface, and to still have MACsec working in
> software (or the opposite, with extra work). For this to work, the
> virtual interface still has to provide an Rx and a Tx functions so that
> programs can bind onto the same interface, regardless of if the
> offloading is enabled.

Do you need extra information and explanations about this? I believe
this point is very important as the design choices were influenced a lot
by reusing the s/w implementation logic and API.

Thanks!
Antoine

--
Antoine T?nart, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com