278 lines
7.0 KiB
C
278 lines
7.0 KiB
C
|
// SPDX-License-Identifier: GPL-2.0
|
||
|
/* Marvell MCS driver
|
||
|
*
|
||
|
* Copyright (C) 2022 Marvell.
|
||
|
*/
|
||
|
|
||
|
#include "mcs.h"
|
||
|
#include "mcs_reg.h"
|
||
|
|
||
|
static struct mcs_ops cnf10kb_mcs_ops = {
|
||
|
.mcs_set_hw_capabilities = cnf10kb_mcs_set_hw_capabilities,
|
||
|
.mcs_parser_cfg = cnf10kb_mcs_parser_cfg,
|
||
|
.mcs_tx_sa_mem_map_write = cnf10kb_mcs_tx_sa_mem_map_write,
|
||
|
.mcs_rx_sa_mem_map_write = cnf10kb_mcs_rx_sa_mem_map_write,
|
||
|
.mcs_flowid_secy_map = cnf10kb_mcs_flowid_secy_map,
|
||
|
.mcs_bbe_intr_handler = cnf10kb_mcs_bbe_intr_handler,
|
||
|
.mcs_pab_intr_handler = cnf10kb_mcs_pab_intr_handler,
|
||
|
};
|
||
|
|
||
|
struct mcs_ops *cnf10kb_get_mac_ops(void)
|
||
|
{
|
||
|
return &cnf10kb_mcs_ops;
|
||
|
}
|
||
|
|
||
|
void cnf10kb_mcs_set_hw_capabilities(struct mcs *mcs)
|
||
|
{
|
||
|
struct hwinfo *hw = mcs->hw;
|
||
|
|
||
|
hw->tcam_entries = 64; /* TCAM entries */
|
||
|
hw->secy_entries = 64; /* SecY entries */
|
||
|
hw->sc_entries = 64; /* SC CAM entries */
|
||
|
hw->sa_entries = 128; /* SA entries */
|
||
|
hw->lmac_cnt = 4; /* lmacs/ports per mcs block */
|
||
|
hw->mcs_x2p_intf = 1; /* x2p clabration intf */
|
||
|
hw->mcs_blks = 7; /* MCS blocks */
|
||
|
hw->ip_vec = MCS_CNF10KB_INT_VEC_IP; /* IP vector */
|
||
|
}
|
||
|
|
||
|
void cnf10kb_mcs_parser_cfg(struct mcs *mcs)
|
||
|
{
|
||
|
u64 reg, val;
|
||
|
|
||
|
/* VLAN Ctag */
|
||
|
val = (0x8100ull & 0xFFFF) | BIT_ULL(20) | BIT_ULL(22);
|
||
|
|
||
|
reg = MCSX_PEX_RX_SLAVE_CUSTOM_TAGX(0);
|
||
|
mcs_reg_write(mcs, reg, val);
|
||
|
|
||
|
reg = MCSX_PEX_TX_SLAVE_CUSTOM_TAGX(0);
|
||
|
mcs_reg_write(mcs, reg, val);
|
||
|
|
||
|
/* VLAN STag */
|
||
|
val = (0x88a8ull & 0xFFFF) | BIT_ULL(20) | BIT_ULL(23);
|
||
|
|
||
|
/* RX */
|
||
|
reg = MCSX_PEX_RX_SLAVE_CUSTOM_TAGX(1);
|
||
|
mcs_reg_write(mcs, reg, val);
|
||
|
|
||
|
/* TX */
|
||
|
reg = MCSX_PEX_TX_SLAVE_CUSTOM_TAGX(1);
|
||
|
mcs_reg_write(mcs, reg, val);
|
||
|
|
||
|
/* Enable custom tage 0 and 1 and sectag */
|
||
|
val = BIT_ULL(0) | BIT_ULL(1) | BIT_ULL(12);
|
||
|
|
||
|
reg = MCSX_PEX_RX_SLAVE_ETYPE_ENABLE;
|
||
|
mcs_reg_write(mcs, reg, val);
|
||
|
|
||
|
reg = MCSX_PEX_TX_SLAVE_ETYPE_ENABLE;
|
||
|
mcs_reg_write(mcs, reg, val);
|
||
|
}
|
||
|
|
||
|
void cnf10kb_mcs_flowid_secy_map(struct mcs *mcs, struct secy_mem_map *map, int dir)
|
||
|
{
|
||
|
u64 reg, val;
|
||
|
|
||
|
val = (map->secy & 0x3F) | (map->ctrl_pkt & 0x1) << 6;
|
||
|
if (dir == MCS_RX) {
|
||
|
reg = MCSX_CPM_RX_SLAVE_SECY_MAP_MEMX(map->flow_id);
|
||
|
} else {
|
||
|
reg = MCSX_CPM_TX_SLAVE_SECY_MAP_MEM_0X(map->flow_id);
|
||
|
mcs_reg_write(mcs, reg, map->sci);
|
||
|
val |= (map->sc & 0x3F) << 7;
|
||
|
reg = MCSX_CPM_TX_SLAVE_SECY_MAP_MEM_1X(map->flow_id);
|
||
|
}
|
||
|
|
||
|
mcs_reg_write(mcs, reg, val);
|
||
|
}
|
||
|
|
||
|
void cnf10kb_mcs_tx_sa_mem_map_write(struct mcs *mcs, struct mcs_tx_sc_sa_map *map)
|
||
|
{
|
||
|
u64 reg, val;
|
||
|
|
||
|
val = (map->sa_index0 & 0x7F) | (map->sa_index1 & 0x7F) << 7;
|
||
|
|
||
|
reg = MCSX_CPM_TX_SLAVE_SA_MAP_MEM_0X(map->sc_id);
|
||
|
mcs_reg_write(mcs, reg, val);
|
||
|
|
||
|
reg = MCSX_CPM_TX_SLAVE_AUTO_REKEY_ENABLE_0;
|
||
|
val = mcs_reg_read(mcs, reg);
|
||
|
|
||
|
if (map->rekey_ena)
|
||
|
val |= BIT_ULL(map->sc_id);
|
||
|
else
|
||
|
val &= ~BIT_ULL(map->sc_id);
|
||
|
|
||
|
mcs_reg_write(mcs, reg, val);
|
||
|
|
||
|
mcs_reg_write(mcs, MCSX_CPM_TX_SLAVE_SA_INDEX0_VLDX(map->sc_id), map->sa_index0_vld);
|
||
|
mcs_reg_write(mcs, MCSX_CPM_TX_SLAVE_SA_INDEX1_VLDX(map->sc_id), map->sa_index1_vld);
|
||
|
|
||
|
mcs_reg_write(mcs, MCSX_CPM_TX_SLAVE_TX_SA_ACTIVEX(map->sc_id), map->tx_sa_active);
|
||
|
}
|
||
|
|
||
|
void cnf10kb_mcs_rx_sa_mem_map_write(struct mcs *mcs, struct mcs_rx_sc_sa_map *map)
|
||
|
{
|
||
|
u64 val, reg;
|
||
|
|
||
|
val = (map->sa_index & 0x7F) | (map->sa_in_use << 7);
|
||
|
|
||
|
reg = MCSX_CPM_RX_SLAVE_SA_MAP_MEMX((4 * map->sc_id) + map->an);
|
||
|
mcs_reg_write(mcs, reg, val);
|
||
|
}
|
||
|
|
||
|
int mcs_set_force_clk_en(struct mcs *mcs, bool set)
|
||
|
{
|
||
|
unsigned long timeout = jiffies + usecs_to_jiffies(2000);
|
||
|
u64 val;
|
||
|
|
||
|
val = mcs_reg_read(mcs, MCSX_MIL_GLOBAL);
|
||
|
|
||
|
if (set) {
|
||
|
val |= BIT_ULL(4);
|
||
|
mcs_reg_write(mcs, MCSX_MIL_GLOBAL, val);
|
||
|
|
||
|
/* Poll till mcsx_mil_ip_gbl_status.mcs_ip_stats_ready value is 1 */
|
||
|
while (!(mcs_reg_read(mcs, MCSX_MIL_IP_GBL_STATUS) & BIT_ULL(0))) {
|
||
|
if (time_after(jiffies, timeout)) {
|
||
|
dev_err(mcs->dev, "MCS set force clk enable failed\n");
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
val &= ~BIT_ULL(4);
|
||
|
mcs_reg_write(mcs, MCSX_MIL_GLOBAL, val);
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/* TX SA interrupt is raised only if autorekey is enabled.
|
||
|
* MCS_CPM_TX_SLAVE_SA_MAP_MEM_0X[sc].tx_sa_active bit gets toggled if
|
||
|
* one of two SAs mapped to SC gets expired. If tx_sa_active=0 implies
|
||
|
* SA in SA_index1 got expired else SA in SA_index0 got expired.
|
||
|
*/
|
||
|
void cnf10kb_mcs_tx_pn_thresh_reached_handler(struct mcs *mcs)
|
||
|
{
|
||
|
struct mcs_intr_event event;
|
||
|
struct rsrc_bmap *sc_bmap;
|
||
|
unsigned long rekey_ena;
|
||
|
u64 val, sa_status;
|
||
|
int sc;
|
||
|
|
||
|
sc_bmap = &mcs->tx.sc;
|
||
|
|
||
|
event.mcs_id = mcs->mcs_id;
|
||
|
event.intr_mask = MCS_CPM_TX_PN_THRESH_REACHED_INT;
|
||
|
|
||
|
rekey_ena = mcs_reg_read(mcs, MCSX_CPM_TX_SLAVE_AUTO_REKEY_ENABLE_0);
|
||
|
|
||
|
for_each_set_bit(sc, sc_bmap->bmap, mcs->hw->sc_entries) {
|
||
|
/* Auto rekey is enable */
|
||
|
if (!test_bit(sc, &rekey_ena))
|
||
|
continue;
|
||
|
sa_status = mcs_reg_read(mcs, MCSX_CPM_TX_SLAVE_TX_SA_ACTIVEX(sc));
|
||
|
/* Check if tx_sa_active status had changed */
|
||
|
if (sa_status == mcs->tx_sa_active[sc])
|
||
|
continue;
|
||
|
|
||
|
/* SA_index0 is expired */
|
||
|
val = mcs_reg_read(mcs, MCSX_CPM_TX_SLAVE_SA_MAP_MEM_0X(sc));
|
||
|
if (sa_status)
|
||
|
event.sa_id = val & 0x7F;
|
||
|
else
|
||
|
event.sa_id = (val >> 7) & 0x7F;
|
||
|
|
||
|
event.pcifunc = mcs->tx.sa2pf_map[event.sa_id];
|
||
|
mcs_add_intr_wq_entry(mcs, &event);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void cnf10kb_mcs_tx_pn_wrapped_handler(struct mcs *mcs)
|
||
|
{
|
||
|
struct mcs_intr_event event = { 0 };
|
||
|
struct rsrc_bmap *sc_bmap;
|
||
|
u64 val;
|
||
|
int sc;
|
||
|
|
||
|
sc_bmap = &mcs->tx.sc;
|
||
|
|
||
|
event.mcs_id = mcs->mcs_id;
|
||
|
event.intr_mask = MCS_CPM_TX_PACKET_XPN_EQ0_INT;
|
||
|
|
||
|
for_each_set_bit(sc, sc_bmap->bmap, mcs->hw->sc_entries) {
|
||
|
val = mcs_reg_read(mcs, MCSX_CPM_TX_SLAVE_SA_MAP_MEM_0X(sc));
|
||
|
|
||
|
if (mcs->tx_sa_active[sc])
|
||
|
/* SA_index1 was used and got expired */
|
||
|
event.sa_id = (val >> 7) & 0x7F;
|
||
|
else
|
||
|
/* SA_index0 was used and got expired */
|
||
|
event.sa_id = val & 0x7F;
|
||
|
|
||
|
event.pcifunc = mcs->tx.sa2pf_map[event.sa_id];
|
||
|
mcs_add_intr_wq_entry(mcs, &event);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void cnf10kb_mcs_bbe_intr_handler(struct mcs *mcs, u64 intr,
|
||
|
enum mcs_direction dir)
|
||
|
{
|
||
|
struct mcs_intr_event event = { 0 };
|
||
|
int i;
|
||
|
|
||
|
if (!(intr & MCS_BBE_INT_MASK))
|
||
|
return;
|
||
|
|
||
|
event.mcs_id = mcs->mcs_id;
|
||
|
event.pcifunc = mcs->pf_map[0];
|
||
|
|
||
|
for (i = 0; i < MCS_MAX_BBE_INT; i++) {
|
||
|
if (!(intr & BIT_ULL(i)))
|
||
|
continue;
|
||
|
|
||
|
/* Lower nibble denotes data fifo overflow interrupts and
|
||
|
* upper nibble indicates policy fifo overflow interrupts.
|
||
|
*/
|
||
|
if (intr & 0xFULL)
|
||
|
event.intr_mask = (dir == MCS_RX) ?
|
||
|
MCS_BBE_RX_DFIFO_OVERFLOW_INT :
|
||
|
MCS_BBE_TX_DFIFO_OVERFLOW_INT;
|
||
|
else
|
||
|
event.intr_mask = (dir == MCS_RX) ?
|
||
|
MCS_BBE_RX_PLFIFO_OVERFLOW_INT :
|
||
|
MCS_BBE_TX_PLFIFO_OVERFLOW_INT;
|
||
|
|
||
|
/* Notify the lmac_id info which ran into BBE fatal error */
|
||
|
event.lmac_id = i & 0x3ULL;
|
||
|
mcs_add_intr_wq_entry(mcs, &event);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void cnf10kb_mcs_pab_intr_handler(struct mcs *mcs, u64 intr,
|
||
|
enum mcs_direction dir)
|
||
|
{
|
||
|
struct mcs_intr_event event = { 0 };
|
||
|
int i;
|
||
|
|
||
|
if (!(intr & MCS_PAB_INT_MASK))
|
||
|
return;
|
||
|
|
||
|
event.mcs_id = mcs->mcs_id;
|
||
|
event.pcifunc = mcs->pf_map[0];
|
||
|
|
||
|
for (i = 0; i < MCS_MAX_PAB_INT; i++) {
|
||
|
if (!(intr & BIT_ULL(i)))
|
||
|
continue;
|
||
|
|
||
|
event.intr_mask = (dir == MCS_RX) ?
|
||
|
MCS_PAB_RX_CHAN_OVERFLOW_INT :
|
||
|
MCS_PAB_TX_CHAN_OVERFLOW_INT;
|
||
|
|
||
|
/* Notify the lmac_id info which ran into PAB fatal error */
|
||
|
event.lmac_id = i;
|
||
|
mcs_add_intr_wq_entry(mcs, &event);
|
||
|
}
|
||
|
}
|