coe: Add Camera Over Ethernet cababilities

The following change is a squash change that aims to reintroduce
Camera Over Ethernet (CoE) functionality to kernel.

Bug 5401884
Bug 5419655

Change-Id: Id2fc0263c43ed8566241dbf712aa603a3b3a76f4
Signed-off-by: Rakibul Hassan <rakibulh@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3419627
Reviewed-by: Anubhav Rai <arai@nvidia.com>
Reviewed-by: Narendra Kondapalli <nkondapalli@nvidia.com>
GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com>
Reviewed-by: Igor Mitsyanko <imitsyanko@nvidia.com>
Reviewed-by: Jon Hunter <jonathanh@nvidia.com>
This commit is contained in:
Rakibul Hassan
2025-07-29 20:53:53 +00:00
committed by mobile promotions
parent a7fae6153a
commit f374450381
12 changed files with 3311 additions and 16 deletions

View File

@@ -19,11 +19,7 @@ endif
ccflags-y += -DLINUX_OS -DNET30 -DNVPKCS_MACSEC -DLINUX_IVC -mno-outline-atomics -Werror \
-I$(srctree.nvidia-oot)/drivers/net/ethernet/nvidia/nvethernet/nvethernetrm/include
ifdef CONFIG_KASAN
ccflags-y += -Wframe-larger-than=4096
else
ccflags-y += -Wframe-larger-than=2048
endif
#ccflags-y += -DOSI_DEBUG -DMACSEC_SUPPORT -DDEBUG_MACSEC -DMACSEC_KEY_PROGRAM
ccflags-y += -DMACSEC_SUPPORT

View File

@@ -25,6 +25,7 @@
#include <soc/tegra/fuse.h>
#include <soc/tegra/fuse-helper.h>
#include <soc/tegra/virt/hv-ivc.h>
#include <soc/tegra/nvethernet-public.h>
#include <linux/time.h>
#ifdef CONFIG_DEBUG_FS
@@ -2053,6 +2054,11 @@ static int ether_request_irqs(struct ether_priv_data *pdata)
"unexpected irq name index received (%d)\n", j);
goto err_chan_irq;
}
if (osi_core->irq_data[i].is_coe == 1U) {
continue;
}
snprintf(pdata->irq_names[j], ETHER_IRQ_NAME_SZ, "%s.vm%d",
netdev_name(pdata->ndev), i);
ret = devm_request_irq(pdata->dev, pdata->vm_irqs[i],
@@ -2169,6 +2175,41 @@ static void ether_napi_enable(struct ether_priv_data *pdata)
}
}
static void ether_free_coe_resource(struct ether_priv_data *pdata)
{
int i;
for (i = 0; i < OSI_MGBE_COE_NUM_RX_FRAMES; i++) {
dma_unmap_single(pdata->dev, pdata->mgbe_coe.rx_fb_addr_phys[i], PAGE_SIZE, DMA_FROM_DEVICE);
free_page(pdata->mgbe_coe.rx_fb_addr[i]);
}
dma_free_coherent(pdata->dev, sizeof(struct osi_mgbe_coe_pib) * pdata->mgbe_coe.rx_pib_sz,
(void *)pdata->mgbe_coe.rx_pib_addr, pdata->mgbe_coe.rx_pib_addr_phys);
}
static int ether_allocate_coe_resource(struct ether_priv_data *pdata)
{
int i;
for (i = 0; i < OSI_MGBE_COE_NUM_RX_FRAMES; i++) {
pdata->mgbe_coe.rx_fb_addr[i] = __get_free_page(GFP_DMA);
pdata->mgbe_coe.rx_fb_addr_phys[i] = dma_map_single(pdata->dev,
(void *)pdata->mgbe_coe.rx_fb_addr[i],
PAGE_SIZE, DMA_FROM_DEVICE);
pr_err("%s: rx_fb_addr[%d]: virt: %#llx phys: %#llx\n", __func__, i,
pdata->mgbe_coe.rx_fb_addr[i],
pdata->mgbe_coe.rx_fb_addr_phys[i]);
}
pdata->mgbe_coe.rx_pib_addr = (u64) dma_alloc_coherent(pdata->dev,
sizeof(struct osi_mgbe_coe_pib) * pdata->mgbe_coe.rx_pib_sz,
(dma_addr_t *) &pdata->mgbe_coe.rx_pib_addr_phys,
GFP_KERNEL | __GFP_ZERO);
pr_err("%s: rx_pib_addr: virt: %#llx phys: %#llx\n", __func__, pdata->mgbe_coe.rx_pib_addr, pdata->mgbe_coe.rx_pib_addr_phys);
return 0;
}
/**
* @brief Free receive skbs
*
@@ -2257,6 +2298,10 @@ static void free_rx_dma_resources(struct osi_dma_priv_data *osi_dma,
pdata->page_pool[chan] = NULL;
}
#endif
if (i == pdata->mgbe_coe.vdma && pdata->coe_enable) {
pr_err("%s: Freeing COE DMA resources for vdma %d\n", __func__, i);
ether_free_coe_resource(pdata);
}
}
}
@@ -2428,6 +2473,7 @@ static int ether_page_pool_create_per_chan(struct ether_priv_data *pdata,
}
#endif
/**
* @brief Allocate Receive DMA channel ring resources.
*
@@ -2448,6 +2494,7 @@ static int ether_allocate_rx_dma_resources(struct osi_dma_priv_data *osi_dma,
unsigned int chan;
unsigned int i;
int ret = 0;
struct osi_ioctl ioctl_data = {};
const nveu32_t max_dma_chan[OSI_MAX_MAC_IP_TYPES] = {
OSI_EQOS_MAX_NUM_CHANS,
OSI_MGBE_T23X_MAX_NUM_CHANS,
@@ -2478,6 +2525,22 @@ static int ether_allocate_rx_dma_resources(struct osi_dma_priv_data *osi_dma,
if (ret < 0) {
goto exit;
}
if (pdata->coe_enable && chan == pdata->mgbe_coe.vdma) {
pr_err("%s: Allocating COE DMA resources for vdma %d\n", __func__, chan);
ret = ether_allocate_coe_resource(pdata);
if (ret < 0) {
goto exit;
}
/* Program the buffers in HW */
memcpy(&ioctl_data.data.mgbe_coe, &pdata->mgbe_coe, sizeof(struct osi_mgbe_coe));
ioctl_data.cmd = OSI_CMD_GMSL_COE_CONFIG;
ret = osi_handle_ioctl(pdata->osi_core, &ioctl_data);
if (ret < 0) {
dev_err(pdata->dev, "Enabling MAC COE in HW failed\n");
} else {
dev_info(pdata->dev, "MAC COE enabled in HW\n");
}
}
}
}
@@ -2666,6 +2729,10 @@ static void ether_init_invalid_chan_ring(struct osi_dma_priv_data *osi_dma)
for (i = osi_dma->num_dma_chans; i < max_dma_chan[osi_dma->mac]; i++) {
osi_dma->dma_chans[i] = ETHER_INVALID_CHAN_NUM;
}
for (i = osi_dma->num_dma_chans_coe; i < max_dma_chan[osi_dma->mac]; i++) {
osi_dma->dma_chans_coe[i] = ETHER_INVALID_CHAN_NUM;
}
}
/**
@@ -3126,6 +3193,14 @@ int ether_open(struct net_device *dev)
}
/* initialize MAC/MTL/DMA Common registers */
/** If COE is enabled, disable RIWT so that IOC is set for all desc. */
if (pdata->coe_enable) {
pdata->osi_dma->use_riwt = OSI_DISABLE;
pdata->osi_dma->coe_enable = pdata->coe_enable;
pdata->osi_dma->mgbe_coe = pdata->mgbe_coe;
pdata->osi_core->coe_enable = pdata->coe_enable;
pdata->osi_core->mgbe_coe = pdata->mgbe_coe;
}
ret = osi_hw_core_init(pdata->osi_core);
if (ret < 0) {
dev_err(pdata->dev,
@@ -3901,8 +3976,8 @@ unsigned short ether_select_queue(struct net_device *dev,
if ((osi_core->pre_sil == OSI_ENABLE) && (pdata->tx_queue_select != 0U)) {
txqueue_select = pdata->tx_queue_select;
} else {
for (i = 0; i < osi_core->num_mtl_queues; i++) {
mtlq = osi_core->mtl_queues[i];
for (i = 0; i < osi_core->num_dma_chans; i++) {
mtlq = osi_core->dma_chans[i];
if (pdata->txq_prio[mtlq] == priority) {
txqueue_select = (unsigned short)i;
break;
@@ -4981,6 +5056,26 @@ static void ether_set_vm_irq_chan_mask(struct ether_vm_irq_data *vm_irq_data,
}
}
/**
* @brief ether_set_coe_chan_mask - Set CoE channels bitmap
*
* @param[in] osi_dma: DMA data
* @param[in] num_vm_chan: Number of VM DMA channels
* @param[in] vm_chans: Pointer to list of VM DMA channels
*
* @retval None.
*/
static void ether_set_coe_chan_mask(struct osi_dma_priv_data *osi_dma,
unsigned int num_vm_chan,
unsigned int *vm_chans)
{
osi_dma->num_dma_chans_coe = num_vm_chan;
for (u32 i = 0; i < num_vm_chan; i++) {
osi_dma->dma_chans_coe[i] = vm_chans[i];
}
}
/**
* @brief ether_get_rx_riit - Get the rx_riit value for speed.
*
@@ -5205,6 +5300,8 @@ static int ether_get_vm_irq_data(struct platform_device *pdev,
child_id = 0;
for_each_child_of_node(vm_node, temp) {
bool is_coe;
ret = of_property_read_u32(temp, "nvidia,vm-irq-id", &vm_irq_id);
if (ret != 0) {
vm_irq_id = child_id;
@@ -5246,15 +5343,35 @@ static int ether_get_vm_irq_data(struct platform_device *pdev,
}
}
is_coe = of_property_read_bool(temp, "nvidia,camera-over-eth");
if (is_coe) {
osi_core->irq_data[node].is_coe = 1U;
dev_info(&pdev->dev, "VM IRQ is handled by Camera CPU: %u\n",
node);
} else {
osi_core->irq_data[node].is_coe = 0U;
}
/* Assuming there would not be more than 0xFFFF nodes */
child_id &= MAX_CHILD_NODES;
child_id++;
}
for (node = 0; node < osi_core->num_vm_irqs; node++) {
ether_set_vm_irq_chan_mask(&pdata->vm_irq_data[node],
if (osi_core->irq_data[node].is_coe) {
if (pdata->osi_dma->num_dma_chans_coe != 0) {
dev_err(&pdev->dev, "Only one CoE IRQ allowed\n");
return -EINVAL;
}
/* CoE channels IRQ will be handled by camera CPU */
ether_set_coe_chan_mask(pdata->osi_dma,
osi_core->irq_data[node].num_vm_chans,
osi_core->irq_data[node].vm_chans);
} else {
ether_set_vm_irq_chan_mask(&pdata->vm_irq_data[node],
osi_core->irq_data[node].num_vm_chans,
osi_core->irq_data[node].vm_chans);
}
pdata->vm_irq_data[node].pdata = pdata;
}
@@ -7690,6 +7807,103 @@ void ether_shutdown(struct platform_device *pdev)
dev_err(pdata->dev, "Failure in ether_close");
}
int nvether_coe_config(struct net_device *ndev,
struct nvether_coe_cfg *ether_coe_cfg)
{
struct ether_priv_data *pdata = netdev_priv(ndev);
struct osi_core_priv_data *osi_core = pdata->osi_core;
struct macsec_priv_data *macsec_pdata = pdata->macsec_pdata;
struct osi_macsec_lut_config lut_config;
int ret = -ENOENT;
/* If macsec not enabled, enable it.
* FIXME: Need a lock to protect any concurrent macsec configuration outside this API from supplicant for ex. */
if (macsec_pdata == NULL) {
dev_err(pdata->dev, "macsec is not supported in platform, COE config failed\n");
return ret;
}
if (macsec_pdata->enabled != OSI_ENABLE) {
ret = macsec_open(macsec_pdata, NULL);
if (ret < 0) {
dev_err(pdata->dev, "macsec_open failure, COE config failed\n");
return ret;
}
}
if (macsec_pdata->coe.enable == OSI_ENABLE) {
return 0;
}
/* Program the COE LUT classifier for AVTP COE packets */
memset(&lut_config, 0, sizeof(lut_config));
lut_config.table_config.ctlr_sel = OSI_CTLR_SEL_RX;
lut_config.table_config.index = 0U;
if (ether_coe_cfg->vlan_enable == COE_VLAN_ENABLE) {
// 16B offset for AV ethtype with VLAN,
// divided by 2 as HW expects offset in multiple of 2.
lut_config.coe_lut_inout.offset = 8U;
}
else if (ether_coe_cfg->vlan_enable == COE_VLAN_DISABLE) {
// 12B offset for AV ethtype without VLAN,
// divided by 2 as HW expects offset in multiple of 2.
lut_config.coe_lut_inout.offset = 6U;
}
else {
dev_err(pdata->dev, "Invalid VLAN enable value\n");
return -EINVAL;
}
lut_config.coe_lut_inout.byte_pattern_mask = 0xF;
lut_config.coe_lut_inout.byte_pattern[1] = (unsigned char) 0x22;
lut_config.coe_lut_inout.byte_pattern[0] = (unsigned char) 0xF0;
lut_config.lut_sel = OSI_LUT_SEL_COE;
lut_config.table_config.rw = OSI_LUT_WRITE;
ret = osi_macsec_config_lut(osi_core, &lut_config);
if (ret < 0) {
dev_err(pdata->dev, "%s: Failed to config COE LUT\n", __func__);
return ret;
}
/* Program the COE header offset and enable COE engine */
ret = macsec_coe_config(macsec_pdata, ether_coe_cfg->coe_enable,
ether_coe_cfg->coe_hdr_offset);
if (ret < 0) {
dev_err(pdata->dev, "COE config in macsec controller failed\n");
return ret;
} else {
macsec_pdata->coe.enable = ether_coe_cfg->coe_enable;
macsec_pdata->coe.hdr_offset = ether_coe_cfg->coe_hdr_offset;
dev_info(pdata->dev, "COE config success\n");
}
return ret;
}
EXPORT_SYMBOL_GPL(nvether_coe_config);
int nvether_coe_chan_config(struct net_device *ndev,
u32 dmachan,
struct nvether_per_coe_cfg *p_coe_cfg)
{
struct ether_priv_data *pdata = netdev_priv(ndev);
struct macsec_priv_data *macsec_pdata = pdata->macsec_pdata;
int ret;
if (macsec_pdata == NULL) {
dev_err(pdata->dev, "macsec is not supported in platform, COE config failed\n");
return -ENONET;
}
if (macsec_pdata->coe.enable != OSI_ENABLE) {
dev_err(pdata->dev, "COE not enabled\n");
return -EIO;
}
ret = macsec_coe_lc(macsec_pdata, dmachan,
p_coe_cfg->lc1,
p_coe_cfg->lc2);
return ret;
}
EXPORT_SYMBOL_GPL(nvether_coe_chan_config);
#ifdef CONFIG_PM
static s32 ether_handle_rx_buffers(struct ether_priv_data *pdata,
uint32_t suspend)
@@ -7893,6 +8107,16 @@ int ether_suspend_noirq(struct device *dev)
OSI_DMA_INTR_DISABLE);
}
for (i = 0; i < osi_dma->num_dma_chans_coe; i++) {
chan = osi_dma->dma_chans_coe[i];
osi_handle_dma_intr(osi_dma, chan,
OSI_DMA_CH_TX_INTR,
OSI_DMA_INTR_DISABLE);
osi_handle_dma_intr(osi_dma, chan,
OSI_DMA_CH_RX_INTR,
OSI_DMA_INTR_DISABLE);
}
if (ether_handle_rx_buffers(pdata, OSI_ENABLE) != 0)
dev_err(dev, "Failed to free the Rx buffers\n");

View File

@@ -755,6 +755,10 @@ struct ether_priv_data {
/** tx bandwidth pkt work queue */
struct workqueue_struct *tx_bw_wq;
#endif
/** COE mode enabled */
u32 coe_enable;
/** OSI instance of COE */
struct osi_mgbe_coe mgbe_coe;
};
/**

View File

@@ -211,6 +211,38 @@ int macsec_close(struct macsec_priv_data *macsec_pdata)
return ret;
}
int macsec_coe_config(struct macsec_priv_data *macsec_pdata,
uint32_t coe_enable, uint32_t coe_hdr_offset)
{
int ret = 0;
struct ether_priv_data *pdata = macsec_pdata->ether_pdata;
struct device *dev = pdata->dev;
/* Input is already validated */
ret = osi_macsec_coe_config(pdata->osi_core, coe_enable,
coe_hdr_offset);
if (ret < 0) {
dev_err(dev, "osi_macsec_coe_config failed, %d\n", ret);
}
return ret;
}
int macsec_coe_lc(struct macsec_priv_data *macsec_pdata,
uint32_t ch, uint32_t lc1, uint32_t lc2)
{
int ret = 0;
struct ether_priv_data *pdata = macsec_pdata->ether_pdata;
struct device *dev = pdata->dev;
/* Input is already validated */
ret = osi_macsec_coe_lc(pdata->osi_core, ch, lc1, lc2);
if (ret < 0) {
dev_err(dev, "osi_macsec_coe_lc failed, %d\n", ret);
}
return ret;
}
int macsec_open(struct macsec_priv_data *macsec_pdata,
void *const genl_info)
{

View File

@@ -205,6 +205,20 @@ struct nvpkcs_data {
u64 nv_kek;
};
/**
* @brief MACsec COE private data structure
*/
struct macsec_coe {
/** Macsec COE state */
unsigned int enable;
/** Macsec COE hdr offset */
unsigned int hdr_offset;
/** Macsec COE line counter threshold 1 */
unsigned int lc1_threshold[OSI_MGBE_MAX_NUM_CHANS];
/** Macsec COE line counter threshold 2 */
unsigned int lc2_threshold[OSI_MGBE_MAX_NUM_CHANS];
};
/**
* @brief MACsec private data structure
*/
@@ -259,9 +273,15 @@ struct macsec_priv_data {
unsigned int macsec_tx_an_map;
/** Macsec RX currently enabled AN */
unsigned int macsec_rx_an_map;
/** Macsec COE instance */
struct macsec_coe coe;
};
int macsec_probe(struct ether_priv_data *pdata);
int macsec_coe_config(struct macsec_priv_data *macsec_pdata,
uint32_t coe_enable, uint32_t coe_hdr_offset);
int macsec_coe_lc(struct macsec_priv_data *macsec_pdata,
uint32_t ch, uint32_t lc1, uint32_t lc2);
void macsec_remove(struct ether_priv_data *pdata);
int macsec_open(struct macsec_priv_data *macsec_pdata,
void *const genl_info);

View File

@@ -533,6 +533,336 @@ static DEVICE_ATTR(macsec_enable, (S_IRUGO | S_IWUSR),
macsec_enable_show,
macsec_enable_store);
#define MACSEC_COE_LC_INPUT_LEN 3
extern int macsec_coe_config(struct macsec_priv_data *macsec_pdata,
uint32_t coe_enable, uint32_t coe_hdr_offset);
/**
* @brief Shows the current COE setting of MACsec controllers enabled
*
* Algorithm: Display the current COE settings for MACsec controllers.
*
* @param[in] dev: Device data.
* @param[in] attr: Device attribute
* @param[in] buf: Buffer to store the current COE setting
*/
static ssize_t macsec_coe_enable_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct net_device *ndev = (struct net_device *)dev_get_drvdata(dev);
struct ether_priv_data *pdata = netdev_priv(ndev);
struct macsec_priv_data *macsec_pdata = pdata->macsec_pdata;
unsigned int coe_enable;
unsigned int coe_hdr_offset;
if (!netif_running(ndev)) {
dev_err(pdata->dev, "Not Allowed. Ether interface is not up\n");
return 0;
}
if ((macsec_pdata == NULL)) {
dev_err(pdata->dev, "Not Allowed. MACSec is not supported on this platform\n");
return 0;
}
if (macsec_pdata->enabled != OSI_ENABLE) {
dev_err(pdata->dev, "Not Allowed. MACSec is not enabled on the controller\n");
return 0;
}
coe_enable = macsec_pdata->coe.enable;
coe_hdr_offset = macsec_pdata->coe.hdr_offset;
if (OSI_ENABLE == coe_enable) {
return scnprintf(buf, PAGE_SIZE, "COE enabled, COE hdr offset: %u\n",
coe_hdr_offset);
} else {
return scnprintf(buf, PAGE_SIZE, "COE disabled\n");
}
}
/**
* @brief Set the MACsec controller COE logic enabled (Rx only)
*
* Algorithm: This is used to set the Rx MACsec controller COE logic enabled.
*
* @param[in] dev: Device data.
* @param[in] attr: Device attribute
* @param[in] buf: Buffer which contains the user settings of MACsec COE enable
* @param[in] size: size of buffer
*
* @return size of buffer.
*/
static ssize_t macsec_coe_enable_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
struct net_device *ndev = (struct net_device *)dev_get_drvdata(dev);
struct ether_priv_data *pdata = netdev_priv(ndev);
struct macsec_priv_data *macsec_pdata = pdata->macsec_pdata;
uint32_t coe_enable, coe_hdr_offset;
int ret = 0, i;
if (!netif_running(ndev)) {
dev_err(pdata->dev, "Not Allowed. Ether interface is not up\n");
return size;
}
if ((macsec_pdata == NULL)) {
dev_err(pdata->dev, "Not Allowed. MACSec is not supported on this platform\n");
return size;
}
if (macsec_pdata->enabled != OSI_ENABLE) {
dev_err(pdata->dev, "Not Allowed. MACSec is not enabled on the controller\n");
return size;
}
/* Read user inputs and validate it */
i = sscanf(buf, "%u %u", &coe_enable, &coe_hdr_offset);
if ((coe_enable != OSI_ENABLE) && (coe_enable != OSI_DISABLE)) {
dev_err(pdata->dev, "Invalid value %u for coe_enable\n", coe_enable);
return size;
}
if ((coe_hdr_offset < 16) || (coe_hdr_offset > 56)) {
dev_err(pdata->dev, "Invalid value %u for coe_hdr_offset\n", coe_hdr_offset);
return size;
}
/* Configure COE */
if (coe_enable == OSI_ENABLE) {
if (macsec_pdata->coe.enable == OSI_ENABLE) {
dev_err(pdata->dev, "COE already enabled\n");
return size;
}
} else {
if (macsec_pdata->coe.enable == OSI_DISABLE) {
dev_err(pdata->dev, "COE already disabled\n");
return size;
}
}
ret = macsec_coe_config(macsec_pdata, coe_enable, coe_hdr_offset);
if (0 == ret) {
macsec_pdata->coe.enable = coe_enable;
macsec_pdata->coe.hdr_offset = coe_hdr_offset;
}
return size;
}
/**
* @brief Sysfs attribute for MACsec COE enable
*
*/
static DEVICE_ATTR(macsec_coe_enable, (S_IRUGO | S_IWUSR),
macsec_coe_enable_show,
macsec_coe_enable_store);
/**
* @brief Shows the current COE setting of MAC controllers enabled
*
* Algorithm: Display the current COE settings for MAC controllers.
*
* @param[in] dev: Device data.
* @param[in] attr: Device attribute
* @param[in] buf: Buffer to store the current COE setting for the MAC
*/
static ssize_t mac_coe_enable_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct net_device *ndev = (struct net_device *)dev_get_drvdata(dev);
struct ether_priv_data *pdata = netdev_priv(ndev);
char *p = buf;
int i, j;
if (!netif_running(ndev)) {
dev_err(pdata->dev, "Not Allowed. Ether interface is not up\n");
return 0;
}
if (OSI_ENABLE == pdata->coe_enable) {
p += scnprintf(p, PAGE_SIZE, "MGBE COE mode enabled\n");
p += scnprintf(p, PAGE_SIZE, "\t vdma: %d\n", pdata->mgbe_coe.vdma);
p += scnprintf(p, PAGE_SIZE, "\t pdma: %d\n", pdata->mgbe_coe.pdma);
p += scnprintf(p, PAGE_SIZE, "\t PIB size: %d\n", pdata->mgbe_coe.rx_pib_sz);
for (j = 0; j < OSI_MGBE_COE_NUM_RX_FRAMES; j++) {
p += scnprintf(p, PAGE_SIZE, "\t FB[%d]:\n", j);
for (i = 0; i < 200; i++) {
p += scnprintf(p, PAGE_SIZE - i, "%02x", *(((unsigned char *)(pdata->mgbe_coe.rx_fb_addr[j])) + i));
}
p += scnprintf(p, PAGE_SIZE - i, "\n");
}
p += scnprintf(p, PAGE_SIZE, "\t PIB:\n");
for (i = 0; i < 200; i++) {
p += scnprintf(p, PAGE_SIZE - i, "%02x", *(((unsigned char *)pdata->mgbe_coe.rx_pib_addr) + i));
}
return p - buf;
} else {
return scnprintf(buf, PAGE_SIZE, "MGBE COE mode disabled\n");
}
}
/**
* @brief Set the MAC controller COE logic enabled (Rx only)
*
* Algorithm: This is used to set the Rx MAC controller COE logic enabled.
*
* @param[in] dev: Device data.
* @param[in] attr: Device attribute
* @param[in] buf: Buffer which contains the user settings of MAC COE enable
* @param[in] size: size of buffer
*
* @return size of buffer.
*/
static ssize_t mac_coe_enable_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
struct net_device *ndev = (struct net_device *)dev_get_drvdata(dev);
struct ether_priv_data *pdata = netdev_priv(ndev);
int32_t coe_enable, vdma, pdma, rx_pib_sz;
if (netif_running(ndev)) {
dev_err(pdata->dev, "Not Allowed. Ether interface is not down\n");
return size;
}
/* Read user inputs and validate it */
sscanf(buf, "%d %d %d %d", &coe_enable, &vdma, &pdma, &rx_pib_sz);
if ((coe_enable != OSI_ENABLE) && (coe_enable != OSI_DISABLE)) {
dev_err(pdata->dev, "Invalid value %u for coe_enable\n", coe_enable);
return size;
}
if ((rx_pib_sz != 256) &&
(rx_pib_sz != 512) &&
(rx_pib_sz != 2048) &&
(rx_pib_sz != 4096)) {
dev_err(pdata->dev, "Invalid value %d for rx_pib_sz\n", rx_pib_sz);
return size;
}
/* Configure COE */
pdata->coe_enable = coe_enable;
pdata->mgbe_coe.vdma = vdma;
pdata->mgbe_coe.pdma = pdma;
pdata->mgbe_coe.rx_pib_sz = rx_pib_sz;
return size;
}
/**
* @brief Sysfs attribute for MAC COE enable
*
*/
static DEVICE_ATTR(mac_coe_enable, (S_IRUGO | S_IWUSR),
mac_coe_enable_show,
mac_coe_enable_store);
extern int macsec_coe_lc(struct macsec_priv_data *macsec_pdata,
uint32_t ch, uint32_t lc1, uint32_t lc2);
/**
* @brief Shows the current COE Line counter thresholds.
*
* Algorithm: Loop through the current COE Line counter thresholds per VDMA
*
* @param[in] dev: Device data.
* @param[in] attr: Device attribute
* @param[in] buf: Buffer to store the current LC thresholds
*/
static ssize_t macsec_coe_lc_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct net_device *ndev = (struct net_device *)dev_get_drvdata(dev);
struct ether_priv_data *pdata = netdev_priv(ndev);
struct macsec_priv_data *macsec_pdata = pdata->macsec_pdata;
unsigned int i;
char *start = buf;
if (!netif_running(ndev)) {
dev_err(pdata->dev, "Not Allowed. Ether interface is not up\n");
return 0;
}
if ((macsec_pdata == NULL)) {
dev_err(pdata->dev, "Not Allowed. MACSec is not supported on this platform\n");
return 0;
}
if (macsec_pdata->enabled != OSI_ENABLE) {
dev_err(pdata->dev, "Not Allowed. MACSec is not enabled on the controller\n");
return 0;
}
for (i = 0U; i < OSI_MGBE_MAX_NUM_CHANS; i++) {
buf += scnprintf(buf, PAGE_SIZE, "ch: %u lc1: %u lc2: %u\n", i,
macsec_pdata->coe.lc1_threshold[i],
macsec_pdata->coe.lc2_threshold[i]);
}
return (buf - start);
}
/**
* @brief Set the MACsec controller COE line counter thresholds
*
* Algorithm: This is used to set threshold per VDMA Rx MACsec COE line counter
*
* @param[in] dev: Device data.
* @param[in] attr: Device attribute
* @param[in] buf: Buffer which contains the user settings of MACsec COE LC
* @param[in] size: size of buffer
*
* @return size of buffer.
*/
static ssize_t macsec_coe_lc_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
struct net_device *ndev = (struct net_device *)dev_get_drvdata(dev);
struct ether_priv_data *pdata = netdev_priv(ndev);
struct macsec_priv_data *macsec_pdata = pdata->macsec_pdata;
uint32_t ch, lc1, lc2;
int ret = 0, i;
if (!netif_running(ndev)) {
dev_err(pdata->dev, "Not Allowed. Ether interface is not up\n");
return size;
}
if ((macsec_pdata == NULL)) {
dev_err(pdata->dev, "Not Allowed. MACSec is not supported on this platform\n");
return size;
}
if (macsec_pdata->enabled != OSI_ENABLE) {
dev_err(pdata->dev, "Not Allowed. MACSec is not enabled on the controller\n");
return size;
}
/* Read user inputs and validate it */
i = sscanf(buf, "%u %u %u", &ch, &lc1, &lc2);
if (i != MACSEC_COE_LC_INPUT_LEN) {
pr_err("%s: Invalid COE LC inputs(read %d)", __func__, i);
return size;
}
if (ch >= OSI_MGBE_MAX_NUM_CHANS) {
dev_err(pdata->dev, "Invalid value %u for channel\n", ch);
return size;
}
if ((lc1 > OSI_MACSEC_COE_MAX_LC) || (lc2 > OSI_MACSEC_COE_MAX_LC)) {
dev_err(pdata->dev, "Line counter threshold has to be < %x\n", OSI_MACSEC_COE_MAX_LC);
return size;
}
/* Configure COE LC threshold */
ret = macsec_coe_lc(macsec_pdata, ch, lc1, lc2);
if (ret != 0) {
dev_err(pdata->dev, "Line counter threshold config failed\n");
} else {
macsec_pdata->coe.lc1_threshold[ch] = lc1;
macsec_pdata->coe.lc2_threshold[ch] = lc2;
}
return size;
}
/**
* @brief Sysfs attribute for MACsec COE LC threshold
*
*/
static DEVICE_ATTR(macsec_coe_lc, (S_IRUGO | S_IWUSR),
macsec_coe_lc_show,
macsec_coe_lc_store);
/**
* @brief Shows the current setting of MACsec cipther set
*
@@ -1726,6 +2056,162 @@ static DEVICE_ATTR(macsec_sci_lut, (S_IRUGO | S_IWUSR),
NULL,
macsec_sci_lut_store);
/**
* @brief Shows the current COE LUT configuration
*
* @param[in] dev: Device data.
* @param[in] attr: Device attribute
* @param[in] buf: Buffer to print the current COE LUT configuration
*/
static ssize_t macsec_coe_lut_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct net_device *ndev = (struct net_device *)dev_get_drvdata(dev);
struct ether_priv_data *pdata = netdev_priv(ndev);
struct macsec_priv_data *macsec_pdata = pdata->macsec_pdata;
struct osi_core_priv_data *osi_core = pdata->osi_core;
struct osi_macsec_lut_config lut_config = {0};
struct osi_coe_lut_inout coe_lut_inout = {0};
int i;
char *start = buf;
if (!netif_running(ndev)) {
dev_err(pdata->dev, "Not Allowed. Ether interface is not up\n");
return 0;
}
if (!macsec_pdata) {
dev_err(pdata->dev, "Not Allowed. MACsec is not supported in platform\n");
return 0;
}
for (i = 0; i < OSI_COE_LUT_MAX_INDEX; i++) {
memset(&lut_config, OSI_NONE, sizeof(lut_config));
lut_config.table_config.ctlr_sel = OSI_CTLR_SEL_RX;
lut_config.lut_sel = OSI_LUT_SEL_COE;
lut_config.table_config.rw = OSI_LUT_READ;
lut_config.table_config.index = i;
if (osi_macsec_config_lut(osi_core, &lut_config) < 0) {
dev_err(dev, "%s: Failed to read COE LUT\n", __func__);
goto exit;
} else {
buf += scnprintf(buf, PAGE_SIZE, "%d.\t", i);
if (lut_config.coe_lut_inout.valid != OSI_COE_LUT_ENTRY_VALID) {
buf += scnprintf(buf, PAGE_SIZE, "Invalid\n");
continue;
}
coe_lut_inout = lut_config.coe_lut_inout;
/* HW design expects offset to be divided by 2.
* So multiply for actual byte offset.
*/
buf += scnprintf(buf, PAGE_SIZE, "Offset: %u ",
coe_lut_inout.offset * 2);
buf += scnprintf(buf, PAGE_SIZE, "Mask: %#x ",
coe_lut_inout.byte_pattern_mask);
buf += scnprintf(buf, PAGE_SIZE, "Pattern: 0x%x%x\n",
coe_lut_inout.byte_pattern[1],
coe_lut_inout.byte_pattern[0]);
}
}
exit:
return (buf - start);
}
#define COE_LUT_INPUTS 5
/**
* @brief Set the COE LUT configuration
*
* @param[in] dev: Device data.
* @param[in] attr: Device attribute
* @param[in] buf: Buffer which contains the desired LUT configuration
* @param[in] size: size of buffer
*
* @return size of buffer.
*/
static ssize_t macsec_coe_lut_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
struct net_device *ndev = (struct net_device *)dev_get_drvdata(dev);
struct ether_priv_data *pdata = netdev_priv(ndev);
struct macsec_priv_data *macsec_pdata = pdata->macsec_pdata;
struct osi_core_priv_data *osi_core = pdata->osi_core;
struct osi_macsec_lut_config lut_config;
int ret, temp[OSI_COE_LUT_BYTE_PATTERN_MAX];
int i;
if (!netif_running(ndev)) {
dev_err(pdata->dev, "Not Allowed. Ether interface is not up\n");
return size;
}
if (!macsec_pdata) {
dev_err(pdata->dev, "Not Allowed. MACsec is not supported on platform\n");
return size;
}
memset(&lut_config, 0, sizeof(lut_config));
lut_config.table_config.ctlr_sel = OSI_CTLR_SEL_RX;
ret = sscanf(buf, "%hu %u %x %x%x",
&lut_config.table_config.index,
&lut_config.coe_lut_inout.offset,
&lut_config.coe_lut_inout.byte_pattern_mask,
&temp[1],
&temp[0]);
if (ret != COE_LUT_INPUTS) {
dev_err(pdata->dev, "Failed to parse COE LUT arguments");
goto exit;
}
if (lut_config.coe_lut_inout.offset % 2 != 0) {
dev_err(pdata->dev, "Offset field is not multiple of 2");
goto exit;
} else {
/* HW is expecting offset to be divided by 2 */
lut_config.coe_lut_inout.offset /= 2;
}
for (i = OSI_COE_LUT_BYTE_PATTERN_MAX - 1; i >= 0; i--) {
if (temp[i] > 0xFF) {
dev_err(pdata->dev, "Invalid byte pattern %d\n", temp[i]);
}
lut_config.coe_lut_inout.byte_pattern[i] = (unsigned char)temp[i];
}
lut_config.lut_sel = OSI_LUT_SEL_COE;
lut_config.table_config.rw = OSI_LUT_WRITE;
/* Rest of LUT attributes are filled by parse_inputs() */
if (lut_config.table_config.index >= OSI_COE_LUT_MAX_INDEX) {
dev_err(dev, "%s: Index can't be >= %d\n", __func__,
OSI_COE_LUT_MAX_INDEX);
goto exit;
}
if (lut_config.coe_lut_inout.offset > OSI_COE_LUT_OFFSET_MAX) {
dev_err(dev, "%s: COE offset can't be > %d\n", __func__,
OSI_COE_LUT_MAX_INDEX);
goto exit;
}
if (osi_macsec_config_lut(osi_core, &lut_config) < 0) {
dev_err(dev, "%s: Failed to config COE LUT\n", __func__);
goto exit;
} else {
dev_err(dev, "%s: Added COE LUT idx: %d", __func__,
lut_config.table_config.index);
}
exit:
return size;
}
/**
* @brief Sysfs attribute for MACsec COE LUT config
*
*/
static DEVICE_ATTR(macsec_coe_lut, (S_IRUGO | S_IWUSR),
macsec_coe_lut_show,
macsec_coe_lut_store);
#ifdef MACSEC_KEY_PROGRAM
static void dump_kt(char **buf_p, unsigned short ctlr_sel,
struct osi_core_priv_data *osi_core,
@@ -3487,6 +3973,7 @@ static DEVICE_ATTR(hsi_enable, 0644,
#endif
#endif /* OSI_STRIPPED_LIB */
/**
* @brief Attributes for nvethernet sysfs
*/
@@ -3529,6 +4016,10 @@ static struct attribute *ether_sysfs_attrs[] = {
&dev_attr_macsec_sc_param_rx_lut.attr,
&dev_attr_macsec_cipher.attr,
&dev_attr_macsec_enable.attr,
&dev_attr_macsec_coe_enable.attr,
&dev_attr_macsec_coe_lc.attr,
&dev_attr_macsec_coe_lut.attr,
&dev_attr_mac_coe_enable.attr,
&dev_attr_macsec_an_status.attr,
&dev_attr_macsec_mmc_counters_tx.attr,
&dev_attr_macsec_mmc_counters_rx.attr,