blob: da21f2276832cc0f9a7fd842945d9bc6235e7c58 [file] [log] [blame]
/*
* Copyright (c) 2012, 2016, The Linux Foundation. All rights reserved.
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all copies.
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/**
* @defgroup isis_fdb ISIS_FDB
* @{
*/
#include "sw.h"
#include "hsl.h"
#include "hsl_dev.h"
#include "hsl_port_prop.h"
#include "isis_fdb.h"
#include "isis_reg.h"
#define ARL_FLUSH_ALL 1
#define ARL_LOAD_ENTRY 2
#define ARL_PURGE_ENTRY 3
#define ARL_FLUSH_ALL_UNLOCK 4
#define ARL_FLUSH_PORT_UNICAST 5
#define ARL_NEXT_ENTRY 6
#define ARL_FIND_ENTRY 7
#define ARL_TRANSFER_ENTRY 8
#define ARL_FIRST_ENTRY 1001
#define ARL_FLUSH_PORT_NO_STATIC 1002
#define ARL_FLUSH_PORT_AND_STATIC 1003
#define ISIS_MAX_FID 4095
#define ISIS_MAX_LEARN_LIMIT_CNT 2047
#define ISIS_MAX_PORT_LEARN_LIMIT_CNT 1023
static sw_error_t
_isis_wl_feature_check(a_uint32_t dev_id)
{
sw_error_t rv;
a_uint32_t entry = 0;
HSL_REG_FIELD_GET(rv, dev_id, MASK_CTL, 0, DEVICE_ID,
(a_uint8_t *) (&entry), sizeof (a_uint32_t));
SW_RTN_ON_ERROR(rv);
if (S17_DEVICE_ID == entry)
{
return SW_OK;
}
else
{
return SW_NOT_SUPPORTED;
}
}
static a_bool_t
_isis_fdb_is_zeroaddr(fal_mac_addr_t addr)
{
a_uint32_t i;
for (i = 0; i < 6; i++)
{
if (addr.uc[i])
{
return A_FALSE;
}
}
return A_TRUE;
}
static void
_isis_fdb_fill_addr(fal_mac_addr_t addr, a_uint32_t * reg0, a_uint32_t * reg1)
{
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC1, AT_ADDR_BYTE0, addr.uc[0], *reg1);
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC1, AT_ADDR_BYTE1, addr.uc[1], *reg1);
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC0, AT_ADDR_BYTE2, addr.uc[2], *reg0);
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC0, AT_ADDR_BYTE3, addr.uc[3], *reg0);
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC0, AT_ADDR_BYTE4, addr.uc[4], *reg0);
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC0, AT_ADDR_BYTE5, addr.uc[5], *reg0);
return;
}
static sw_error_t
_isis_atu_sw_to_hw(a_uint32_t dev_id, const fal_fdb_entry_t * entry,
a_uint32_t reg[])
{
a_uint32_t port;
sw_error_t rv;
if (A_TRUE == entry->white_list_en)
{
rv = _isis_wl_feature_check(dev_id);
SW_RTN_ON_ERROR(rv);
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC2, WL_EN, 1, reg[2]);
}
if (FAL_SVL_FID == entry->fid)
{
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC2, AT_VID, 0, reg[2]);
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC1, AT_SVL_EN, 1, reg[1]);
}
else if (ISIS_MAX_FID >= entry->fid)
{
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC2, AT_VID, (entry->fid), reg[2]);
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC1, AT_SVL_EN, 0, reg[1]);
}
else
{
return SW_BAD_PARAM;
}
if (A_FALSE == entry->portmap_en)
{
if (A_TRUE !=
hsl_port_prop_check(dev_id, entry->port.id, HSL_PP_INCL_CPU))
{
return SW_BAD_PARAM;
}
port = 0x1UL << entry->port.id;
}
else
{
if (A_FALSE ==
hsl_mports_prop_check(dev_id, entry->port.map, HSL_PP_INCL_CPU))
{
return SW_BAD_PARAM;
}
port = entry->port.map;
}
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC1, DES_PORT, port, reg[1]);
if (FAL_MAC_CPY_TO_CPU == entry->dacmd)
{
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC2, COPY_TO_CPU, 1, reg[2]);
}
else if (FAL_MAC_RDT_TO_CPU == entry->dacmd)
{
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC2, REDRCT_TO_CPU, 1, reg[2]);
}
else if (FAL_MAC_FRWRD != entry->dacmd)
{
return SW_NOT_SUPPORTED;
}
if (A_TRUE == entry->leaky_en)
{
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC2, LEAKY_EN, 1, reg[2]);
}
else
{
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC2, LEAKY_EN, 0, reg[2]);
}
if (A_TRUE == entry->static_en)
{
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC2, AT_STATUS, 15, reg[2]);
}
else
{
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC2, AT_STATUS, 7, reg[2]);
}
if (FAL_MAC_DROP == entry->sacmd)
{
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC1, SA_DROP_EN, 1, reg[1]);
}
else if (FAL_MAC_FRWRD != entry->sacmd)
{
return SW_NOT_SUPPORTED;
}
if (A_TRUE == entry->mirror_en)
{
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC1, MIRROR_EN, 1, reg[1]);
}
if (A_TRUE == entry->cross_pt_state)
{
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC1, CROSS_PT, 1, reg[1]);
}
else
{
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC1, CROSS_PT, 0, reg[1]);
}
if (A_TRUE == entry->da_pri_en)
{
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC1, AT_PRI_EN, 1, reg[1]);
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC1, AT_PRI, (entry->da_queue & 0x7),
reg[1]);
}
else
{
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC1, AT_PRI_EN, 0, reg[1]);
}
_isis_fdb_fill_addr(entry->addr, &reg[0], &reg[1]);
return SW_OK;
}
static void
_isis_atu_hw_to_sw(const a_uint32_t reg[], fal_fdb_entry_t * entry)
{
a_uint32_t i, data;
aos_mem_zero(entry, sizeof (fal_fdb_entry_t));
SW_GET_FIELD_BY_REG(ADDR_TABLE_FUNC1, AT_SVL_EN, data, reg[1]);
if (data)
{
entry->fid = FAL_SVL_FID;
}
else
{
SW_GET_FIELD_BY_REG(ADDR_TABLE_FUNC2, AT_VID, data, reg[2]);
entry->fid = data;
}
entry->dacmd = FAL_MAC_FRWRD;
SW_GET_FIELD_BY_REG(ADDR_TABLE_FUNC2, COPY_TO_CPU, data, reg[2]);
if (1 == data)
{
entry->dacmd = FAL_MAC_CPY_TO_CPU;
}
SW_GET_FIELD_BY_REG(ADDR_TABLE_FUNC2, REDRCT_TO_CPU, data, reg[2]);
if (1 == data)
{
entry->dacmd = FAL_MAC_RDT_TO_CPU;
}
entry->sacmd = FAL_MAC_FRWRD;
SW_GET_FIELD_BY_REG(ADDR_TABLE_FUNC1, SA_DROP_EN, data, reg[1]);
if (1 == data)
{
entry->sacmd = FAL_MAC_DROP;
}
entry->leaky_en = A_FALSE;
SW_GET_FIELD_BY_REG(ADDR_TABLE_FUNC2, LEAKY_EN, data, reg[2]);
if (1 == data)
{
entry->leaky_en = A_TRUE;
}
entry->static_en = A_FALSE;
SW_GET_FIELD_BY_REG(ADDR_TABLE_FUNC2, AT_STATUS, data, reg[2]);
if (0xf == data)
{
entry->static_en = A_TRUE;
}
entry->mirror_en = A_FALSE;
SW_GET_FIELD_BY_REG(ADDR_TABLE_FUNC1, MIRROR_EN, data, reg[1]);
if (1 == data)
{
entry->mirror_en = A_TRUE;
}
entry->da_pri_en = A_FALSE;
SW_GET_FIELD_BY_REG(ADDR_TABLE_FUNC1, AT_PRI_EN, data, reg[1]);
if (1 == data)
{
SW_GET_FIELD_BY_REG(ADDR_TABLE_FUNC1, AT_PRI, data, reg[1]);
entry->da_pri_en = A_TRUE;
entry->da_queue = data & 0x7;
}
entry->cross_pt_state = A_FALSE;
SW_GET_FIELD_BY_REG(ADDR_TABLE_FUNC1, CROSS_PT, data, reg[1]);
if (1 == data)
{
entry->cross_pt_state = A_TRUE;
}
SW_GET_FIELD_BY_REG(ADDR_TABLE_FUNC1, DES_PORT, data, reg[1]);
entry->portmap_en = A_TRUE;
entry->port.map = data;
for (i = 2; i < 6; i++)
{
entry->addr.uc[i] = (reg[0] >> ((5 - i) << 3)) & 0xff;
}
for (i = 0; i < 2; i++)
{
entry->addr.uc[i] = (reg[1] >> ((1 - i) << 3)) & 0xff;
}
entry->white_list_en = A_FALSE;
SW_GET_FIELD_BY_REG(ADDR_TABLE_FUNC2, WL_EN, data, reg[2]);
if (1 == data)
{
entry->white_list_en = A_TRUE;
}
return;
}
static sw_error_t
_isis_atu_down_to_hw(a_uint32_t dev_id, a_uint32_t reg[])
{
sw_error_t rv;
HSL_REG_ENTRY_SET(rv, dev_id, ADDR_TABLE_FUNC0, 0,
(a_uint8_t *) (&reg[0]), sizeof (a_uint32_t));
SW_RTN_ON_ERROR(rv);
HSL_REG_ENTRY_SET(rv, dev_id, ADDR_TABLE_FUNC1, 0,
(a_uint8_t *) (&reg[1]), sizeof (a_uint32_t));
SW_RTN_ON_ERROR(rv);
HSL_REG_ENTRY_SET(rv, dev_id, ADDR_TABLE_FUNC2, 0,
(a_uint8_t *) (&reg[2]), sizeof (a_uint32_t));
SW_RTN_ON_ERROR(rv);
HSL_REG_ENTRY_SET(rv, dev_id, ADDR_TABLE_FUNC3, 0,
(a_uint8_t *) (&reg[3]), sizeof (a_uint32_t));
return rv;
}
static sw_error_t
_isis_atu_up_to_sw(a_uint32_t dev_id, a_uint32_t reg[])
{
sw_error_t rv;
HSL_REG_ENTRY_GET(rv, dev_id, ADDR_TABLE_FUNC0, 0,
(a_uint8_t *) (&reg[0]), sizeof (a_uint32_t));
SW_RTN_ON_ERROR(rv);
HSL_REG_ENTRY_GET(rv, dev_id, ADDR_TABLE_FUNC1, 0,
(a_uint8_t *) (&reg[1]), sizeof (a_uint32_t));
SW_RTN_ON_ERROR(rv);
HSL_REG_ENTRY_GET(rv, dev_id, ADDR_TABLE_FUNC2, 0,
(a_uint8_t *) (&reg[2]), sizeof (a_uint32_t));
SW_RTN_ON_ERROR(rv);
HSL_REG_ENTRY_GET(rv, dev_id, ADDR_TABLE_FUNC3, 0,
(a_uint8_t *) (&reg[3]), sizeof (a_uint32_t));
return rv;
}
static sw_error_t
_isis_fdb_commit(a_uint32_t dev_id, a_uint32_t op)
{
sw_error_t rv;
a_uint32_t busy = 1;
a_uint32_t full_vio;
a_uint32_t i = 2000;
a_uint32_t entry = 0;
a_uint32_t hwop = op;
while (busy && --i)
{
HSL_REG_ENTRY_GET(rv, dev_id, ADDR_TABLE_FUNC3, 0,
(a_uint8_t *) (&entry), sizeof (a_uint32_t));
SW_RTN_ON_ERROR(rv);
SW_GET_FIELD_BY_REG(ADDR_TABLE_FUNC3, AT_BUSY, busy, entry);
aos_udelay(5);
}
if (0 == i)
{
printk("%s BUSY\n", __FUNCTION__);
return SW_BUSY;
}
if (ARL_FIRST_ENTRY == op)
{
hwop = ARL_NEXT_ENTRY;
}
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC3, AT_BUSY, 1, entry);
if (ARL_FLUSH_PORT_AND_STATIC == hwop)
{
hwop = ARL_FLUSH_PORT_UNICAST;
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC3, FLUSH_ST_EN, 1, entry);
}
if (ARL_FLUSH_PORT_NO_STATIC == hwop)
{
hwop = ARL_FLUSH_PORT_UNICAST;
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC3, FLUSH_ST_EN, 0, entry);
}
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC3, AT_FUNC, hwop, entry);
HSL_REG_ENTRY_SET(rv, dev_id, ADDR_TABLE_FUNC3, 0,
(a_uint8_t *) (&entry), sizeof (a_uint32_t));
SW_RTN_ON_ERROR(rv);
busy = 1;
i = 2000;
while (busy && --i)
{
HSL_REG_ENTRY_GET(rv, dev_id, ADDR_TABLE_FUNC3, 0,
(a_uint8_t *) (&entry), sizeof (a_uint32_t));
SW_RTN_ON_ERROR(rv);
SW_GET_FIELD_BY_REG(ADDR_TABLE_FUNC3, AT_BUSY, busy, entry);
}
if (0 == i)
{
return SW_FAIL;
}
SW_GET_FIELD_BY_REG(ADDR_TABLE_FUNC3, AT_FULL_VIO, full_vio, entry);
if (full_vio)
{
/* must clear AT_FULL_VOI bit */
entry = 0x1000;
HSL_REG_ENTRY_SET(rv, dev_id, ADDR_TABLE_FUNC3, 0,
(a_uint8_t *) (&entry), sizeof (a_uint32_t));
SW_RTN_ON_ERROR(rv);
if (ARL_LOAD_ENTRY == hwop)
{
return SW_FULL;
}
else if ((ARL_PURGE_ENTRY == hwop)
|| (ARL_FLUSH_PORT_UNICAST == hwop))
{
return SW_NOT_FOUND;
}
else
{
return SW_FAIL;
}
}
return SW_OK;
}
static sw_error_t
_isis_fdb_get(a_uint32_t dev_id, fal_fdb_op_t * option, fal_fdb_entry_t * entry,
a_uint32_t hwop)
{
sw_error_t rv;
a_uint32_t i, port = 0, status, reg[4] = { 0 };
HSL_DEV_ID_CHECK(dev_id);
if (A_TRUE == option->port_en)
{
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC3, AT_PORT_EN, 1, reg[3]);
if (A_FALSE == entry->portmap_en)
{
if (A_TRUE !=
hsl_port_prop_check(dev_id, entry->port.id, HSL_PP_INCL_CPU))
{
return SW_BAD_PARAM;
}
port = entry->port.id;
}
else
{
if (A_FALSE ==
hsl_mports_prop_check(dev_id, entry->port.map,
HSL_PP_INCL_CPU))
{
return SW_BAD_PARAM;
}
status = 0;
for (i = 0; i < SW_MAX_NR_PORT; i++)
{
if ((entry->port.map) & (0x1UL << i))
{
if (status)
{
return SW_BAD_PARAM;
}
port = i;
status = 1;
}
}
}
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC3, AT_PORT_NUM, port, reg[3]);
}
if (A_TRUE == option->fid_en)
{
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC3, AT_VID_EN, 1, reg[3]);
}
if (A_TRUE == option->multicast_en)
{
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC3, AT_MULTI_EN, 1, reg[3]);
}
if (FAL_SVL_FID == entry->fid)
{
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC2, AT_VID, 0, reg[2]);
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC1, AT_SVL_EN, 1, reg[1]);
}
else if (ISIS_MAX_FID >= entry->fid)
{
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC2, AT_VID, entry->fid, reg[2]);
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC1, AT_SVL_EN, 0, reg[1]);
}
else
{
return SW_BAD_PARAM;
}
if (ARL_FIRST_ENTRY != hwop)
{
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC2, AT_STATUS, 0xf, reg[2]);
}
_isis_fdb_fill_addr(entry->addr, &reg[0], &reg[1]);
rv = _isis_atu_down_to_hw(dev_id, reg);
SW_RTN_ON_ERROR(rv);
rv = _isis_fdb_commit(dev_id, hwop);
SW_RTN_ON_ERROR(rv);
rv = _isis_atu_up_to_sw(dev_id, reg);
SW_RTN_ON_ERROR(rv);
_isis_atu_hw_to_sw(reg, entry);
SW_GET_FIELD_BY_REG(ADDR_TABLE_FUNC2, AT_STATUS, status, reg[2]);
if ((A_TRUE == _isis_fdb_is_zeroaddr(entry->addr))
&& (0 == status))
{
if (ARL_NEXT_ENTRY == hwop)
{
return SW_NO_MORE;
}
else
{
return SW_NOT_FOUND;
}
}
else
{
return SW_OK;
}
return SW_OK;
}
static sw_error_t
_isis_fdb_add(a_uint32_t dev_id, const fal_fdb_entry_t * entry)
{
sw_error_t rv;
a_uint32_t reg[4] = { 0 };
HSL_DEV_ID_CHECK(dev_id);
rv = _isis_atu_sw_to_hw(dev_id, entry, reg);
SW_RTN_ON_ERROR(rv);
rv = _isis_atu_down_to_hw(dev_id, reg);
SW_RTN_ON_ERROR(rv);
rv = _isis_fdb_commit(dev_id, ARL_LOAD_ENTRY);
return rv;
}
static sw_error_t
_isis_fdb_del_all(a_uint32_t dev_id, a_uint32_t flag)
{
sw_error_t rv;
HSL_DEV_ID_CHECK(dev_id);
if (FAL_FDB_DEL_STATIC & flag)
{
rv = _isis_fdb_commit(dev_id, ARL_FLUSH_ALL);
}
else
{
rv = _isis_fdb_commit(dev_id, ARL_FLUSH_ALL_UNLOCK);
}
return rv;
}
static sw_error_t
_isis_fdb_del_by_port(a_uint32_t dev_id, fal_port_t port_id, a_uint32_t flag)
{
sw_error_t rv;
a_uint32_t reg = 0;
HSL_DEV_ID_CHECK(dev_id);
if (A_FALSE == hsl_port_prop_check(dev_id, port_id, HSL_PP_INCL_CPU))
{
return SW_BAD_PARAM;
}
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC3, AT_PORT_NUM, port_id, reg);
HSL_REG_ENTRY_SET(rv, dev_id, ADDR_TABLE_FUNC3, 0, (a_uint8_t *) (&reg),
sizeof (a_uint32_t));
SW_RTN_ON_ERROR(rv);
if (FAL_FDB_DEL_STATIC & flag)
{
rv = _isis_fdb_commit(dev_id, ARL_FLUSH_PORT_AND_STATIC);
}
else
{
rv = _isis_fdb_commit(dev_id, ARL_FLUSH_PORT_NO_STATIC);
}
return rv;
}
static sw_error_t
_isis_fdb_del_by_mac(a_uint32_t dev_id, const fal_fdb_entry_t * entry)
{
sw_error_t rv;
a_uint32_t reg0 = 0, reg1 = 0, reg2 = 0;
HSL_DEV_ID_CHECK(dev_id);
_isis_fdb_fill_addr(entry->addr, &reg0, &reg1);
if (FAL_SVL_FID == entry->fid)
{
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC2, AT_VID, 0, reg2);
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC1, AT_SVL_EN, 1, reg1);
}
else if (ISIS_MAX_FID >= entry->fid)
{
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC2, AT_VID, (entry->fid), reg2);
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC1, AT_SVL_EN, 0, reg1);
}
else
{
return SW_BAD_PARAM;
}
HSL_REG_ENTRY_SET(rv, dev_id, ADDR_TABLE_FUNC2, 0, (a_uint8_t *) (&reg2),
sizeof (a_uint32_t));
SW_RTN_ON_ERROR(rv);
HSL_REG_ENTRY_SET(rv, dev_id, ADDR_TABLE_FUNC1, 0, (a_uint8_t *) (&reg1),
sizeof (a_uint32_t));
SW_RTN_ON_ERROR(rv);
HSL_REG_ENTRY_SET(rv, dev_id, ADDR_TABLE_FUNC0, 0, (a_uint8_t *) (&reg0),
sizeof (a_uint32_t));
SW_RTN_ON_ERROR(rv);
rv = _isis_fdb_commit(dev_id, ARL_PURGE_ENTRY);
return rv;
}
static sw_error_t
_isis_fdb_find(a_uint32_t dev_id, fal_fdb_entry_t * entry)
{
sw_error_t rv;
fal_fdb_op_t option;
aos_mem_zero(&option, sizeof (fal_fdb_op_t));
rv = _isis_fdb_get(dev_id, &option, entry, ARL_FIND_ENTRY);
return rv;
}
static sw_error_t
_isis_fdb_extend_next(a_uint32_t dev_id, fal_fdb_op_t * option,
fal_fdb_entry_t * entry)
{
sw_error_t rv;
rv = _isis_fdb_get(dev_id, option, entry, ARL_NEXT_ENTRY);
return rv;
}
static sw_error_t
_isis_fdb_extend_first(a_uint32_t dev_id, fal_fdb_op_t * option,
fal_fdb_entry_t * entry)
{
sw_error_t rv;
rv = _isis_fdb_get(dev_id, option, entry, ARL_FIRST_ENTRY);
return rv;
}
static sw_error_t
_isis_fdb_transfer(a_uint32_t dev_id, fal_port_t old_port, fal_port_t new_port,
a_uint32_t fid, fal_fdb_op_t * option)
{
sw_error_t rv;
a_uint32_t reg[4] = { 0 };
if (A_TRUE == option->port_en)
{
return SW_NOT_SUPPORTED;
}
if (A_TRUE == option->fid_en)
{
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC3, AT_VID_EN, 1, reg[3]);
}
if (A_TRUE == option->multicast_en)
{
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC3, AT_MULTI_EN, 1, reg[3]);
}
if (FAL_SVL_FID == fid)
{
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC2, AT_VID, 0, reg[2]);
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC1, AT_SVL_EN, 1, reg[1]);
}
else if (ISIS_MAX_FID >= fid)
{
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC2, AT_VID, fid, reg[2]);
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC1, AT_SVL_EN, 0, reg[1]);
}
else
{
return SW_BAD_PARAM;
}
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC3, AT_PORT_NUM, old_port, reg[3]);
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC3, NEW_PORT_NUM, new_port, reg[3]);
rv = _isis_atu_down_to_hw(dev_id, reg);
SW_RTN_ON_ERROR(rv);
rv = _isis_fdb_commit(dev_id, ARL_TRANSFER_ENTRY);
return rv;
}
static sw_error_t
_isis_fdb_port_learn_set(a_uint32_t dev_id, fal_port_t port_id, a_bool_t enable)
{
a_uint32_t data;
sw_error_t rv;
HSL_DEV_ID_CHECK(dev_id);
if (A_TRUE != hsl_port_prop_check(dev_id, port_id, HSL_PP_INCL_CPU))
{
return SW_BAD_PARAM;
}
if (A_TRUE == enable)
{
data = 1;
}
else if (A_FALSE == enable)
{
data = 0;
}
else
{
return SW_BAD_PARAM;
}
HSL_REG_FIELD_SET(rv, dev_id, PORT_LOOKUP_CTL, port_id, LEARN_EN,
(a_uint8_t *) (&data), sizeof (a_uint32_t));
return rv;
}
static sw_error_t
_isis_fdb_port_learn_get(a_uint32_t dev_id, fal_port_t port_id,
a_bool_t * enable)
{
a_uint32_t data = 0;
sw_error_t rv;
HSL_DEV_ID_CHECK(dev_id);
if (A_TRUE != hsl_port_prop_check(dev_id, port_id, HSL_PP_INCL_CPU))
{
return SW_BAD_PARAM;
}
HSL_REG_FIELD_GET(rv, dev_id, PORT_LOOKUP_CTL, port_id, LEARN_EN,
(a_uint8_t *) (&data), sizeof (a_uint32_t));
SW_RTN_ON_ERROR(rv);
if (1 == data)
{
*enable = A_TRUE;
}
else
{
*enable = A_FALSE;
}
return SW_OK;
}
static sw_error_t
_isis_fdb_age_ctrl_set(a_uint32_t dev_id, a_bool_t enable)
{
a_uint32_t data;
sw_error_t rv;
HSL_DEV_ID_CHECK(dev_id);
if (A_TRUE == enable)
{
data = 1;
}
else if (A_FALSE == enable)
{
data = 0;
}
else
{
return SW_BAD_PARAM;
}
HSL_REG_FIELD_SET(rv, dev_id, ADDR_TABLE_CTL, 0, AGE_EN,
(a_uint8_t *) (&data), sizeof (a_uint32_t));
return rv;
}
static sw_error_t
_isis_fdb_age_ctrl_get(a_uint32_t dev_id, a_bool_t * enable)
{
a_uint32_t data = 0;
sw_error_t rv;
HSL_DEV_ID_CHECK(dev_id);
HSL_REG_FIELD_GET(rv, dev_id, ADDR_TABLE_CTL, 0, AGE_EN,
(a_uint8_t *) (&data), sizeof (a_uint32_t));
SW_RTN_ON_ERROR(rv);
if (1 == data)
{
*enable = A_TRUE;
}
else
{
*enable = A_FALSE;
}
return SW_OK;
}
static sw_error_t
_isis_fdb_age_time_set(a_uint32_t dev_id, a_uint32_t * time)
{
a_uint32_t data;
sw_error_t rv;
HSL_DEV_ID_CHECK(dev_id);
if ((65535 * 7 < *time) || (7 > *time))
{
return SW_BAD_PARAM;
}
data = *time / 7;
*time = data * 7;
HSL_REG_FIELD_SET(rv, dev_id, ADDR_TABLE_CTL, 0, AGE_TIME,
(a_uint8_t *) (&data), sizeof (a_uint32_t));
return rv;
}
static sw_error_t
_isis_fdb_age_time_get(a_uint32_t dev_id, a_uint32_t * time)
{
a_uint32_t data = 0;
sw_error_t rv;
HSL_DEV_ID_CHECK(dev_id);
HSL_REG_FIELD_GET(rv, dev_id, ADDR_TABLE_CTL, 0, AGE_TIME,
(a_uint8_t *) (&data), sizeof (a_uint32_t));
SW_RTN_ON_ERROR(rv);
*time = data * 7;
return SW_OK;
}
static sw_error_t
_isis_port_fdb_learn_limit_set(a_uint32_t dev_id, fal_port_t port_id,
a_bool_t enable, a_uint32_t cnt)
{
sw_error_t rv;
a_uint32_t reg = 0;
HSL_DEV_ID_CHECK(dev_id);
if (A_TRUE != hsl_port_prop_check(dev_id, port_id, HSL_PP_INCL_CPU))
{
return SW_BAD_PARAM;
}
HSL_REG_ENTRY_GET(rv, dev_id, PORT_LEARN_LIMIT_CTL, port_id,
(a_uint8_t *) (&reg), sizeof (a_uint32_t));
SW_RTN_ON_ERROR(rv);
if (A_TRUE == enable)
{
if (ISIS_MAX_PORT_LEARN_LIMIT_CNT < cnt)
{
return SW_BAD_PARAM;
}
SW_SET_REG_BY_FIELD(PORT_LEARN_LIMIT_CTL, SA_LEARN_LIMIT_EN, 1, reg);
SW_SET_REG_BY_FIELD(PORT_LEARN_LIMIT_CTL, SA_LEARN_CNT, cnt, reg);
}
else if (A_FALSE == enable)
{
SW_SET_REG_BY_FIELD(PORT_LEARN_LIMIT_CTL, SA_LEARN_LIMIT_EN, 0, reg);
SW_SET_REG_BY_FIELD(PORT_LEARN_LIMIT_CTL, SA_LEARN_CNT, 0, reg);
}
else
{
return SW_BAD_PARAM;
}
HSL_REG_ENTRY_SET(rv, dev_id, PORT_LEARN_LIMIT_CTL, port_id,
(a_uint8_t *) (&reg), sizeof (a_uint32_t));
return rv;
}
static sw_error_t
_isis_port_fdb_learn_limit_get(a_uint32_t dev_id, fal_port_t port_id,
a_bool_t * enable, a_uint32_t * cnt)
{
sw_error_t rv;
a_uint32_t data, reg = 0;
HSL_DEV_ID_CHECK(dev_id);
if (A_TRUE != hsl_port_prop_check(dev_id, port_id, HSL_PP_INCL_CPU))
{
return SW_BAD_PARAM;
}
HSL_REG_ENTRY_GET(rv, dev_id, PORT_LEARN_LIMIT_CTL, port_id,
(a_uint8_t *) (&reg), sizeof (a_uint32_t));
SW_RTN_ON_ERROR(rv);
SW_GET_FIELD_BY_REG(PORT_LEARN_LIMIT_CTL, SA_LEARN_LIMIT_EN, data, reg);
if (data)
{
SW_GET_FIELD_BY_REG(PORT_LEARN_LIMIT_CTL, SA_LEARN_CNT, data, reg);
*enable = A_TRUE;
*cnt = data;
}
else
{
*enable = A_FALSE;
*cnt = 0;
}
return SW_OK;
}
static sw_error_t
_isis_port_fdb_learn_exceed_cmd_set(a_uint32_t dev_id, fal_port_t port_id,
fal_fwd_cmd_t cmd)
{
sw_error_t rv;
a_uint32_t data = 0;
HSL_DEV_ID_CHECK(dev_id);
if (A_TRUE != hsl_port_prop_check(dev_id, port_id, HSL_PP_INCL_CPU))
{
return SW_BAD_PARAM;
}
if (FAL_MAC_DROP == cmd)
{
data = 1;
}
else if (FAL_MAC_RDT_TO_CPU == cmd)
{
data = 0;
}
else
{
return SW_NOT_SUPPORTED;
}
HSL_REG_FIELD_SET(rv, dev_id, PORT_LEARN_LIMIT_CTL, port_id,
SA_LEARN_LIMIT_DROP_EN, (a_uint8_t *) (&data),
sizeof (a_uint32_t));
return rv;
}
static sw_error_t
_isis_port_fdb_learn_exceed_cmd_get(a_uint32_t dev_id, fal_port_t port_id,
fal_fwd_cmd_t * cmd)
{
sw_error_t rv;
a_uint32_t data = 0;
HSL_DEV_ID_CHECK(dev_id);
if (A_TRUE != hsl_port_prop_check(dev_id, port_id, HSL_PP_INCL_CPU))
{
return SW_BAD_PARAM;
}
HSL_REG_FIELD_GET(rv, dev_id, PORT_LEARN_LIMIT_CTL, port_id,
SA_LEARN_LIMIT_DROP_EN, (a_uint8_t *) (&data),
sizeof (a_uint32_t));
SW_RTN_ON_ERROR(rv);
if (data)
{
*cmd = FAL_MAC_DROP;
}
else
{
*cmd = FAL_MAC_RDT_TO_CPU;
}
return SW_OK;
}
static sw_error_t
_isis_fdb_learn_limit_set(a_uint32_t dev_id, a_bool_t enable, a_uint32_t cnt)
{
sw_error_t rv;
a_uint32_t reg = 0;
HSL_REG_ENTRY_GET(rv, dev_id, GLOBAL_LEARN_LIMIT_CTL, 0,
(a_uint8_t *) (&reg), sizeof (a_uint32_t));
SW_RTN_ON_ERROR(rv);
if (A_TRUE == enable)
{
if (ISIS_MAX_LEARN_LIMIT_CNT < cnt)
{
return SW_BAD_PARAM;
}
SW_SET_REG_BY_FIELD(GLOBAL_LEARN_LIMIT_CTL, GOL_SA_LEARN_LIMIT_EN, 1,
reg);
SW_SET_REG_BY_FIELD(GLOBAL_LEARN_LIMIT_CTL, GOL_SA_LEARN_CNT, cnt, reg);
}
else if (A_FALSE == enable)
{
SW_SET_REG_BY_FIELD(GLOBAL_LEARN_LIMIT_CTL, GOL_SA_LEARN_LIMIT_EN, 0,
reg);
SW_SET_REG_BY_FIELD(GLOBAL_LEARN_LIMIT_CTL, GOL_SA_LEARN_CNT, 0, reg);
}
else
{
return SW_BAD_PARAM;
}
HSL_REG_ENTRY_SET(rv, dev_id, GLOBAL_LEARN_LIMIT_CTL, 0,
(a_uint8_t *) (&reg), sizeof (a_uint32_t));
return rv;
}
static sw_error_t
_isis_fdb_learn_limit_get(a_uint32_t dev_id, a_bool_t * enable,
a_uint32_t * cnt)
{
sw_error_t rv;
a_uint32_t data, reg = 0;
HSL_REG_ENTRY_GET(rv, dev_id, GLOBAL_LEARN_LIMIT_CTL, 0,
(a_uint8_t *) (&reg), sizeof (a_uint32_t));
SW_RTN_ON_ERROR(rv);
SW_GET_FIELD_BY_REG(GLOBAL_LEARN_LIMIT_CTL, GOL_SA_LEARN_LIMIT_EN, data,
reg);
if (data)
{
SW_GET_FIELD_BY_REG(GLOBAL_LEARN_LIMIT_CTL, GOL_SA_LEARN_CNT, data,
reg);
*enable = A_TRUE;
*cnt = data;
}
else
{
*enable = A_FALSE;
*cnt = 0;
}
return SW_OK;
}
static sw_error_t
_isis_fdb_learn_exceed_cmd_set(a_uint32_t dev_id, fal_fwd_cmd_t cmd)
{
sw_error_t rv;
a_uint32_t data = 0;
HSL_DEV_ID_CHECK(dev_id);
if (FAL_MAC_DROP == cmd)
{
data = 1;
}
else if (FAL_MAC_RDT_TO_CPU == cmd)
{
data = 0;
}
else
{
return SW_NOT_SUPPORTED;
}
HSL_REG_FIELD_SET(rv, dev_id, GLOBAL_LEARN_LIMIT_CTL, 0,
GOL_SA_LEARN_LIMIT_DROP_EN, (a_uint8_t *) (&data),
sizeof (a_uint32_t));
return rv;
}
static sw_error_t
_isis_fdb_learn_exceed_cmd_get(a_uint32_t dev_id, fal_fwd_cmd_t * cmd)
{
sw_error_t rv;
a_uint32_t data = 0;
HSL_DEV_ID_CHECK(dev_id);
HSL_REG_FIELD_GET(rv, dev_id, GLOBAL_LEARN_LIMIT_CTL, 0,
GOL_SA_LEARN_LIMIT_DROP_EN, (a_uint8_t *) (&data),
sizeof (a_uint32_t));
SW_RTN_ON_ERROR(rv);
if (data)
{
*cmd = FAL_MAC_DROP;
}
else
{
*cmd = FAL_MAC_RDT_TO_CPU;
}
return SW_OK;
}
#define ISIS_RESV_ADDR_NUM 32
#define RESV_ADDR_TBL0_ADDR 0x3c000
#define RESV_ADDR_TBL1_ADDR 0x3c004
#define RESV_ADDR_TBL2_ADDR 0x3c008
static void
_isis_resv_addr_parse(const a_uint32_t reg[], fal_mac_addr_t * addr)
{
a_uint32_t i;
for (i = 2; i < 6; i++)
{
addr->uc[i] = (reg[0] >> ((5 - i) << 3)) & 0xff;
}
for (i = 0; i < 2; i++)
{
addr->uc[i] = (reg[1] >> ((1 - i) << 3)) & 0xff;
}
}
static sw_error_t
_isis_resv_atu_sw_to_hw(a_uint32_t dev_id, fal_fdb_entry_t * entry,
a_uint32_t reg[])
{
a_uint32_t port;
if (A_FALSE == entry->portmap_en)
{
if (A_TRUE !=
hsl_port_prop_check(dev_id, entry->port.id, HSL_PP_INCL_CPU))
{
return SW_BAD_PARAM;
}
port = 0x1UL << entry->port.id;
}
else
{
if (A_FALSE ==
hsl_mports_prop_check(dev_id, entry->port.map, HSL_PP_INCL_CPU))
{
return SW_BAD_PARAM;
}
port = entry->port.map;
}
SW_SET_REG_BY_FIELD(RESV_ADDR_TBL1, RESV_DES_PORT, port, reg[1]);
if (FAL_MAC_CPY_TO_CPU == entry->dacmd)
{
SW_SET_REG_BY_FIELD(RESV_ADDR_TBL1, RESV_COPY_TO_CPU, 1, reg[1]);
}
else if (FAL_MAC_RDT_TO_CPU == entry->dacmd)
{
SW_SET_REG_BY_FIELD(RESV_ADDR_TBL1, RESV_REDRCT_TO_CPU, 1, reg[1]);
}
else if (FAL_MAC_FRWRD != entry->dacmd)
{
return SW_NOT_SUPPORTED;
}
if (FAL_MAC_FRWRD != entry->sacmd)
{
return SW_NOT_SUPPORTED;
}
if (A_TRUE == entry->leaky_en)
{
SW_SET_REG_BY_FIELD(RESV_ADDR_TBL1, RESV_LEAKY_EN, 1, reg[1]);
}
else
{
SW_SET_REG_BY_FIELD(RESV_ADDR_TBL1, RESV_LEAKY_EN, 0, reg[1]);
}
if (A_TRUE != entry->static_en)
{
return SW_NOT_SUPPORTED;
}
SW_SET_REG_BY_FIELD(RESV_ADDR_TBL2, RESV_STATUS, 1, reg[2]);
if (A_TRUE == entry->mirror_en)
{
SW_SET_REG_BY_FIELD(RESV_ADDR_TBL1, RESV_MIRROR_EN, 1, reg[1]);
}
if (A_TRUE == entry->cross_pt_state)
{
SW_SET_REG_BY_FIELD(RESV_ADDR_TBL1, RESV_CROSS_PT, 1, reg[1]);
}
if (A_TRUE == entry->da_pri_en)
{
SW_SET_REG_BY_FIELD(RESV_ADDR_TBL1, RESV_PRI_EN, 1, reg[1]);
SW_SET_REG_BY_FIELD(RESV_ADDR_TBL1, RESV_PRI, (entry->da_queue & 0x7),
reg[1]);
}
_isis_fdb_fill_addr(entry->addr, &reg[0], &reg[1]);
return SW_OK;
}
static void
_isis_resv_atu_hw_to_sw(const a_uint32_t reg[], fal_fdb_entry_t * entry)
{
a_uint32_t data;
aos_mem_zero(entry, sizeof (fal_fdb_entry_t));
entry->fid = FAL_SVL_FID;
entry->dacmd = FAL_MAC_FRWRD;
SW_GET_FIELD_BY_REG(RESV_ADDR_TBL1, RESV_COPY_TO_CPU, data, reg[1]);
if (1 == data)
{
entry->dacmd = FAL_MAC_CPY_TO_CPU;
}
SW_GET_FIELD_BY_REG(RESV_ADDR_TBL1, RESV_REDRCT_TO_CPU, data, reg[1]);
if (1 == data)
{
entry->dacmd = FAL_MAC_RDT_TO_CPU;
}
entry->sacmd = FAL_MAC_FRWRD;
entry->leaky_en = A_FALSE;
SW_GET_FIELD_BY_REG(RESV_ADDR_TBL1, RESV_LEAKY_EN, data, reg[1]);
if (1 == data)
{
entry->leaky_en = A_TRUE;
}
entry->static_en = A_TRUE;
entry->mirror_en = A_FALSE;
SW_GET_FIELD_BY_REG(RESV_ADDR_TBL1, RESV_MIRROR_EN, data, reg[1]);
if (1 == data)
{
entry->mirror_en = A_TRUE;
}
entry->da_pri_en = A_FALSE;
SW_GET_FIELD_BY_REG(RESV_ADDR_TBL1, RESV_PRI_EN, data, reg[1]);
if (1 == data)
{
SW_GET_FIELD_BY_REG(RESV_ADDR_TBL1, RESV_PRI, data, reg[1]);
entry->da_pri_en = A_TRUE;
entry->da_queue = data & 0x7;
}
entry->cross_pt_state = A_FALSE;
SW_GET_FIELD_BY_REG(RESV_ADDR_TBL1, RESV_CROSS_PT, data, reg[1]);
if (1 == data)
{
entry->cross_pt_state = A_TRUE;
}
SW_GET_FIELD_BY_REG(RESV_ADDR_TBL1, RESV_DES_PORT, data, reg[1]);
entry->portmap_en = A_TRUE;
entry->port.map = data;
_isis_resv_addr_parse(reg, &(entry->addr));
return;
}
static sw_error_t
_isis_fdb_resv_commit(a_uint32_t dev_id, fal_fdb_entry_t * entry, a_uint32_t op,
a_uint32_t * empty)
{
a_uint32_t index, addr, data, tbl[3] = { 0 };
sw_error_t rv;
fal_mac_addr_t mac_tmp;
*empty = ISIS_RESV_ADDR_NUM;
for (index = 0; index < ISIS_RESV_ADDR_NUM; index++)
{
addr = RESV_ADDR_TBL2_ADDR + (index << 4);
HSL_REG_ENTRY_GEN_GET(rv, dev_id, addr, sizeof (a_uint32_t),
(a_uint8_t *) (&(tbl[2])), sizeof (a_uint32_t));
SW_RTN_ON_ERROR(rv);
SW_GET_FIELD_BY_REG(RESV_ADDR_TBL2, RESV_STATUS, data, tbl[2]);
if (data)
{
addr = RESV_ADDR_TBL0_ADDR + (index << 4);
HSL_REG_ENTRY_GEN_GET(rv, dev_id, addr, sizeof (a_uint32_t),
(a_uint8_t *) (&(tbl[0])),
sizeof (a_uint32_t));
SW_RTN_ON_ERROR(rv);
addr = RESV_ADDR_TBL1_ADDR + (index << 4);
HSL_REG_ENTRY_GEN_GET(rv, dev_id, addr, sizeof (a_uint32_t),
(a_uint8_t *) (&(tbl[1])),
sizeof (a_uint32_t));
SW_RTN_ON_ERROR(rv);
_isis_resv_addr_parse(tbl, &mac_tmp);
if (!aos_mem_cmp
((void *) &(entry->addr), (void *) &mac_tmp,
sizeof (fal_mac_addr_t)))
{
if (ARL_PURGE_ENTRY == op)
{
addr = RESV_ADDR_TBL2_ADDR + (index << 4);
tbl[2] = 0;
HSL_REG_ENTRY_GEN_SET(rv, dev_id, addr, sizeof (a_uint32_t),
(a_uint8_t *) (&(tbl[2])),
sizeof (a_uint32_t));
return rv;
}
else if (ARL_LOAD_ENTRY == op)
{
return SW_ALREADY_EXIST;
}
else if (ARL_FIND_ENTRY == op)
{
_isis_resv_atu_hw_to_sw(tbl, entry);
return SW_OK;
}
}
}
else
{
*empty = index;
}
}
return SW_NOT_FOUND;
}
static sw_error_t
_isis_fdb_resv_add(a_uint32_t dev_id, fal_fdb_entry_t * entry)
{
sw_error_t rv;
a_uint32_t i, empty, addr, tbl[3] = { 0 };
rv = _isis_resv_atu_sw_to_hw(dev_id, entry, tbl);
SW_RTN_ON_ERROR(rv);
rv = _isis_fdb_resv_commit(dev_id, entry, ARL_LOAD_ENTRY, &empty);
if (SW_ALREADY_EXIST == rv)
{
return rv;
}
if (ISIS_RESV_ADDR_NUM == empty)
{
return SW_NO_RESOURCE;
}
for (i = 0; i < 3; i++)
{
addr = RESV_ADDR_TBL0_ADDR + (empty << 4) + (i << 2);
HSL_REG_ENTRY_GEN_SET(rv, dev_id, addr, sizeof (a_uint32_t),
(a_uint8_t *) (&(tbl[i])), sizeof (a_uint32_t));
SW_RTN_ON_ERROR(rv);
}
return SW_OK;
}
static sw_error_t
_isis_fdb_resv_del(a_uint32_t dev_id, fal_fdb_entry_t * entry)
{
sw_error_t rv;
a_uint32_t empty;
rv = _isis_fdb_resv_commit(dev_id, entry, ARL_PURGE_ENTRY, &empty);
return rv;
}
static sw_error_t
_isis_fdb_resv_find(a_uint32_t dev_id, fal_fdb_entry_t * entry)
{
sw_error_t rv;
a_uint32_t empty;
rv = _isis_fdb_resv_commit(dev_id, entry, ARL_FIND_ENTRY, &empty);
return rv;
}
static sw_error_t
_isis_fdb_resv_iterate(a_uint32_t dev_id, a_uint32_t * iterator,
fal_fdb_entry_t * entry)
{
a_uint32_t index, addr, data, tbl[3] = { 0 };
sw_error_t rv;
if ((NULL == iterator) || (NULL == entry))
{
return SW_BAD_PTR;
}
if (ISIS_RESV_ADDR_NUM < *iterator)
{
return SW_BAD_PARAM;
}
for (index = *iterator; index < ISIS_RESV_ADDR_NUM; index++)
{
addr = RESV_ADDR_TBL2_ADDR + (index << 4);
HSL_REG_ENTRY_GEN_GET(rv, dev_id, addr, sizeof (a_uint32_t),
(a_uint8_t *) (&(tbl[2])), sizeof (a_uint32_t));
SW_RTN_ON_ERROR(rv);
SW_GET_FIELD_BY_REG(RESV_ADDR_TBL2, RESV_STATUS, data, tbl[2]);
if (data)
{
addr = RESV_ADDR_TBL0_ADDR + (index << 4);
HSL_REG_ENTRY_GEN_GET(rv, dev_id, addr, sizeof (a_uint32_t),
(a_uint8_t *) (&(tbl[0])),
sizeof (a_uint32_t));
SW_RTN_ON_ERROR(rv);
addr = RESV_ADDR_TBL1_ADDR + (index << 4);
HSL_REG_ENTRY_GEN_GET(rv, dev_id, addr, sizeof (a_uint32_t),
(a_uint8_t *) (&(tbl[1])),
sizeof (a_uint32_t));
SW_RTN_ON_ERROR(rv);
_isis_resv_atu_hw_to_sw(tbl, entry);
break;
}
}
if (ISIS_RESV_ADDR_NUM == index)
{
return SW_NO_MORE;
}
*iterator = index + 1;
return SW_OK;
}
static sw_error_t
_isis_fdb_port_learn_static_set(a_uint32_t dev_id, fal_port_t port_id,
a_bool_t enable)
{
a_uint32_t data;
sw_error_t rv;
HSL_DEV_ID_CHECK(dev_id);
if (A_TRUE != hsl_port_prop_check(dev_id, port_id, HSL_PP_INCL_CPU))
{
return SW_BAD_PARAM;
}
if (A_TRUE == enable)
{
data = 0xf;
}
else if (A_FALSE == enable)
{
data = 0x7;
}
else
{
return SW_BAD_PARAM;
}
HSL_REG_FIELD_SET(rv, dev_id, PORT_LEARN_LIMIT_CTL, port_id,
SA_LEARN_STATUS, (a_uint8_t *) (&data),
sizeof (a_uint32_t));
return rv;
}
static sw_error_t
_isis_fdb_port_learn_static_get(a_uint32_t dev_id, fal_port_t port_id,
a_bool_t * enable)
{
a_uint32_t data = 0;
sw_error_t rv;
HSL_DEV_ID_CHECK(dev_id);
if (A_TRUE != hsl_port_prop_check(dev_id, port_id, HSL_PP_INCL_CPU))
{
return SW_BAD_PARAM;
}
HSL_REG_FIELD_GET(rv, dev_id, PORT_LEARN_LIMIT_CTL, port_id,
SA_LEARN_STATUS, (a_uint8_t *) (&data),
sizeof (a_uint32_t));
SW_RTN_ON_ERROR(rv);
if (0xf == data)
{
*enable = A_TRUE;
}
else
{
*enable = A_FALSE;
}
return SW_OK;
}
static sw_error_t
_isis_fdb_port_update(a_uint32_t dev_id, a_uint32_t fid, fal_mac_addr_t * addr, fal_port_t port_id, a_uint32_t op)
{
sw_error_t rv;
fal_fdb_entry_t entry;
fal_fdb_op_t option;
a_uint32_t reg, port;
HSL_DEV_ID_CHECK(dev_id);
if (FAL_SVL_FID < fid)
{
return SW_BAD_PARAM;
}
if (A_TRUE != hsl_port_prop_check(dev_id, port_id, HSL_PP_INCL_CPU))
{
return SW_BAD_PARAM;
}
aos_mem_zero(&option, sizeof(fal_fdb_op_t));
aos_mem_copy(&(entry.addr), addr, sizeof(fal_mac_addr_t));
entry.fid = fid & 0xffff;
rv = _isis_fdb_get(dev_id, &option, &entry, ARL_FIND_ENTRY);
SW_RTN_ON_ERROR(rv);
HSL_REG_ENTRY_GET(rv, dev_id, ADDR_TABLE_FUNC1, 0,
(a_uint8_t *) (&reg), sizeof (a_uint32_t));
SW_RTN_ON_ERROR(rv);
SW_GET_FIELD_BY_REG(ADDR_TABLE_FUNC1, DES_PORT, port, reg);
if (op)
{
port |= (0x1 << port_id);
}
else
{
port &= (~(0x1 << port_id));
}
SW_SET_REG_BY_FIELD(ADDR_TABLE_FUNC1, DES_PORT, port, reg);
HSL_REG_ENTRY_SET(rv, dev_id, ADDR_TABLE_FUNC1, 0,
(a_uint8_t *) (&reg), sizeof (a_uint32_t));
rv = _isis_fdb_commit(dev_id, ARL_LOAD_ENTRY);
return rv;
}
/**
* @brief Add a Fdb entry
* @param[in] dev_id device id
* @param[in] entry fdb entry
* @return SW_OK or error code
*/
HSL_LOCAL sw_error_t
isis_fdb_add(a_uint32_t dev_id, const fal_fdb_entry_t * entry)
{
sw_error_t rv;
HSL_API_LOCK;
rv = _isis_fdb_add(dev_id, entry);
HSL_API_UNLOCK;
return rv;
}
/**
* @brief Delete all Fdb entries
* @details Comments:
* If set FAL_FDB_DEL_STATIC bit in flag which means delete all fdb
* entries otherwise only delete dynamic entries.
* @param[in] dev_id device id
* @param[in] flag delete operation option
* @return SW_OK or error code
*/
HSL_LOCAL sw_error_t
isis_fdb_del_all(a_uint32_t dev_id, a_uint32_t flag)
{
sw_error_t rv;
HSL_API_LOCK;
rv = _isis_fdb_del_all(dev_id, flag);
HSL_API_UNLOCK;
return rv;
}
/**
* @brief Delete Fdb entries on a particular port
* @details Comments:
* If set FAL_FDB_DEL_STATIC bit in flag which means delete all fdb
* entries otherwise only delete dynamic entries.
* @param[in] dev_id device id
* @param[in] port_id port id
* @param[in] flag delete operation option
* @return SW_OK or error code
*/
HSL_LOCAL sw_error_t
isis_fdb_del_by_port(a_uint32_t dev_id, fal_port_t port_id, a_uint32_t flag)
{
sw_error_t rv;
HSL_API_LOCK;
rv = _isis_fdb_del_by_port(dev_id, port_id, flag);
HSL_API_UNLOCK;
return rv;
}
/**
* @brief Delete a particular Fdb entry through mac address
* @details Comments:
* Only addr field in entry is meaning. For IVL learning vid or fid field
* also is meaning.
* @param[in] dev_id device id
* @param[in] entry fdb entry
* @return SW_OK or error code
*/
HSL_LOCAL sw_error_t
isis_fdb_del_by_mac(a_uint32_t dev_id, const fal_fdb_entry_t * entry)
{
sw_error_t rv;
HSL_API_LOCK;
rv = _isis_fdb_del_by_mac(dev_id, entry);
HSL_API_UNLOCK;
return rv;
}
/**
* @brief Find a particular Fdb entry from device through mac address.
* @details Comments:
For input parameter only addr field in entry is meaning.
* @param[in] dev_id device id
* @param[in] entry fdb entry
* @param[out] entry fdb entry
* @return SW_OK or error code
*/
HSL_LOCAL sw_error_t
isis_fdb_find(a_uint32_t dev_id, fal_fdb_entry_t * entry)
{
sw_error_t rv;
HSL_API_LOCK;
rv = _isis_fdb_find(dev_id, entry);
HSL_API_UNLOCK;
return rv;
}
/**
* @brief Get next Fdb entry from a particular device
* @param[in] dev_id device id
* @param[in] option next operation options
* @param[out] entry fdb entry
* @return SW_OK or error code
*/
HSL_LOCAL sw_error_t
isis_fdb_extend_next(a_uint32_t dev_id, fal_fdb_op_t * option,
fal_fdb_entry_t * entry)
{
sw_error_t rv;
HSL_API_LOCK;
rv = _isis_fdb_extend_next(dev_id, option, entry);
HSL_API_UNLOCK;
return rv;
}
/**
* @brief Get first Fdb entry from a particular device
* @param[in] dev_id device id
* @param[in] option first operation options
* @param[out] entry fdb entry
* @return SW_OK or error code
*/
HSL_LOCAL sw_error_t
isis_fdb_extend_first(a_uint32_t dev_id, fal_fdb_op_t * option,
fal_fdb_entry_t * entry)
{
sw_error_t rv;
HSL_API_LOCK;
rv = _isis_fdb_extend_first(dev_id, option, entry);
HSL_API_UNLOCK;
return rv;
}
/**
* @brief Transfer fdb entries port information on a particular device.
* @param[in] dev_id device id
* @param[in] old_port source port id
* @param[in] new_port destination port id
* @param[in] fid filter database id
* @param[in] option transfer operation options
* @return SW_OK or error code
*/
HSL_LOCAL sw_error_t
isis_fdb_transfer(a_uint32_t dev_id, fal_port_t old_port, fal_port_t new_port,
a_uint32_t fid, fal_fdb_op_t * option)
{
sw_error_t rv;
HSL_API_LOCK;
rv = _isis_fdb_transfer(dev_id, old_port, new_port, fid, option);
HSL_API_UNLOCK;
return rv;
}
/**
* @brief Set dynamic address learning status on a particular port.
* @details Comments:
* This operation will enable or disable dynamic address learning
* feature on a particular port.
* @param[in] dev_id device id
* @param[in] port_id port id
* @param[in] enable enable or disable
* @return SW_OK or error code
*/
HSL_LOCAL sw_error_t
isis_fdb_port_learn_set(a_uint32_t dev_id, fal_port_t port_id, a_bool_t enable)
{
sw_error_t rv;
HSL_API_LOCK;
rv = _isis_fdb_port_learn_set(dev_id, port_id, enable);
HSL_API_UNLOCK;
return rv;
}
/**
* @brief Get dynamic address learning status on a particular port.
* @param[in] dev_id device id
* @param[in] port_id port id
* @param[out] enable A_TRUE or A_FALSE
* @return SW_OK or error code
*/
HSL_LOCAL sw_error_t
isis_fdb_port_learn_get(a_uint32_t dev_id, fal_port_t port_id,
a_bool_t * enable)
{
sw_error_t rv;
HSL_API_LOCK;
rv = _isis_fdb_port_learn_get(dev_id, port_id, enable);
HSL_API_UNLOCK;
return rv;
}
/**
* @brief Set dynamic address aging status on particular device.
* @details Comments:
* This operation will enable or disable dynamic address aging
* feature on particular device.
* @param[in] dev_id device id
* @param[in] enable enable or disable
* @return SW_OK or error code
*/
HSL_LOCAL sw_error_t
isis_fdb_age_ctrl_set(a_uint32_t dev_id, a_bool_t enable)
{
sw_error_t rv;
HSL_API_LOCK;
rv = _isis_fdb_age_ctrl_set(dev_id, enable);
HSL_API_UNLOCK;
return rv;
}
/**
* @brief Get dynamic address aging status on particular device.
* @param[in] dev_id device id
* @param[in] enable enable or disable
* @return SW_OK or error code
*/
HSL_LOCAL sw_error_t
isis_fdb_age_ctrl_get(a_uint32_t dev_id, a_bool_t * enable)
{
sw_error_t rv;
HSL_API_LOCK;
rv = _isis_fdb_age_ctrl_get(dev_id, enable);
HSL_API_UNLOCK;
return rv;
}
/**
* @brief Set dynamic address aging time on a particular device.
* @details Comments:
* This operation will set dynamic address aging time on a particular device.
* The unit of time is second. Because different device has differnet
* hardware granularity function will return actual time in hardware.
* @param[in] dev_id device id
* @param time aging time
* @return SW_OK or error code
*/
HSL_LOCAL sw_error_t
isis_fdb_age_time_set(a_uint32_t dev_id, a_uint32_t * time)
{
sw_error_t rv;
HSL_API_LOCK;
rv = _isis_fdb_age_time_set(dev_id, time);
HSL_API_UNLOCK;
return rv;
}
/**
* @brief Get dynamic address aging time on a particular device.
* @param[in] dev_id device id
* @param[out] time aging time
* @return SW_OK or error code
*/
HSL_LOCAL sw_error_t
isis_fdb_age_time_get(a_uint32_t dev_id, a_uint32_t * time)
{
sw_error_t rv;
HSL_API_LOCK;
rv = _isis_fdb_age_time_get(dev_id, time);
HSL_API_UNLOCK;
return rv;
}
/**
* @brief Set dynamic address learning count limit on a particular port.
* @param[in] dev_id device id
* @param[in] port_id port id
* @param[in] enable A_TRUE or A_FALSE
* @param[in] cnt limit count
* @return SW_OK or error code
*/
HSL_LOCAL sw_error_t
isis_port_fdb_learn_limit_set(a_uint32_t dev_id, fal_port_t port_id,
a_bool_t enable, a_uint32_t cnt)
{
sw_error_t rv;
HSL_API_LOCK;
rv = _isis_port_fdb_learn_limit_set(dev_id, port_id, enable, cnt);
HSL_API_UNLOCK;
return rv;
}
/**
* @brief Get dynamic address learning count limit on a particular port.
* @param[in] dev_id device id
* @param[in] port_id port id
* @param[out] enable A_TRUE or A_FALSE
* @param[out] cnt limit count
* @return SW_OK or error code
*/
HSL_LOCAL sw_error_t
isis_port_fdb_learn_limit_get(a_uint32_t dev_id, fal_port_t port_id,
a_bool_t * enable, a_uint32_t * cnt)
{
sw_error_t rv;
HSL_API_LOCK;
rv = _isis_port_fdb_learn_limit_get(dev_id, port_id, enable, cnt);
HSL_API_UNLOCK;
return rv;
}
/**
* @brief Set dynamic address learning count exceed command on a particular port.
* @param[in] dev_id device id
* @param[in] port_id port id
* @param[in] cmd forwarding command
* @return SW_OK or error code
*/
HSL_LOCAL sw_error_t
isis_port_fdb_learn_exceed_cmd_set(a_uint32_t dev_id, fal_port_t port_id,
fal_fwd_cmd_t cmd)
{
sw_error_t rv;
HSL_API_LOCK;
rv = _isis_port_fdb_learn_exceed_cmd_set(dev_id, port_id, cmd);
HSL_API_UNLOCK;
return rv;
}
/**
* @brief Get dynamic address learning count exceed command on a particular port.
* @param[in] dev_id device id
* @param[in] port_id port id
* @param[out] cmd forwarding command
* @return SW_OK or error code
*/
HSL_LOCAL sw_error_t
isis_port_fdb_learn_exceed_cmd_get(a_uint32_t dev_id, fal_port_t port_id,
fal_fwd_cmd_t * cmd)
{
sw_error_t rv;
HSL_API_LOCK;
rv = _isis_port_fdb_learn_exceed_cmd_get(dev_id, port_id, cmd);
HSL_API_UNLOCK;
return rv;
}
/**
* @brief Set dynamic address learning count limit on a particular device.
* @param[in] dev_id device id
* @param[in] enable A_TRUE or A_FALSE
* @param[in] cnt limit count
* @return SW_OK or error code
*/
HSL_LOCAL sw_error_t
isis_fdb_learn_limit_set(a_uint32_t dev_id, a_bool_t enable, a_uint32_t cnt)
{
sw_error_t rv;
HSL_API_LOCK;
rv = _isis_fdb_learn_limit_set(dev_id, enable, cnt);
HSL_API_UNLOCK;
return rv;
}
/**
* @brief Get dynamic address learning count limit on a particular device.
* @param[in] dev_id device id
* @param[in] enable A_TRUE or A_FALSE
* @param[in] cnt limit count
* @return SW_OK or error code
*/
HSL_LOCAL sw_error_t
isis_fdb_learn_limit_get(a_uint32_t dev_id, a_bool_t * enable, a_uint32_t * cnt)
{
sw_error_t rv;
HSL_API_LOCK;
rv = _isis_fdb_learn_limit_get(dev_id, enable, cnt);
HSL_API_UNLOCK;
return rv;
}
/**
* @brief Set dynamic address learning count exceed command on a particular device.
* @param[in] dev_id device id
* @param[in] cmd forwarding command
* @return SW_OK or error code
*/
HSL_LOCAL sw_error_t
isis_fdb_learn_exceed_cmd_set(a_uint32_t dev_id, fal_fwd_cmd_t cmd)
{
sw_error_t rv;
HSL_API_LOCK;
rv = _isis_fdb_learn_exceed_cmd_set(dev_id, cmd);
HSL_API_UNLOCK;
return rv;
}
/**
* @brief Get dynamic address learning count exceed command on a particular device.
* @param[in] dev_id device id
* @param[out] cmd forwarding command
* @return SW_OK or error code
*/
HSL_LOCAL sw_error_t
isis_fdb_learn_exceed_cmd_get(a_uint32_t dev_id, fal_fwd_cmd_t * cmd)
{
sw_error_t rv;
HSL_API_LOCK;
rv = _isis_fdb_learn_exceed_cmd_get(dev_id, cmd);
HSL_API_UNLOCK;
return rv;
}
/**
* @brief Add a particular reserve Fdb entry
* @param[in] dev_id device id
* @param[in] entry reserve fdb entry
* @return SW_OK or error code
*/
HSL_LOCAL sw_error_t
isis_fdb_resv_add(a_uint32_t dev_id, fal_fdb_entry_t * entry)
{
sw_error_t rv;
HSL_API_LOCK;
rv = _isis_fdb_resv_add(dev_id, entry);
HSL_API_UNLOCK;
return rv;
}
/**
* @brief Delete a particular reserve Fdb entry through mac address
* @param[in] dev_id device id
* @param[in] entry reserve fdb entry
* @return SW_OK or error code
*/
HSL_LOCAL sw_error_t
isis_fdb_resv_del(a_uint32_t dev_id, fal_fdb_entry_t * entry)
{
sw_error_t rv;
HSL_API_LOCK;
rv = _isis_fdb_resv_del(dev_id, entry);
HSL_API_UNLOCK;
return rv;
}
/**
* @brief Find a particular reserve Fdb entry through mac address
* @param[in] dev_id device id
* @param[in] entry reserve fdb entry
* @param[out] entry reserve fdb entry
* @return SW_OK or error code
*/
HSL_LOCAL sw_error_t
isis_fdb_resv_find(a_uint32_t dev_id, fal_fdb_entry_t * entry)
{
sw_error_t rv;
HSL_API_LOCK;
rv = _isis_fdb_resv_find(dev_id, entry);
HSL_API_UNLOCK;
return rv;
}
/**
* @brief Iterate all reserve fdb entries on a particular device.
* @param[in] dev_id device id
* @param[in] iterator reserve fdb entry index if it's zero means get the first entry
* @param[out] iterator next valid fdb entry index
* @param[out] entry reserve fdb entry
* @return SW_OK or error code
*/
HSL_LOCAL sw_error_t
isis_fdb_resv_iterate(a_uint32_t dev_id, a_uint32_t * iterator,
fal_fdb_entry_t * entry)
{
sw_error_t rv;
HSL_API_LOCK;
rv = _isis_fdb_resv_iterate(dev_id, iterator, entry);
HSL_API_UNLOCK;
return rv;
}
/**
* @brief Set the static status of fdb entries which learned by hardware on a particular port.
* @param[in] dev_id device id
* @param[in] port_id port id
* @param[in] enable A_TRUE or A_FALSE
* @return SW_OK or error code
*/
HSL_LOCAL sw_error_t
isis_fdb_port_learn_static_set(a_uint32_t dev_id, fal_port_t port_id,
a_bool_t enable)
{
sw_error_t rv;
HSL_API_LOCK;
rv = _isis_fdb_port_learn_static_set(dev_id, port_id, enable);
HSL_API_UNLOCK;
return rv;
}
/**
* @brief Get the static status of fdb entries which learned by hardware on a particular port.
* @param[in] dev_id device id
* @param[in] port_id port id
* @param[out] enable A_TRUE or A_FALSE
* @return SW_OK or error code
*/
HSL_LOCAL sw_error_t
isis_fdb_port_learn_static_get(a_uint32_t dev_id, fal_port_t port_id,
a_bool_t * enable)
{
sw_error_t rv;
HSL_API_LOCK;
rv = _isis_fdb_port_learn_static_get(dev_id, port_id, enable);
HSL_API_UNLOCK;
return rv;
}
/**
* @brief Add a port to an exsiting entry
* @param[in] dev_id device id
* @param[in] fid filtering database id
* @param[in] addr MAC address
* @param[in] port_id port id
* @return SW_OK or error code, If entry not exist will return error.
*/
HSL_LOCAL sw_error_t
isis_fdb_port_add(a_uint32_t dev_id, a_uint32_t fid, fal_mac_addr_t * addr, fal_port_t port_id)
{
sw_error_t rv;
HSL_API_LOCK;
rv = _isis_fdb_port_update(dev_id, fid, addr, port_id, 1);
HSL_API_UNLOCK;
return rv;
}
/**
* @brief Delete a port from an exsiting entry
* @param[in] dev_id device id
* @param[in] fid filtering database id
* @param[in] addr MAC address
* @param[in] port_id port id
* @return SW_OK or error code, If entry not exist will return error.
*/
HSL_LOCAL sw_error_t
isis_fdb_port_del(a_uint32_t dev_id, a_uint32_t fid, fal_mac_addr_t * addr, fal_port_t port_id)
{
sw_error_t rv;
HSL_API_LOCK;
rv = _isis_fdb_port_update(dev_id, fid, addr, port_id, 0);
HSL_API_UNLOCK;
return rv;
}
sw_error_t
isis_fdb_init(a_uint32_t dev_id)
{
HSL_DEV_ID_CHECK(dev_id);
#ifndef HSL_STANDALONG
{
hsl_api_t *p_api;
SW_RTN_ON_NULL(p_api = hsl_api_ptr_get(dev_id));
p_api->fdb_add = isis_fdb_add;
p_api->fdb_del_all = isis_fdb_del_all;
p_api->fdb_del_by_port = isis_fdb_del_by_port;
p_api->fdb_del_by_mac = isis_fdb_del_by_mac;
p_api->fdb_extend_first = isis_fdb_extend_first;
p_api->fdb_extend_next = isis_fdb_extend_next;
p_api->fdb_find = isis_fdb_find;
p_api->port_learn_set = isis_fdb_port_learn_set;
p_api->port_learn_get = isis_fdb_port_learn_get;
p_api->age_ctrl_set = isis_fdb_age_ctrl_set;
p_api->age_ctrl_get = isis_fdb_age_ctrl_get;
p_api->age_time_set = isis_fdb_age_time_set;
p_api->age_time_get = isis_fdb_age_time_get;
p_api->fdb_extend_next = isis_fdb_extend_next;
p_api->fdb_extend_first = isis_fdb_extend_first;
p_api->fdb_transfer = isis_fdb_transfer;
p_api->port_fdb_learn_limit_set = isis_port_fdb_learn_limit_set;
p_api->port_fdb_learn_limit_get = isis_port_fdb_learn_limit_get;
p_api->port_fdb_learn_exceed_cmd_set = isis_port_fdb_learn_exceed_cmd_set;
p_api->port_fdb_learn_exceed_cmd_get = isis_port_fdb_learn_exceed_cmd_get;
p_api->fdb_learn_limit_set = isis_fdb_learn_limit_set;
p_api->fdb_learn_limit_get = isis_fdb_learn_limit_get;
p_api->fdb_learn_exceed_cmd_set = isis_fdb_learn_exceed_cmd_set;
p_api->fdb_learn_exceed_cmd_get = isis_fdb_learn_exceed_cmd_get;
p_api->fdb_resv_add = isis_fdb_resv_add;
p_api->fdb_resv_del = isis_fdb_resv_del;
p_api->fdb_resv_find = isis_fdb_resv_find;
p_api->fdb_resv_iterate = isis_fdb_resv_iterate;
p_api->fdb_port_learn_static_set = isis_fdb_port_learn_static_set;
p_api->fdb_port_learn_static_get = isis_fdb_port_learn_static_get;
p_api->fdb_port_add = isis_fdb_port_add;
p_api->fdb_port_del = isis_fdb_port_del;
}
#endif
return SW_OK;
}
/**
* @}
*/