Files
nvethernetrm/osi/core/macsec.c
Sanath Kumar Gampa c52ad89f9d osi:macsec:lowest pn changes to enable sa
Enhancement to receive lowest_pn from supplicant
as part of receive AN enable

Bug 3371004

Change-Id: If81f8449f7ebda996c95117e2c84722fdc57c5d0
Signed-off-by: Sanath Kumar Gampa <sgampa@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/kernel/nvethernetrm/+/2619949
Reviewed-by: svcacv <svcacv@nvidia.com>
Reviewed-by: Mahesh Patil <maheshp@nvidia.com>
Reviewed-by: Bhadram Varka <vbhadram@nvidia.com>
Reviewed-by: Krishna Thota <kthota@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
GVS: Gerrit_Virtual_Submit
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
2021-11-11 20:39:08 -08:00

3332 lines
94 KiB
C

/*
* 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.
*/
#ifdef MACSEC_KEY_PROGRAM
#include <linux/crypto.h>
#endif
#include <osi_macsec.h>
#include "macsec.h"
#include "../osi/common/common.h"
#include "core_local.h"
#ifdef DEBUG_MACSEC
#include <linux/printk.h>
#else
#define pr_cont(args...)
#define pr_err(args...)
#endif
/**
* @brief poll_for_dbg_buf_update - Query the status of a debug buffer update.
*
* @param[in] osi_core: OSI Core private data structure.
*
* @retval 0 on Success
* @retval -1 on Failure
*/
static nve32_t poll_for_dbg_buf_update(struct osi_core_priv_data *const osi_core)
{
nve32_t retry = RETRY_COUNT;
nveu32_t dbg_buf_config;
nve32_t cond = COND_NOT_MET;
nveu32_t count;
count = 0;
while (cond == COND_NOT_MET) {
if (count > retry) {
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"timeout!\n", 0ULL);
return -1;
}
dbg_buf_config = osi_readla(osi_core,
(nveu8_t *)osi_core->macsec_base +
MACSEC_DEBUG_BUF_CONFIG_0);
if ((dbg_buf_config & MACSEC_DEBUG_BUF_CONFIG_0_UPDATE) == 0U) {
cond = COND_MET;
}
count++;
/* wait on UPDATE bit to reset */
osi_core->osd_ops.udelay(10U);
}
return 0;
}
/**
* @brief write_dbg_buf_data - Commit.debug buffer to HW
*
* @param[in] osi_core: OSI Core private data structure.
* @param[in] dbg_buf: Pointer to debug buffer data to be written
*
* @retval none
*/
static inline void write_dbg_buf_data(
struct osi_core_priv_data *const osi_core,
nveu32_t const *const dbg_buf)
{
nveu8_t *base = (nveu8_t *)osi_core->macsec_base;
nveu32_t i;
/* Commit the dbg buffer to HW */
for (i = 0; i < DBG_BUF_LEN; i++) {
/* pr_err("%s: dbg_buf_data[%d]: 0x%x\n", __func__,
i, dbg_buf[i]);
*/
osi_writela(osi_core, dbg_buf[i], base +
MACSEC_DEBUG_BUF_DATA_0(i));
}
}
/**
* @brief read_dbg_buf_data - Read.debug buffer from HW
*
* @param[in] osi_core: OSI Core private data structure.
* @param[in] dbg_buf: Pointer to debug buffer data to be read
*
* @retval none
*/
static inline void read_dbg_buf_data(
struct osi_core_priv_data *const osi_core,
nveu32_t *dbg_buf)
{
nveu8_t *base = (nveu8_t *)osi_core->macsec_base;
nveu32_t i;
/* Read debug buffer from HW */
for (i = 0; i < DBG_BUF_LEN; i++) {
dbg_buf[i] = osi_readla(osi_core, base +
MACSEC_DEBUG_BUF_DATA_0(i));
/* pr_err("%s: dbg_buf_data[%d]: 0x%x\n", __func__,
i, dbg_buf[i]); */
}
}
/**
* @brief tx_dbg_trigger_evts - Enable/Disable TX debug trigger events.
*
* @param[in] osi_core: OSI Core private data structure.
* @param[in] dbg_buf_config: Pointer to debug buffer config data structure.
*
* @retval None
*/
static void tx_dbg_trigger_evts(
struct osi_core_priv_data *const osi_core,
struct osi_macsec_dbg_buf_config *const dbg_buf_config)
{
nveu8_t *base = (nveu8_t *)osi_core->macsec_base;
nveu32_t flags = 0;
nveu32_t tx_trigger_evts, debug_ctrl_reg;
if (dbg_buf_config->rw == OSI_DBG_TBL_WRITE) {
flags = dbg_buf_config->flags;
tx_trigger_evts = osi_readla(osi_core,
base + MACSEC_TX_DEBUG_TRIGGER_EN_0);
if (flags & OSI_TX_DBG_LKUP_MISS_EVT) {
tx_trigger_evts |= MACSEC_TX_DBG_LKUP_MISS;
} else {
tx_trigger_evts &= ~MACSEC_TX_DBG_LKUP_MISS;
}
if (flags & OSI_TX_DBG_AN_NOT_VALID_EVT) {
tx_trigger_evts |= MACSEC_TX_DBG_AN_NOT_VALID;
} else {
tx_trigger_evts &= ~MACSEC_TX_DBG_AN_NOT_VALID;
}
if (flags & OSI_TX_DBG_KEY_NOT_VALID_EVT) {
tx_trigger_evts |= MACSEC_TX_DBG_KEY_NOT_VALID;
} else {
tx_trigger_evts &= ~MACSEC_TX_DBG_KEY_NOT_VALID;
}
if (flags & OSI_TX_DBG_CRC_CORRUPT_EVT) {
tx_trigger_evts |= MACSEC_TX_DBG_CRC_CORRUPT;
} else {
tx_trigger_evts &= ~MACSEC_TX_DBG_CRC_CORRUPT;
}
if (flags & OSI_TX_DBG_ICV_CORRUPT_EVT) {
tx_trigger_evts |= MACSEC_TX_DBG_ICV_CORRUPT;
} else {
tx_trigger_evts &= ~MACSEC_TX_DBG_ICV_CORRUPT;
}
if (flags & OSI_TX_DBG_CAPTURE_EVT) {
tx_trigger_evts |= MACSEC_TX_DBG_CAPTURE;
} else {
tx_trigger_evts &= ~MACSEC_TX_DBG_CAPTURE;
}
pr_err("%s: tx_dbg_trigger_evts 0x%x", __func__,
tx_trigger_evts);
osi_writela(osi_core, tx_trigger_evts,
base + MACSEC_TX_DEBUG_TRIGGER_EN_0);
if (tx_trigger_evts != OSI_NONE) {
/** Start the tx debug buffer capture */
debug_ctrl_reg = osi_readla(osi_core,
base + MACSEC_TX_DEBUG_CONTROL_0);
debug_ctrl_reg |= MACSEC_TX_DEBUG_CONTROL_0_START_CAP;
pr_err("%s: debug_ctrl_reg 0x%x", __func__,
debug_ctrl_reg);
osi_writela(osi_core, debug_ctrl_reg,
base + MACSEC_TX_DEBUG_CONTROL_0);
}
} else {
tx_trigger_evts = osi_readla(osi_core,
base + MACSEC_TX_DEBUG_TRIGGER_EN_0);
pr_err("%s: tx_dbg_trigger_evts 0x%x", __func__,
tx_trigger_evts);
if (tx_trigger_evts & MACSEC_TX_DBG_LKUP_MISS) {
flags |= OSI_TX_DBG_LKUP_MISS_EVT;
}
if (tx_trigger_evts & MACSEC_TX_DBG_AN_NOT_VALID) {
flags |= OSI_TX_DBG_AN_NOT_VALID_EVT;
}
if (tx_trigger_evts & MACSEC_TX_DBG_KEY_NOT_VALID) {
flags |= OSI_TX_DBG_KEY_NOT_VALID_EVT;
}
if (tx_trigger_evts & MACSEC_TX_DBG_CRC_CORRUPT) {
flags |= OSI_TX_DBG_CRC_CORRUPT_EVT;
}
if (tx_trigger_evts & MACSEC_TX_DBG_ICV_CORRUPT) {
flags |= OSI_TX_DBG_ICV_CORRUPT_EVT;
}
if (tx_trigger_evts & MACSEC_TX_DBG_CAPTURE) {
flags |= OSI_TX_DBG_CAPTURE_EVT;
}
dbg_buf_config->flags = flags;
}
}
/**
* @brief rx_dbg_trigger_evts - Enable/Disable RX debug trigger events.
*
* @param[in] osi_core: OSI Core private data structure.
* @param[in] dbg_buf_config: Pointer to debug buffer config data structure.
*
* @retval None
*/
static void rx_dbg_trigger_evts(
struct osi_core_priv_data *const osi_core,
struct osi_macsec_dbg_buf_config *const dbg_buf_config)
{
nveu8_t *base = (nveu8_t *)osi_core->macsec_base;
nveu32_t flags = 0;
nveu32_t rx_trigger_evts, debug_ctrl_reg;
if (dbg_buf_config->rw == OSI_DBG_TBL_WRITE) {
flags = dbg_buf_config->flags;
rx_trigger_evts = osi_readla(osi_core,
base + MACSEC_RX_DEBUG_TRIGGER_EN_0);
if (flags & OSI_RX_DBG_LKUP_MISS_EVT) {
rx_trigger_evts |= MACSEC_RX_DBG_LKUP_MISS;
} else {
rx_trigger_evts &= ~MACSEC_RX_DBG_LKUP_MISS;
}
if (flags & OSI_RX_DBG_KEY_NOT_VALID_EVT) {
rx_trigger_evts |= MACSEC_RX_DBG_KEY_NOT_VALID;
} else {
rx_trigger_evts &= ~MACSEC_RX_DBG_KEY_NOT_VALID;
}
if (flags & OSI_RX_DBG_REPLAY_ERR_EVT) {
rx_trigger_evts |= MACSEC_RX_DBG_REPLAY_ERR;
} else {
rx_trigger_evts &= ~MACSEC_RX_DBG_REPLAY_ERR;
}
if (flags & OSI_RX_DBG_CRC_CORRUPT_EVT) {
rx_trigger_evts |= MACSEC_RX_DBG_CRC_CORRUPT;
} else {
rx_trigger_evts &= ~MACSEC_RX_DBG_CRC_CORRUPT;
}
if (flags & OSI_RX_DBG_ICV_ERROR_EVT) {
rx_trigger_evts |= MACSEC_RX_DBG_ICV_ERROR;
} else {
rx_trigger_evts &= ~MACSEC_RX_DBG_ICV_ERROR;
}
if (flags & OSI_RX_DBG_CAPTURE_EVT) {
rx_trigger_evts |= MACSEC_RX_DBG_CAPTURE;
} else {
rx_trigger_evts &= ~MACSEC_RX_DBG_CAPTURE;
}
pr_err("%s: rx_dbg_trigger_evts 0x%x", __func__,
rx_trigger_evts);
osi_writela(osi_core, rx_trigger_evts,
base + MACSEC_RX_DEBUG_TRIGGER_EN_0);
if (rx_trigger_evts != OSI_NONE) {
/** Start the tx debug buffer capture */
debug_ctrl_reg = osi_readla(osi_core,
base + MACSEC_RX_DEBUG_CONTROL_0);
debug_ctrl_reg |= MACSEC_RX_DEBUG_CONTROL_0_START_CAP;
pr_err("%s: debug_ctrl_reg 0x%x", __func__,
debug_ctrl_reg);
osi_writela(osi_core, debug_ctrl_reg,
base + MACSEC_RX_DEBUG_CONTROL_0);
}
} else {
rx_trigger_evts = osi_readla(osi_core,
base + MACSEC_RX_DEBUG_TRIGGER_EN_0);
pr_err("%s: rx_dbg_trigger_evts 0x%x", __func__,
rx_trigger_evts);
if (rx_trigger_evts & MACSEC_RX_DBG_LKUP_MISS) {
flags |= OSI_RX_DBG_LKUP_MISS_EVT;
}
if (rx_trigger_evts & MACSEC_RX_DBG_KEY_NOT_VALID) {
flags |= OSI_RX_DBG_KEY_NOT_VALID_EVT;
}
if (rx_trigger_evts & MACSEC_RX_DBG_REPLAY_ERR) {
flags |= OSI_RX_DBG_REPLAY_ERR_EVT;
}
if (rx_trigger_evts & MACSEC_RX_DBG_CRC_CORRUPT) {
flags |= OSI_RX_DBG_CRC_CORRUPT_EVT;
}
if (rx_trigger_evts & MACSEC_RX_DBG_ICV_ERROR) {
flags |= OSI_RX_DBG_ICV_ERROR_EVT;
}
if (rx_trigger_evts & MACSEC_RX_DBG_CAPTURE) {
flags |= OSI_RX_DBG_CAPTURE_EVT;
}
dbg_buf_config->flags = flags;
}
}
/**
* @brief macsec_dbg_buf_config - Read/Write debug buffers.
*
* @param[in] osi_core: OSI Core private data structure.
* @param[in] dbg_buf_config: Pointer to debug buffer config data structure.
*
* @retval 0 on Success
* @retval -1 on Failure
*/
static nve32_t macsec_dbg_buf_config(struct osi_core_priv_data *const osi_core,
struct osi_macsec_dbg_buf_config *const dbg_buf_config)
{
nveu8_t *base = (nveu8_t *)osi_core->macsec_base;
nveu32_t dbg_config_reg = 0;
nve32_t ret = 0;
/* Validate inputs */
if ((dbg_buf_config->rw > OSI_RW_MAX) ||
(dbg_buf_config->ctlr_sel > OSI_CTLR_SEL_MAX)) {
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"Params validation failed\n", 0ULL);
return -1;
}
if ((dbg_buf_config->ctlr_sel == OSI_CTLR_SEL_TX &&
dbg_buf_config->index > OSI_TX_DBG_BUF_IDX_MAX) ||
(dbg_buf_config->ctlr_sel == OSI_CTLR_SEL_RX &&
dbg_buf_config->index > OSI_RX_DBG_BUF_IDX_MAX)) {
pr_err("%s(): Wrong index %d\n", __func__,
dbg_buf_config->index);
return -1;
}
/* Wait for previous debug table update to finish */
ret = poll_for_dbg_buf_update(osi_core);
if (ret < 0) {
return ret;
}
/* pr_err("%s: ctrl: %hu rw: %hu idx: %hu\n", __func__,
dbg_buf_config->ctlr_sel, dbg_buf_config->rw,
dbg_buf_config->index); */
dbg_config_reg = osi_readla(osi_core, base + MACSEC_DEBUG_BUF_CONFIG_0);
if (dbg_buf_config->ctlr_sel) {
dbg_config_reg |= MACSEC_DEBUG_BUF_CONFIG_0_CTLR_SEL;
} else {
dbg_config_reg &= ~MACSEC_DEBUG_BUF_CONFIG_0_CTLR_SEL;
}
if (dbg_buf_config->rw) {
dbg_config_reg |= MACSEC_DEBUG_BUF_CONFIG_0_RW;
/** Write data to debug buffer */
write_dbg_buf_data(osi_core, dbg_buf_config->dbg_buf);
} else {
dbg_config_reg &= ~MACSEC_DEBUG_BUF_CONFIG_0_RW;
}
dbg_config_reg &= ~MACSEC_DEBUG_BUF_CONFIG_0_IDX_MASK;
dbg_config_reg |= dbg_buf_config->index ;
dbg_config_reg |= MACSEC_DEBUG_BUF_CONFIG_0_UPDATE;
osi_writela(osi_core, dbg_config_reg, base + MACSEC_DEBUG_BUF_CONFIG_0);
ret = poll_for_dbg_buf_update(osi_core);
if (ret < 0) {
return ret;
}
if (!dbg_buf_config->rw) {
read_dbg_buf_data(osi_core, dbg_buf_config->dbg_buf);
}
return 0;
}
nve32_t macsec_dbg_events_config(
struct osi_core_priv_data *const osi_core,
struct osi_macsec_dbg_buf_config *const dbg_buf_config)
{
nveu32_t i, events = 0;
nveu32_t flags = dbg_buf_config->flags;
pr_err("%s():", __func__);
/* Validate inputs */
if ((dbg_buf_config->rw > OSI_RW_MAX) ||
(dbg_buf_config->ctlr_sel > OSI_CTLR_SEL_MAX)) {
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"Params validation failed!\n", 0ULL);
return -1;
}
/* Only one event allowed to configure at a time */
if (flags != OSI_NONE && dbg_buf_config->rw == OSI_DBG_TBL_WRITE) {
for (i = 0; i < 32U; i++) {
if (flags & (1U << i)) {
events++;
}
}
if (events > 1U) {
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"Don't allow more than one debug events set\n", flags);
return -1;
}
}
switch (dbg_buf_config->ctlr_sel) {
case OSI_CTLR_SEL_TX:
tx_dbg_trigger_evts(osi_core, dbg_buf_config);
break;
case OSI_CTLR_SEL_RX:
rx_dbg_trigger_evts(osi_core, dbg_buf_config);
break;
}
return 0;
}
/**
* @brief update_macsec_mmc_val - function to read register and return value
* to callee
* Algorithm: Read the registers, check for boundary, if more, reset
* counters else return same to caller.
*
* @param[in] osi_core: OSI core private data structure.
* @param[in] offset: HW register offset
*
* @note
* 1) MAC/MACSEC should be init and started.
*
* @retval value on current MMC counter value.
*/
static inline unsigned long long update_macsec_mmc_val(
struct osi_core_priv_data *osi_core,
unsigned long offset)
{
nveul64_t temp;
nveu32_t value_lo, value_hi;
value_lo = osi_readla(osi_core,
(nveu8_t *)osi_core->macsec_base + offset);
value_hi = osi_readla(osi_core,
(nveu8_t *)osi_core->macsec_base +
(offset + 4U));
temp = (value_lo | value_hi << 31);
return temp;
}
/**
* @brief macsec_read_mmc - To read statitics registers and update structure
* variable
*
* Algorithm: Pass register offset and old value to helper function and
* update structure.
*
* @param[in] osi_core: OSI core private data structure.
*
* @note
* 1) MAC/MACSEC should be init and started.
*/
void macsec_read_mmc(struct osi_core_priv_data *const osi_core)
{
struct osi_macsec_mmc_counters *mmc = &osi_core->macsec_mmc;
nveu16_t i;
mmc->tx_pkts_untaged =
update_macsec_mmc_val(osi_core, MACSEC_TX_PKTS_UNTG_LO_0);
mmc->tx_pkts_too_long =
update_macsec_mmc_val(osi_core, MACSEC_TX_PKTS_TOO_LONG_LO_0);
mmc->tx_octets_protected =
update_macsec_mmc_val(osi_core, MACSEC_TX_OCTETS_PRTCTD_LO_0);
mmc->rx_pkts_no_tag =
update_macsec_mmc_val(osi_core, MACSEC_RX_PKTS_NOTG_LO_0);
mmc->rx_pkts_untagged =
update_macsec_mmc_val(osi_core, MACSEC_RX_PKTS_UNTG_LO_0);
mmc->rx_pkts_bad_tag =
update_macsec_mmc_val(osi_core, MACSEC_RX_PKTS_BADTAG_LO_0);
mmc->rx_pkts_no_sa_err =
update_macsec_mmc_val(osi_core, MACSEC_RX_PKTS_NOSAERROR_LO_0);
mmc->rx_pkts_no_sa =
update_macsec_mmc_val(osi_core, MACSEC_RX_PKTS_NOSA_LO_0);
mmc->rx_pkts_overrun =
update_macsec_mmc_val(osi_core, MACSEC_RX_PKTS_OVRRUN_LO_0);
mmc->rx_octets_validated =
update_macsec_mmc_val(osi_core, MACSEC_RX_OCTETS_VLDTD_LO_0);
for (i = 0; i <= OSI_SC_INDEX_MAX; i++) {
mmc->tx_pkts_protected[i] =
update_macsec_mmc_val(osi_core,
MACSEC_TX_PKTS_PROTECTED_SCx_LO_0(i));
mmc->rx_pkts_late[i] =
update_macsec_mmc_val(osi_core,
MACSEC_RX_PKTS_LATE_SCx_LO_0(i));
mmc->rx_pkts_delayed[i] = mmc->rx_pkts_late[i];
mmc->rx_pkts_not_valid[i] =
update_macsec_mmc_val(osi_core,
MACSEC_RX_PKTS_NOTVALID_SCx_LO_0(i));
mmc->in_pkts_invalid[i] = mmc->rx_pkts_not_valid[i];
mmc->rx_pkts_unchecked[i] = mmc->rx_pkts_not_valid[i];
mmc->rx_pkts_ok[i] =
update_macsec_mmc_val(osi_core,
MACSEC_RX_PKTS_OK_SCx_LO_0(i));
}
}
nve32_t macsec_enable(struct osi_core_priv_data *osi_core, nveu32_t enable)
{
nveu32_t val;
nveu8_t *base = (nveu8_t *)osi_core->macsec_base;
val = osi_readla(osi_core, base + MACSEC_CONTROL0);
pr_err("Read MACSEC_CONTROL0: 0x%x\n", val);
if ((enable & OSI_MACSEC_TX_EN) == OSI_MACSEC_TX_EN) {
pr_err("\tEnabling macsec TX");
val |= (MACSEC_TX_EN);
} else {
pr_err("\tDisabling macsec TX");
val &= ~(MACSEC_TX_EN);
}
if ((enable & OSI_MACSEC_RX_EN) == OSI_MACSEC_RX_EN) {
pr_err("\tEnabling macsec RX");
val |= (MACSEC_RX_EN);
} else {
pr_err("\tDisabling macsec RX");
val &= ~(MACSEC_RX_EN);
}
pr_err("Write MACSEC_CONTROL0: 0x%x\n", val);
osi_writela(osi_core, val, base + MACSEC_CONTROL0);
return 0;
}
#ifdef MACSEC_KEY_PROGRAM
/**
* @brief poll_for_kt_update - Query the status of a KT update.
*
* @param[in] osi_core: OSI Core private data structure.
*
* @retval 0 on Success
* @retval -1 on Failure
*/
static inline nve32_t poll_for_kt_update(struct osi_core_priv_data *osi_core)
{
/* half sec timeout */
nveu32_t retry = 50000;
nveu32_t kt_config;
nveu32_t count;
nve32_t cond = 1;
count = 0;
while (cond == 1) {
if (count > retry) {
OSI_CORE_ERR(osi_core->osd,
OSI_LOG_ARG_HW_FAIL,
"KT update timed out\n",
0ULL);
return -1;
}
count++;
kt_config = osi_readla(osi_core,
(nveu8_t *)osi_core->tz_base +
MACSEC_GCM_KEYTABLE_CONFIG);
if ((kt_config & MACSEC_KT_CONFIG_UPDATE) == 0U) {
/* exit loop */
cond = 0;
} else {
/* wait on UPDATE bit to reset */
osi_core->osd_ops.udelay(10U);
}
}
return 0;
}
static nve32_t kt_key_read(struct osi_core_priv_data *const osi_core,
struct osi_macsec_kt_config *const kt_config)
{
nveu32_t kt_key[MACSEC_KT_DATA_REG_CNT] = {0};
nve32_t i, j;
for (i = 0; i < MACSEC_KT_DATA_REG_CNT; i++) {
kt_key[i] = osi_readla(osi_core,
(nveu8_t *)osi_core->tz_base +
MACSEC_GCM_KEYTABLE_DATA(i));
}
if ((kt_key[MACSEC_KT_DATA_REG_CNT - 1] & MACSEC_KT_ENTRY_VALID) ==
MACSEC_KT_ENTRY_VALID) {
kt_config->flags |= OSI_LUT_FLAGS_ENTRY_VALID;
}
for (i = 0; i < MACSEC_KT_DATA_REG_SAK_CNT; i++) {
for (j = 0; j < INTEGER_LEN; j++) {
kt_config->entry.sak[i * 4 + j] =
(kt_key[i] >> (j * 8) & 0xFF);
}
}
for (i = 0; i < MACSEC_KT_DATA_REG_H_CNT; i++) {
for (j = 0; j < INTEGER_LEN; j++) {
kt_config->entry.h[i * 4 + j] =
(kt_key[i + MACSEC_KT_DATA_REG_SAK_CNT] >> (j * 8)
& 0xFF);
}
}
return 0;
}
static nve32_t kt_key_write(struct osi_core_priv_data *const osi_core,
struct osi_macsec_kt_config *const kt_config)
{
nveu32_t kt_key[MACSEC_KT_DATA_REG_CNT] = {0};
struct osi_kt_entry entry = kt_config->entry;
nve32_t i, j;
/* write SAK */
for (i = 0; i < MACSEC_KT_DATA_REG_SAK_CNT; i++) {
/* 4-bytes in each register */
for (j = 0; j < INTEGER_LEN; j++) {
kt_key[i] |= (entry.sak[i * 4 + j] << (j * 8));
}
}
/* write H-key */
for (i = 0; i < MACSEC_KT_DATA_REG_H_CNT; i++) {
/* 4-bytes in each register */
for (j = 0; j < INTEGER_LEN; j++) {
kt_key[i + MACSEC_KT_DATA_REG_SAK_CNT] |=
(entry.h[i * 4 + j] << (j * 8));
}
}
if ((kt_config->flags & OSI_LUT_FLAGS_ENTRY_VALID) ==
OSI_LUT_FLAGS_ENTRY_VALID) {
kt_key[MACSEC_KT_DATA_REG_CNT - 1] |= MACSEC_KT_ENTRY_VALID;
}
for (i = 0; i < MACSEC_KT_DATA_REG_CNT; i++) {
/* pr_err("%s: kt_key[%d]: 0x%x\n", __func__, i, kt_key[i]); */
osi_writela(osi_core, kt_key[i],
(nveu8_t *)osi_core->tz_base +
MACSEC_GCM_KEYTABLE_DATA(i));
}
return 0;
}
static nve32_t macsec_kt_config(struct osi_core_priv_data *const osi_core,
struct osi_macsec_kt_config *const kt_config)
{
nve32_t ret = 0;
nveu32_t kt_config_reg = 0;
nveu8_t *base = (nveu8_t *)osi_core->tz_base;
/* Validate KT config */
if ((kt_config->table_config.ctlr_sel > OSI_CTLR_SEL_MAX) ||
(kt_config->table_config.rw > OSI_RW_MAX) ||
(kt_config->table_config.index > OSI_TABLE_INDEX_MAX)) {
return -1;
}
/* Wait for previous KT update to finish */
ret = poll_for_kt_update(osi_core);
if (ret < 0) {
return ret;
}
/* pr_err("%s: ctrl: %hu rw: %hu idx: %hu flags: %#x\n", __func__,
kt_config->table_config.ctlr_sel,
kt_config->table_config.rw, kt_config->table_config.index,
kt_config->flags); */
kt_config_reg = osi_readla(osi_core, base + MACSEC_GCM_KEYTABLE_CONFIG);
if (kt_config->table_config.ctlr_sel) {
kt_config_reg |= MACSEC_KT_CONFIG_CTLR_SEL;
} else {
kt_config_reg &= ~MACSEC_KT_CONFIG_CTLR_SEL;
}
if (kt_config->table_config.rw) {
kt_config_reg |= MACSEC_KT_CONFIG_RW;
/* For write operation, load the lut_data registers */
ret = kt_key_write(osi_core, kt_config);
if (ret < 0) {
return ret;
}
} else {
kt_config_reg &= ~MACSEC_KT_CONFIG_RW;
}
kt_config_reg &= ~MACSEC_KT_CONFIG_INDEX_MASK;
kt_config_reg |= (kt_config->table_config.index);
kt_config_reg |= MACSEC_KT_CONFIG_UPDATE;
osi_writela(osi_core, kt_config_reg, base + MACSEC_GCM_KEYTABLE_CONFIG);
/* Wait for this KT update to finish */
ret = poll_for_kt_update(osi_core);
if (ret < 0) {
return ret;
}
if (!kt_config->table_config.rw) {
ret = kt_key_read(osi_core, kt_config);
if (ret < 0) {
return ret;
}
}
return ret;
}
#endif /* MACSEC_KEY_PROGRAM */
/**
* @brief poll_for_lut_update - Query the status of a LUT update.
*
* @param[in] osi_core: OSI Core private data structure.
*
* @retval 0 on Success
* @retval -1 on Failure
*/
static inline nve32_t poll_for_lut_update(struct osi_core_priv_data *osi_core)
{
/* half sec timeout */
nveu32_t retry = 50000;
nveu32_t lut_config;
nveu32_t count;
nve32_t cond = 1;
count = 0;
while (cond == 1) {
if (count > retry) {
OSI_CORE_ERR(osi_core->osd,
OSI_LOG_ARG_HW_FAIL,
"LUT update timed out\n",
0ULL);
return -1;
}
count++;
lut_config = osi_readla(osi_core,
(nveu8_t *)osi_core->macsec_base +
MACSEC_LUT_CONFIG);
if ((lut_config & MACSEC_LUT_CONFIG_UPDATE) == 0U) {
/* exit loop */
cond = 0;
} else {
/* wait on UPDATE bit to reset */
osi_core->osd_ops.udelay(10U);
}
}
return 0;
}
static inline void read_lut_data(struct osi_core_priv_data *const osi_core,
nveu32_t *const lut_data)
{
nveu8_t *base = (nveu8_t *)osi_core->macsec_base;
nve32_t i;
/* Commit the LUT entry to HW */
for (i = 0; i < MACSEC_LUT_DATA_REG_CNT; i++) {
lut_data[i] = osi_readla(osi_core, base + MACSEC_LUT_DATA(i));
//pr_err("%s: lut_data[%d]: 0x%x\n", __func__, i, lut_data[i]);
}
}
static nve32_t lut_read_inputs(struct osi_macsec_lut_config *const lut_config,
nveu32_t *const lut_data)
{
struct osi_lut_inputs entry = {0};
nveu32_t flags = 0;
/* MAC DA */
if ((lut_data[1] & MACSEC_LUT_DA_BYTE0_INACTIVE) !=
MACSEC_LUT_DA_BYTE0_INACTIVE) {
entry.da[0] = lut_data[0] & 0xFF;
flags |= OSI_LUT_FLAGS_DA_BYTE0_VALID;
}
if ((lut_data[1] & MACSEC_LUT_DA_BYTE1_INACTIVE) !=
MACSEC_LUT_DA_BYTE1_INACTIVE) {
entry.da[1] = lut_data[0] >> 8 & 0xFF;
flags |= OSI_LUT_FLAGS_DA_BYTE1_VALID;
}
if ((lut_data[1] & MACSEC_LUT_DA_BYTE2_INACTIVE) !=
MACSEC_LUT_DA_BYTE2_INACTIVE) {
entry.da[2] = lut_data[0] >> 16 & 0xFF;
flags |= OSI_LUT_FLAGS_DA_BYTE2_VALID;
}
if ((lut_data[1] & MACSEC_LUT_DA_BYTE3_INACTIVE) !=
MACSEC_LUT_DA_BYTE3_INACTIVE) {
entry.da[3] = lut_data[0] >> 24 & 0xFF;
flags |= OSI_LUT_FLAGS_DA_BYTE3_VALID;
}
if ((lut_data[1] & MACSEC_LUT_DA_BYTE4_INACTIVE) !=
MACSEC_LUT_DA_BYTE4_INACTIVE) {
entry.da[4] = lut_data[1] & 0xFF;
flags |= OSI_LUT_FLAGS_DA_BYTE4_VALID;
}
if ((lut_data[1] & MACSEC_LUT_DA_BYTE5_INACTIVE) !=
MACSEC_LUT_DA_BYTE5_INACTIVE) {
entry.da[5] = lut_data[1] >> 8 & 0xFF;
flags |= OSI_LUT_FLAGS_DA_BYTE5_VALID;
}
/* MAC SA */
if ((lut_data[3] & MACSEC_LUT_SA_BYTE0_INACTIVE) !=
MACSEC_LUT_SA_BYTE0_INACTIVE) {
entry.sa[0] = lut_data[1] >> 22 & 0xFF;
flags |= OSI_LUT_FLAGS_SA_BYTE0_VALID;
}
if ((lut_data[3] & MACSEC_LUT_SA_BYTE1_INACTIVE) !=
MACSEC_LUT_SA_BYTE1_INACTIVE) {
entry.sa[1] = (lut_data[1] >> 30) |
((lut_data[2] & 0x3F) << 2);
flags |= OSI_LUT_FLAGS_SA_BYTE1_VALID;
}
if ((lut_data[3] & MACSEC_LUT_SA_BYTE2_INACTIVE) !=
MACSEC_LUT_SA_BYTE2_INACTIVE) {
entry.sa[2] = lut_data[2] >> 6 & 0xFF;
flags |= OSI_LUT_FLAGS_SA_BYTE2_VALID;
}
if ((lut_data[3] & MACSEC_LUT_SA_BYTE3_INACTIVE) !=
MACSEC_LUT_SA_BYTE3_INACTIVE) {
entry.sa[3] = lut_data[2] >> 14 & 0xFF;
flags |= OSI_LUT_FLAGS_SA_BYTE3_VALID;
}
if ((lut_data[3] & MACSEC_LUT_SA_BYTE4_INACTIVE) !=
MACSEC_LUT_SA_BYTE4_INACTIVE) {
entry.sa[4] = lut_data[2] >> 22 & 0xFF;
flags |= OSI_LUT_FLAGS_SA_BYTE4_VALID;
}
if ((lut_data[3] & MACSEC_LUT_SA_BYTE5_INACTIVE) !=
MACSEC_LUT_SA_BYTE5_INACTIVE) {
entry.sa[5] = (lut_data[2] >> 30) |
((lut_data[3] & 0x3F) << 2);
flags |= OSI_LUT_FLAGS_SA_BYTE5_VALID;
}
/* Ether type */
if ((lut_data[3] & MACSEC_LUT_ETHTYPE_INACTIVE) !=
MACSEC_LUT_ETHTYPE_INACTIVE) {
entry.ethtype[0] = lut_data[3] >> 12 & 0xFF;
entry.ethtype[1] = lut_data[3] >> 20 & 0xFF;
flags |= OSI_LUT_FLAGS_ETHTYPE_VALID;
}
/* VLAN */
if ((lut_data[4] & MACSEC_LUT_VLAN_ACTIVE) == MACSEC_LUT_VLAN_ACTIVE) {
flags |= OSI_LUT_FLAGS_VLAN_VALID;
/* VLAN PCP */
if ((lut_data[4] & MACSEC_LUT_VLAN_PCP_INACTIVE) !=
MACSEC_LUT_VLAN_PCP_INACTIVE) {
flags |= OSI_LUT_FLAGS_VLAN_PCP_VALID;
entry.vlan_pcp = lut_data[3] >> 29;
}
/* VLAN ID */
if ((lut_data[4] & MACSEC_LUT_VLAN_ID_INACTIVE) !=
MACSEC_LUT_VLAN_ID_INACTIVE) {
flags |= OSI_LUT_FLAGS_VLAN_ID_VALID;
entry.vlan_id = lut_data[4] >> 1 & 0xFFF;
}
}
/* Byte patterns */
if ((lut_data[4] & MACSEC_LUT_BYTE0_PATTERN_INACTIVE) !=
MACSEC_LUT_BYTE0_PATTERN_INACTIVE) {
flags |= OSI_LUT_FLAGS_BYTE0_PATTERN_VALID;
entry.byte_pattern[0] = lut_data[4] >> 15 & 0xFF;
entry.byte_pattern_offset[0] = lut_data[4] >> 23 & 0x3F;
}
if ((lut_data[5] & MACSEC_LUT_BYTE1_PATTERN_INACTIVE) !=
MACSEC_LUT_BYTE1_PATTERN_INACTIVE) {
flags |= OSI_LUT_FLAGS_BYTE1_PATTERN_VALID;
entry.byte_pattern[1] = (lut_data[4] >> 30) |
((lut_data[5] & 0x3F) << 2);
entry.byte_pattern_offset[1] = lut_data[5] >> 6 & 0x3F;
}
if ((lut_data[5] & MACSEC_LUT_BYTE2_PATTERN_INACTIVE) !=
MACSEC_LUT_BYTE2_PATTERN_INACTIVE) {
flags |= OSI_LUT_FLAGS_BYTE2_PATTERN_VALID;
entry.byte_pattern[2] = lut_data[5] >> 13 & 0xFF;
entry.byte_pattern_offset[2] = lut_data[5] >> 21 & 0x3F;
}
if ((lut_data[6] & MACSEC_LUT_BYTE3_PATTERN_INACTIVE) !=
MACSEC_LUT_BYTE3_PATTERN_INACTIVE) {
flags |= OSI_LUT_FLAGS_BYTE3_PATTERN_VALID;
entry.byte_pattern[3] = (lut_data[5] >> 28) |
((lut_data[6] & 0xF) << 4);
entry.byte_pattern_offset[3] = lut_data[6] >> 4 & 0x3F;
}
/* Preempt mask */
if ((lut_data[6] & MACSEC_LUT_PREEMPT_INACTIVE) !=
MACSEC_LUT_PREEMPT_INACTIVE) {
flags |= OSI_LUT_FLAGS_PREEMPT_VALID;
if ((lut_data[6] & MACSEC_LUT_PREEMPT) == MACSEC_LUT_PREEMPT) {
flags |= OSI_LUT_FLAGS_PREEMPT;
}
}
lut_config->lut_in = entry;
lut_config->flags = flags;
return 0;
}
static nve32_t byp_lut_read(struct osi_core_priv_data *const osi_core,
struct osi_macsec_lut_config *const lut_config)
{
nveu32_t lut_data[MACSEC_LUT_DATA_REG_CNT] = {0};
nveu32_t flags = 0, val = 0;
nveu32_t index = lut_config->table_config.index;
nveu8_t *addr = (nveu8_t *)osi_core->macsec_base;
nveu8_t *paddr = OSI_NULL;
read_lut_data(osi_core, lut_data);
if (lut_read_inputs(lut_config, lut_data) != 0) {
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"LUT inputs error\n", 0ULL);
return -1;
}
/* Lookup output */
if ((lut_data[6] & MACSEC_LUT_CONTROLLED_PORT) ==
MACSEC_LUT_CONTROLLED_PORT) {
flags |= OSI_LUT_FLAGS_CONTROLLED_PORT;
}
if ((lut_data[6] & MACSEC_BYP_LUT_DVLAN_PKT) ==
MACSEC_BYP_LUT_DVLAN_PKT) {
flags |= OSI_LUT_FLAGS_DVLAN_PKT;
}
if ((lut_data[6] & BYP_LUT_DVLAN_OUTER_INNER_TAG_SEL) ==
BYP_LUT_DVLAN_OUTER_INNER_TAG_SEL) {
flags |= OSI_LUT_FLAGS_DVLAN_OUTER_INNER_TAG_SEL;
}
switch (lut_config->table_config.ctlr_sel) {
case OSI_CTLR_SEL_TX:
paddr = addr + MACSEC_TX_BYP_LUT_VALID;
break;
case OSI_CTLR_SEL_RX:
paddr = addr + MACSEC_RX_BYP_LUT_VALID;
break;
default:
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"Unknown controller select\n", 0ULL);
return -1;
}
val = osi_readla(osi_core, paddr);
if (val & (1U << index)) {
flags |= OSI_LUT_FLAGS_ENTRY_VALID;
}
lut_config->flags |= flags;
return 0;
}
static nve32_t sci_lut_read(struct osi_core_priv_data *const osi_core,
struct osi_macsec_lut_config *const lut_config)
{
nveu32_t lut_data[MACSEC_LUT_DATA_REG_CNT] = {0};
nveu32_t flags = 0;
nveu8_t *addr = (nveu8_t *)osi_core->macsec_base;
nveu32_t val = 0;
nveu32_t index = lut_config->table_config.index;
if (index > OSI_SC_LUT_MAX_INDEX) {
return -1;
}
read_lut_data(osi_core, lut_data);
switch (lut_config->table_config.ctlr_sel) {
case OSI_CTLR_SEL_TX:
if (lut_read_inputs(lut_config, lut_data) != 0) {
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"LUT inputs error\n", 0ULL);
return -1;
}
if ((lut_data[6] & MACSEC_LUT_AN0_VALID) ==
MACSEC_LUT_AN0_VALID) {
lut_config->sci_lut_out.an_valid |= OSI_AN0_VALID;
}
if ((lut_data[6] & MACSEC_LUT_AN1_VALID) ==
MACSEC_LUT_AN1_VALID) {
lut_config->sci_lut_out.an_valid |= OSI_AN1_VALID;
}
if ((lut_data[6] & MACSEC_LUT_AN2_VALID) ==
MACSEC_LUT_AN2_VALID) {
lut_config->sci_lut_out.an_valid |= OSI_AN2_VALID;
}
if ((lut_data[6] & MACSEC_LUT_AN3_VALID) ==
MACSEC_LUT_AN3_VALID) {
lut_config->sci_lut_out.an_valid |= OSI_AN3_VALID;
}
lut_config->sci_lut_out.sc_index = lut_data[6] >> 17 & 0xF;
if ((lut_data[6] & MACSEC_TX_SCI_LUT_DVLAN_PKT) ==
MACSEC_TX_SCI_LUT_DVLAN_PKT) {
lut_config->flags |= OSI_LUT_FLAGS_DVLAN_PKT;
}
if ((lut_data[6] & MACSEC_TX_SCI_LUT_DVLAN_OUTER_INNER_TAG_SEL) ==
MACSEC_TX_SCI_LUT_DVLAN_OUTER_INNER_TAG_SEL) {
lut_config->flags |=
OSI_LUT_FLAGS_DVLAN_OUTER_INNER_TAG_SEL;
}
val = osi_readla(osi_core, addr+MACSEC_TX_SCI_LUT_VALID);
if (val & (1U << index)) {
lut_config->flags |= OSI_LUT_FLAGS_ENTRY_VALID;
}
break;
case OSI_CTLR_SEL_RX:
lut_config->sci_lut_out.sci[0] = lut_data[0] & 0xFF;
lut_config->sci_lut_out.sci[1] = lut_data[0] >> 8 & 0xFF;
lut_config->sci_lut_out.sci[2] = lut_data[0] >> 16 & 0xFF;
lut_config->sci_lut_out.sci[3] = lut_data[0] >> 24 & 0xFF;
lut_config->sci_lut_out.sci[4] = lut_data[1] & 0xFF;
lut_config->sci_lut_out.sci[5] = lut_data[1] >> 8 & 0xFF;
lut_config->sci_lut_out.sci[6] = lut_data[1] >> 16 & 0xFF;
lut_config->sci_lut_out.sci[7] = lut_data[1] >> 24 & 0xFF;
lut_config->sci_lut_out.sc_index = lut_data[2] >> 10 & 0xF;
if ((lut_data[2] & MACSEC_RX_SCI_LUT_PREEMPT_INACTIVE) !=
MACSEC_RX_SCI_LUT_PREEMPT_INACTIVE) {
flags |= OSI_LUT_FLAGS_PREEMPT_VALID;
if ((lut_data[2] & MACSEC_RX_SCI_LUT_PREEMPT) ==
MACSEC_RX_SCI_LUT_PREEMPT) {
flags |= OSI_LUT_FLAGS_PREEMPT;
}
}
val = osi_readla(osi_core, addr+MACSEC_RX_SCI_LUT_VALID);
if (val & (1U << index)) {
lut_config->flags |= OSI_LUT_FLAGS_ENTRY_VALID;
}
break;
default:
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"Unknown controller selected\n", 0ULL);
return -1;
}
/* Lookup output */
return 0;
}
static nve32_t sc_param_lut_read(struct osi_core_priv_data *const osi_core,
struct osi_macsec_lut_config *const lut_config)
{
nveu32_t lut_data[MACSEC_LUT_DATA_REG_CNT] = {0};
read_lut_data(osi_core, lut_data);
switch (lut_config->table_config.ctlr_sel) {
case OSI_CTLR_SEL_TX:
lut_config->sc_param_out.key_index_start = lut_data[0] & 0x1F;
lut_config->sc_param_out.pn_max = (lut_data[0] >> 5) |
(lut_data[1] << 27);
lut_config->sc_param_out.pn_threshold = (lut_data[1] >> 5) |
(lut_data[2] << 27);
lut_config->sc_param_out.tci = (lut_data[2] >> 5) & 0x3;
lut_config->sc_param_out.sci[0] = lut_data[2] >> 8 & 0xFF;
lut_config->sc_param_out.sci[1] = lut_data[2] >> 16 & 0xFF;
lut_config->sc_param_out.sci[2] = lut_data[2] >> 24 & 0xFF;
lut_config->sc_param_out.sci[3] = lut_data[3] & 0xFF;
lut_config->sc_param_out.sci[4] = lut_data[3] >> 8 & 0xFF;
lut_config->sc_param_out.sci[5] = lut_data[3] >> 16 & 0xFF;
lut_config->sc_param_out.sci[6] = lut_data[3] >> 24 & 0xFF;
lut_config->sc_param_out.sci[7] = lut_data[4] & 0xFF;
lut_config->sc_param_out.vlan_in_clear =
(lut_data[4] >> 8) & 0x1;
break;
case OSI_CTLR_SEL_RX:
lut_config->sc_param_out.key_index_start = lut_data[0] & 0x1F;
lut_config->sc_param_out.pn_window = (lut_data[0] >> 5) |
(lut_data[1] << 27);
lut_config->sc_param_out.pn_max = (lut_data[1] >> 5) |
(lut_data[2] << 27);
break;
default:
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"Unknown controller selected\n", 0ULL);
return -1;
}
/* Lookup output */
return 0;
}
static nve32_t sc_state_lut_read(struct osi_core_priv_data *const osi_core,
struct osi_macsec_lut_config *const lut_config)
{
nveu32_t lut_data[MACSEC_LUT_DATA_REG_CNT] = {0};
read_lut_data(osi_core, lut_data);
lut_config->sc_state_out.curr_an = lut_data[0];
return 0;
}
static nve32_t sa_state_lut_read(struct osi_core_priv_data *const osi_core,
struct osi_macsec_lut_config *const lut_config)
{
nveu32_t lut_data[MACSEC_LUT_DATA_REG_CNT] = {0};
read_lut_data(osi_core, lut_data);
switch (lut_config->table_config.ctlr_sel) {
case OSI_CTLR_SEL_TX:
lut_config->sa_state_out.next_pn = lut_data[0];
if ((lut_data[1] & MACSEC_SA_STATE_LUT_ENTRY_VALID) ==
MACSEC_SA_STATE_LUT_ENTRY_VALID) {
lut_config->flags |= OSI_LUT_FLAGS_ENTRY_VALID;
}
break;
case OSI_CTLR_SEL_RX:
lut_config->sa_state_out.next_pn = lut_data[0];
lut_config->sa_state_out.lowest_pn = lut_data[1];
break;
default:
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"Unknown controller selected\n", 0ULL);
return -1;
}
/* Lookup output */
return 0;
}
static nve32_t lut_data_read(struct osi_core_priv_data *const osi_core,
struct osi_macsec_lut_config *const lut_config)
{
switch (lut_config->lut_sel) {
case OSI_LUT_SEL_BYPASS:
if (byp_lut_read(osi_core, lut_config) != 0) {
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"BYP LUT read err\n", 0ULL);
return -1;
}
break;
case OSI_LUT_SEL_SCI:
if (sci_lut_read(osi_core, lut_config) != 0) {
pr_err("\n");
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"SCI LUT read err\n", 0ULL);
return -1;
}
break;
case OSI_LUT_SEL_SC_PARAM:
if (sc_param_lut_read(osi_core, lut_config) != 0) {
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"SC param LUT read err\n", 0ULL);
return -1;
}
break;
case OSI_LUT_SEL_SC_STATE:
if (sc_state_lut_read(osi_core, lut_config) != 0) {
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"SC state LUT read err\n", 0ULL);
return -1;
}
break;
case OSI_LUT_SEL_SA_STATE:
if (sa_state_lut_read(osi_core, lut_config) != 0) {
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"SA state LUT read err\n", 0ULL);
return -1;
}
break;
default:
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"Unsupported LUT\n", 0ULL);
return -1;
}
return 0;
}
static inline void commit_lut_data(struct osi_core_priv_data *const osi_core,
nveu32_t const *const lut_data)
{
nveu8_t *base = (nveu8_t *)osi_core->macsec_base;
nve32_t i;
/* Commit the LUT entry to HW */
for (i = 0; i < MACSEC_LUT_DATA_REG_CNT; i++) {
//pr_err("%s: lut_data[%d]: 0x%x\n", __func__, i, lut_data[i]);
osi_writela(osi_core, lut_data[i], base + MACSEC_LUT_DATA(i));
}
}
static void rx_sa_state_lut_config(
struct osi_macsec_lut_config *const lut_config,
nveu32_t *const lut_data)
{
struct osi_sa_state_outputs entry = lut_config->sa_state_out;
lut_data[0] |= entry.next_pn;
lut_data[1] |= entry.lowest_pn;
}
static void tx_sa_state_lut_config(
struct osi_macsec_lut_config *const lut_config,
nveu32_t *const lut_data)
{
nveu32_t flags = lut_config->flags;
struct osi_sa_state_outputs entry = lut_config->sa_state_out;
lut_data[0] |= entry.next_pn;
if ((flags & OSI_LUT_FLAGS_ENTRY_VALID) == OSI_LUT_FLAGS_ENTRY_VALID) {
lut_data[1] |= MACSEC_SA_STATE_LUT_ENTRY_VALID;
}
}
static nve32_t sa_state_lut_config(struct osi_core_priv_data *const osi_core,
struct osi_macsec_lut_config *const lut_config)
{
nveu32_t lut_data[MACSEC_LUT_DATA_REG_CNT] = {0};
struct osi_macsec_table_config table_config = lut_config->table_config;
switch (table_config.ctlr_sel) {
case OSI_CTLR_SEL_TX:
tx_sa_state_lut_config(lut_config, lut_data);
break;
case OSI_CTLR_SEL_RX:
rx_sa_state_lut_config(lut_config, lut_data);
break;
default:
return -1;
}
commit_lut_data(osi_core, lut_data);
return 0;
}
static nve32_t sc_state_lut_config(struct osi_core_priv_data *const osi_core,
struct osi_macsec_lut_config *const lut_config)
{
nveu32_t lut_data[MACSEC_LUT_DATA_REG_CNT] = {0};
struct osi_sc_state_outputs entry = lut_config->sc_state_out;
lut_data[0] |= entry.curr_an;
commit_lut_data(osi_core, lut_data);
return 0;
}
static void rx_sc_param_lut_config(
struct osi_macsec_lut_config *const lut_config,
nveu32_t *const lut_data)
{
struct osi_sc_param_outputs entry = lut_config->sc_param_out;
lut_data[0] |= entry.key_index_start;
lut_data[0] |= entry.pn_window << 5;
lut_data[1] |= entry.pn_window >> 27;
lut_data[1] |= entry.pn_max << 5;
lut_data[2] |= entry.pn_max >> 27;
}
static void tx_sc_param_lut_config(
struct osi_macsec_lut_config *const lut_config,
nveu32_t *const lut_data)
{
struct osi_sc_param_outputs entry = lut_config->sc_param_out;
lut_data[0] |= entry.key_index_start;
lut_data[0] |= entry.pn_max << 5;
lut_data[1] |= entry.pn_max >> 27;
lut_data[1] |= entry.pn_threshold << 5;
lut_data[2] |= entry.pn_threshold >> 27;
lut_data[2] |= entry.tci << 5;
lut_data[2] |= entry.sci[0] << 8;
lut_data[2] |= entry.sci[1] << 16;
lut_data[2] |= entry.sci[2] << 24;
lut_data[3] |= entry.sci[3];
lut_data[3] |= entry.sci[4] << 8;
lut_data[3] |= entry.sci[5] << 16;
lut_data[3] |= entry.sci[6] << 24;
lut_data[4] |= entry.sci[7];
lut_data[4] |= entry.vlan_in_clear << 8;
}
static nve32_t sc_param_lut_config(struct osi_core_priv_data *const osi_core,
struct osi_macsec_lut_config *const lut_config)
{
nveu32_t lut_data[MACSEC_LUT_DATA_REG_CNT] = {0};
struct osi_macsec_table_config table_config = lut_config->table_config;
struct osi_sc_param_outputs entry = lut_config->sc_param_out;
if (entry.key_index_start > OSI_KEY_INDEX_MAX) {
return -1;
}
switch (table_config.ctlr_sel) {
case OSI_CTLR_SEL_TX:
tx_sc_param_lut_config(lut_config, lut_data);
break;
case OSI_CTLR_SEL_RX:
rx_sc_param_lut_config(lut_config, lut_data);
break;
}
commit_lut_data(osi_core, lut_data);
return 0;
}
static nve32_t lut_config_inputs(struct osi_macsec_lut_config *const lut_config,
nveu32_t *const lut_data)
{
struct osi_lut_inputs entry = lut_config->lut_in;
nveu32_t flags = lut_config->flags;
nve32_t i, j;
for (i = 0, j = OSI_LUT_FLAGS_BYTE0_PATTERN_VALID;
i < OSI_LUT_BYTE_PATTERN_MAX; i++, j <<= 1) {
if ((flags & j) == j) {
if (entry.byte_pattern_offset[i] >
OSI_LUT_BYTE_PATTERN_MAX_OFFSET) {
return -1;
}
}
}
if ((flags & OSI_LUT_FLAGS_BYTE0_PATTERN_VALID) ==
OSI_LUT_FLAGS_BYTE0_PATTERN_VALID) {
if (entry.byte_pattern_offset[0] >
OSI_LUT_BYTE_PATTERN_MAX_OFFSET) {
return -1;
}
}
if ((flags & OSI_LUT_FLAGS_VLAN_VALID) == OSI_LUT_FLAGS_VLAN_VALID) {
if ((entry.vlan_pcp > OSI_VLAN_PCP_MAX) ||
(entry.vlan_id > OSI_VLAN_ID_MAX)) {
return -1;
}
}
/* MAC DA */
if ((flags & OSI_LUT_FLAGS_DA_BYTE0_VALID) ==
OSI_LUT_FLAGS_DA_BYTE0_VALID) {
lut_data[0] |= entry.da[0];
lut_data[1] &= ~MACSEC_LUT_DA_BYTE0_INACTIVE;
} else {
lut_data[1] |= MACSEC_LUT_DA_BYTE0_INACTIVE;
}
if ((flags & OSI_LUT_FLAGS_DA_BYTE1_VALID) ==
OSI_LUT_FLAGS_DA_BYTE1_VALID) {
lut_data[0] |= entry.da[1] << 8;
lut_data[1] &= ~MACSEC_LUT_DA_BYTE1_INACTIVE;
} else {
lut_data[1] |= MACSEC_LUT_DA_BYTE1_INACTIVE;
}
if ((flags & OSI_LUT_FLAGS_DA_BYTE2_VALID) ==
OSI_LUT_FLAGS_DA_BYTE2_VALID) {
lut_data[0] |= entry.da[2] << 16;
lut_data[1] &= ~MACSEC_LUT_DA_BYTE2_INACTIVE;
} else {
lut_data[1] |= MACSEC_LUT_DA_BYTE2_INACTIVE;
}
if ((flags & OSI_LUT_FLAGS_DA_BYTE3_VALID) ==
OSI_LUT_FLAGS_DA_BYTE3_VALID) {
lut_data[0] |= entry.da[3] << 24;
lut_data[1] &= ~MACSEC_LUT_DA_BYTE3_INACTIVE;
} else {
lut_data[1] |= MACSEC_LUT_DA_BYTE3_INACTIVE;
}
if ((flags & OSI_LUT_FLAGS_DA_BYTE4_VALID) ==
OSI_LUT_FLAGS_DA_BYTE4_VALID) {
lut_data[1] |= entry.da[4];
lut_data[1] &= ~MACSEC_LUT_DA_BYTE4_INACTIVE;
} else {
lut_data[1] |= MACSEC_LUT_DA_BYTE4_INACTIVE;
}
if ((flags & OSI_LUT_FLAGS_DA_BYTE5_VALID) ==
OSI_LUT_FLAGS_DA_BYTE5_VALID) {
lut_data[1] |= entry.da[5] << 8;
lut_data[1] &= ~MACSEC_LUT_DA_BYTE5_INACTIVE;
} else {
lut_data[1] |= MACSEC_LUT_DA_BYTE5_INACTIVE;
}
/* MAC SA */
if ((flags & OSI_LUT_FLAGS_SA_BYTE0_VALID) ==
OSI_LUT_FLAGS_SA_BYTE0_VALID) {
lut_data[1] |= entry.sa[0] << 22;
lut_data[3] &= ~MACSEC_LUT_SA_BYTE0_INACTIVE;
} else {
lut_data[3] |= MACSEC_LUT_SA_BYTE0_INACTIVE;
}
if ((flags & OSI_LUT_FLAGS_SA_BYTE1_VALID) ==
OSI_LUT_FLAGS_SA_BYTE1_VALID) {
lut_data[1] |= entry.sa[1] << 30;
lut_data[2] |= (entry.sa[1] >> 2);
lut_data[3] &= ~MACSEC_LUT_SA_BYTE1_INACTIVE;
} else {
lut_data[3] |= MACSEC_LUT_SA_BYTE1_INACTIVE;
}
if ((flags & OSI_LUT_FLAGS_SA_BYTE2_VALID) ==
OSI_LUT_FLAGS_SA_BYTE2_VALID) {
lut_data[2] |= entry.sa[2] << 6;
lut_data[3] &= ~MACSEC_LUT_SA_BYTE2_INACTIVE;
} else {
lut_data[3] |= MACSEC_LUT_SA_BYTE2_INACTIVE;
}
if ((flags & OSI_LUT_FLAGS_SA_BYTE3_VALID) ==
OSI_LUT_FLAGS_SA_BYTE3_VALID) {
lut_data[2] |= entry.sa[3] << 14;
lut_data[3] &= ~MACSEC_LUT_SA_BYTE3_INACTIVE;
} else {
lut_data[3] |= MACSEC_LUT_SA_BYTE3_INACTIVE;
}
if ((flags & OSI_LUT_FLAGS_SA_BYTE4_VALID) ==
OSI_LUT_FLAGS_SA_BYTE4_VALID) {
lut_data[2] |= entry.sa[4] << 22;
lut_data[3] &= ~MACSEC_LUT_SA_BYTE4_INACTIVE;
} else {
lut_data[3] |= MACSEC_LUT_SA_BYTE4_INACTIVE;
}
if ((flags & OSI_LUT_FLAGS_SA_BYTE5_VALID) ==
OSI_LUT_FLAGS_SA_BYTE5_VALID) {
lut_data[2] |= entry.sa[5] << 30;
lut_data[3] |= (entry.sa[5] >> 2);
lut_data[3] &= ~MACSEC_LUT_SA_BYTE5_INACTIVE;
} else {
lut_data[3] |= MACSEC_LUT_SA_BYTE5_INACTIVE;
}
/* Ether type */
if ((flags & OSI_LUT_FLAGS_ETHTYPE_VALID) ==
OSI_LUT_FLAGS_ETHTYPE_VALID) {
lut_data[3] |= entry.ethtype[0] << 12;
lut_data[3] |= entry.ethtype[1] << 20;
lut_data[3] &= ~MACSEC_LUT_ETHTYPE_INACTIVE;
} else {
lut_data[3] |= MACSEC_LUT_ETHTYPE_INACTIVE;
}
/* VLAN */
if ((flags & OSI_LUT_FLAGS_VLAN_VALID) == OSI_LUT_FLAGS_VLAN_VALID) {
/* VLAN PCP */
if ((flags & OSI_LUT_FLAGS_VLAN_PCP_VALID) ==
OSI_LUT_FLAGS_VLAN_PCP_VALID) {
lut_data[3] |= entry.vlan_pcp << 29;
lut_data[4] &= ~MACSEC_LUT_VLAN_PCP_INACTIVE;
} else {
lut_data[4] |= MACSEC_LUT_VLAN_PCP_INACTIVE;
}
/* VLAN ID */
if ((flags & OSI_LUT_FLAGS_VLAN_ID_VALID) ==
OSI_LUT_FLAGS_VLAN_ID_VALID) {
lut_data[4] |= entry.vlan_id << 1;
lut_data[4] &= ~MACSEC_LUT_VLAN_ID_INACTIVE;
} else {
lut_data[4] |= MACSEC_LUT_VLAN_ID_INACTIVE;
}
lut_data[4] |= MACSEC_LUT_VLAN_ACTIVE;
} else {
lut_data[4] |= MACSEC_LUT_VLAN_PCP_INACTIVE;
lut_data[4] |= MACSEC_LUT_VLAN_ID_INACTIVE;
lut_data[4] &= ~MACSEC_LUT_VLAN_ACTIVE;
}
/* Byte patterns */
if ((flags & OSI_LUT_FLAGS_BYTE0_PATTERN_VALID) ==
OSI_LUT_FLAGS_BYTE0_PATTERN_VALID) {
lut_data[4] |= entry.byte_pattern[0] << 15;
lut_data[4] |= entry.byte_pattern_offset[0] << 23;
lut_data[4] &= ~MACSEC_LUT_BYTE0_PATTERN_INACTIVE;
} else {
lut_data[4] |= MACSEC_LUT_BYTE0_PATTERN_INACTIVE;
}
if ((flags & OSI_LUT_FLAGS_BYTE1_PATTERN_VALID) ==
OSI_LUT_FLAGS_BYTE1_PATTERN_VALID) {
lut_data[4] |= entry.byte_pattern[1] << 30;
lut_data[5] |= entry.byte_pattern[1] >> 2;
lut_data[5] |= entry.byte_pattern_offset[1] << 6;
lut_data[5] &= ~MACSEC_LUT_BYTE1_PATTERN_INACTIVE;
} else {
lut_data[5] |= MACSEC_LUT_BYTE1_PATTERN_INACTIVE;
}
if ((flags & OSI_LUT_FLAGS_BYTE2_PATTERN_VALID) ==
OSI_LUT_FLAGS_BYTE2_PATTERN_VALID) {
lut_data[5] |= entry.byte_pattern[2] << 13;
lut_data[5] |= entry.byte_pattern_offset[2] << 21;
lut_data[5] &= ~MACSEC_LUT_BYTE2_PATTERN_INACTIVE;
} else {
lut_data[5] |= MACSEC_LUT_BYTE2_PATTERN_INACTIVE;
}
if ((flags & OSI_LUT_FLAGS_BYTE3_PATTERN_VALID) ==
OSI_LUT_FLAGS_BYTE3_PATTERN_VALID) {
lut_data[5] |= entry.byte_pattern[3] << 28;
lut_data[6] |= entry.byte_pattern[3] >> 4;
lut_data[6] |= entry.byte_pattern_offset[3] << 4;
lut_data[6] &= ~MACSEC_LUT_BYTE3_PATTERN_INACTIVE;
} else {
lut_data[6] |= MACSEC_LUT_BYTE3_PATTERN_INACTIVE;
}
/* Preempt mask */
if ((flags & OSI_LUT_FLAGS_PREEMPT_VALID) ==
OSI_LUT_FLAGS_PREEMPT_VALID) {
if ((flags & OSI_LUT_FLAGS_PREEMPT) == OSI_LUT_FLAGS_PREEMPT) {
lut_data[6] |= MACSEC_LUT_PREEMPT;
} else {
lut_data[6] &= ~MACSEC_LUT_PREEMPT;
}
lut_data[6] &= ~MACSEC_LUT_PREEMPT_INACTIVE;
} else {
lut_data[6] |= MACSEC_LUT_PREEMPT_INACTIVE;
}
return 0;
}
static nve32_t rx_sci_lut_config(
struct osi_macsec_lut_config *const lut_config,
nveu32_t *const lut_data)
{
nveu32_t flags = lut_config->flags;
struct osi_sci_lut_outputs entry = lut_config->sci_lut_out;
if (entry.sc_index > OSI_SC_INDEX_MAX) {
return -1;
}
lut_data[0] |= (entry.sci[0] |
(entry.sci[1] << 8) |
(entry.sci[2] << 16) |
(entry.sci[3] << 24));
lut_data[1] |= (entry.sci[4] |
(entry.sci[5] << 8) |
(entry.sci[6] << 16) |
(entry.sci[7] << 24));
/* Preempt mask */
if ((flags & OSI_LUT_FLAGS_PREEMPT_VALID) ==
OSI_LUT_FLAGS_PREEMPT_VALID) {
if ((flags & OSI_LUT_FLAGS_PREEMPT) == OSI_LUT_FLAGS_PREEMPT) {
lut_data[2] |= MACSEC_RX_SCI_LUT_PREEMPT;
} else {
lut_data[2] &= ~MACSEC_RX_SCI_LUT_PREEMPT;
}
lut_data[2] &= ~MACSEC_RX_SCI_LUT_PREEMPT_INACTIVE;
} else {
lut_data[2] |= MACSEC_RX_SCI_LUT_PREEMPT_INACTIVE;
}
lut_data[2] |= entry.sc_index << 10;
return 0;
}
static nve32_t tx_sci_lut_config(
struct osi_macsec_lut_config *const lut_config,
nveu32_t *const lut_data)
{
nveu32_t flags = lut_config->flags;
struct osi_sci_lut_outputs entry = lut_config->sci_lut_out;
nveu32_t an_valid = entry.an_valid;
if (lut_config_inputs(lut_config, lut_data) != 0) {
return -1;
}
/* Lookup result fields */
if ((an_valid & OSI_AN0_VALID) == OSI_AN0_VALID) {
lut_data[6] |= MACSEC_LUT_AN0_VALID;
}
if ((an_valid & OSI_AN1_VALID) == OSI_AN1_VALID) {
lut_data[6] |= MACSEC_LUT_AN1_VALID;
}
if ((an_valid & OSI_AN2_VALID) == OSI_AN2_VALID) {
lut_data[6] |= MACSEC_LUT_AN2_VALID;
}
if ((an_valid & OSI_AN3_VALID) == OSI_AN3_VALID) {
lut_data[6] |= MACSEC_LUT_AN3_VALID;
}
lut_data[6] |= entry.sc_index << 17;
if ((flags & OSI_LUT_FLAGS_DVLAN_PKT) == OSI_LUT_FLAGS_DVLAN_PKT) {
lut_data[6] |= MACSEC_TX_SCI_LUT_DVLAN_PKT;
}
if ((flags & OSI_LUT_FLAGS_DVLAN_OUTER_INNER_TAG_SEL) ==
OSI_LUT_FLAGS_DVLAN_OUTER_INNER_TAG_SEL) {
lut_data[6] |= MACSEC_TX_SCI_LUT_DVLAN_OUTER_INNER_TAG_SEL;
}
return 0;
}
static nve32_t sci_lut_config(struct osi_core_priv_data *const osi_core,
struct osi_macsec_lut_config *const lut_config)
{
nveu32_t lut_data[MACSEC_LUT_DATA_REG_CNT] = {0};
struct osi_macsec_table_config table_config = lut_config->table_config;
struct osi_sci_lut_outputs entry = lut_config->sci_lut_out;
nveu8_t *addr = (nveu8_t *)osi_core->macsec_base;
nveu32_t val = 0;
nveu32_t index = lut_config->table_config.index;
if ((entry.sc_index > OSI_SC_INDEX_MAX) ||
(lut_config->table_config.index > OSI_SC_LUT_MAX_INDEX)) {
return -1;
}
switch (table_config.ctlr_sel) {
case OSI_CTLR_SEL_TX:
if (tx_sci_lut_config(lut_config, lut_data) < 0) {
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"Failed to config tx sci LUT\n", 0ULL);
return -1;
}
commit_lut_data(osi_core, lut_data);
if ((lut_config->flags & OSI_LUT_FLAGS_ENTRY_VALID) ==
OSI_LUT_FLAGS_ENTRY_VALID) {
val = osi_readla(osi_core, addr +
MACSEC_TX_SCI_LUT_VALID);
val |= (1 << index);
osi_writela(osi_core, val, addr +
MACSEC_TX_SCI_LUT_VALID);
} else {
val = osi_readla(osi_core, addr +
MACSEC_TX_SCI_LUT_VALID);
val &= ~(1 << index);
osi_writela(osi_core, val, addr +
MACSEC_TX_SCI_LUT_VALID);
}
break;
case OSI_CTLR_SEL_RX:
if (rx_sci_lut_config(lut_config, lut_data) < 0) {
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"Failed to config rx sci LUT\n", 0ULL);
return -1;
}
commit_lut_data(osi_core, lut_data);
if ((lut_config->flags & OSI_LUT_FLAGS_ENTRY_VALID) ==
OSI_LUT_FLAGS_ENTRY_VALID) {
val = osi_readla(osi_core, addr +
MACSEC_RX_SCI_LUT_VALID);
val |= (1 << index);
osi_writela(osi_core, val, addr +
MACSEC_RX_SCI_LUT_VALID);
} else {
val = osi_readla(osi_core, addr +
MACSEC_RX_SCI_LUT_VALID);
val &= ~(1 << index);
osi_writela(osi_core, val, addr +
MACSEC_RX_SCI_LUT_VALID);
}
break;
default:
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"Unknown controller select\n", 0ULL);
return -1;
}
return 0;
}
static nve32_t byp_lut_config(struct osi_core_priv_data *const osi_core,
struct osi_macsec_lut_config *const lut_config)
{
nveu32_t lut_data[MACSEC_LUT_DATA_REG_CNT] = {0};
nveu32_t flags = lut_config->flags;
nveu8_t *addr = (nveu8_t *)osi_core->macsec_base;
nveu32_t val = 0;
nveu32_t index = lut_config->table_config.index;
if (lut_config_inputs(lut_config, lut_data) != 0) {
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"LUT inputs error\n", 0ULL);
return -1;
}
/* Lookup output */
if ((flags & OSI_LUT_FLAGS_CONTROLLED_PORT) ==
OSI_LUT_FLAGS_CONTROLLED_PORT) {
lut_data[6] |= MACSEC_LUT_CONTROLLED_PORT;
}
if ((flags & OSI_LUT_FLAGS_DVLAN_PKT) == OSI_LUT_FLAGS_DVLAN_PKT) {
lut_data[6] |= MACSEC_BYP_LUT_DVLAN_PKT;
}
if ((flags & OSI_LUT_FLAGS_DVLAN_OUTER_INNER_TAG_SEL) ==
OSI_LUT_FLAGS_DVLAN_OUTER_INNER_TAG_SEL) {
lut_data[6] |= BYP_LUT_DVLAN_OUTER_INNER_TAG_SEL;
}
commit_lut_data(osi_core, lut_data);
switch (lut_config->table_config.ctlr_sel) {
case OSI_CTLR_SEL_TX:
if ((flags & OSI_LUT_FLAGS_ENTRY_VALID) ==
OSI_LUT_FLAGS_ENTRY_VALID) {
val = osi_readla(osi_core, addr +
MACSEC_TX_BYP_LUT_VALID);
val |= (1 << index);
osi_writela(osi_core, val, addr +
MACSEC_TX_BYP_LUT_VALID);
} else {
val = osi_readla(osi_core, addr +
MACSEC_TX_BYP_LUT_VALID);
val &= ~(1 << index);
osi_writela(osi_core, val, addr +
MACSEC_TX_BYP_LUT_VALID);
}
break;
case OSI_CTLR_SEL_RX:
if ((flags & OSI_LUT_FLAGS_ENTRY_VALID) ==
OSI_LUT_FLAGS_ENTRY_VALID) {
val = osi_readla(osi_core, addr +
MACSEC_RX_BYP_LUT_VALID);
val |= (1 << index);
osi_writela(osi_core, val, addr +
MACSEC_RX_BYP_LUT_VALID);
} else {
val = osi_readla(osi_core, addr +
MACSEC_RX_BYP_LUT_VALID);
val &= ~(1 << index);
osi_writela(osi_core, val, addr +
MACSEC_RX_BYP_LUT_VALID);
}
break;
default:
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"Unknown controller select\n", 0ULL);
return -1;
}
return 0;
}
static inline nve32_t lut_data_write(struct osi_core_priv_data *const osi_core,
struct osi_macsec_lut_config *const lut_config)
{
switch (lut_config->lut_sel) {
case OSI_LUT_SEL_BYPASS:
if (byp_lut_config(osi_core, lut_config) != 0) {
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"BYP LUT config err\n", 0ULL);
return -1;
}
break;
case OSI_LUT_SEL_SCI:
if (sci_lut_config(osi_core, lut_config) != 0) {
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"SCI LUT config err\n", 0ULL);
return -1;
}
break;
case OSI_LUT_SEL_SC_PARAM:
if (sc_param_lut_config(osi_core, lut_config) != 0) {
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"SC param LUT config err\n", 0ULL);
return -1;
}
break;
case OSI_LUT_SEL_SC_STATE:
if (sc_state_lut_config(osi_core, lut_config) != 0) {
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"SC state LUT config err\n", 0ULL);
return -1;
}
break;
case OSI_LUT_SEL_SA_STATE:
if (sa_state_lut_config(osi_core, lut_config) != 0) {
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"SA state LUT config err\n", 0ULL);
return -1;
}
break;
default:
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"Unsupported LUT\n", 0ULL);
return -1;
}
return 0;
}
static nve32_t macsec_lut_config(struct osi_core_priv_data *const osi_core,
struct osi_macsec_lut_config *const lut_config)
{
nve32_t ret = 0;
nveu32_t lut_config_reg;
nveu8_t *base = (nveu8_t *)osi_core->macsec_base;
/* Validate LUT config */
if ((lut_config->table_config.ctlr_sel > OSI_CTLR_SEL_MAX) ||
(lut_config->table_config.rw > OSI_RW_MAX) ||
(lut_config->table_config.index > OSI_TABLE_INDEX_MAX) ||
(lut_config->lut_sel > OSI_LUT_SEL_MAX)) {
pr_err("Validating LUT config failed. ctrl: %hu,"
" rw: %hu, index: %hu, lut_sel: %hu",
lut_config->table_config.ctlr_sel,
lut_config->table_config.rw,
lut_config->table_config.index, lut_config->lut_sel);
return -1;
}
/* Wait for previous LUT update to finish */
ret = poll_for_lut_update(osi_core);
if (ret < 0) {
return ret;
}
/* pr_err("%s: LUT: %hu ctrl: %hu rw: %hu idx: %hu flags: %#x\n", __func__,
lut_config->lut_sel, lut_config->table_config.ctlr_sel,
lut_config->table_config.rw, lut_config->table_config.index,
lut_config->flags);
*/
lut_config_reg = osi_readla(osi_core, base + MACSEC_LUT_CONFIG);
if (lut_config->table_config.ctlr_sel) {
lut_config_reg |= MACSEC_LUT_CONFIG_CTLR_SEL;
} else {
lut_config_reg &= ~MACSEC_LUT_CONFIG_CTLR_SEL;
}
if (lut_config->table_config.rw) {
lut_config_reg |= MACSEC_LUT_CONFIG_RW;
/* For write operation, load the lut_data registers */
ret = lut_data_write(osi_core, lut_config);
if (ret < 0) {
return ret;
}
} else {
lut_config_reg &= ~MACSEC_LUT_CONFIG_RW;
}
lut_config_reg &= ~MACSEC_LUT_CONFIG_LUT_SEL_MASK;
lut_config_reg |= (lut_config->lut_sel <<
MACSEC_LUT_CONFIG_LUT_SEL_SHIFT);
lut_config_reg &= ~MACSEC_LUT_CONFIG_INDEX_MASK;
lut_config_reg |= (lut_config->table_config.index);
lut_config_reg |= MACSEC_LUT_CONFIG_UPDATE;
osi_writela(osi_core, lut_config_reg, base + MACSEC_LUT_CONFIG);
/* Wait for this LUT update to finish */
ret = poll_for_lut_update(osi_core);
if (ret < 0) {
return ret;
}
if (!lut_config->table_config.rw) {
ret = lut_data_read(osi_core, lut_config);
if (ret < 0) {
return ret;
}
}
return 0;
}
static inline void handle_rx_sc_invalid_key(
struct osi_core_priv_data *const osi_core)
{
nveu8_t *addr = (nveu8_t *)osi_core->macsec_base;
nveu32_t clear = 0;
pr_err("%s()\n", __func__);
/** check which SC/AN had triggered and clear */
/* rx_sc0_7 */
clear = osi_readla(osi_core, addr + MACSEC_RX_SC_KEY_INVALID_STS0_0);
osi_writela(osi_core, clear, addr + MACSEC_RX_SC_KEY_INVALID_STS0_0);
/* rx_sc8_15 */
clear = osi_readla(osi_core, addr + MACSEC_RX_SC_KEY_INVALID_STS1_0);
osi_writela(osi_core, clear, addr + MACSEC_RX_SC_KEY_INVALID_STS1_0);
}
static inline void handle_tx_sc_invalid_key(
struct osi_core_priv_data *const osi_core)
{
nveu8_t *addr = (nveu8_t *)osi_core->macsec_base;
nveu32_t clear = 0;
pr_err("%s()\n", __func__);
/** check which SC/AN had triggered and clear */
/* tx_sc0_7 */
clear = osi_readla(osi_core, addr + MACSEC_TX_SC_KEY_INVALID_STS0_0);
osi_writela(osi_core, clear, addr + MACSEC_TX_SC_KEY_INVALID_STS0_0);
/* tx_sc8_15 */
clear = osi_readla(osi_core, addr + MACSEC_TX_SC_KEY_INVALID_STS1_0);
osi_writela(osi_core, clear, addr + MACSEC_TX_SC_KEY_INVALID_STS1_0);
}
static inline void handle_safety_err_irq(
struct osi_core_priv_data *const osi_core)
{
pr_err("%s()\n", __func__);
}
static inline void handle_rx_sc_replay_err(
struct osi_core_priv_data *const osi_core)
{
nveu8_t *addr = (nveu8_t *)osi_core->macsec_base;
nveu32_t clear = 0;
/* pr_err("%s()\n", __func__); */
/* rx_sc0_7 */
clear = osi_readla(osi_core, addr +
MACSEC_RX_SC_REPLAY_ERROR_STATUS0_0);
osi_writela(osi_core, clear, addr +
MACSEC_RX_SC_REPLAY_ERROR_STATUS0_0);
/* rx_sc8_15 */
clear = osi_readla(osi_core, addr +
MACSEC_RX_SC_REPLAY_ERROR_STATUS1_0);
osi_writela(osi_core, clear, addr +
MACSEC_RX_SC_REPLAY_ERROR_STATUS1_0);
}
static inline void handle_rx_pn_exhausted(
struct osi_core_priv_data *const osi_core)
{
nveu8_t *addr = (nveu8_t *)osi_core->macsec_base;
nveu32_t clear = 0;
/* pr_err("%s()\n", __func__); */
/* Check which SC/AN had triggered and clear */
/* rx_sc0_7 */
clear = osi_readla(osi_core, addr +
MACSEC_RX_SC_PN_EXHAUSTED_STATUS0_0);
osi_writela(osi_core, clear, addr +
MACSEC_RX_SC_PN_EXHAUSTED_STATUS0_0);
/* rx_sc8_15 */
clear = osi_readla(osi_core, addr +
MACSEC_RX_SC_PN_EXHAUSTED_STATUS1_0);
osi_writela(osi_core, clear, addr +
MACSEC_RX_SC_PN_EXHAUSTED_STATUS1_0);
}
static inline void handle_tx_sc_err(struct osi_core_priv_data *const osi_core)
{
nveu8_t *addr = (nveu8_t *)osi_core->macsec_base;
nveu32_t clear = 0;
/* pr_err("%s()\n", __func__); */
clear = osi_readla(osi_core, addr +
MACSEC_TX_SC_ERROR_INTERRUPT_STATUS_0);
osi_writela(osi_core, clear, addr +
MACSEC_TX_SC_ERROR_INTERRUPT_STATUS_0);
}
static inline void handle_tx_pn_threshold(
struct osi_core_priv_data *const osi_core)
{
nveu8_t *addr = (nveu8_t *)osi_core->macsec_base;
nveu32_t clear = 0;
/* pr_err("%s()\n", __func__); */
/* check which SC/AN had triggered and clear */
/* tx_sc0_7 */
clear = osi_readla(osi_core, addr +
MACSEC_TX_SC_PN_THRESHOLD_STATUS0_0);
osi_writela(osi_core, clear, addr +
MACSEC_TX_SC_PN_THRESHOLD_STATUS0_0);
/* tx_sc8_15 */
clear = osi_readla(osi_core, addr +
MACSEC_TX_SC_PN_THRESHOLD_STATUS1_0);
osi_writela(osi_core, clear, addr +
MACSEC_TX_SC_PN_THRESHOLD_STATUS1_0);
}
static inline void handle_tx_pn_exhausted(
struct osi_core_priv_data *const osi_core)
{
nveu8_t *addr = (nveu8_t *)osi_core->macsec_base;
nveu32_t clear = 0;
/* pr_err("%s()\n", __func__); */
/* check which SC/AN had triggered and clear */
/* tx_sc0_7 */
clear = osi_readla(osi_core, addr +
MACSEC_TX_SC_PN_EXHAUSTED_STATUS0_0);
osi_writela(osi_core, clear, addr +
MACSEC_TX_SC_PN_EXHAUSTED_STATUS0_0);
/* tx_sc8_15 */
clear = osi_readla(osi_core, addr +
MACSEC_TX_SC_PN_EXHAUSTED_STATUS1_0);
osi_writela(osi_core, clear, addr +
MACSEC_TX_SC_PN_EXHAUSTED_STATUS1_0);
}
static inline void handle_dbg_evt_capture_done(
struct osi_core_priv_data *const osi_core,
nveu16_t ctrl_sel)
{
nveu8_t *addr = (nveu8_t *)osi_core->macsec_base;
nveu32_t trigger_evts = 0;
if (ctrl_sel == OSI_CTLR_SEL_TX) {
trigger_evts = osi_readla(osi_core, addr +
MACSEC_TX_DEBUG_STATUS_0);
pr_err("%s: MACSEC_TX_DEBUG_STATUS_0 0x%x", __func__, trigger_evts);
osi_writela(osi_core, trigger_evts, addr +
MACSEC_TX_DEBUG_STATUS_0);
/* clear all trigger events */
trigger_evts = 0U;
osi_writela(osi_core, trigger_evts,
addr + MACSEC_TX_DEBUG_TRIGGER_EN_0);
} else if (ctrl_sel == OSI_CTLR_SEL_RX) {
trigger_evts = osi_readla(osi_core, addr +
MACSEC_RX_DEBUG_STATUS_0);
pr_err("%s: MACSEC_RX_DEBUG_STATUS_0 0x%x", __func__, trigger_evts);
osi_writela(osi_core, trigger_evts, addr +
MACSEC_RX_DEBUG_STATUS_0);
/* clear all trigger events */
trigger_evts = 0U;
osi_writela(osi_core, trigger_evts,
addr + MACSEC_RX_DEBUG_TRIGGER_EN_0);
}
}
static inline void handle_tx_irq(struct osi_core_priv_data *const osi_core)
{
nveu32_t tx_isr, clear = 0;
nveu8_t *addr = (nveu8_t *)osi_core->macsec_base;
tx_isr = osi_readla(osi_core, addr + MACSEC_TX_ISR);
pr_err("%s(): tx_isr 0x%x\n", __func__, tx_isr);
if ((tx_isr & MACSEC_TX_DBG_BUF_CAPTURE_DONE) ==
MACSEC_TX_DBG_BUF_CAPTURE_DONE) {
handle_dbg_evt_capture_done(osi_core, OSI_CTLR_SEL_TX);
osi_core->macsec_irq_stats.tx_dbg_capture_done++;
clear |= MACSEC_TX_DBG_BUF_CAPTURE_DONE;
}
if ((tx_isr & MACSEC_TX_MTU_CHECK_FAIL) == MACSEC_TX_MTU_CHECK_FAIL) {
osi_core->macsec_irq_stats.tx_mtu_check_fail++;
clear |= MACSEC_TX_MTU_CHECK_FAIL;
}
if ((tx_isr & MACSEC_TX_AES_GCM_BUF_OVF) == MACSEC_TX_AES_GCM_BUF_OVF) {
osi_core->macsec_irq_stats.tx_aes_gcm_buf_ovf++;
clear |= MACSEC_TX_AES_GCM_BUF_OVF;
}
if ((tx_isr & MACSEC_TX_SC_AN_NOT_VALID) == MACSEC_TX_SC_AN_NOT_VALID) {
osi_core->macsec_irq_stats.tx_sc_an_not_valid++;
handle_tx_sc_err(osi_core);
clear |= MACSEC_TX_SC_AN_NOT_VALID;
}
if ((tx_isr & MACSEC_TX_MAC_CRC_ERROR) == MACSEC_TX_MAC_CRC_ERROR) {
osi_core->macsec_irq_stats.tx_mac_crc_error++;
clear |= MACSEC_TX_MAC_CRC_ERROR;
}
if ((tx_isr & MACSEC_TX_PN_THRSHLD_RCHD) == MACSEC_TX_PN_THRSHLD_RCHD) {
osi_core->macsec_irq_stats.tx_pn_threshold++;
handle_tx_pn_threshold(osi_core);
clear |= MACSEC_TX_PN_THRSHLD_RCHD;
}
if ((tx_isr & MACSEC_TX_PN_EXHAUSTED) == MACSEC_TX_PN_EXHAUSTED) {
osi_core->macsec_irq_stats.tx_pn_exhausted++;
handle_tx_pn_exhausted(osi_core);
clear |= MACSEC_TX_PN_EXHAUSTED;
}
if (clear) {
pr_err("%s(): write tx_isr 0x%x\n", __func__, clear);
osi_writela(osi_core, clear, addr + MACSEC_TX_ISR);
}
}
static inline void handle_rx_irq(struct osi_core_priv_data *const osi_core)
{
nveu32_t rx_isr, clear = 0;
nveu8_t *addr = (nveu8_t *)osi_core->macsec_base;
rx_isr = osi_readla(osi_core, addr + MACSEC_RX_ISR);
pr_err("%s(): rx_isr 0x%x\n", __func__, rx_isr);
if ((rx_isr & MACSEC_RX_DBG_BUF_CAPTURE_DONE) ==
MACSEC_RX_DBG_BUF_CAPTURE_DONE) {
handle_dbg_evt_capture_done(osi_core, OSI_CTLR_SEL_RX);
osi_core->macsec_irq_stats.rx_dbg_capture_done++;
clear |= MACSEC_RX_DBG_BUF_CAPTURE_DONE;
}
if ((rx_isr & MACSEC_RX_ICV_ERROR) == MACSEC_RX_ICV_ERROR) {
osi_core->macsec_irq_stats.rx_icv_err_threshold++;
clear |= MACSEC_RX_ICV_ERROR;
}
if ((rx_isr & MACSEC_RX_REPLAY_ERROR) == MACSEC_RX_REPLAY_ERROR) {
osi_core->macsec_irq_stats.rx_replay_error++;
handle_rx_sc_replay_err(osi_core);
clear |= MACSEC_RX_REPLAY_ERROR;
}
if ((rx_isr & MACSEC_RX_MTU_CHECK_FAIL) == MACSEC_RX_MTU_CHECK_FAIL) {
osi_core->macsec_irq_stats.rx_mtu_check_fail++;
clear |= MACSEC_RX_MTU_CHECK_FAIL;
}
if ((rx_isr & MACSEC_RX_AES_GCM_BUF_OVF) == MACSEC_RX_AES_GCM_BUF_OVF) {
osi_core->macsec_irq_stats.rx_aes_gcm_buf_ovf++;
clear |= MACSEC_RX_AES_GCM_BUF_OVF;
}
if ((rx_isr & MACSEC_RX_MAC_CRC_ERROR) == MACSEC_RX_MAC_CRC_ERROR) {
osi_core->macsec_irq_stats.rx_mac_crc_error++;
clear |= MACSEC_RX_MAC_CRC_ERROR;
}
if ((rx_isr & MACSEC_RX_PN_EXHAUSTED) == MACSEC_RX_PN_EXHAUSTED) {
osi_core->macsec_irq_stats.rx_pn_exhausted++;
handle_rx_pn_exhausted(osi_core);
clear |= MACSEC_RX_PN_EXHAUSTED;
}
if (clear) {
pr_err("%s(): write rx_isr 0x%x\n", __func__, clear);
osi_writela(osi_core, clear, addr + MACSEC_RX_ISR);
}
}
static inline void handle_common_irq(struct osi_core_priv_data *const osi_core)
{
nveu32_t common_isr, clear = 0;
nveu8_t *addr = (nveu8_t *)osi_core->macsec_base;
common_isr = osi_readla(osi_core, addr + MACSEC_COMMON_ISR);
pr_err("%s(): common_isr 0x%x\n", __func__, common_isr);
if ((common_isr & MACSEC_SECURE_REG_VIOL) == MACSEC_SECURE_REG_VIOL) {
osi_core->macsec_irq_stats.secure_reg_viol++;
clear |= MACSEC_SECURE_REG_VIOL;
}
if ((common_isr & MACSEC_RX_UNINIT_KEY_SLOT) ==
MACSEC_RX_UNINIT_KEY_SLOT) {
osi_core->macsec_irq_stats.rx_uninit_key_slot++;
clear |= MACSEC_RX_UNINIT_KEY_SLOT;
handle_rx_sc_invalid_key(osi_core);
}
if ((common_isr & MACSEC_RX_LKUP_MISS) == MACSEC_RX_LKUP_MISS) {
osi_core->macsec_irq_stats.rx_lkup_miss++;
clear |= MACSEC_RX_LKUP_MISS;
}
if ((common_isr & MACSEC_TX_UNINIT_KEY_SLOT) ==
MACSEC_TX_UNINIT_KEY_SLOT) {
osi_core->macsec_irq_stats.tx_uninit_key_slot++;
clear |= MACSEC_TX_UNINIT_KEY_SLOT;
handle_tx_sc_invalid_key(osi_core);
}
if ((common_isr & MACSEC_TX_LKUP_MISS) == MACSEC_TX_LKUP_MISS) {
osi_core->macsec_irq_stats.tx_lkup_miss++;
clear |= MACSEC_TX_LKUP_MISS;
}
if (clear) {
osi_writela(osi_core, clear, addr + MACSEC_COMMON_ISR);
}
}
static void macsec_handle_ns_irq(struct osi_core_priv_data *const osi_core)
{
nveu32_t irq_common_sr, common_isr;
nveu8_t *addr = (nveu8_t *)osi_core->macsec_base;
irq_common_sr = osi_readla(osi_core, addr + MACSEC_INTERRUPT_COMMON_SR);
pr_err("%s(): common_sr 0x%x\n", __func__, irq_common_sr);
if ((irq_common_sr & MACSEC_COMMON_SR_TX) == MACSEC_COMMON_SR_TX) {
handle_tx_irq(osi_core);
}
if ((irq_common_sr & MACSEC_COMMON_SR_RX) == MACSEC_COMMON_SR_RX) {
handle_rx_irq(osi_core);
}
if ((irq_common_sr & MACSEC_COMMON_SR_SFTY_ERR) ==
MACSEC_COMMON_SR_SFTY_ERR) {
handle_safety_err_irq(osi_core);
}
common_isr = osi_readla(osi_core, addr + MACSEC_COMMON_ISR);
if (common_isr != OSI_NONE) {
handle_common_irq(osi_core);
}
}
static void macsec_handle_s_irq(struct osi_core_priv_data *const osi_core)
{
nveu32_t common_isr;
nveu8_t *addr = (nveu8_t *)osi_core->macsec_base;
pr_err("%s()\n", __func__);
common_isr = osi_readla(osi_core, addr + MACSEC_COMMON_ISR);
if (common_isr != OSI_NONE) {
handle_common_irq(osi_core);
}
return;
}
static nve32_t macsec_cipher_config(struct osi_core_priv_data *const osi_core,
nveu32_t cipher)
{
nveu8_t *base = (nveu8_t *)osi_core->macsec_base;
nveu32_t val;
val = osi_readla(osi_core, base + MACSEC_GCM_AES_CONTROL_0);
pr_err("Read MACSEC_GCM_AES_CONTROL_0: 0x%x\n", val);
val &= ~MACSEC_TX_AES_MODE_MASK;
val &= ~MACSEC_RX_AES_MODE_MASK;
if (cipher == OSI_MACSEC_CIPHER_AES128) {
val |= MACSEC_TX_AES_MODE_AES128;
val |= MACSEC_RX_AES_MODE_AES128;
} else if (cipher == OSI_MACSEC_CIPHER_AES256) {
val |= MACSEC_TX_AES_MODE_AES256;
val |= MACSEC_RX_AES_MODE_AES256;
} else {
return -1;
}
pr_err("Write MACSEC_GCM_AES_CONTROL_0: 0x%x\n", val);
osi_writela(osi_core, val, base + MACSEC_GCM_AES_CONTROL_0);
return 0;
}
static nve32_t macsec_loopback_config(
struct osi_core_priv_data *const osi_core,
nveu32_t enable)
{
nveu8_t *base = (nveu8_t *)osi_core->macsec_base;
nveu32_t val;
val = osi_readla(osi_core, base + MACSEC_CONTROL1);
pr_err("Read MACSEC_CONTROL1: 0x%x\n", val);
if (enable == OSI_ENABLE) {
val |= MACSEC_LOOPBACK_MODE_EN;
} else if (enable == OSI_DISABLE) {
val &= ~MACSEC_LOOPBACK_MODE_EN;
} else {
return -1;
}
pr_err("Write MACSEC_CONTROL1: 0x%x\n", val);
osi_writela(osi_core, val, base + MACSEC_CONTROL1);
return 0;
}
static nve32_t clear_lut(struct osi_core_priv_data *const osi_core)
{
struct osi_macsec_lut_config lut_config = {0};
#ifdef MACSEC_KEY_PROGRAM
struct osi_macsec_kt_config kt_config = {0};
#endif
struct osi_macsec_table_config *table_config = &lut_config.table_config;
nveu32_t i, j;
nve32_t ret = 0;
table_config->rw = OSI_LUT_WRITE;
/* Clear all the LUT's which have a dedicated LUT valid bit per entry */
/* Tx/Rx BYP LUT */
lut_config.lut_sel = OSI_LUT_SEL_BYPASS;
for (i = 0; i <= OSI_CTLR_SEL_MAX; i++) {
table_config->ctlr_sel = i;
for (j = 0; j <= OSI_BYP_LUT_MAX_INDEX; j++) {
table_config->index = j;
ret = macsec_lut_config(osi_core, &lut_config);
if (ret < 0) {
pr_err("Error clearing CTLR:LUT:INDEX: %d:%d:%d\n",
i, lut_config.lut_sel, j);
return ret;
}
}
}
/* Tx/Rx SCI LUT */
lut_config.lut_sel = OSI_LUT_SEL_SCI;
for (i = 0; i <= OSI_CTLR_SEL_MAX; i++) {
table_config->ctlr_sel = i;
for (j = 0; j <= OSI_SC_LUT_MAX_INDEX; j++) {
table_config->index = j;
ret = macsec_lut_config(osi_core, &lut_config);
if (ret < 0) {
pr_err("Error clearing CTLR:LUT:INDEX: %d:%d:%d\n",
i, lut_config.lut_sel, j);
return ret;
}
}
}
/* Tx/Rx SC param LUT */
lut_config.lut_sel = OSI_LUT_SEL_SC_PARAM;
for (i = 0; i <= OSI_CTLR_SEL_MAX; i++) {
table_config->ctlr_sel = i;
for (j = 0; j <= OSI_SC_LUT_MAX_INDEX; j++) {
table_config->index = j;
ret = macsec_lut_config(osi_core, &lut_config);
if (ret < 0) {
pr_err("Error clearing CTLR:LUT:INDEX: %d:%d:%d\n",
i, lut_config.lut_sel, j);
return ret;
}
}
}
/* Tx/Rx SC state */
lut_config.lut_sel = OSI_LUT_SEL_SC_STATE;
for (i = 0; i <= OSI_CTLR_SEL_MAX; i++) {
table_config->ctlr_sel = i;
for (j = 0; j <= OSI_SC_LUT_MAX_INDEX; j++) {
table_config->index = j;
ret = macsec_lut_config(osi_core, &lut_config);
if (ret < 0) {
pr_err("Error clearing CTLR:LUT:INDEX: %d:%d:%d\n",
i, lut_config.lut_sel, j);
return ret;
}
}
}
/* Tx SA state LUT */
lut_config.lut_sel = OSI_LUT_SEL_SA_STATE;
table_config->ctlr_sel = OSI_CTLR_SEL_TX;
for (j = 0; j <= OSI_SA_LUT_MAX_INDEX; j++) {
table_config->index = j;
ret = macsec_lut_config(osi_core, &lut_config);
if (ret < 0) {
pr_err("Error clearing Tx LUT:INDEX: %d:%d\n",
lut_config.lut_sel, j);
return ret;
}
}
/* Rx SA state LUT */
lut_config.lut_sel = OSI_LUT_SEL_SA_STATE;
table_config->ctlr_sel = OSI_CTLR_SEL_RX;
for (j = 0; j <= OSI_SA_LUT_MAX_INDEX; j++) {
table_config->index = j;
ret = macsec_lut_config(osi_core, &lut_config);
if (ret < 0) {
pr_err("Error clearing Rx LUT:INDEX: %d:%d\n",
lut_config.lut_sel, j);
return ret;
}
}
#ifdef MACSEC_KEY_PROGRAM
/* Key table */
table_config = &kt_config.table_config;
table_config->rw = OSI_LUT_WRITE;
for (i = 0; i <= OSI_CTLR_SEL_MAX; i++) {
table_config->ctlr_sel = i;
for (j = 0; j <= OSI_TABLE_INDEX_MAX; j++) {
table_config->index = j;
ret = macsec_kt_config(osi_core, &kt_config);
if (ret < 0) {
pr_err("Error clearing KT CTLR:INDEX: %d:%d\n",
i, j);
return ret;
}
}
}
#endif /* MACSEC_KEY_PROGRAM */
return ret;
}
static nve32_t macsec_deinit(struct osi_core_priv_data *const osi_core)
{
nveu32_t i;
struct core_local *l_core = (struct core_local *)osi_core;
for (i = OSI_CTLR_SEL_TX; i <= OSI_CTLR_SEL_RX; i++) {
osi_memset(&osi_core->macsec_lut_status[i], OSI_NONE,
sizeof(struct osi_macsec_lut_status));
}
/* Update MAC as per macsec requirement */
if (l_core->ops_p->macsec_config_mac != OSI_NULL) {
l_core->ops_p->macsec_config_mac(osi_core, OSI_DISABLE);
} else {
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"Failed config MAC per macsec\n", 0ULL);
}
return 0;
}
static nve32_t macsec_init(struct osi_core_priv_data *const osi_core)
{
nveu32_t val = 0;
struct osi_macsec_lut_config lut_config = {0};
struct osi_macsec_table_config *table_config = &lut_config.table_config;
struct core_local *l_core = (struct core_local *)osi_core;
/* Store MAC address in reverse, per HW design */
nveu8_t mac_da_mkpdu[OSI_ETH_ALEN] = {0x3, 0x0, 0x0,
0xC2, 0x80, 0x01};
nveu8_t mac_da_bc[OSI_ETH_ALEN] = {0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF};
nveu32_t mtu = osi_core->mtu;
nveu8_t *addr = (nveu8_t *)osi_core->macsec_base;
nve32_t ret = 0;
nveu16_t i, j;
/* Update MAC value as per macsec requirement */
if (l_core->ops_p->macsec_config_mac != OSI_NULL) {
l_core->ops_p->macsec_config_mac(osi_core, OSI_ENABLE);
} else {
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"Failed to config mac per macsec\n", 0ULL);
}
/* Set MTU */
val = osi_readla(osi_core, addr + MACSEC_TX_MTU_LEN);
pr_err("Read MACSEC_TX_MTU_LEN: 0x%x\n", val);
val &= ~(MTU_LENGTH_MASK);
val |= (mtu & MTU_LENGTH_MASK);
pr_err("Write MACSEC_TX_MTU_LEN: 0x%x\n", val);
osi_writela(osi_core, val, addr + MACSEC_TX_MTU_LEN);
val = osi_readla(osi_core, addr + MACSEC_RX_MTU_LEN);
pr_err("Read MACSEC_RX_MTU_LEN: 0x%x\n", val);
val &= ~(MTU_LENGTH_MASK);
val |= (mtu & MTU_LENGTH_MASK);
pr_err("Write MACSEC_RX_MTU_LEN: 0x%x\n", val);
osi_writela(osi_core, val, addr + MACSEC_RX_MTU_LEN);
/* set TX/RX SOT, as SOT value different for eqos.
* default value matches for MGBE
*/
if (osi_core->mac == OSI_MAC_HW_EQOS) {
val = osi_readla(osi_core, addr + MACSEC_TX_SOT_DELAY);
pr_err("Read MACSEC_TX_SOT_DELAY: 0x%x\n", val);
val &= ~(SOT_LENGTH_MASK);
val |= (EQOS_MACSEC_SOT_DELAY & SOT_LENGTH_MASK);
pr_err("Write MACSEC_TX_SOT_DELAY: 0x%x\n", val);
osi_writela(osi_core, val, addr + MACSEC_TX_SOT_DELAY);
val = osi_readla(osi_core, addr + MACSEC_RX_SOT_DELAY);
pr_err("Read MACSEC_RX_SOT_DELAY: 0x%x\n", val);
val &= ~(SOT_LENGTH_MASK);
val |= (EQOS_MACSEC_SOT_DELAY & SOT_LENGTH_MASK);
pr_err("Write MACSEC_RX_SOT_DELAY: 0x%x\n", val);
osi_writela(osi_core, val, addr + MACSEC_RX_SOT_DELAY);
}
/* Set essential MACsec control configuration */
val = osi_readla(osi_core, addr + MACSEC_CONTROL0);
pr_err("Read MACSEC_CONTROL0: 0x%x\n", val);
val |= (MACSEC_TX_LKUP_MISS_NS_INTR | MACSEC_RX_LKUP_MISS_NS_INTR |
MACSEC_TX_LKUP_MISS_BYPASS | MACSEC_RX_LKUP_MISS_BYPASS);
val &= ~(MACSEC_VALIDATE_FRAMES_MASK);
val |= MACSEC_VALIDATE_FRAMES_STRICT;
val |= MACSEC_RX_REPLAY_PROT_EN;
pr_err("Write MACSEC_CONTROL0: 0x%x\n", val);
osi_writela(osi_core, val, addr + MACSEC_CONTROL0);
val = osi_readla(osi_core, addr + MACSEC_CONTROL1);
pr_err("Read MACSEC_CONTROL1: 0x%x\n", val);
val |= (MACSEC_RX_MTU_CHECK_EN | MACSEC_TX_LUT_PRIO_BYP |
MACSEC_TX_MTU_CHECK_EN);
pr_err("Write MACSEC_CONTROL1: 0x%x\n", val);
osi_writela(osi_core, val, addr + MACSEC_CONTROL1);
/* set DVLAN tag ethertype */
/* val = DVLAN_TAG_ETHERTYPE;
* pr_err("Write MACSEC_TX_DVLAN_CONTROL_0: 0x%x\n", val);
* osi_writela(osi_core, val, addr + MACSEC_TX_DVLAN_CONTROL_0);
* pr_err("Write MACSEC_RX_DVLAN_CONTROL_0: 0x%x\n", val);
* osi_writela(osi_core, val, addr + MACSEC_RX_DVLAN_CONTROL_0);
*/
val = osi_readla(osi_core, addr + MACSEC_STATS_CONTROL_0);
pr_err("Read MACSEC_STATS_CONTROL_0: 0x%x\n", val);
/* set STATS rollover bit */
val |= MACSEC_STATS_CONTROL0_CNT_RL_OVR_CPY;
pr_err("Write MACSEC_STATS_CONTROL_0: 0x%x\n", val);
osi_writela(osi_core, val, addr + MACSEC_STATS_CONTROL_0);
/* Enable default interrupts needed */
val = osi_readla(osi_core, addr + MACSEC_TX_IMR);
pr_err("Read MACSEC_TX_IMR: 0x%x\n", val);
val |= (MACSEC_TX_DBG_BUF_CAPTURE_DONE_INT_EN |
MACSEC_TX_MTU_CHECK_FAIL_INT_EN |
MACSEC_TX_MAC_CRC_ERROR_INT_EN |
MACSEC_TX_SC_AN_NOT_VALID_INT_EN |
MACSEC_TX_AES_GCM_BUF_OVF_INT_EN |
MACSEC_TX_PN_EXHAUSTED_INT_EN |
MACSEC_TX_PN_THRSHLD_RCHD_INT_EN);
pr_err("Write MACSEC_TX_IMR: 0x%x\n", val);
osi_writela(osi_core, val, addr + MACSEC_TX_IMR);
val = osi_readla(osi_core, addr + MACSEC_RX_IMR);
pr_err("Read MACSEC_RX_IMR: 0x%x\n", val);
val |= (MACSEC_RX_DBG_BUF_CAPTURE_DONE_INT_EN |
MACSEC_RX_ICV_ERROR_INT_EN | RX_REPLAY_ERROR_INT_EN |
MACSEC_RX_MTU_CHECK_FAIL_INT_EN |
MACSEC_RX_MAC_CRC_ERROR_INT_EN |
MACSEC_RX_AES_GCM_BUF_OVF_INT_EN |
MACSEC_RX_PN_EXHAUSTED_INT_EN
);
pr_err("Write MACSEC_RX_IMR: 0x%x\n", val);
osi_writela(osi_core, val, addr + MACSEC_RX_IMR);
val = osi_readla(osi_core, addr + MACSEC_COMMON_IMR);
pr_err("Read MACSEC_COMMON_IMR: 0x%x\n", val);
val |= (MACSEC_SECURE_REG_VIOL_INT_EN |
MACSEC_RX_UNINIT_KEY_SLOT_INT_EN |
MACSEC_RX_LKUP_MISS_INT_EN |
MACSEC_TX_UNINIT_KEY_SLOT_INT_EN |
MACSEC_TX_LKUP_MISS_INT_EN);
pr_err("Write MACSEC_COMMON_IMR: 0x%x\n", val);
osi_writela(osi_core, val, addr + MACSEC_COMMON_IMR);
/* Set AES mode
* Default power on reset is AES-GCM128, leave it.
*/
/* Invalidate LUT entries */
ret = clear_lut(osi_core);
if (ret < 0) {
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"Invalidating all LUT's failed\n", ret);
return ret;
}
/* Set default BYP for MKPDU/BC packets */
table_config->rw = OSI_LUT_WRITE;
lut_config.lut_sel = OSI_LUT_SEL_BYPASS;
lut_config.flags |= (OSI_LUT_FLAGS_DA_VALID |
OSI_LUT_FLAGS_ENTRY_VALID);
for (j = 0; j < OSI_ETH_ALEN; j++) {
lut_config.lut_in.da[j] = mac_da_bc[j];
}
for (i = OSI_CTLR_SEL_TX; i <= OSI_CTLR_SEL_RX; i++) {
table_config->ctlr_sel = i;
table_config->index =
osi_core->macsec_lut_status[i].next_byp_idx;
ret = macsec_lut_config(osi_core, &lut_config);
if (ret < 0) {
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"Failed to set BYP for BC addr\n", ret);
goto exit;
} else {
osi_core->macsec_lut_status[i].next_byp_idx++;
}
}
for (j = 0; j < OSI_ETH_ALEN; j++) {
lut_config.lut_in.da[j] = mac_da_mkpdu[j];
}
for (i = OSI_CTLR_SEL_TX; i <= OSI_CTLR_SEL_RX; i++) {
table_config->ctlr_sel = i;
table_config->index =
osi_core->macsec_lut_status[i].next_byp_idx;
ret = macsec_lut_config(osi_core, &lut_config);
if (ret < 0) {
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"Failed to set BYP for MKPDU multicast DA\n", ret);
goto exit;
} else {
osi_core->macsec_lut_status[i].next_byp_idx++;
}
}
exit:
return ret;
}
static struct osi_macsec_sc_info *find_existing_sc(
struct osi_core_priv_data *const osi_core,
struct osi_macsec_sc_info *const sc,
nveu16_t ctlr)
{
struct osi_macsec_lut_status *lut_status =
&osi_core->macsec_lut_status[ctlr];
nveu32_t i;
for (i = 0; i < lut_status->next_sc_idx; i++) {
if (osi_memcmp(lut_status->sc_info[i].sci, sc->sci,
OSI_SCI_LEN) == OSI_NONE) {
return &lut_status->sc_info[i];
}
}
return OSI_NULL;
}
nve32_t macsec_get_sc_lut_key_index(struct osi_core_priv_data *const osi_core,
nveu8_t *sci, nve32_t *key_index, nveu16_t ctlr)
{
struct osi_macsec_sc_info sc;
struct osi_macsec_sc_info *sc_info = OSI_NULL;
/* Validate inputs */
if ((sci == OSI_NULL) || (key_index == OSI_NULL) ||
(ctlr > OSI_CTLR_SEL_MAX)) {
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"Params validation failed\n", 0ULL);
return -1;
}
osi_memcpy(sc.sci, sci, OSI_SCI_LEN);
sc_info = find_existing_sc(osi_core, &sc, ctlr);
if (sc_info == OSI_NULL) {
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"SCI Not found\n", 0ULL);
return -1;
}
*key_index = (sc_info->sc_idx_start * OSI_MAX_NUM_SA);
return 0;
}
static nve32_t del_upd_sc(struct osi_core_priv_data *const osi_core,
struct osi_macsec_sc_info *existing_sc,
struct osi_macsec_sc_info *const sc,
nveu16_t ctlr, nveu16_t *kt_idx)
{
#ifdef MACSEC_KEY_PROGRAM
struct osi_macsec_kt_config kt_config = {0};
#endif /* MACSEC_KEY_PROGRAM */
struct osi_macsec_lut_config lut_config = {0};
struct osi_macsec_table_config *table_config;
nve32_t ret;
/* All input/output fields are already zero'd in declaration.
* Write all 0's to LUT index to clear everything
*/
table_config = &lut_config.table_config;
table_config->ctlr_sel = ctlr;
table_config->rw = OSI_LUT_WRITE;
/* If curr_an of existing SC is same as AN being deleted, then remove
* SCI LUT entry as well. If not, it means some other AN is already
* enabled, so leave the SC configuration as is.
*/
if (existing_sc->curr_an == sc->curr_an) {
/* 1. SCI LUT */
lut_config.lut_sel = OSI_LUT_SEL_SCI;
table_config->index = existing_sc->sc_idx_start;
ret = macsec_lut_config(osi_core, &lut_config);
if (ret < 0) {
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"Failed to del SCI LUT idx\n",
sc->sc_idx_start);
goto err_sci;
}
/* 2. SC Param LUT */
lut_config.lut_sel = OSI_LUT_SEL_SC_PARAM;
ret = macsec_lut_config(osi_core, &lut_config);
if (ret < 0) {
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"Failed to del SC param\n", ret);
goto err_sc_param;
}
/* 3. SC state LUT */
lut_config.lut_sel = OSI_LUT_SEL_SC_STATE;
ret = macsec_lut_config(osi_core, &lut_config);
if (ret < 0) {
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"Failed to del SC state\n", ret);
goto err_sc_state;
}
}
/* 4. SA State LUT */
lut_config.lut_sel = OSI_LUT_SEL_SA_STATE;
table_config->index = (existing_sc->sc_idx_start * OSI_MAX_NUM_SA) +
sc->curr_an;
ret = macsec_lut_config(osi_core, &lut_config);
if (ret < 0) {
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"Failed to del SA state\n", ret);
goto err_sa_state;
}
/* Store key table index returned to osd */
*kt_idx = (existing_sc->sc_idx_start * OSI_MAX_NUM_SA) + sc->curr_an;
#ifdef MACSEC_KEY_PROGRAM
/* 5. Key LUT */
table_config = &kt_config.table_config;
table_config->ctlr_sel = ctlr;
table_config->rw = OSI_LUT_WRITE;
/* Each SC has OSI_MAX_NUM_SA's supported in HW */
table_config->index = *kt_idx;
ret = macsec_kt_config(osi_core, &kt_config);
if (ret < 0) {
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"Failed to del SAK\n", ret);
goto err_kt;
}
#endif /* MACSEC_KEY_PROGRAM */
existing_sc->an_valid &= ~OSI_BIT(sc->curr_an);
return 0;
#ifdef MACSEC_KEY_PROGRAM
err_kt:
#endif
err_sa_state:
err_sc_state:
err_sc_param:
err_sci:
return -1;
}
static nve32_t add_upd_sc(struct osi_core_priv_data *const osi_core,
struct osi_macsec_sc_info *const sc,
nveu16_t ctlr, nveu16_t *kt_idx)
{
struct osi_macsec_lut_config lut_config = {0};
struct osi_macsec_table_config *table_config;
nve32_t ret, i;
#ifdef MACSEC_KEY_PROGRAM
struct osi_macsec_kt_config kt_config = {0};
#endif /* MACSEC_KEY_PROGRAM */
#ifdef MACSEC_KEY_PROGRAM
/* HKEY GENERATION */
struct crypto_cipher *tfm;
nveu8_t hkey[OSI_KEY_LEN_128];
nveu8_t zeros[OSI_KEY_LEN_128] = {0};
tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
if (crypto_cipher_setkey(tfm, sc->sak, OSI_KEY_LEN_128)) {
pr_err("%s: Failed to set cipher key for H generation",
__func__);
return -1;
}
crypto_cipher_encrypt_one(tfm, hkey, zeros);
pr_err("\n%s: Generated H key: ", __func__);
for (i = 0; i < OSI_KEY_LEN_128; i++) {
pr_cont(" %02x", hkey[i]);
}
pr_err("\n");
crypto_free_cipher(tfm);
#endif /* MACSEC_KEY_PROGRAM */
/* Store key table index returned to osd */
*kt_idx = (sc->sc_idx_start * OSI_MAX_NUM_SA) + sc->curr_an;
#ifdef MACSEC_KEY_PROGRAM
/* 1. Key LUT */
table_config = &kt_config.table_config;
table_config->ctlr_sel = ctlr;
table_config->rw = OSI_LUT_WRITE;
/* Each SC has OSI_MAX_NUM_SA's supported in HW */
table_config->index = *kt_idx;
kt_config.flags |= OSI_LUT_FLAGS_ENTRY_VALID;
/* Program in reverse order as per HW design */
for (i = 0; i < OSI_KEY_LEN_128; i++) {
kt_config.entry.sak[i] = sc->sak[OSI_KEY_LEN_128 - 1 - i];
kt_config.entry.h[i] = hkey[OSI_KEY_LEN_128 - 1 - i];
}
ret = macsec_kt_config(osi_core, &kt_config);
if (ret < 0) {
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"Failed to set SAK\n", ret);
return -1;
}
#endif /* MACSEC_KEY_PROGRAM */
table_config = &lut_config.table_config;
table_config->ctlr_sel = ctlr;
table_config->rw = OSI_LUT_WRITE;
/* 2. SA state LUT */
lut_config.lut_sel = OSI_LUT_SEL_SA_STATE;
table_config->index = (sc->sc_idx_start * OSI_MAX_NUM_SA) + sc->curr_an;
lut_config.sa_state_out.next_pn = sc->next_pn;
lut_config.sa_state_out.lowest_pn = sc->lowest_pn;
lut_config.flags |= OSI_LUT_FLAGS_ENTRY_VALID;
ret = macsec_lut_config(osi_core, &lut_config);
if (ret < 0) {
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"Failed to set SA state\n", ret);
goto err_sa_state;
}
/* 3. SC state LUT */
lut_config.flags = OSI_NONE;
lut_config.lut_sel = OSI_LUT_SEL_SC_STATE;
table_config->index = sc->sc_idx_start;
lut_config.sc_state_out.curr_an = sc->curr_an;
ret = macsec_lut_config(osi_core, &lut_config);
if (ret < 0) {
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"Failed to set SC state\n", ret);
goto err_sc_state;
}
/* 4. SC param LUT */
lut_config.flags = OSI_NONE;
lut_config.lut_sel = OSI_LUT_SEL_SC_PARAM;
table_config->index = sc->sc_idx_start;
/* Program in reverse order as per HW design */
for (i = 0; i < OSI_SCI_LEN; i++) {
lut_config.sc_param_out.sci[i] = sc->sci[OSI_SCI_LEN - 1 - i];
}
lut_config.sc_param_out.key_index_start =
(sc->sc_idx_start * OSI_MAX_NUM_SA);
lut_config.sc_param_out.pn_max = OSI_PN_MAX_DEFAULT;
lut_config.sc_param_out.pn_threshold = OSI_PN_THRESHOLD_DEFAULT;
lut_config.sc_param_out.pn_window = sc->pn_window;
lut_config.sc_param_out.tci = OSI_TCI_DEFAULT;
lut_config.sc_param_out.vlan_in_clear = OSI_VLAN_IN_CLEAR_DEFAULT;
ret = macsec_lut_config(osi_core, &lut_config);
if (ret < 0) {
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"Failed to set SC param\n", ret);
goto err_sc_param;
}
/* 5. SCI LUT */
lut_config.flags = OSI_NONE;
lut_config.lut_sel = OSI_LUT_SEL_SCI;
table_config->index = sc->sc_idx_start;
/* Program in reverse order as per HW design */
for (i = 0; i < OSI_ETH_ALEN; i++) {
/* Extract the mac sa from the SCI itself */
lut_config.lut_in.sa[i] = sc->sci[OSI_ETH_ALEN - 1 - i];
}
lut_config.flags |= OSI_LUT_FLAGS_SA_VALID;
lut_config.sci_lut_out.sc_index = sc->sc_idx_start;
for (i = 0; i < OSI_SCI_LEN; i++) {
lut_config.sci_lut_out.sci[i] = sc->sci[OSI_SCI_LEN - 1 - i];
}
lut_config.sci_lut_out.an_valid = sc->an_valid;
lut_config.flags |= OSI_LUT_FLAGS_ENTRY_VALID;
ret = macsec_lut_config(osi_core, &lut_config);
if (ret < 0) {
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"Failed to set SCI LUT\n", ret);
goto err_sci;
}
return 0;
err_sci:
/* cleanup SC param */
osi_memset(&lut_config, 0, sizeof(lut_config));
table_config = &lut_config.table_config;
table_config->ctlr_sel = ctlr;
lut_config.lut_sel = OSI_LUT_SEL_SC_PARAM;
table_config->index = sc->sc_idx_start;
macsec_lut_config(osi_core, &lut_config);
err_sc_param:
/* cleanup SC state */
osi_memset(&lut_config, 0, sizeof(lut_config));
table_config = &lut_config.table_config;
table_config->ctlr_sel = ctlr;
lut_config.lut_sel = OSI_LUT_SEL_SC_STATE;
table_config->index = sc->sc_idx_start;
macsec_lut_config(osi_core, &lut_config);
err_sc_state:
/* Cleanup SA state LUT */
osi_memset(&lut_config, 0, sizeof(lut_config));
table_config = &lut_config.table_config;
table_config->ctlr_sel = ctlr;
table_config->rw = OSI_LUT_WRITE;
lut_config.lut_sel = OSI_LUT_SEL_SA_STATE;
table_config->index = (sc->sc_idx_start * OSI_MAX_NUM_SA) + sc->curr_an;
macsec_lut_config(osi_core, &lut_config);
err_sa_state:
#ifdef MACSEC_KEY_PROGRAM
osi_memset(&kt_config, 0, sizeof(kt_config));
table_config = &kt_config.table_config;
table_config->ctlr_sel = ctlr;
table_config->rw = OSI_LUT_WRITE;
table_config->index = *kt_idx;
macsec_kt_config(osi_core, &kt_config);
#endif /* MACSEC_KEY_PROGRAM */
return -1;
}
static nve32_t macsec_config(struct osi_core_priv_data *const osi_core,
struct osi_macsec_sc_info *const sc,
nveu32_t enable, nveu16_t ctlr,
nveu16_t *kt_idx)
{
struct osi_macsec_sc_info *existing_sc = OSI_NULL, *new_sc = OSI_NULL;
struct osi_macsec_sc_info tmp_sc;
struct osi_macsec_sc_info *tmp_sc_p = &tmp_sc;
struct osi_macsec_lut_status *lut_status;
nve32_t i;
/* Validate inputs */
if ((enable != OSI_ENABLE && enable != OSI_DISABLE) ||
(ctlr != OSI_CTLR_SEL_TX && ctlr != OSI_CTLR_SEL_RX) ||
(kt_idx == OSI_NULL)) {
return -1;
}
lut_status = &osi_core->macsec_lut_status[ctlr];
/* 1. Find if SC is already existing in HW */
existing_sc = find_existing_sc(osi_core, sc, ctlr);
if (existing_sc == OSI_NULL) {
if (enable == OSI_DISABLE) {
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"trying to delete non-existing SC ?\n",
0ULL);
return -1;
} else {
pr_err("%s: Adding new SC/SA: ctlr: %hu", __func__,
ctlr);
if (lut_status->next_sc_idx >= OSI_MAX_NUM_SC) {
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"Err: Reached max SC LUT entries!\n", 0ULL);
return -1;
}
new_sc = &lut_status->sc_info[lut_status->next_sc_idx];
osi_memcpy(new_sc->sci, sc->sci, OSI_SCI_LEN);
osi_memcpy(new_sc->sak, sc->sak, OSI_KEY_LEN_128);
new_sc->curr_an = sc->curr_an;
new_sc->next_pn = sc->next_pn;
new_sc->pn_window = sc->pn_window;
new_sc->sc_idx_start = lut_status->next_sc_idx;
new_sc->an_valid |= OSI_BIT(sc->curr_an);
pr_err("%s: Adding new SC\n"
"\tsci: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n"
"\tan: %u\n"
"\tpn: %u"
"\tsc_idx_start: %u"
"\tan_valid: %#x \tpn_window: %#x", __func__,
new_sc->sci[0], new_sc->sci[1], new_sc->sci[2],
new_sc->sci[3], new_sc->sci[4], new_sc->sci[5],
new_sc->sci[6], new_sc->sci[7],
new_sc->curr_an, new_sc->next_pn,
new_sc->sc_idx_start,
new_sc->an_valid, new_sc->pn_window);
pr_err("\tkey: ");
for (i = 0; i < OSI_KEY_LEN_128; i++) {
pr_cont(" %02x", new_sc->sak[i]);
}
pr_err("");
if (add_upd_sc(osi_core, new_sc, ctlr, kt_idx) !=
OSI_NONE) {
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"failed to add new SC\n", 0ULL);
return -1;
} else {
/* Update lut status */
lut_status->next_sc_idx++;
pr_err("%s: Added new SC ctlr: %u "
"nxt_sc_idx: %u",
__func__, ctlr,
lut_status->next_sc_idx);
return 0;
}
}
} else {
pr_err("%s: Updating existing SC", __func__);
if (enable == OSI_DISABLE) {
pr_err("%s: Deleting existing SA", __func__);
if (del_upd_sc(osi_core, existing_sc, sc, ctlr, kt_idx) !=
OSI_NONE) {
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"failed to del SA\n", 0ULL);
return -1;
} else {
if (existing_sc->an_valid == OSI_NONE) {
lut_status->next_sc_idx--;
osi_memset(existing_sc, OSI_NONE,
sizeof(*existing_sc));
}
return 0;
}
} else {
/* Take backup copy.
* Don't directly commit SC changes until LUT's are
* programmed successfully
*/
*tmp_sc_p = *existing_sc;
osi_memcpy(tmp_sc_p->sak, sc->sak, OSI_KEY_LEN_128);
tmp_sc_p->curr_an = sc->curr_an;
tmp_sc_p->next_pn = sc->next_pn;
tmp_sc_p->pn_window = sc->pn_window;
tmp_sc_p->an_valid |= OSI_BIT(sc->curr_an);
pr_err("%s: Adding new SA to SC\n"
"\tsci: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n"
"\tan: %u\n"
"\tpn: %u"
"\tsc_idx_start: %u"
"\tan_valid: %#x \tpn_window: %#x", __func__,
tmp_sc_p->sci[0], tmp_sc_p->sci[1],
tmp_sc_p->sci[2], tmp_sc_p->sci[3],
tmp_sc_p->sci[4], tmp_sc_p->sci[5],
tmp_sc_p->sci[6], tmp_sc_p->sci[7],
tmp_sc_p->curr_an, tmp_sc_p->next_pn,
tmp_sc_p->sc_idx_start,
tmp_sc_p->an_valid, tmp_sc_p->pn_window);
pr_err("\tkey: ");
for (i = 0; i < OSI_KEY_LEN_128; i++) {
pr_cont(" %02x", tmp_sc_p->sak[i]);
}
pr_err("");
if (add_upd_sc(osi_core, tmp_sc_p, ctlr, kt_idx) !=
OSI_NONE) {
OSI_CORE_ERR(osi_core->osd, OSI_LOG_ARG_HW_FAIL,
"failed to add new SA\n", 0ULL);
return -1;
} else {
pr_err("%s: Updated new SC ctlr: %u "
"nxt_sc_idx: %u",
__func__, ctlr,
lut_status->next_sc_idx);
/* Now commit the changes */
*existing_sc = *tmp_sc_p;
return 0;
}
}
return -1;
}
}
static struct osi_macsec_core_ops macsec_ops = {
.init = macsec_init,
.deinit = macsec_deinit,
.handle_ns_irq = macsec_handle_ns_irq,
.handle_s_irq = macsec_handle_s_irq,
.lut_config = macsec_lut_config,
#ifdef MACSEC_KEY_PROGRAM
.kt_config = macsec_kt_config,
#endif /* MACSEC_KEY_PROGRAM */
.cipher_config = macsec_cipher_config,
.loopback_config = macsec_loopback_config,
.macsec_en = macsec_enable,
.config = macsec_config,
.read_mmc = macsec_read_mmc,
.dbg_buf_config = macsec_dbg_buf_config,
.dbg_events_config = macsec_dbg_events_config,
.get_sc_lut_key_index = macsec_get_sc_lut_key_index,
};
/**
* @brief if_ops - Static core interface operations for virtual
* case
*/
static struct osi_macsec_core_ops virt_macsec_ops;
static struct osi_macsec_lut_status lut_status[OSI_NUM_CTLR];
nve32_t osi_init_macsec_ops(struct osi_core_priv_data *const osi_core)
{
if (osi_core->use_virtualization == OSI_ENABLE) {
osi_core->macsec_ops = &virt_macsec_ops;
ivc_init_macsec_ops(osi_core->macsec_ops);
} else {
if (osi_core->macsec_base == OSI_NULL) {
return -1;
}
osi_core->macsec_ops = &macsec_ops;
}
osi_core->macsec_lut_status = lut_status;
return 0;
}
nve32_t osi_macsec_init(struct osi_core_priv_data *const osi_core)
{
if (osi_core != OSI_NULL && osi_core->macsec_ops != OSI_NULL &&
osi_core->macsec_ops->init != OSI_NULL) {
return osi_core->macsec_ops->init(osi_core);
}
return -1;
}
nve32_t osi_macsec_deinit(struct osi_core_priv_data *const osi_core)
{
if (osi_core != OSI_NULL && osi_core->macsec_ops != OSI_NULL &&
osi_core->macsec_ops->deinit != OSI_NULL) {
return osi_core->macsec_ops->deinit(osi_core);
}
return -1;
}
void osi_macsec_ns_isr(struct osi_core_priv_data *const osi_core)
{
if (osi_core != OSI_NULL && osi_core->macsec_ops != OSI_NULL &&
osi_core->macsec_ops->handle_ns_irq != OSI_NULL) {
osi_core->macsec_ops->handle_ns_irq(osi_core);
}
}
void osi_macsec_s_isr(struct osi_core_priv_data *const osi_core)
{
if (osi_core != OSI_NULL && osi_core->macsec_ops != OSI_NULL &&
osi_core->macsec_ops->handle_s_irq != OSI_NULL) {
osi_core->macsec_ops->handle_s_irq(osi_core);
}
}
nve32_t osi_macsec_lut_config(struct osi_core_priv_data *const osi_core,
struct osi_macsec_lut_config *const lut_config)
{
if (osi_core != OSI_NULL && osi_core->macsec_ops != OSI_NULL &&
osi_core->macsec_ops->lut_config != OSI_NULL) {
return osi_core->macsec_ops->lut_config(osi_core, lut_config);
}
return -1;
}
nve32_t osi_macsec_get_sc_lut_key_index(struct osi_core_priv_data *const osi_core,
nveu8_t *sci, nve32_t *key_index,
nveu16_t ctlr)
{
if (osi_core != OSI_NULL && osi_core->macsec_ops != OSI_NULL &&
osi_core->macsec_ops->get_sc_lut_key_index != OSI_NULL) {
return osi_core->macsec_ops->get_sc_lut_key_index(osi_core, sci, key_index,
ctlr);
}
return -1;
}
#ifdef MACSEC_KEY_PROGRAM
nve32_t osi_macsec_kt_config(struct osi_core_priv_data *const osi_core,
struct osi_macsec_kt_config *const kt_config)
{
if (osi_core != OSI_NULL && osi_core->macsec_ops != OSI_NULL &&
osi_core->macsec_ops->kt_config != OSI_NULL &&
kt_config != OSI_NULL) {
return osi_core->macsec_ops->kt_config(osi_core, kt_config);
}
return -1;
}
#endif /* MACSEC_KEY_PROGRAM */
nve32_t osi_macsec_cipher_config(struct osi_core_priv_data *const osi_core,
nveu32_t cipher)
{
if (osi_core != OSI_NULL && osi_core->macsec_ops != OSI_NULL &&
osi_core->macsec_ops->cipher_config != OSI_NULL) {
return osi_core->macsec_ops->cipher_config(osi_core, cipher);
}
return -1;
}
nve32_t osi_macsec_loopback(struct osi_core_priv_data *const osi_core,
nveu32_t enable)
{
if (osi_core != OSI_NULL && osi_core->macsec_ops != OSI_NULL &&
osi_core->macsec_ops->loopback_config != OSI_NULL) {
return osi_core->macsec_ops->loopback_config(osi_core, enable);
}
return -1;
}
nve32_t osi_macsec_en(struct osi_core_priv_data *const osi_core,
nveu32_t enable)
{
if (((enable & OSI_MACSEC_TX_EN) != OSI_MACSEC_TX_EN) &&
((enable & OSI_MACSEC_RX_EN) != OSI_MACSEC_RX_EN) &&
(enable != OSI_DISABLE)) {
return -1;
}
if (osi_core != OSI_NULL && osi_core->macsec_ops != OSI_NULL &&
osi_core->macsec_ops->macsec_en != OSI_NULL) {
return osi_core->macsec_ops->macsec_en(osi_core, enable);
}
return -1;
}
nve32_t osi_macsec_config(struct osi_core_priv_data *const osi_core,
struct osi_macsec_sc_info *const sc,
nveu32_t enable, nveu16_t ctlr,
nveu16_t *kt_idx)
{
if ((enable != OSI_ENABLE && enable != OSI_DISABLE) ||
(ctlr != OSI_CTLR_SEL_TX && ctlr != OSI_CTLR_SEL_RX) ||
(kt_idx == OSI_NULL)) {
return -1;
}
if (osi_core != OSI_NULL && osi_core->macsec_ops != OSI_NULL &&
osi_core->macsec_ops->config != OSI_NULL && sc != OSI_NULL) {
return osi_core->macsec_ops->config(osi_core, sc,
enable, ctlr, kt_idx);
}
return -1;
}
nve32_t osi_macsec_read_mmc(struct osi_core_priv_data *const osi_core)
{
if (osi_core != OSI_NULL && osi_core->macsec_ops != OSI_NULL &&
osi_core->macsec_ops->read_mmc != OSI_NULL) {
osi_core->macsec_ops->read_mmc(osi_core);
return 0;
}
return -1;
}
nve32_t osi_macsec_dbg_buf_config(
struct osi_core_priv_data *const osi_core,
struct osi_macsec_dbg_buf_config *const dbg_buf_config)
{
if (osi_core != OSI_NULL && osi_core->macsec_ops != OSI_NULL &&
osi_core->macsec_ops->dbg_buf_config != OSI_NULL) {
return osi_core->macsec_ops->dbg_buf_config(osi_core,
dbg_buf_config);
}
return -1;
}
nve32_t osi_macsec_dbg_events_config(
struct osi_core_priv_data *const osi_core,
struct osi_macsec_dbg_buf_config *const dbg_buf_config)
{
if (osi_core != OSI_NULL && osi_core->macsec_ops != OSI_NULL &&
osi_core->macsec_ops->dbg_events_config != OSI_NULL) {
return osi_core->macsec_ops->dbg_events_config(osi_core,
dbg_buf_config);
}
return -1;
}