Commit 2e5bd96e authored by Christian Marangi's avatar Christian Marangi Committed by Jakub Kicinski

net: dsa: qca8k: move port FDB/MDB function to common code

The same port FDB/MDB function are used by drivers based on qca8k family
switch. Move them to common code to make them accessible also by other
drivers.
Also drop bulk read/write functions and make them static
Signed-off-by: default avatarChristian Marangi <ansuelsmth@gmail.com>
Reviewed-by: default avatarVladimir Oltean <olteanv@gmail.com>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent b3a302b1
...@@ -441,217 +441,6 @@ static struct regmap_config qca8k_regmap_config = { ...@@ -441,217 +441,6 @@ static struct regmap_config qca8k_regmap_config = {
.cache_type = REGCACHE_NONE, /* Explicitly disable CACHE */ .cache_type = REGCACHE_NONE, /* Explicitly disable CACHE */
}; };
static int
qca8k_fdb_read(struct qca8k_priv *priv, struct qca8k_fdb *fdb)
{
u32 reg[3];
int ret;
/* load the ARL table into an array */
ret = qca8k_bulk_read(priv, QCA8K_REG_ATU_DATA0, reg, sizeof(reg));
if (ret)
return ret;
/* vid - 83:72 */
fdb->vid = FIELD_GET(QCA8K_ATU_VID_MASK, reg[2]);
/* aging - 67:64 */
fdb->aging = FIELD_GET(QCA8K_ATU_STATUS_MASK, reg[2]);
/* portmask - 54:48 */
fdb->port_mask = FIELD_GET(QCA8K_ATU_PORT_MASK, reg[1]);
/* mac - 47:0 */
fdb->mac[0] = FIELD_GET(QCA8K_ATU_ADDR0_MASK, reg[1]);
fdb->mac[1] = FIELD_GET(QCA8K_ATU_ADDR1_MASK, reg[1]);
fdb->mac[2] = FIELD_GET(QCA8K_ATU_ADDR2_MASK, reg[0]);
fdb->mac[3] = FIELD_GET(QCA8K_ATU_ADDR3_MASK, reg[0]);
fdb->mac[4] = FIELD_GET(QCA8K_ATU_ADDR4_MASK, reg[0]);
fdb->mac[5] = FIELD_GET(QCA8K_ATU_ADDR5_MASK, reg[0]);
return 0;
}
static void
qca8k_fdb_write(struct qca8k_priv *priv, u16 vid, u8 port_mask, const u8 *mac,
u8 aging)
{
u32 reg[3] = { 0 };
/* vid - 83:72 */
reg[2] = FIELD_PREP(QCA8K_ATU_VID_MASK, vid);
/* aging - 67:64 */
reg[2] |= FIELD_PREP(QCA8K_ATU_STATUS_MASK, aging);
/* portmask - 54:48 */
reg[1] = FIELD_PREP(QCA8K_ATU_PORT_MASK, port_mask);
/* mac - 47:0 */
reg[1] |= FIELD_PREP(QCA8K_ATU_ADDR0_MASK, mac[0]);
reg[1] |= FIELD_PREP(QCA8K_ATU_ADDR1_MASK, mac[1]);
reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR2_MASK, mac[2]);
reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR3_MASK, mac[3]);
reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR4_MASK, mac[4]);
reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR5_MASK, mac[5]);
/* load the array into the ARL table */
qca8k_bulk_write(priv, QCA8K_REG_ATU_DATA0, reg, sizeof(reg));
}
static int
qca8k_fdb_access(struct qca8k_priv *priv, enum qca8k_fdb_cmd cmd, int port)
{
u32 reg;
int ret;
/* Set the command and FDB index */
reg = QCA8K_ATU_FUNC_BUSY;
reg |= cmd;
if (port >= 0) {
reg |= QCA8K_ATU_FUNC_PORT_EN;
reg |= FIELD_PREP(QCA8K_ATU_FUNC_PORT_MASK, port);
}
/* Write the function register triggering the table access */
ret = qca8k_write(priv, QCA8K_REG_ATU_FUNC, reg);
if (ret)
return ret;
/* wait for completion */
ret = qca8k_busy_wait(priv, QCA8K_REG_ATU_FUNC, QCA8K_ATU_FUNC_BUSY);
if (ret)
return ret;
/* Check for table full violation when adding an entry */
if (cmd == QCA8K_FDB_LOAD) {
ret = qca8k_read(priv, QCA8K_REG_ATU_FUNC, &reg);
if (ret < 0)
return ret;
if (reg & QCA8K_ATU_FUNC_FULL)
return -1;
}
return 0;
}
static int
qca8k_fdb_next(struct qca8k_priv *priv, struct qca8k_fdb *fdb, int port)
{
int ret;
qca8k_fdb_write(priv, fdb->vid, fdb->port_mask, fdb->mac, fdb->aging);
ret = qca8k_fdb_access(priv, QCA8K_FDB_NEXT, port);
if (ret < 0)
return ret;
return qca8k_fdb_read(priv, fdb);
}
static int
qca8k_fdb_add(struct qca8k_priv *priv, const u8 *mac, u16 port_mask,
u16 vid, u8 aging)
{
int ret;
mutex_lock(&priv->reg_mutex);
qca8k_fdb_write(priv, vid, port_mask, mac, aging);
ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1);
mutex_unlock(&priv->reg_mutex);
return ret;
}
static int
qca8k_fdb_del(struct qca8k_priv *priv, const u8 *mac, u16 port_mask, u16 vid)
{
int ret;
mutex_lock(&priv->reg_mutex);
qca8k_fdb_write(priv, vid, port_mask, mac, 0);
ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1);
mutex_unlock(&priv->reg_mutex);
return ret;
}
static void
qca8k_fdb_flush(struct qca8k_priv *priv)
{
mutex_lock(&priv->reg_mutex);
qca8k_fdb_access(priv, QCA8K_FDB_FLUSH, -1);
mutex_unlock(&priv->reg_mutex);
}
static int
qca8k_fdb_search_and_insert(struct qca8k_priv *priv, u8 port_mask,
const u8 *mac, u16 vid)
{
struct qca8k_fdb fdb = { 0 };
int ret;
mutex_lock(&priv->reg_mutex);
qca8k_fdb_write(priv, vid, 0, mac, 0);
ret = qca8k_fdb_access(priv, QCA8K_FDB_SEARCH, -1);
if (ret < 0)
goto exit;
ret = qca8k_fdb_read(priv, &fdb);
if (ret < 0)
goto exit;
/* Rule exist. Delete first */
if (!fdb.aging) {
ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1);
if (ret)
goto exit;
}
/* Add port to fdb portmask */
fdb.port_mask |= port_mask;
qca8k_fdb_write(priv, vid, fdb.port_mask, mac, fdb.aging);
ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1);
exit:
mutex_unlock(&priv->reg_mutex);
return ret;
}
static int
qca8k_fdb_search_and_del(struct qca8k_priv *priv, u8 port_mask,
const u8 *mac, u16 vid)
{
struct qca8k_fdb fdb = { 0 };
int ret;
mutex_lock(&priv->reg_mutex);
qca8k_fdb_write(priv, vid, 0, mac, 0);
ret = qca8k_fdb_access(priv, QCA8K_FDB_SEARCH, -1);
if (ret < 0)
goto exit;
/* Rule doesn't exist. Why delete? */
if (!fdb.aging) {
ret = -EINVAL;
goto exit;
}
ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1);
if (ret)
goto exit;
/* Only port in the rule is this port. Don't re insert */
if (fdb.port_mask == port_mask)
goto exit;
/* Remove port from port mask */
fdb.port_mask &= ~port_mask;
qca8k_fdb_write(priv, vid, fdb.port_mask, mac, fdb.aging);
ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1);
exit:
mutex_unlock(&priv->reg_mutex);
return ret;
}
static int static int
qca8k_vlan_access(struct qca8k_priv *priv, enum qca8k_vlan_cmd cmd, u16 vid) qca8k_vlan_access(struct qca8k_priv *priv, enum qca8k_vlan_cmd cmd, u16 vid)
{ {
...@@ -1898,101 +1687,6 @@ qca8k_get_ethtool_stats_eth(struct dsa_switch *ds, int port, u64 *data) ...@@ -1898,101 +1687,6 @@ qca8k_get_ethtool_stats_eth(struct dsa_switch *ds, int port, u64 *data)
return ret; return ret;
} }
static void
qca8k_port_fast_age(struct dsa_switch *ds, int port)
{
struct qca8k_priv *priv = ds->priv;
mutex_lock(&priv->reg_mutex);
qca8k_fdb_access(priv, QCA8K_FDB_FLUSH_PORT, port);
mutex_unlock(&priv->reg_mutex);
}
static int
qca8k_port_fdb_insert(struct qca8k_priv *priv, const u8 *addr,
u16 port_mask, u16 vid)
{
/* Set the vid to the port vlan id if no vid is set */
if (!vid)
vid = QCA8K_PORT_VID_DEF;
return qca8k_fdb_add(priv, addr, port_mask, vid,
QCA8K_ATU_STATUS_STATIC);
}
static int
qca8k_port_fdb_add(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid,
struct dsa_db db)
{
struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
u16 port_mask = BIT(port);
return qca8k_port_fdb_insert(priv, addr, port_mask, vid);
}
static int
qca8k_port_fdb_del(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid,
struct dsa_db db)
{
struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
u16 port_mask = BIT(port);
if (!vid)
vid = QCA8K_PORT_VID_DEF;
return qca8k_fdb_del(priv, addr, port_mask, vid);
}
static int
qca8k_port_fdb_dump(struct dsa_switch *ds, int port,
dsa_fdb_dump_cb_t *cb, void *data)
{
struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
struct qca8k_fdb _fdb = { 0 };
int cnt = QCA8K_NUM_FDB_RECORDS;
bool is_static;
int ret = 0;
mutex_lock(&priv->reg_mutex);
while (cnt-- && !qca8k_fdb_next(priv, &_fdb, port)) {
if (!_fdb.aging)
break;
is_static = (_fdb.aging == QCA8K_ATU_STATUS_STATIC);
ret = cb(_fdb.mac, _fdb.vid, is_static, data);
if (ret)
break;
}
mutex_unlock(&priv->reg_mutex);
return 0;
}
static int
qca8k_port_mdb_add(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_mdb *mdb,
struct dsa_db db)
{
struct qca8k_priv *priv = ds->priv;
const u8 *addr = mdb->addr;
u16 vid = mdb->vid;
return qca8k_fdb_search_and_insert(priv, BIT(port), addr, vid);
}
static int
qca8k_port_mdb_del(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_mdb *mdb,
struct dsa_db db)
{
struct qca8k_priv *priv = ds->priv;
const u8 *addr = mdb->addr;
u16 vid = mdb->vid;
return qca8k_fdb_search_and_del(priv, BIT(port), addr, vid);
}
static int static int
qca8k_port_mirror_add(struct dsa_switch *ds, int port, qca8k_port_mirror_add(struct dsa_switch *ds, int port,
struct dsa_mall_mirror_tc_entry *mirror, struct dsa_mall_mirror_tc_entry *mirror,
......
...@@ -102,7 +102,7 @@ const struct regmap_access_table qca8k_readable_table = { ...@@ -102,7 +102,7 @@ const struct regmap_access_table qca8k_readable_table = {
}; };
/* TODO: remove these extra ops when we can support regmap bulk read/write */ /* TODO: remove these extra ops when we can support regmap bulk read/write */
int qca8k_bulk_read(struct qca8k_priv *priv, u32 reg, u32 *val, int len) static int qca8k_bulk_read(struct qca8k_priv *priv, u32 reg, u32 *val, int len)
{ {
int i, count = len / sizeof(u32), ret; int i, count = len / sizeof(u32), ret;
...@@ -120,7 +120,7 @@ int qca8k_bulk_read(struct qca8k_priv *priv, u32 reg, u32 *val, int len) ...@@ -120,7 +120,7 @@ int qca8k_bulk_read(struct qca8k_priv *priv, u32 reg, u32 *val, int len)
} }
/* TODO: remove these extra ops when we can support regmap bulk read/write */ /* TODO: remove these extra ops when we can support regmap bulk read/write */
int qca8k_bulk_write(struct qca8k_priv *priv, u32 reg, u32 *val, int len) static int qca8k_bulk_write(struct qca8k_priv *priv, u32 reg, u32 *val, int len)
{ {
int i, count = len / sizeof(u32), ret; int i, count = len / sizeof(u32), ret;
u32 tmp; u32 tmp;
...@@ -148,6 +148,211 @@ int qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask) ...@@ -148,6 +148,211 @@ int qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask)
QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC); QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC);
} }
static int qca8k_fdb_read(struct qca8k_priv *priv, struct qca8k_fdb *fdb)
{
u32 reg[3];
int ret;
/* load the ARL table into an array */
ret = qca8k_bulk_read(priv, QCA8K_REG_ATU_DATA0, reg, sizeof(reg));
if (ret)
return ret;
/* vid - 83:72 */
fdb->vid = FIELD_GET(QCA8K_ATU_VID_MASK, reg[2]);
/* aging - 67:64 */
fdb->aging = FIELD_GET(QCA8K_ATU_STATUS_MASK, reg[2]);
/* portmask - 54:48 */
fdb->port_mask = FIELD_GET(QCA8K_ATU_PORT_MASK, reg[1]);
/* mac - 47:0 */
fdb->mac[0] = FIELD_GET(QCA8K_ATU_ADDR0_MASK, reg[1]);
fdb->mac[1] = FIELD_GET(QCA8K_ATU_ADDR1_MASK, reg[1]);
fdb->mac[2] = FIELD_GET(QCA8K_ATU_ADDR2_MASK, reg[0]);
fdb->mac[3] = FIELD_GET(QCA8K_ATU_ADDR3_MASK, reg[0]);
fdb->mac[4] = FIELD_GET(QCA8K_ATU_ADDR4_MASK, reg[0]);
fdb->mac[5] = FIELD_GET(QCA8K_ATU_ADDR5_MASK, reg[0]);
return 0;
}
static void qca8k_fdb_write(struct qca8k_priv *priv, u16 vid, u8 port_mask,
const u8 *mac, u8 aging)
{
u32 reg[3] = { 0 };
/* vid - 83:72 */
reg[2] = FIELD_PREP(QCA8K_ATU_VID_MASK, vid);
/* aging - 67:64 */
reg[2] |= FIELD_PREP(QCA8K_ATU_STATUS_MASK, aging);
/* portmask - 54:48 */
reg[1] = FIELD_PREP(QCA8K_ATU_PORT_MASK, port_mask);
/* mac - 47:0 */
reg[1] |= FIELD_PREP(QCA8K_ATU_ADDR0_MASK, mac[0]);
reg[1] |= FIELD_PREP(QCA8K_ATU_ADDR1_MASK, mac[1]);
reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR2_MASK, mac[2]);
reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR3_MASK, mac[3]);
reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR4_MASK, mac[4]);
reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR5_MASK, mac[5]);
/* load the array into the ARL table */
qca8k_bulk_write(priv, QCA8K_REG_ATU_DATA0, reg, sizeof(reg));
}
static int qca8k_fdb_access(struct qca8k_priv *priv, enum qca8k_fdb_cmd cmd,
int port)
{
u32 reg;
int ret;
/* Set the command and FDB index */
reg = QCA8K_ATU_FUNC_BUSY;
reg |= cmd;
if (port >= 0) {
reg |= QCA8K_ATU_FUNC_PORT_EN;
reg |= FIELD_PREP(QCA8K_ATU_FUNC_PORT_MASK, port);
}
/* Write the function register triggering the table access */
ret = qca8k_write(priv, QCA8K_REG_ATU_FUNC, reg);
if (ret)
return ret;
/* wait for completion */
ret = qca8k_busy_wait(priv, QCA8K_REG_ATU_FUNC, QCA8K_ATU_FUNC_BUSY);
if (ret)
return ret;
/* Check for table full violation when adding an entry */
if (cmd == QCA8K_FDB_LOAD) {
ret = qca8k_read(priv, QCA8K_REG_ATU_FUNC, &reg);
if (ret < 0)
return ret;
if (reg & QCA8K_ATU_FUNC_FULL)
return -1;
}
return 0;
}
static int qca8k_fdb_next(struct qca8k_priv *priv, struct qca8k_fdb *fdb,
int port)
{
int ret;
qca8k_fdb_write(priv, fdb->vid, fdb->port_mask, fdb->mac, fdb->aging);
ret = qca8k_fdb_access(priv, QCA8K_FDB_NEXT, port);
if (ret < 0)
return ret;
return qca8k_fdb_read(priv, fdb);
}
static int qca8k_fdb_add(struct qca8k_priv *priv, const u8 *mac,
u16 port_mask, u16 vid, u8 aging)
{
int ret;
mutex_lock(&priv->reg_mutex);
qca8k_fdb_write(priv, vid, port_mask, mac, aging);
ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1);
mutex_unlock(&priv->reg_mutex);
return ret;
}
static int qca8k_fdb_del(struct qca8k_priv *priv, const u8 *mac,
u16 port_mask, u16 vid)
{
int ret;
mutex_lock(&priv->reg_mutex);
qca8k_fdb_write(priv, vid, port_mask, mac, 0);
ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1);
mutex_unlock(&priv->reg_mutex);
return ret;
}
void qca8k_fdb_flush(struct qca8k_priv *priv)
{
mutex_lock(&priv->reg_mutex);
qca8k_fdb_access(priv, QCA8K_FDB_FLUSH, -1);
mutex_unlock(&priv->reg_mutex);
}
static int qca8k_fdb_search_and_insert(struct qca8k_priv *priv, u8 port_mask,
const u8 *mac, u16 vid)
{
struct qca8k_fdb fdb = { 0 };
int ret;
mutex_lock(&priv->reg_mutex);
qca8k_fdb_write(priv, vid, 0, mac, 0);
ret = qca8k_fdb_access(priv, QCA8K_FDB_SEARCH, -1);
if (ret < 0)
goto exit;
ret = qca8k_fdb_read(priv, &fdb);
if (ret < 0)
goto exit;
/* Rule exist. Delete first */
if (!fdb.aging) {
ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1);
if (ret)
goto exit;
}
/* Add port to fdb portmask */
fdb.port_mask |= port_mask;
qca8k_fdb_write(priv, vid, fdb.port_mask, mac, fdb.aging);
ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1);
exit:
mutex_unlock(&priv->reg_mutex);
return ret;
}
static int qca8k_fdb_search_and_del(struct qca8k_priv *priv, u8 port_mask,
const u8 *mac, u16 vid)
{
struct qca8k_fdb fdb = { 0 };
int ret;
mutex_lock(&priv->reg_mutex);
qca8k_fdb_write(priv, vid, 0, mac, 0);
ret = qca8k_fdb_access(priv, QCA8K_FDB_SEARCH, -1);
if (ret < 0)
goto exit;
/* Rule doesn't exist. Why delete? */
if (!fdb.aging) {
ret = -EINVAL;
goto exit;
}
ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1);
if (ret)
goto exit;
/* Only port in the rule is this port. Don't re insert */
if (fdb.port_mask == port_mask)
goto exit;
/* Remove port from port mask */
fdb.port_mask &= ~port_mask;
qca8k_fdb_write(priv, vid, fdb.port_mask, mac, fdb.aging);
ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1);
exit:
mutex_unlock(&priv->reg_mutex);
return ret;
}
int qca8k_mib_init(struct qca8k_priv *priv) int qca8k_mib_init(struct qca8k_priv *priv)
{ {
int ret; int ret;
...@@ -369,6 +574,15 @@ void qca8k_port_bridge_leave(struct dsa_switch *ds, int port, ...@@ -369,6 +574,15 @@ void qca8k_port_bridge_leave(struct dsa_switch *ds, int port,
QCA8K_PORT_LOOKUP_MEMBER, BIT(cpu_port)); QCA8K_PORT_LOOKUP_MEMBER, BIT(cpu_port));
} }
void qca8k_port_fast_age(struct dsa_switch *ds, int port)
{
struct qca8k_priv *priv = ds->priv;
mutex_lock(&priv->reg_mutex);
qca8k_fdb_access(priv, QCA8K_FDB_FLUSH_PORT, port);
mutex_unlock(&priv->reg_mutex);
}
int qca8k_set_ageing_time(struct dsa_switch *ds, unsigned int msecs) int qca8k_set_ageing_time(struct dsa_switch *ds, unsigned int msecs)
{ {
struct qca8k_priv *priv = ds->priv; struct qca8k_priv *priv = ds->priv;
...@@ -453,3 +667,82 @@ int qca8k_port_max_mtu(struct dsa_switch *ds, int port) ...@@ -453,3 +667,82 @@ int qca8k_port_max_mtu(struct dsa_switch *ds, int port)
{ {
return QCA8K_MAX_MTU; return QCA8K_MAX_MTU;
} }
int qca8k_port_fdb_insert(struct qca8k_priv *priv, const u8 *addr,
u16 port_mask, u16 vid)
{
/* Set the vid to the port vlan id if no vid is set */
if (!vid)
vid = QCA8K_PORT_VID_DEF;
return qca8k_fdb_add(priv, addr, port_mask, vid,
QCA8K_ATU_STATUS_STATIC);
}
int qca8k_port_fdb_add(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid,
struct dsa_db db)
{
struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
u16 port_mask = BIT(port);
return qca8k_port_fdb_insert(priv, addr, port_mask, vid);
}
int qca8k_port_fdb_del(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid,
struct dsa_db db)
{
struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
u16 port_mask = BIT(port);
if (!vid)
vid = QCA8K_PORT_VID_DEF;
return qca8k_fdb_del(priv, addr, port_mask, vid);
}
int qca8k_port_fdb_dump(struct dsa_switch *ds, int port,
dsa_fdb_dump_cb_t *cb, void *data)
{
struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
struct qca8k_fdb _fdb = { 0 };
int cnt = QCA8K_NUM_FDB_RECORDS;
bool is_static;
int ret = 0;
mutex_lock(&priv->reg_mutex);
while (cnt-- && !qca8k_fdb_next(priv, &_fdb, port)) {
if (!_fdb.aging)
break;
is_static = (_fdb.aging == QCA8K_ATU_STATUS_STATIC);
ret = cb(_fdb.mac, _fdb.vid, is_static, data);
if (ret)
break;
}
mutex_unlock(&priv->reg_mutex);
return 0;
}
int qca8k_port_mdb_add(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_mdb *mdb,
struct dsa_db db)
{
struct qca8k_priv *priv = ds->priv;
const u8 *addr = mdb->addr;
u16 vid = mdb->vid;
return qca8k_fdb_search_and_insert(priv, BIT(port), addr, vid);
}
int qca8k_port_mdb_del(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_mdb *mdb,
struct dsa_db db)
{
struct qca8k_priv *priv = ds->priv;
const u8 *addr = mdb->addr;
u16 vid = mdb->vid;
return qca8k_fdb_search_and_del(priv, BIT(port), addr, vid);
}
...@@ -438,11 +438,9 @@ int qca8k_read(struct qca8k_priv *priv, u32 reg, u32 *val); ...@@ -438,11 +438,9 @@ int qca8k_read(struct qca8k_priv *priv, u32 reg, u32 *val);
int qca8k_write(struct qca8k_priv *priv, u32 reg, u32 val); int qca8k_write(struct qca8k_priv *priv, u32 reg, u32 val);
int qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val); int qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val);
int qca8k_bulk_read(struct qca8k_priv *priv, u32 reg, u32 *val, int len);
int qca8k_bulk_write(struct qca8k_priv *priv, u32 reg, u32 *val, int len);
/* Common ops function */ /* Common ops function */
int qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask); int qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask);
void qca8k_fdb_flush(struct qca8k_priv *priv);
/* Common ethtool stats function */ /* Common ethtool stats function */
void qca8k_get_strings(struct dsa_switch *ds, int port, u32 stringset, uint8_t *data); void qca8k_get_strings(struct dsa_switch *ds, int port, u32 stringset, uint8_t *data);
...@@ -473,6 +471,27 @@ int qca8k_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu); ...@@ -473,6 +471,27 @@ int qca8k_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu);
int qca8k_port_max_mtu(struct dsa_switch *ds, int port); int qca8k_port_max_mtu(struct dsa_switch *ds, int port);
/* Common fast age function */ /* Common fast age function */
void qca8k_port_fast_age(struct dsa_switch *ds, int port);
int qca8k_set_ageing_time(struct dsa_switch *ds, unsigned int msecs); int qca8k_set_ageing_time(struct dsa_switch *ds, unsigned int msecs);
/* Common FDB function */
int qca8k_port_fdb_insert(struct qca8k_priv *priv, const u8 *addr,
u16 port_mask, u16 vid);
int qca8k_port_fdb_add(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid,
struct dsa_db db);
int qca8k_port_fdb_del(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid,
struct dsa_db db);
int qca8k_port_fdb_dump(struct dsa_switch *ds, int port,
dsa_fdb_dump_cb_t *cb, void *data);
/* Common MDB function */
int qca8k_port_mdb_add(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_mdb *mdb,
struct dsa_db db);
int qca8k_port_mdb_del(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_mdb *mdb,
struct dsa_db db);
#endif /* __QCA8K_H */ #endif /* __QCA8K_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment