mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-25 10:42:21 +03:00
nvethernet: Add support for MACsec controller
This commit adds the driver interface for the MACsec controller. The driver interface is invoked using generic netlink messages from userspace MACsec key agreement agent. Currently sysfs node is added to check the irq stats for default macsec controller operation. Bug 2913560 Change-Id: I07b0b778ba1c6674e87b103a3e68e158fea61c2c Signed-off-by: Srinivas Ramachandran <srinivasra@nvidia.com>
This commit is contained in:
committed by
Revanth Kumar Uppala
parent
c651869a94
commit
805fe9c4fa
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2018-2020, NVIDIA CORPORATION. All rights reserved.
|
||||
# Copyright (c) 2018-2021, NVIDIA CORPORATION. All rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms and conditions of the GNU General Public License,
|
||||
@@ -21,13 +21,17 @@ obj-$(CONFIG_NVETHERNET) += nvethernet.o
|
||||
ccflags-y += -DTHERMAL_CAL -DLINUX_IVC -I$(srctree.nvidia)/drivers/net/ethernet/nvidia/nvethernet/nvethernetrm/include \
|
||||
-I$(srctree.nvidia)/drivers/net/ethernet/nvidia/nvethernet/nvethernetrm/osi/common/include
|
||||
|
||||
ccflags-y += -DMACSEC_SUPPORT -DNET30 -DMACSEC_DEBUG
|
||||
|
||||
nvethernet-objs:= ether_linux.o \
|
||||
osd.o \
|
||||
ethtool.o \
|
||||
sysfs.o \
|
||||
ioctl.o \
|
||||
ptp.o \
|
||||
macsec.o \
|
||||
$(OSI_CORE)/osi_core.o \
|
||||
$(OSI_CORE)/macsec.o \
|
||||
$(OSI_COMMON)/osi_common.o \
|
||||
$(OSI_COMMON)/eqos_common.o \
|
||||
$(OSI_COMMON)/mgbe_common.o \
|
||||
|
||||
@@ -804,7 +804,7 @@ static int ether_init_ivc(struct ether_priv_data *pdata)
|
||||
}
|
||||
|
||||
dev_info(dev, "Reserved IVC channel #%u - frame_size=%d irq %d\n",
|
||||
id, ictxt->ivck->frame_size, ictxt->ivck->irq);
|
||||
id, ictxt->ivck->frame_size, ictxt->ivck->irq);
|
||||
osi_core->osd_ops.ivc_send = osd_ivc_send_cmd;
|
||||
init_completion(&ictxt->msg_complete);
|
||||
ether_start_ivc(pdata);
|
||||
@@ -1603,6 +1603,14 @@ static void ether_reset(struct ether_priv_data *pdata)
|
||||
unsigned int val;
|
||||
void __iomem *addr = devm_ioremap(pdata->dev, 0x21460018, 0x4);
|
||||
|
||||
#if 1 /* Rakesh WAR for AN 0 issue */
|
||||
/* power ungate and ether_reset will be moved to bpmp fw so reset()
|
||||
* api should be called. TODO HACK by writing oxffff to
|
||||
* CLK_RST_CONTROLLER_RST_DEV_MGBE_0
|
||||
*/
|
||||
writel(0xffff, addr);
|
||||
#endif
|
||||
|
||||
val = readl(addr);
|
||||
val &= ~BIT(0);
|
||||
writel(val, addr);
|
||||
@@ -1614,6 +1622,15 @@ static void ether_reset(struct ether_priv_data *pdata)
|
||||
val = readl(addr);
|
||||
val &= ~BIT(8);
|
||||
writel(val, addr);
|
||||
|
||||
#if 1
|
||||
/* NET30 enables secure reset, WAR to reset macsec secure RST, this
|
||||
* should be moved to bbmp fw
|
||||
*/
|
||||
val = readl(addr);
|
||||
val &= ~BIT(12);
|
||||
writel(val, addr);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void power_ungate(struct ether_priv_data *pdata)
|
||||
@@ -1776,6 +1793,17 @@ static int ether_open(struct net_device *dev)
|
||||
/* Enable napi before requesting irq to be ready to handle it */
|
||||
ether_napi_enable(pdata);
|
||||
|
||||
#ifdef MACSEC_SUPPORT
|
||||
#ifdef DEBUG_MACSEC
|
||||
ret = macsec_open(pdata->macsec_pdata);
|
||||
if (ret < 0) {
|
||||
dev_err(&dev->dev, "%s: failed to open macsec with reason %d\n",
|
||||
__func__, ret);
|
||||
goto err_macsec_open;
|
||||
}
|
||||
#endif
|
||||
#endif /* MACSEC_SUPPORT */
|
||||
|
||||
/* request tx/rx/common irq */
|
||||
ret = ether_request_irqs(pdata);
|
||||
if (ret < 0) {
|
||||
@@ -1802,6 +1830,11 @@ static int ether_open(struct net_device *dev)
|
||||
|
||||
return ret;
|
||||
|
||||
#ifdef MACSEC_SUPPORT
|
||||
#ifdef DEBUG_MACSEC
|
||||
err_macsec_open:
|
||||
#endif
|
||||
#endif /* MACSEC_SUPPORT */
|
||||
err_r_irq:
|
||||
ether_napi_disable(pdata);
|
||||
ether_ptp_remove(pdata);
|
||||
@@ -1944,6 +1977,15 @@ static int ether_close(struct net_device *ndev)
|
||||
/* Disable clock */
|
||||
ether_disable_clks(pdata);
|
||||
|
||||
#ifdef MACSEC_SUPPORT
|
||||
#ifdef DEBUG_MACSEC
|
||||
ret = macsec_close(pdata->macsec_pdata);
|
||||
if (ret < 0) {
|
||||
dev_err(pdata->dev, "Failed to close macsec");
|
||||
}
|
||||
#endif
|
||||
#endif /* MACSEC_SUPPORT */
|
||||
|
||||
/* Reset stats since interface is going down */
|
||||
ether_reset_stats(pdata);
|
||||
|
||||
@@ -4482,6 +4524,11 @@ static int ether_probe(struct platform_device *pdev)
|
||||
struct net_device *ndev;
|
||||
int ret = 0, i;
|
||||
|
||||
#ifdef TEST
|
||||
macsec_genl_register();
|
||||
return 0;
|
||||
#endif /* TEST */
|
||||
|
||||
ether_get_num_dma_chan_mtl_q(pdev, &num_dma_chans,
|
||||
&mac, &num_mtl_queues);
|
||||
|
||||
@@ -4619,6 +4666,28 @@ static int ether_probe(struct platform_device *pdev)
|
||||
ether_tx_usecs_hrtimer;
|
||||
}
|
||||
|
||||
#ifdef MACSEC_SUPPORT
|
||||
ret = macsec_probe(pdata);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to setup macsec\n");
|
||||
goto err_macsec;
|
||||
} else if (ret == 0) {
|
||||
/* Macsec is initialized, reduce MTU
|
||||
* TODO: MTU_ADDONS also to be reduced ?
|
||||
*/
|
||||
pdata->max_platform_mtu -= MACSEC_TAG_ICV_LEN;
|
||||
ndev->max_mtu = pdata->max_platform_mtu;
|
||||
osi_core->mtu -= MACSEC_TAG_ICV_LEN;
|
||||
osi_dma->mtu = osi_core->mtu;
|
||||
ndev->mtu = osi_core->mtu;
|
||||
dev_info(&pdev->dev, "Macsec: Reduced MTU: %d Max: %d\n",
|
||||
ndev->mtu, ndev->max_mtu);
|
||||
} else {
|
||||
; //Nothing to do, macsec is not supported
|
||||
dev_info(&pdev->dev, "Macsec not enabled - ignore\n");
|
||||
}
|
||||
#endif /* MACSEC_SUPPORT */
|
||||
|
||||
ret = register_netdev(ndev);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to register netdev\n");
|
||||
@@ -4656,6 +4725,9 @@ static int ether_probe(struct platform_device *pdev)
|
||||
err_sysfs:
|
||||
unregister_netdev(ndev);
|
||||
err_netdev:
|
||||
#ifdef MACSEC_SUPPORT
|
||||
err_macsec:
|
||||
#endif /* MACSEC_SUPPORT */
|
||||
err_napi:
|
||||
mdiobus_unregister(pdata->mii);
|
||||
err_dma_mask:
|
||||
@@ -4688,6 +4760,14 @@ static int ether_remove(struct platform_device *pdev)
|
||||
struct net_device *ndev = platform_get_drvdata(pdev);
|
||||
struct ether_priv_data *pdata = netdev_priv(ndev);
|
||||
|
||||
#ifdef MACSEC_SUPPORT
|
||||
#ifdef TEST
|
||||
macsec_genl_unregister();
|
||||
return 0;
|
||||
#endif /* TEST */
|
||||
macsec_remove(pdata);
|
||||
#endif /* MACSEC_SUPPORT */
|
||||
|
||||
unregister_netdev(ndev);
|
||||
|
||||
/* remove nvethernet sysfs group under /sys/devices/<ether_device>/ */
|
||||
|
||||
@@ -52,7 +52,9 @@
|
||||
#include <osi_dma.h>
|
||||
#include <mmc.h>
|
||||
#include "ioctl.h"
|
||||
|
||||
#ifdef MACSEC_SUPPORT
|
||||
#include "macsec.h"
|
||||
#endif
|
||||
/**
|
||||
* @brief Max number of Ethernet IRQs supported in HW
|
||||
*/
|
||||
@@ -271,7 +273,7 @@ struct ether_ivc_ctxt {
|
||||
* @brief Ethernet driver private data
|
||||
*/
|
||||
struct ether_priv_data {
|
||||
/** OSI core private data */
|
||||
/** OSI core private data */
|
||||
struct osi_core_priv_data *osi_core;
|
||||
/** OSI DMA private data */
|
||||
struct osi_dma_priv_data *osi_dma;
|
||||
@@ -342,7 +344,7 @@ struct ether_priv_data {
|
||||
unsigned int txq_prio[OSI_MGBE_MAX_NUM_CHANS];
|
||||
|
||||
#ifdef THERMAL_CAL
|
||||
/** Pointer to thermal cooling device which this driver registers
|
||||
/** Pointer to thermal cooling device which this driver registers
|
||||
* with the kernel. Kernel will invoke the callback ops for this
|
||||
* cooling device when temperate in thermal zone defined in DT
|
||||
* binding for this driver is tripped */
|
||||
@@ -405,6 +407,10 @@ struct ether_priv_data {
|
||||
/** Register dump debug fs pointer */
|
||||
struct dentry *dbgfs_reg_dump;
|
||||
#endif
|
||||
#ifdef MACSEC_SUPPORT
|
||||
/** MACsec priv data */
|
||||
struct macsec_priv_data *macsec_pdata;
|
||||
#endif /* MACSEC_SUPPORT */
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -482,7 +488,7 @@ int ether_conf_eee(struct ether_priv_data *pdata, unsigned int tx_lpi_enable);
|
||||
|
||||
#if IS_ENABLED(CONFIG_NVETHERNET_SELFTESTS)
|
||||
void ether_selftest_run(struct net_device *dev,
|
||||
struct ethtool_test *etest, u64 *buf);
|
||||
struct ethtool_test *etest, u64 *buf);
|
||||
void ether_selftest_get_strings(struct ether_priv_data *pdata, u8 *data);
|
||||
int ether_selftest_get_count(struct ether_priv_data *pdata);
|
||||
#else
|
||||
|
||||
957
drivers/net/ethernet/nvidia/nvethernet/macsec.c
Normal file
957
drivers/net/ethernet/nvidia/nvethernet/macsec.c
Normal file
@@ -0,0 +1,957 @@
|
||||
/*
|
||||
* Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ether_linux.h"
|
||||
|
||||
static irqreturn_t macsec_s_isr(int irq, void *data)
|
||||
{
|
||||
struct macsec_priv_data *macsec_pdata = (struct macsec_priv_data *)data;
|
||||
struct ether_priv_data *pdata = macsec_pdata->ether_pdata;
|
||||
|
||||
osi_macsec_s_isr(pdata->osi_core);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t macsec_ns_isr(int irq, void *data)
|
||||
{
|
||||
struct macsec_priv_data *macsec_pdata = (struct macsec_priv_data *)data;
|
||||
struct ether_priv_data *pdata = macsec_pdata->ether_pdata;
|
||||
|
||||
osi_macsec_ns_isr(pdata->osi_core);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int macsec_disable_car(struct macsec_priv_data *macsec_pdata)
|
||||
{
|
||||
struct ether_priv_data *pdata = macsec_pdata->ether_pdata;
|
||||
struct device *dev = pdata->dev;
|
||||
void __iomem *addr = NULL;
|
||||
unsigned int val = 0;
|
||||
|
||||
PRINT_ENTRY();
|
||||
if (!pdata->osi_core->pre_si) {
|
||||
if (macsec_pdata->ns_rst) {
|
||||
reset_control_assert(macsec_pdata->ns_rst);
|
||||
}
|
||||
|
||||
if (!IS_ERR_OR_NULL(macsec_pdata->apb_pclk)) {
|
||||
clk_disable_unprepare(macsec_pdata->apb_pclk);
|
||||
}
|
||||
if (!IS_ERR_OR_NULL(macsec_pdata->tx_clk)) {
|
||||
clk_disable_unprepare(macsec_pdata->tx_clk);
|
||||
}
|
||||
if (!IS_ERR_OR_NULL(macsec_pdata->rx_clk)) {
|
||||
clk_disable_unprepare(macsec_pdata->rx_clk);
|
||||
}
|
||||
} else {
|
||||
/* For Pre-sil only, reset the MACsec controller directly.
|
||||
* Assert the reset Bit 8 in CLK_RST_CONTROLLER_RST_DEV_MGBE_0.
|
||||
*/
|
||||
addr = devm_ioremap(dev, 0x21460018, 0x4);
|
||||
if (addr) {
|
||||
val = readl(addr);
|
||||
val |= BIT(8);
|
||||
writel(val, addr);
|
||||
devm_iounmap(dev, addr);
|
||||
}
|
||||
addr = devm_ioremap(dev, 0x21460080, 0x4);
|
||||
if (addr) {
|
||||
val = readl(addr);
|
||||
val &= ~BIT(2);
|
||||
writel(val, addr);
|
||||
devm_iounmap(dev, addr);
|
||||
}
|
||||
}
|
||||
|
||||
PRINT_EXIT();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int macsec_enable_car(struct macsec_priv_data *macsec_pdata)
|
||||
{
|
||||
struct ether_priv_data *pdata = macsec_pdata->ether_pdata;
|
||||
struct device *dev = pdata->dev;
|
||||
void __iomem *addr = NULL;
|
||||
unsigned int val = 0;
|
||||
int ret = 0;
|
||||
|
||||
PRINT_ENTRY();
|
||||
if (!pdata->osi_core->pre_si) {
|
||||
if (!IS_ERR_OR_NULL(macsec_pdata->apb_pclk)) {
|
||||
ret = clk_prepare_enable(macsec_pdata->apb_pclk);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to enable macsec pclk\n");
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
if (!IS_ERR_OR_NULL(macsec_pdata->tx_clk)) {
|
||||
ret = clk_prepare_enable(macsec_pdata->tx_clk);
|
||||
if (ret < 0) {
|
||||
dev_err(dev,
|
||||
"failed to enable macsec_tx_clk\n");
|
||||
goto err_tx_clk;
|
||||
}
|
||||
}
|
||||
if (!IS_ERR_OR_NULL(macsec_pdata->rx_clk)) {
|
||||
ret = clk_prepare_enable(macsec_pdata->rx_clk);
|
||||
if (ret < 0) {
|
||||
dev_err(dev,
|
||||
"failed to enable macsec_rx_clk\n");
|
||||
goto err_rx_clk;
|
||||
}
|
||||
}
|
||||
/* TODO:
|
||||
* 1. Any delay needed in silicon for clocks to stabilize ?
|
||||
*/
|
||||
if (macsec_pdata->ns_rst) {
|
||||
ret = reset_control_reset(macsec_pdata->ns_rst);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to reset macsec\n");
|
||||
goto err_ns_rst;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* For Pre-sil only, reset the MACsec controller directly.
|
||||
* clk ungate first, followed by disabling reset
|
||||
* Bit 8 in CLK_RST_CONTROLLER_RST_DEV_MGBE_0 register.
|
||||
*/
|
||||
addr = devm_ioremap(dev, 0x21460080, 0x4);
|
||||
if (addr) {
|
||||
val = readl(addr);
|
||||
val |= BIT(2);
|
||||
writel(val, addr);
|
||||
devm_iounmap(dev, addr);
|
||||
}
|
||||
|
||||
/* Followed by disabling reset - Bit 8 in
|
||||
* CLK_RST_CONTROLLER_RST_DEV_MGBE_0 register.
|
||||
*/
|
||||
addr = devm_ioremap(dev, 0x21460018, 0x4);
|
||||
if (addr) {
|
||||
val = readl(addr);
|
||||
val &= ~BIT(8);
|
||||
writel(val, addr);
|
||||
devm_iounmap(dev, addr);
|
||||
}
|
||||
}
|
||||
|
||||
goto exit;
|
||||
|
||||
err_ns_rst:
|
||||
if (!IS_ERR_OR_NULL(macsec_pdata->rx_clk)) {
|
||||
clk_disable_unprepare(macsec_pdata->rx_clk);
|
||||
}
|
||||
err_rx_clk:
|
||||
if (!IS_ERR_OR_NULL(macsec_pdata->tx_clk)) {
|
||||
clk_disable_unprepare(macsec_pdata->tx_clk);
|
||||
}
|
||||
err_tx_clk:
|
||||
if (!IS_ERR_OR_NULL(macsec_pdata->apb_pclk)) {
|
||||
clk_disable_unprepare(macsec_pdata->apb_pclk);
|
||||
}
|
||||
exit:
|
||||
PRINT_EXIT();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int macsec_close(struct macsec_priv_data *macsec_pdata)
|
||||
{
|
||||
struct ether_priv_data *pdata = macsec_pdata->ether_pdata;
|
||||
struct device *dev = pdata->dev;
|
||||
int ret = 0;
|
||||
|
||||
PRINT_ENTRY();
|
||||
#ifdef DEBUG_MACSEC
|
||||
macsec_disable_car(macsec_pdata);
|
||||
#endif
|
||||
/* 1. Disable the macsec controller */
|
||||
ret = osi_macsec_en(pdata->osi_core, OSI_DISABLE);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%s: Failed to enable macsec Tx/Rx, %d\n",
|
||||
__func__, ret);
|
||||
return ret;
|
||||
}
|
||||
macsec_pdata->enabled = OSI_DISABLE;
|
||||
osi_macsec_deinit(pdata->osi_core);
|
||||
|
||||
devm_free_irq(dev, macsec_pdata->ns_irq, macsec_pdata);
|
||||
devm_free_irq(dev, macsec_pdata->s_irq, macsec_pdata);
|
||||
PRINT_EXIT();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int macsec_open(struct macsec_priv_data *macsec_pdata)
|
||||
{
|
||||
struct ether_priv_data *pdata = macsec_pdata->ether_pdata;
|
||||
struct device *dev = pdata->dev;
|
||||
int ret = 0;
|
||||
|
||||
PRINT_ENTRY();
|
||||
/* 1. Request macsec irqs */
|
||||
snprintf(macsec_pdata->irq_name[0], MACSEC_IRQ_NAME_SZ, "%s.macsec_s",
|
||||
netdev_name(pdata->ndev));
|
||||
ret = devm_request_irq(dev, macsec_pdata->s_irq, macsec_s_isr,
|
||||
IRQF_TRIGGER_NONE, macsec_pdata->irq_name[0],
|
||||
macsec_pdata);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to request irq %d\n", __LINE__);
|
||||
goto exit;
|
||||
}
|
||||
pr_err("%s: requested s_irq %d: %s\n", __func__, macsec_pdata->s_irq,
|
||||
macsec_pdata->irq_name[0]);
|
||||
|
||||
snprintf(macsec_pdata->irq_name[1], MACSEC_IRQ_NAME_SZ, "%s.macsec_ns",
|
||||
netdev_name(pdata->ndev));
|
||||
ret = devm_request_irq(dev, macsec_pdata->ns_irq, macsec_ns_isr,
|
||||
IRQF_TRIGGER_NONE, macsec_pdata->irq_name[1],
|
||||
macsec_pdata);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to request irq %d\n", __LINE__);
|
||||
goto err_ns_irq;
|
||||
}
|
||||
pr_err("%s: requested ns_irq %d: %s\n", __func__, macsec_pdata->ns_irq,
|
||||
macsec_pdata->irq_name[1]);
|
||||
|
||||
#ifdef DEBUG_MACSEC
|
||||
/* 2. Enable CAR */
|
||||
ret = macsec_enable_car(macsec_pdata);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Unable to enable macsec clks & reset\n");
|
||||
goto err_car;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* 3. invoke OSI HW initialization, initialize standard BYP entries */
|
||||
ret = osi_macsec_init(pdata->osi_core);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "osi_macsec_init failed, %d\n", ret);
|
||||
goto err_osi_init;
|
||||
}
|
||||
|
||||
/* 4. Enable the macsec controller */
|
||||
ret = osi_macsec_en(pdata->osi_core,
|
||||
(OSI_MACSEC_TX_EN | OSI_MACSEC_RX_EN));
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%s: Failed to enable macsec Tx/Rx, %d\n",
|
||||
__func__, ret);
|
||||
goto err_osi_init;
|
||||
}
|
||||
macsec_pdata->enabled = (OSI_MACSEC_TX_EN | OSI_MACSEC_RX_EN);
|
||||
|
||||
goto exit;
|
||||
|
||||
err_osi_init:
|
||||
#ifdef DEBUG_MACSEC
|
||||
macsec_disable_car(macsec_pdata);
|
||||
err_car:
|
||||
#endif
|
||||
devm_free_irq(dev, macsec_pdata->ns_irq, macsec_pdata);
|
||||
err_ns_irq:
|
||||
devm_free_irq(dev, macsec_pdata->s_irq, macsec_pdata);
|
||||
exit:
|
||||
PRINT_EXIT();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int macsec_get_platform_res(struct macsec_priv_data *macsec_pdata)
|
||||
{
|
||||
struct ether_priv_data *pdata = macsec_pdata->ether_pdata;
|
||||
struct device *dev = pdata->dev;
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
int ret = 0;
|
||||
|
||||
PRINT_ENTRY();
|
||||
if (!pdata->osi_core->pre_si) {
|
||||
/* 1. Get resets */
|
||||
macsec_pdata->ns_rst = devm_reset_control_get(dev,
|
||||
"macsec_rst");
|
||||
if (IS_ERR_OR_NULL(macsec_pdata->ns_rst)) {
|
||||
dev_err(dev, "Failed to get macsec_ns_rst\n");
|
||||
ret = PTR_ERR(macsec_pdata->ns_rst);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* 2. Get clks */
|
||||
macsec_pdata->apb_pclk = devm_clk_get(dev, "macsec_pclk");
|
||||
if (IS_ERR(macsec_pdata->apb_pclk)) {
|
||||
dev_err(dev, "failed to get macsec_pclk\n");
|
||||
ret = PTR_ERR(macsec_pdata->apb_pclk);
|
||||
goto exit;
|
||||
}
|
||||
macsec_pdata->tx_clk = devm_clk_get(dev, "macsec_tx_clk");
|
||||
if (IS_ERR(macsec_pdata->tx_clk)) {
|
||||
dev_err(dev, "failed to get macsec_tx_clk\n");
|
||||
ret = PTR_ERR(macsec_pdata->tx_clk);
|
||||
goto exit;
|
||||
}
|
||||
macsec_pdata->rx_clk = devm_clk_get(dev, "macsec_rx_clk");
|
||||
if (IS_ERR(macsec_pdata->rx_clk)) {
|
||||
dev_err(dev, "failed to get macsec_rx_clk\n");
|
||||
ret = PTR_ERR(macsec_pdata->rx_clk);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
/* 3. Get irqs */
|
||||
macsec_pdata->ns_irq = platform_get_irq_byname(pdev, "macsec-ns-irq");
|
||||
if (macsec_pdata->ns_irq < 0) {
|
||||
dev_err(dev, "failed to get macsec-ns-irq\n");
|
||||
ret = macsec_pdata->ns_irq;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
macsec_pdata->s_irq = platform_get_irq_byname(pdev, "macsec-s-irq");
|
||||
if (macsec_pdata->s_irq < 0) {
|
||||
dev_err(dev, "failed to get macsec-s-irq\n");
|
||||
ret = macsec_pdata->s_irq;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Sucess */
|
||||
exit:
|
||||
PRINT_EXIT();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void macsec_release_platform_res(struct macsec_priv_data *macsec_pdata)
|
||||
{
|
||||
struct ether_priv_data *pdata = macsec_pdata->ether_pdata;
|
||||
struct device *dev = pdata->dev;
|
||||
|
||||
PRINT_ENTRY();
|
||||
if (!pdata->osi_core->pre_si) {
|
||||
if (!IS_ERR_OR_NULL(macsec_pdata->apb_pclk)) {
|
||||
devm_clk_put(dev, macsec_pdata->apb_pclk);
|
||||
}
|
||||
if (!IS_ERR_OR_NULL(macsec_pdata->tx_clk)) {
|
||||
devm_clk_put(dev, macsec_pdata->tx_clk);
|
||||
}
|
||||
if (!IS_ERR_OR_NULL(macsec_pdata->rx_clk)) {
|
||||
devm_clk_put(dev, macsec_pdata->rx_clk);
|
||||
}
|
||||
}
|
||||
PRINT_EXIT();
|
||||
}
|
||||
|
||||
static struct macsec_priv_data *genl_to_macsec_pdata(struct genl_info *info)
|
||||
{
|
||||
struct nlattr **attrs = info->attrs;
|
||||
struct net_device *ndev;
|
||||
struct ether_priv_data *pdata = NULL;
|
||||
struct macsec_priv_data *macsec_pdata = NULL;
|
||||
char ifname[IFNAMSIZ];
|
||||
|
||||
PRINT_ENTRY();
|
||||
|
||||
nla_strlcpy(ifname, attrs[NV_MACSEC_ATTR_IFNAME], sizeof(ifname));
|
||||
ndev = dev_get_by_name(genl_info_net(info),
|
||||
ifname);
|
||||
if (!ndev) {
|
||||
pr_err("%s: Unable to get netdev\n", __func__);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
pdata = netdev_priv(ndev);
|
||||
macsec_pdata = pdata->macsec_pdata;
|
||||
dev_put(ndev);
|
||||
exit:
|
||||
PRINT_EXIT();
|
||||
return macsec_pdata;
|
||||
}
|
||||
|
||||
static int macsec_set_prot_frames(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct nlattr **attrs = info->attrs;
|
||||
struct macsec_priv_data *macsec_pdata;
|
||||
int ret = 0;
|
||||
|
||||
PRINT_ENTRY();
|
||||
if (!attrs[NV_MACSEC_ATTR_IFNAME] ||
|
||||
!attrs[NV_MACSEC_ATTR_PROT_FRAMES_EN]) {
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
macsec_pdata = genl_to_macsec_pdata(info);
|
||||
if (!macsec_pdata) {
|
||||
ret = -EOPNOTSUPP;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
macsec_pdata->protect_frames =
|
||||
nla_get_u32(attrs[NV_MACSEC_ATTR_PROT_FRAMES_EN]);
|
||||
|
||||
exit:
|
||||
PRINT_EXIT();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int macsec_set_cipher(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int macsec_set_controlled_port(struct sk_buff *skb,
|
||||
struct genl_info *info)
|
||||
{
|
||||
struct nlattr **attrs = info->attrs;
|
||||
struct macsec_priv_data *macsec_pdata;
|
||||
unsigned int enable = 0;
|
||||
unsigned int macsec_en = 0;
|
||||
int ret = 0;
|
||||
|
||||
PRINT_ENTRY();
|
||||
if (!attrs[NV_MACSEC_ATTR_IFNAME] ||
|
||||
!attrs[NV_MACSEC_ATTR_CTRL_PORT_EN]) {
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
macsec_pdata = genl_to_macsec_pdata(info);
|
||||
if (!macsec_pdata) {
|
||||
ret = -EOPNOTSUPP;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
enable = nla_get_u32(attrs[NV_MACSEC_ATTR_CTRL_PORT_EN]);
|
||||
if (enable) {
|
||||
macsec_en |= OSI_MACSEC_RX_EN;
|
||||
if (macsec_pdata->protect_frames)
|
||||
macsec_en |= OSI_MACSEC_TX_EN;
|
||||
}
|
||||
|
||||
ret = osi_macsec_en(macsec_pdata->ether_pdata->osi_core, macsec_en);
|
||||
if (ret < 0) {
|
||||
ret = -EOPNOTSUPP;
|
||||
goto exit;
|
||||
}
|
||||
macsec_pdata->enabled = macsec_en;
|
||||
|
||||
exit:
|
||||
PRINT_EXIT();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int parse_sa_config(struct nlattr **attrs, struct nlattr **tb_sa,
|
||||
struct osi_macsec_sc_info *sc_info)
|
||||
{
|
||||
if (!attrs[NV_MACSEC_ATTR_SA_CONFIG])
|
||||
return -EINVAL;
|
||||
|
||||
if (nla_parse_nested(tb_sa, NV_MACSEC_SA_ATTR_MAX,
|
||||
attrs[NV_MACSEC_ATTR_SA_CONFIG],
|
||||
nv_macsec_sa_genl_policy, NULL))
|
||||
return -EINVAL;
|
||||
|
||||
if (tb_sa[NV_MACSEC_SA_ATTR_SCI]) {
|
||||
memcpy(sc_info->sci, nla_data(tb_sa[NV_MACSEC_SA_ATTR_SCI]),
|
||||
sizeof(sc_info->sci));
|
||||
}
|
||||
if (tb_sa[NV_MACSEC_SA_ATTR_AN]) {
|
||||
sc_info->curr_an = nla_get_u8(tb_sa[NV_MACSEC_SA_ATTR_AN]);
|
||||
}
|
||||
if (tb_sa[NV_MACSEC_SA_ATTR_PN]) {
|
||||
sc_info->next_pn = nla_get_u32(tb_sa[NV_MACSEC_SA_ATTR_PN]);
|
||||
}
|
||||
if (tb_sa[NV_MACSEC_SA_ATTR_KEY]) {
|
||||
memcpy(sc_info->sak, nla_data(tb_sa[NV_MACSEC_SA_ATTR_KEY]),
|
||||
sizeof(sc_info->sak));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int macsec_dis_rx_sa(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct nlattr **attrs = info->attrs;
|
||||
struct macsec_priv_data *macsec_pdata;
|
||||
struct ether_priv_data *pdata;
|
||||
struct osi_macsec_sc_info rx_sa;
|
||||
struct nlattr *tb_sa[NUM_NV_MACSEC_SA_ATTR];
|
||||
int ret = 0, i = 0;
|
||||
|
||||
PRINT_ENTRY();
|
||||
if (!attrs[NV_MACSEC_ATTR_IFNAME] ||
|
||||
parse_sa_config(attrs, tb_sa, &rx_sa)) {
|
||||
pr_err("%s: failed to parse nlattrs", __func__);
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
macsec_pdata = genl_to_macsec_pdata(info);
|
||||
if (macsec_pdata) {
|
||||
pdata = macsec_pdata->ether_pdata;
|
||||
} else {
|
||||
#ifndef TEST
|
||||
ret = -EOPNOTSUPP;
|
||||
goto exit;
|
||||
#endif
|
||||
}
|
||||
|
||||
pr_err("%s:\n"
|
||||
"\tsci: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n"
|
||||
"\tan: %u\n"
|
||||
"\tpn: %u",
|
||||
__func__,
|
||||
rx_sa.sci[0], rx_sa.sci[1], rx_sa.sci[2], rx_sa.sci[3],
|
||||
rx_sa.sci[4], rx_sa.sci[5], rx_sa.sci[6], rx_sa.sci[7],
|
||||
rx_sa.curr_an, rx_sa.next_pn);
|
||||
pr_err("\tkey: ");
|
||||
for (i = 0; i < 16; i++) {
|
||||
pr_cont(" %02x", rx_sa.sak[i]);
|
||||
}
|
||||
pr_err("");
|
||||
|
||||
#ifndef TEST
|
||||
ret = osi_macsec_config(pdata->osi_core, &rx_sa, OSI_DISABLE,
|
||||
CTLR_SEL_RX);
|
||||
if (ret < 0) {
|
||||
pr_err("%s: failed to disable Rx SA", __func__);
|
||||
}
|
||||
#endif
|
||||
|
||||
exit:
|
||||
PRINT_EXIT();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int macsec_en_rx_sa(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct nlattr **attrs = info->attrs;
|
||||
struct macsec_priv_data *macsec_pdata;
|
||||
struct ether_priv_data *pdata;
|
||||
struct osi_macsec_sc_info rx_sa;
|
||||
struct nlattr *tb_sa[NUM_NV_MACSEC_SA_ATTR];
|
||||
int ret = 0, i = 0;
|
||||
|
||||
PRINT_ENTRY();
|
||||
if (!attrs[NV_MACSEC_ATTR_IFNAME] ||
|
||||
parse_sa_config(attrs, tb_sa, &rx_sa)) {
|
||||
pr_err("%s: failed to parse nlattrs", __func__);
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
macsec_pdata = genl_to_macsec_pdata(info);
|
||||
if (macsec_pdata) {
|
||||
pdata = macsec_pdata->ether_pdata;
|
||||
} else {
|
||||
#ifndef TEST
|
||||
ret = -EOPNOTSUPP;
|
||||
goto exit;
|
||||
#endif
|
||||
}
|
||||
|
||||
pr_err("%s:\n"
|
||||
"\tsci: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n"
|
||||
"\tan: %u\n"
|
||||
"\tpn: %u",
|
||||
__func__,
|
||||
rx_sa.sci[0], rx_sa.sci[1], rx_sa.sci[2], rx_sa.sci[3],
|
||||
rx_sa.sci[4], rx_sa.sci[5], rx_sa.sci[6], rx_sa.sci[7],
|
||||
rx_sa.curr_an, rx_sa.next_pn);
|
||||
pr_err("\tkey: ");
|
||||
for (i = 0; i < 16; i++) {
|
||||
pr_cont(" %02x", rx_sa.sak[i]);
|
||||
}
|
||||
pr_err("");
|
||||
|
||||
#ifndef TEST
|
||||
ret = osi_macsec_config(pdata->osi_core, &rx_sa, OSI_ENABLE,
|
||||
CTLR_SEL_RX);
|
||||
if (ret < 0) {
|
||||
pr_err("%s: failed to enable Rx SA", __func__);
|
||||
}
|
||||
#endif
|
||||
|
||||
exit:
|
||||
PRINT_EXIT();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int macsec_dis_tx_sa(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct nlattr **attrs = info->attrs;
|
||||
struct macsec_priv_data *macsec_pdata;
|
||||
struct ether_priv_data *pdata;
|
||||
struct osi_macsec_sc_info tx_sa;
|
||||
struct nlattr *tb_sa[NUM_NV_MACSEC_SA_ATTR];
|
||||
int ret = 0, i = 0;
|
||||
|
||||
PRINT_ENTRY();
|
||||
if (!attrs[NV_MACSEC_ATTR_IFNAME] ||
|
||||
parse_sa_config(attrs, tb_sa, &tx_sa)) {
|
||||
pr_err("%s: failed to parse nlattrs", __func__);
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
macsec_pdata = genl_to_macsec_pdata(info);
|
||||
if (macsec_pdata) {
|
||||
pdata = macsec_pdata->ether_pdata;
|
||||
} else {
|
||||
#ifndef TEST
|
||||
ret = -EOPNOTSUPP;
|
||||
goto exit;
|
||||
#endif
|
||||
}
|
||||
|
||||
pr_err("%s:\n"
|
||||
"\tsci: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n"
|
||||
"\tan: %u\n"
|
||||
"\tpn: %u",
|
||||
__func__,
|
||||
tx_sa.sci[0], tx_sa.sci[1], tx_sa.sci[2], tx_sa.sci[3],
|
||||
tx_sa.sci[4], tx_sa.sci[5], tx_sa.sci[6], tx_sa.sci[7],
|
||||
tx_sa.curr_an, tx_sa.next_pn);
|
||||
pr_err("\tkey: ");
|
||||
for (i = 0; i < 16; i++) {
|
||||
pr_cont(" %02x", tx_sa.sak[i]);
|
||||
}
|
||||
pr_err("");
|
||||
|
||||
#ifndef TEST
|
||||
ret = osi_macsec_config(pdata->osi_core, &tx_sa, OSI_DISABLE,
|
||||
CTLR_SEL_TX);
|
||||
if (ret < 0) {
|
||||
pr_err("%s: failed to disable Tx SA", __func__);
|
||||
}
|
||||
#endif
|
||||
|
||||
exit:
|
||||
PRINT_EXIT();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int macsec_en_tx_sa(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct nlattr **attrs = info->attrs;
|
||||
struct macsec_priv_data *macsec_pdata;
|
||||
struct ether_priv_data *pdata;
|
||||
struct osi_macsec_sc_info tx_sa;
|
||||
struct nlattr *tb_sa[NUM_NV_MACSEC_SA_ATTR];
|
||||
int ret = 0, i = 0;
|
||||
|
||||
PRINT_ENTRY();
|
||||
if (!attrs[NV_MACSEC_ATTR_IFNAME] ||
|
||||
parse_sa_config(attrs, tb_sa, &tx_sa)) {
|
||||
pr_err("%s: failed to parse nlattrs", __func__);
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
macsec_pdata = genl_to_macsec_pdata(info);
|
||||
if (macsec_pdata) {
|
||||
pdata = macsec_pdata->ether_pdata;
|
||||
} else {
|
||||
#ifndef TEST
|
||||
ret = -EOPNOTSUPP;
|
||||
goto exit;
|
||||
#endif
|
||||
}
|
||||
|
||||
pr_err("%s:\n"
|
||||
"\tsci: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n"
|
||||
"\tan: %u\n"
|
||||
"\tpn: %u",
|
||||
__func__,
|
||||
tx_sa.sci[0], tx_sa.sci[1], tx_sa.sci[2], tx_sa.sci[3],
|
||||
tx_sa.sci[4], tx_sa.sci[5], tx_sa.sci[6], tx_sa.sci[7],
|
||||
tx_sa.curr_an, tx_sa.next_pn);
|
||||
pr_err("\tkey: ");
|
||||
for (i = 0; i < 16; i++) {
|
||||
pr_cont(" %02x", tx_sa.sak[i]);
|
||||
}
|
||||
pr_err("");
|
||||
|
||||
#ifndef TEST
|
||||
ret = osi_macsec_config(pdata->osi_core, &tx_sa, OSI_ENABLE,
|
||||
CTLR_SEL_TX);
|
||||
if (ret < 0) {
|
||||
pr_err("%s: failed to enable Tx SA", __func__);
|
||||
}
|
||||
#endif
|
||||
|
||||
exit:
|
||||
PRINT_EXIT();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int macsec_deinit(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct nlattr **attrs = info->attrs;
|
||||
struct macsec_priv_data *macsec_pdata;
|
||||
int ret = 0;
|
||||
|
||||
PRINT_ENTRY();
|
||||
if (!attrs[NV_MACSEC_ATTR_IFNAME]) {
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
macsec_pdata = genl_to_macsec_pdata(info);
|
||||
if (!macsec_pdata) {
|
||||
ret = -EOPNOTSUPP;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = macsec_close(macsec_pdata);
|
||||
//TODO - check why needs -EOPNOTSUPP, why not pass ret val
|
||||
if (ret < 0) {
|
||||
ret = -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
exit:
|
||||
PRINT_EXIT();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int macsec_init(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct nlattr **attrs = info->attrs;
|
||||
struct macsec_priv_data *macsec_pdata;
|
||||
int ret = 0;
|
||||
|
||||
PRINT_ENTRY();
|
||||
if (!attrs[NV_MACSEC_ATTR_IFNAME]) {
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
macsec_pdata = genl_to_macsec_pdata(info);
|
||||
if (!macsec_pdata) {
|
||||
ret = -EOPNOTSUPP;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = macsec_open(macsec_pdata);
|
||||
//TODO - check why needs -EOPNOTSUPP, why not pass ret val
|
||||
if (ret < 0) {
|
||||
ret = -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
exit:
|
||||
PRINT_EXIT();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int macsec_set_replay_prot(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct nlattr **attrs = info->attrs;
|
||||
unsigned int replay_prot, window;
|
||||
|
||||
if (!attrs[NV_MACSEC_ATTR_IFNAME] ||
|
||||
!attrs[NV_MACSEC_ATTR_REPLAY_PROT_EN] ||
|
||||
!attrs[NV_MACSEC_ATTR_REPLAY_WINDOW]) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
replay_prot = nla_get_u32(attrs[NV_MACSEC_ATTR_REPLAY_PROT_EN]);
|
||||
window = nla_get_u32(attrs[NV_MACSEC_ATTR_REPLAY_WINDOW]);
|
||||
pr_err("replay_prot(window): %u(%u)\n",
|
||||
replay_prot, window);
|
||||
|
||||
|
||||
/* TODO - set replay window for all active SA's.
|
||||
* Store window in macsec_pdata so that future SA's can be updated
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct genl_ops nv_macsec_genl_ops[] = {
|
||||
{
|
||||
.cmd = NV_MACSEC_CMD_INIT,
|
||||
.doit = macsec_init,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
},
|
||||
{
|
||||
.cmd = NV_MACSEC_CMD_SET_PROT_FRAMES,
|
||||
.doit = macsec_set_prot_frames,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
},
|
||||
{
|
||||
.cmd = NV_MACSEC_CMD_SET_REPLAY_PROT,
|
||||
.doit = macsec_set_replay_prot,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
},
|
||||
{
|
||||
.cmd = NV_MACSEC_CMD_SET_CIPHER,
|
||||
.doit = macsec_set_cipher,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
},
|
||||
{
|
||||
.cmd = NV_MACSEC_CMD_SET_CONTROLLED_PORT,
|
||||
.doit = macsec_set_controlled_port,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
},
|
||||
{
|
||||
.cmd = NV_MACSEC_CMD_DEINIT,
|
||||
.doit = macsec_deinit,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
},
|
||||
{
|
||||
.cmd = NV_MACSEC_CMD_EN_TX_SA,
|
||||
.doit = macsec_en_tx_sa,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
},
|
||||
{
|
||||
.cmd = NV_MACSEC_CMD_DIS_TX_SA,
|
||||
.doit = macsec_dis_tx_sa,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
},
|
||||
{
|
||||
.cmd = NV_MACSEC_CMD_EN_RX_SA,
|
||||
.doit = macsec_en_rx_sa,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
},
|
||||
{
|
||||
.cmd = NV_MACSEC_CMD_DIS_RX_SA,
|
||||
.doit = macsec_dis_rx_sa,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct genl_family nv_macsec_fam __ro_after_init = {
|
||||
.name = NV_MACSEC_GENL_NAME,
|
||||
.hdrsize = 0,
|
||||
.version = NV_MACSEC_GENL_VERSION,
|
||||
.maxattr = NV_MACSEC_ATTR_MAX,
|
||||
.module = THIS_MODULE,
|
||||
.ops = nv_macsec_genl_ops,
|
||||
.n_ops = ARRAY_SIZE(nv_macsec_genl_ops),
|
||||
};
|
||||
|
||||
void macsec_remove(struct ether_priv_data *pdata)
|
||||
{
|
||||
struct macsec_priv_data *macsec_pdata = NULL;
|
||||
|
||||
PRINT_ENTRY();
|
||||
macsec_pdata = pdata->macsec_pdata;
|
||||
|
||||
if (macsec_pdata) {
|
||||
/* 1. Unregister generic netlink */
|
||||
genl_unregister_family(&nv_macsec_fam);
|
||||
|
||||
/* 2. Release platform resources */
|
||||
macsec_release_platform_res(macsec_pdata);
|
||||
}
|
||||
PRINT_EXIT();
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
int macsec_genl_register(void)
|
||||
{
|
||||
int ret = 0;
|
||||
ret = genl_register_family(&nv_macsec_fam);
|
||||
if (ret < 0) {
|
||||
pr_err("Srini:failed to register genl\n");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void macsec_genl_unregister(void)
|
||||
{
|
||||
genl_unregister_family(&nv_macsec_fam);
|
||||
}
|
||||
#endif /* TEST */
|
||||
|
||||
int macsec_probe(struct ether_priv_data *pdata)
|
||||
{
|
||||
struct device *dev = pdata->dev;
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct osi_core_priv_data *osi_core = pdata->osi_core;
|
||||
struct macsec_priv_data *macsec_pdata = NULL;
|
||||
struct resource *res = NULL;
|
||||
int ret = 0;
|
||||
|
||||
PRINT_ENTRY();
|
||||
/* 1. Check if MACsec is enabled in DT, if so map the I/O base addr */
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "macsec-base");
|
||||
if (res) {
|
||||
osi_core->macsec_base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(osi_core->macsec_base)) {
|
||||
dev_err(dev, "failed to ioremap MACsec base addr\n");
|
||||
ret = PTR_ERR(osi_core->macsec_base);
|
||||
goto exit;
|
||||
}
|
||||
} else {
|
||||
/* MACsec not enabled in DT, nothing more to do */
|
||||
osi_core->macsec_base = NULL;
|
||||
osi_core->tz_base = NULL;
|
||||
pdata->macsec_pdata = NULL;
|
||||
|
||||
/* Return positive value to indicate MACsec not enabled in DT */
|
||||
ret = 1;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
//TODO: Move to TZ window
|
||||
osi_core->tz_base = devm_ioremap(dev, 0x68C0000, 0x10000);
|
||||
if (IS_ERR(osi_core->tz_base)) {
|
||||
dev_err(dev, "failed to ioremap TZ base addr\n");
|
||||
ret = PTR_ERR(osi_core->tz_base);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* 2. Alloc macsec priv data structure */
|
||||
macsec_pdata = devm_kzalloc(dev, sizeof(struct macsec_priv_data),
|
||||
GFP_KERNEL);
|
||||
if (macsec_pdata == NULL) {
|
||||
dev_err(dev, "failed to alloc macsec_priv_data\n");
|
||||
ret = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
macsec_pdata->ether_pdata = pdata;
|
||||
pdata->macsec_pdata = macsec_pdata;
|
||||
|
||||
/* 3. Get OSI MACsec ops */
|
||||
if (osi_init_macsec_ops(osi_core) != 0) {
|
||||
dev_err(dev, "osi_init_macsec_ops failed\n");
|
||||
ret = -1;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* 4. Get platform resources - clks, resets, irqs.
|
||||
* CAR is not enabled and irqs not requested until macsec_init()
|
||||
*/
|
||||
ret = macsec_get_platform_res(macsec_pdata);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "macsec_get_platform_res failed\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* 2. Enable CAR */
|
||||
ret = macsec_enable_car(macsec_pdata);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Unable to enable macsec clks & reset\n");
|
||||
goto exit;
|
||||
}
|
||||
/* 5. Register macsec sysfs node - done from sysfs.c */
|
||||
|
||||
/* 6. Register macsec generic netlink ops */
|
||||
ret = genl_register_family(&nv_macsec_fam);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to register GENL ops\n");
|
||||
macsec_disable_car(macsec_pdata);
|
||||
}
|
||||
|
||||
exit:
|
||||
PRINT_EXIT();
|
||||
return ret;
|
||||
}
|
||||
147
drivers/net/ethernet/nvidia/nvethernet/macsec.h
Normal file
147
drivers/net/ethernet/nvidia/nvethernet/macsec.h
Normal file
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_MACSEC_H
|
||||
#define INCLUDED_MACSEC_H
|
||||
|
||||
#include <osi_macsec.h>
|
||||
#include <linux/random.h>
|
||||
#include <net/genetlink.h>
|
||||
#include <linux/crypto.h>
|
||||
|
||||
//#define TEST 1
|
||||
|
||||
/**
|
||||
* @brief Size of Macsec IRQ name.
|
||||
*/
|
||||
#define MACSEC_IRQ_NAME_SZ 32
|
||||
|
||||
//TODO - include name of driver interface as well
|
||||
#define NV_MACSEC_GENL_NAME "nv_macsec"
|
||||
#define NV_MACSEC_GENL_VERSION 1
|
||||
|
||||
enum nv_macsec_sa_attrs {
|
||||
NV_MACSEC_SA_ATTR_UNSPEC,
|
||||
NV_MACSEC_SA_ATTR_SCI,
|
||||
NV_MACSEC_SA_ATTR_AN,
|
||||
NV_MACSEC_SA_ATTR_PN,
|
||||
NV_MACSEC_SA_ATTR_KEY,
|
||||
__NV_MACSEC_SA_ATTR_END,
|
||||
NUM_NV_MACSEC_SA_ATTR = __NV_MACSEC_SA_ATTR_END,
|
||||
NV_MACSEC_SA_ATTR_MAX = __NV_MACSEC_SA_ATTR_END - 1,
|
||||
};
|
||||
|
||||
enum nv_macsec_attrs {
|
||||
NV_MACSEC_ATTR_UNSPEC,
|
||||
NV_MACSEC_ATTR_IFNAME,
|
||||
NV_MACSEC_ATTR_TXSC_PORT,
|
||||
NV_MACSEC_ATTR_PROT_FRAMES_EN,
|
||||
NV_MACSEC_ATTR_REPLAY_PROT_EN,
|
||||
NV_MACSEC_ATTR_REPLAY_WINDOW,
|
||||
NV_MACSEC_ATTR_CIPHER_SUITE,
|
||||
NV_MACSEC_ATTR_CTRL_PORT_EN,
|
||||
NV_MACSEC_ATTR_SA_CONFIG, /* Nested SA config */
|
||||
__NV_MACSEC_ATTR_END,
|
||||
NUM_NV_MACSEC_ATTR = __NV_MACSEC_ATTR_END,
|
||||
NV_MACSEC_ATTR_MAX = __NV_MACSEC_ATTR_END - 1,
|
||||
};
|
||||
|
||||
static const struct nla_policy nv_macsec_sa_genl_policy[NUM_NV_MACSEC_SA_ATTR] = {
|
||||
[NV_MACSEC_SA_ATTR_SCI] = { .type = NLA_BINARY,
|
||||
.len = 8, }, /* SCI is 64bit */
|
||||
[NV_MACSEC_SA_ATTR_AN] = { .type = NLA_U8 },
|
||||
[NV_MACSEC_SA_ATTR_PN] = { .type = NLA_U32 },
|
||||
[NV_MACSEC_SA_ATTR_KEY] = { .type = NLA_BINARY,
|
||||
.len = KEY_LEN_128,},
|
||||
};
|
||||
|
||||
static const struct nla_policy nv_macsec_genl_policy[NUM_NV_MACSEC_ATTR] = {
|
||||
[NV_MACSEC_ATTR_IFNAME] = { .type = NLA_STRING },
|
||||
[NV_MACSEC_ATTR_TXSC_PORT] = { .type = NLA_U16 },
|
||||
[NV_MACSEC_ATTR_REPLAY_PROT_EN] = { .type = NLA_U32 },
|
||||
[NV_MACSEC_ATTR_REPLAY_WINDOW] = { .type = NLA_U32 },
|
||||
[NV_MACSEC_ATTR_SA_CONFIG] = { .type = NLA_NESTED },
|
||||
};
|
||||
|
||||
enum nv_macsec_nl_commands {
|
||||
NV_MACSEC_CMD_INIT,
|
||||
NV_MACSEC_CMD_GET_TX_NEXT_PN,
|
||||
NV_MACSEC_CMD_SET_PROT_FRAMES,
|
||||
NV_MACSEC_CMD_SET_REPLAY_PROT,
|
||||
NV_MACSEC_CMD_SET_CIPHER,
|
||||
NV_MACSEC_CMD_SET_CONTROLLED_PORT,
|
||||
NV_MACSEC_CMD_EN_TX_SA,
|
||||
NV_MACSEC_CMD_DIS_TX_SA,
|
||||
NV_MACSEC_CMD_EN_RX_SA,
|
||||
NV_MACSEC_CMD_DIS_RX_SA,
|
||||
NV_MACSEC_CMD_DEINIT,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief MACsec private data structure
|
||||
*/
|
||||
struct macsec_priv_data {
|
||||
/** Non secure reset */
|
||||
struct reset_control *ns_rst;
|
||||
/** APB interface clk - macsec_pclk */
|
||||
struct clk *apb_pclk;
|
||||
/** macsec Tx clock */
|
||||
struct clk *tx_clk;
|
||||
/** macsec Rx clock */
|
||||
struct clk *rx_clk;
|
||||
/** Secure irq */
|
||||
int s_irq;
|
||||
/** Non secure irq */
|
||||
int ns_irq;
|
||||
/** pointer to ether private data struct */
|
||||
struct ether_priv_data *ether_pdata;
|
||||
/** macsec IRQ name strings */
|
||||
char irq_name[2][MACSEC_IRQ_NAME_SZ];
|
||||
/** loopback mode */
|
||||
unsigned int loopback_mode;
|
||||
/** MACsec protect frames variable */
|
||||
unsigned int protect_frames;
|
||||
/** MACsec enabled flags for Tx/Rx controller status */
|
||||
unsigned int enabled;
|
||||
/** MACsec controller initialized flag */
|
||||
unsigned int init_done;
|
||||
};
|
||||
|
||||
int macsec_probe(struct ether_priv_data *pdata);
|
||||
void macsec_remove(struct ether_priv_data *pdata);
|
||||
int macsec_open(struct macsec_priv_data *macsec_pdata);
|
||||
int macsec_close(struct macsec_priv_data *macsec_pdata);
|
||||
#ifdef TEST
|
||||
int macsec_genl_register(void);
|
||||
void macsec_genl_unregister(void);
|
||||
#endif /* TEST */
|
||||
|
||||
#ifdef MACSEC_DEBUG
|
||||
#define PRINT_ENTRY() (pr_info("-->%s()\n", __func__))
|
||||
#define PRINT_EXIT() (pr_info("<--%s()\n", __func__))
|
||||
#else
|
||||
#define PRINT_ENTRY()
|
||||
#define PRINT_EXIT()
|
||||
#endif /* MACSEC_DEBUG */
|
||||
|
||||
#endif /* INCLUDED_MACSEC_H */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user