diff options
author | Christian Marangi <ansuelsmth@gmail.com> | 2022-09-12 18:40:16 +0200 |
---|---|---|
committer | Christian Marangi <ansuelsmth@gmail.com> | 2022-09-19 15:19:53 +0200 |
commit | 7ace30aeb6ff58b4de845dd4722b281afd0c7eae (patch) | |
tree | 41c627ab344f5b8012610cccf5592d5876bc6586 /target/linux/generic/backport-5.15/771-v6.0-10-net-dsa-qca8k-move-port-FDB-MDB-function-to-common-c.patch | |
parent | ddcebda08b26142d47eb3c2009d48d12781d76a3 (diff) | |
download | upstream-7ace30aeb6ff58b4de845dd4722b281afd0c7eae.tar.gz upstream-7ace30aeb6ff58b4de845dd4722b281afd0c7eae.tar.bz2 upstream-7ace30aeb6ff58b4de845dd4722b281afd0c7eae.zip |
generic: 5.15: qca8k: backport code split patch
Backport upstream code split patch for qca8k needed for ipq40xx target
to correctly implement a DSA driver.
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
Diffstat (limited to 'target/linux/generic/backport-5.15/771-v6.0-10-net-dsa-qca8k-move-port-FDB-MDB-function-to-common-c.patch')
-rw-r--r-- | target/linux/generic/backport-5.15/771-v6.0-10-net-dsa-qca8k-move-port-FDB-MDB-function-to-common-c.patch | 704 |
1 files changed, 704 insertions, 0 deletions
diff --git a/target/linux/generic/backport-5.15/771-v6.0-10-net-dsa-qca8k-move-port-FDB-MDB-function-to-common-c.patch b/target/linux/generic/backport-5.15/771-v6.0-10-net-dsa-qca8k-move-port-FDB-MDB-function-to-common-c.patch new file mode 100644 index 0000000000..96468ae74e --- /dev/null +++ b/target/linux/generic/backport-5.15/771-v6.0-10-net-dsa-qca8k-move-port-FDB-MDB-function-to-common-c.patch @@ -0,0 +1,704 @@ +From 2e5bd96eea86a246b4de3bf756f7a11b43e6187d Mon Sep 17 00:00:00 2001 +From: Christian Marangi <ansuelsmth@gmail.com> +Date: Wed, 27 Jul 2022 13:35:19 +0200 +Subject: [PATCH 10/14] 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: Christian Marangi <ansuelsmth@gmail.com> +Reviewed-by: Vladimir Oltean <olteanv@gmail.com> +Signed-off-by: Jakub Kicinski <kuba@kernel.org> +--- + drivers/net/dsa/qca/qca8k-8xxx.c | 306 ----------------------------- + drivers/net/dsa/qca/qca8k-common.c | 297 +++++++++++++++++++++++++++- + drivers/net/dsa/qca/qca8k.h | 25 ++- + 3 files changed, 317 insertions(+), 311 deletions(-) + +--- a/drivers/net/dsa/qca/qca8k-8xxx.c ++++ b/drivers/net/dsa/qca/qca8k-8xxx.c +@@ -442,217 +442,6 @@ static struct regmap_config qca8k_regmap + }; + + 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, ®); +- 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 + qca8k_vlan_access(struct qca8k_priv *priv, enum qca8k_vlan_cmd cmd, u16 vid) + { + u32 reg; +@@ -2048,97 +1837,6 @@ exit: + 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 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 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 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 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 + qca8k_port_mirror_add(struct dsa_switch *ds, int port, + struct dsa_mall_mirror_tc_entry *mirror, +--- a/drivers/net/dsa/qca/qca8k-common.c ++++ b/drivers/net/dsa/qca/qca8k-common.c +@@ -103,7 +103,7 @@ const struct regmap_access_table qca8k_r + }; + + /* 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; + +@@ -121,7 +121,7 @@ int qca8k_bulk_read(struct qca8k_priv *p + } + + /* 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; + u32 tmp; +@@ -149,6 +149,211 @@ int qca8k_busy_wait(struct qca8k_priv *p + 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, ®); ++ 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 ret; +@@ -368,6 +573,15 @@ void qca8k_port_bridge_leave(struct dsa_ + 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) + { + struct qca8k_priv *priv = ds->priv; +@@ -452,3 +666,78 @@ int qca8k_port_max_mtu(struct dsa_switch + { + 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 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 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 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 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); ++} +--- a/drivers/net/dsa/qca/qca8k.h ++++ b/drivers/net/dsa/qca/qca8k.h +@@ -430,11 +430,9 @@ int qca8k_read(struct qca8k_priv *priv, + 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_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 */ + int qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask); ++void qca8k_fdb_flush(struct qca8k_priv *priv); + + /* Common ethtool stats function */ + void qca8k_get_strings(struct dsa_switch *ds, int port, u32 stringset, uint8_t *data); +@@ -463,6 +461,23 @@ int qca8k_port_change_mtu(struct dsa_swi + int qca8k_port_max_mtu(struct dsa_switch *ds, int port); + + /* 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); + ++/* 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); ++int qca8k_port_fdb_del(struct dsa_switch *ds, int port, ++ const unsigned char *addr, u16 vid); ++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); ++int qca8k_port_mdb_del(struct dsa_switch *ds, int port, ++ const struct switchdev_obj_port_mdb *mdb); ++ + #endif /* __QCA8K_H */ |