2022-07-27 12:08:21

by Christian Marangi

[permalink] [raw]
Subject: [net-next PATCH v5 00/14] net: dsa: qca8k: code split for qca8k

This is needed ad ipq4019 SoC have an internal switch that is
based on qca8k with very minor changes. The general function is equal.

Because of this we split the driver to common and specific code.

As the common function needs to be moved to a different file to be
reused, we had to convert every remaining user of qca8k_read/write/rmw
to regmap variant.
We had also to generilized the special handling for the ethtool_stats
function that makes use of the autocast mib. (ipq4019 will have a
different tagger and use mmio so it could be quicker to use mmio instead
of automib feature)
And we had to convert the regmap read/write to bulk implementation to
drop the special function that makes use of it. This will be compatible
with ipq4019 and at the same time permits normal switch to use the eth
mgmt way to send the entire ATU table read/write in one go.

v5:
- Wrap function to single line/80 char
- Cache match data even for read_switch function
- Add additional review tag
v4:
- Fix compilation error with clang compiler reported by kernel
test bot
v3:
- Squash more patch to skip even more "migration patch"
- Add new patch to cache match data in priv struct
- Fix extra space
- Drop unnecessary cast to qca8k_priv from void pointers
v2:
- Rework patch to drop dependency with bulk regmap (will be
converted later)
- Split the split patch to additional patch
- Rework autocast_mib function and move it to match data

Christian Marangi (14):
net: dsa: qca8k: cache match data to speed up access
net: dsa: qca8k: make mib autocast feature optional
net: dsa: qca8k: move mib struct to common code
net: dsa: qca8k: move qca8k read/write/rmw and reg table to common
code
net: dsa: qca8k: move qca8k bulk read/write helper to common code
net: dsa: qca8k: move mib init function to common code
net: dsa: qca8k: move port set status/eee/ethtool stats function to
common code
net: dsa: qca8k: move bridge functions to common code
net: dsa: qca8k: move set age/MTU/port enable/disable functions to
common code
net: dsa: qca8k: move port FDB/MDB function to common code
net: dsa: qca8k: move port mirror functions to common code
net: dsa: qca8k: move port VLAN functions to common code
net: dsa: qca8k: move port LAG functions to common code
net: dsa: qca8k: move read_switch_id function to common code

drivers/net/dsa/qca/Makefile | 1 +
drivers/net/dsa/qca/{qca8k.c => qca8k-8xxx.c} | 1711 +++--------------
drivers/net/dsa/qca/qca8k-common.c | 1210 ++++++++++++
drivers/net/dsa/qca/qca8k.h | 100 +
4 files changed, 1549 insertions(+), 1473 deletions(-)
rename drivers/net/dsa/qca/{qca8k.c => qca8k-8xxx.c} (63%)
create mode 100644 drivers/net/dsa/qca/qca8k-common.c

--
2.36.1


2022-07-27 12:12:30

by Christian Marangi

[permalink] [raw]
Subject: [net-next PATCH v5 02/14] net: dsa: qca8k: make mib autocast feature optional

Some switch may not support mib autocast feature and require the legacy
way of reading the regs directly.
Make the mib autocast feature optional and permit to declare support for
it using match_data struct in a dedicated qca8k_info_ops struct.

Signed-off-by: Christian Marangi <[email protected]>
---
drivers/net/dsa/qca/qca8k.c | 11 +++++++++--
drivers/net/dsa/qca/qca8k.h | 5 +++++
2 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/net/dsa/qca/qca8k.c b/drivers/net/dsa/qca/qca8k.c
index 64524a721221..02a4765f267e 100644
--- a/drivers/net/dsa/qca/qca8k.c
+++ b/drivers/net/dsa/qca/qca8k.c
@@ -2104,8 +2104,8 @@ qca8k_get_ethtool_stats(struct dsa_switch *ds, int port,
u32 hi = 0;
int ret;

- if (priv->mgmt_master &&
- qca8k_get_ethtool_stats_eth(ds, port, data) > 0)
+ if (priv->mgmt_master && priv->info->ops->autocast_mib &&
+ priv->info->ops->autocast_mib(ds, port, data) > 0)
return;

for (i = 0; i < priv->info->mib_count; i++) {
@@ -3243,20 +3243,27 @@ static int qca8k_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(qca8k_pm_ops,
qca8k_suspend, qca8k_resume);

+static const struct qca8k_info_ops qca8xxx_ops = {
+ .autocast_mib = qca8k_get_ethtool_stats_eth,
+};
+
static const struct qca8k_match_data qca8327 = {
.id = QCA8K_ID_QCA8327,
.reduced_package = true,
.mib_count = QCA8K_QCA832X_MIB_COUNT,
+ .ops = &qca8xxx_ops,
};

static const struct qca8k_match_data qca8328 = {
.id = QCA8K_ID_QCA8327,
.mib_count = QCA8K_QCA832X_MIB_COUNT,
+ .ops = &qca8xxx_ops,
};

static const struct qca8k_match_data qca833x = {
.id = QCA8K_ID_QCA8337,
.mib_count = QCA8K_QCA833X_MIB_COUNT,
+ .ops = &qca8xxx_ops,
};

static const struct of_device_id qca8k_of_match[] = {
diff --git a/drivers/net/dsa/qca/qca8k.h b/drivers/net/dsa/qca/qca8k.h
index 0b990b46890a..377ce8c72914 100644
--- a/drivers/net/dsa/qca/qca8k.h
+++ b/drivers/net/dsa/qca/qca8k.h
@@ -324,10 +324,15 @@ enum qca8k_mid_cmd {
QCA8K_MIB_CAST = 3,
};

+struct qca8k_info_ops {
+ int (*autocast_mib)(struct dsa_switch *ds, int port, u64 *data);
+};
+
struct qca8k_match_data {
u8 id;
bool reduced_package;
u8 mib_count;
+ const struct qca8k_info_ops *ops;
};

enum {
--
2.36.1

2022-07-27 12:14:32

by Christian Marangi

[permalink] [raw]
Subject: [net-next PATCH v5 08/14] net: dsa: qca8k: move bridge functions to common code

The same bridge functions are used by drivers based on qca8k family
switch. Move them to common code to make them accessible also by other
drivers.
While at it also drop unnecessary qca8k_priv cast for void pointers.

Signed-off-by: Christian Marangi <[email protected]>
Reviewed-by: Vladimir Oltean <[email protected]>
---
drivers/net/dsa/qca/qca8k-8xxx.c | 93 ------------------------------
drivers/net/dsa/qca/qca8k-common.c | 93 ++++++++++++++++++++++++++++++
drivers/net/dsa/qca/qca8k.h | 9 +++
3 files changed, 102 insertions(+), 93 deletions(-)

diff --git a/drivers/net/dsa/qca/qca8k-8xxx.c b/drivers/net/dsa/qca/qca8k-8xxx.c
index 9729aabbd83d..11d3116733af 100644
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
@@ -1898,99 +1898,6 @@ qca8k_get_ethtool_stats_eth(struct dsa_switch *ds, int port, u64 *data)
return ret;
}

-static void
-qca8k_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
-{
- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
- u32 stp_state;
-
- switch (state) {
- case BR_STATE_DISABLED:
- stp_state = QCA8K_PORT_LOOKUP_STATE_DISABLED;
- break;
- case BR_STATE_BLOCKING:
- stp_state = QCA8K_PORT_LOOKUP_STATE_BLOCKING;
- break;
- case BR_STATE_LISTENING:
- stp_state = QCA8K_PORT_LOOKUP_STATE_LISTENING;
- break;
- case BR_STATE_LEARNING:
- stp_state = QCA8K_PORT_LOOKUP_STATE_LEARNING;
- break;
- case BR_STATE_FORWARDING:
- default:
- stp_state = QCA8K_PORT_LOOKUP_STATE_FORWARD;
- break;
- }
-
- qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
- QCA8K_PORT_LOOKUP_STATE_MASK, stp_state);
-}
-
-static int qca8k_port_bridge_join(struct dsa_switch *ds, int port,
- struct dsa_bridge bridge,
- bool *tx_fwd_offload,
- struct netlink_ext_ack *extack)
-{
- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
- int port_mask, cpu_port;
- int i, ret;
-
- cpu_port = dsa_to_port(ds, port)->cpu_dp->index;
- port_mask = BIT(cpu_port);
-
- for (i = 0; i < QCA8K_NUM_PORTS; i++) {
- if (dsa_is_cpu_port(ds, i))
- continue;
- if (!dsa_port_offloads_bridge(dsa_to_port(ds, i), &bridge))
- continue;
- /* Add this port to the portvlan mask of the other ports
- * in the bridge
- */
- ret = regmap_set_bits(priv->regmap,
- QCA8K_PORT_LOOKUP_CTRL(i),
- BIT(port));
- if (ret)
- return ret;
- if (i != port)
- port_mask |= BIT(i);
- }
-
- /* Add all other ports to this ports portvlan mask */
- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
- QCA8K_PORT_LOOKUP_MEMBER, port_mask);
-
- return ret;
-}
-
-static void qca8k_port_bridge_leave(struct dsa_switch *ds, int port,
- struct dsa_bridge bridge)
-{
- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
- int cpu_port, i;
-
- cpu_port = dsa_to_port(ds, port)->cpu_dp->index;
-
- for (i = 0; i < QCA8K_NUM_PORTS; i++) {
- if (dsa_is_cpu_port(ds, i))
- continue;
- if (!dsa_port_offloads_bridge(dsa_to_port(ds, i), &bridge))
- continue;
- /* Remove this port to the portvlan mask of the other ports
- * in the bridge
- */
- regmap_clear_bits(priv->regmap,
- QCA8K_PORT_LOOKUP_CTRL(i),
- BIT(port));
- }
-
- /* Set the cpu port to be the only one in the portvlan mask of
- * this port
- */
- qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
- QCA8K_PORT_LOOKUP_MEMBER, BIT(cpu_port));
-}
-
static void
qca8k_port_fast_age(struct dsa_switch *ds, int port)
{
diff --git a/drivers/net/dsa/qca/qca8k-common.c b/drivers/net/dsa/qca/qca8k-common.c
index c662fdbae51f..13069c9ba3e6 100644
--- a/drivers/net/dsa/qca/qca8k-common.c
+++ b/drivers/net/dsa/qca/qca8k-common.c
@@ -8,6 +8,7 @@

#include <linux/netdevice.h>
#include <net/dsa.h>
+#include <linux/if_bridge.h>

#include "qca8k.h"

@@ -275,3 +276,95 @@ int qca8k_get_mac_eee(struct dsa_switch *ds, int port,
/* Nothing to do on the port's MAC */
return 0;
}
+
+void qca8k_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
+{
+ struct qca8k_priv *priv = ds->priv;
+ u32 stp_state;
+
+ switch (state) {
+ case BR_STATE_DISABLED:
+ stp_state = QCA8K_PORT_LOOKUP_STATE_DISABLED;
+ break;
+ case BR_STATE_BLOCKING:
+ stp_state = QCA8K_PORT_LOOKUP_STATE_BLOCKING;
+ break;
+ case BR_STATE_LISTENING:
+ stp_state = QCA8K_PORT_LOOKUP_STATE_LISTENING;
+ break;
+ case BR_STATE_LEARNING:
+ stp_state = QCA8K_PORT_LOOKUP_STATE_LEARNING;
+ break;
+ case BR_STATE_FORWARDING:
+ default:
+ stp_state = QCA8K_PORT_LOOKUP_STATE_FORWARD;
+ break;
+ }
+
+ qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
+ QCA8K_PORT_LOOKUP_STATE_MASK, stp_state);
+}
+
+int qca8k_port_bridge_join(struct dsa_switch *ds, int port,
+ struct dsa_bridge bridge,
+ bool *tx_fwd_offload,
+ struct netlink_ext_ack *extack)
+{
+ struct qca8k_priv *priv = ds->priv;
+ int port_mask, cpu_port;
+ int i, ret;
+
+ cpu_port = dsa_to_port(ds, port)->cpu_dp->index;
+ port_mask = BIT(cpu_port);
+
+ for (i = 0; i < QCA8K_NUM_PORTS; i++) {
+ if (dsa_is_cpu_port(ds, i))
+ continue;
+ if (!dsa_port_offloads_bridge(dsa_to_port(ds, i), &bridge))
+ continue;
+ /* Add this port to the portvlan mask of the other ports
+ * in the bridge
+ */
+ ret = regmap_set_bits(priv->regmap,
+ QCA8K_PORT_LOOKUP_CTRL(i),
+ BIT(port));
+ if (ret)
+ return ret;
+ if (i != port)
+ port_mask |= BIT(i);
+ }
+
+ /* Add all other ports to this ports portvlan mask */
+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
+ QCA8K_PORT_LOOKUP_MEMBER, port_mask);
+
+ return ret;
+}
+
+void qca8k_port_bridge_leave(struct dsa_switch *ds, int port,
+ struct dsa_bridge bridge)
+{
+ struct qca8k_priv *priv = ds->priv;
+ int cpu_port, i;
+
+ cpu_port = dsa_to_port(ds, port)->cpu_dp->index;
+
+ for (i = 0; i < QCA8K_NUM_PORTS; i++) {
+ if (dsa_is_cpu_port(ds, i))
+ continue;
+ if (!dsa_port_offloads_bridge(dsa_to_port(ds, i), &bridge))
+ continue;
+ /* Remove this port to the portvlan mask of the other ports
+ * in the bridge
+ */
+ regmap_clear_bits(priv->regmap,
+ QCA8K_PORT_LOOKUP_CTRL(i),
+ BIT(port));
+ }
+
+ /* Set the cpu port to be the only one in the portvlan mask of
+ * this port
+ */
+ qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
+ QCA8K_PORT_LOOKUP_MEMBER, BIT(cpu_port));
+}
diff --git a/drivers/net/dsa/qca/qca8k.h b/drivers/net/dsa/qca/qca8k.h
index c73cbdfc6ac6..edb2b23a02b9 100644
--- a/drivers/net/dsa/qca/qca8k.h
+++ b/drivers/net/dsa/qca/qca8k.h
@@ -454,4 +454,13 @@ int qca8k_get_sset_count(struct dsa_switch *ds, int port, int sset);
int qca8k_set_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *eee);
int qca8k_get_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e);

+/* Common bridge function */
+void qca8k_port_stp_state_set(struct dsa_switch *ds, int port, u8 state);
+int qca8k_port_bridge_join(struct dsa_switch *ds, int port,
+ struct dsa_bridge bridge,
+ bool *tx_fwd_offload,
+ struct netlink_ext_ack *extack);
+void qca8k_port_bridge_leave(struct dsa_switch *ds, int port,
+ struct dsa_bridge bridge);
+
#endif /* __QCA8K_H */
--
2.36.1

2022-07-27 12:18:49

by Christian Marangi

[permalink] [raw]
Subject: [net-next PATCH v5 01/14] net: dsa: qca8k: cache match data to speed up access

Using of_device_get_match_data is expensive. Cache match data to speed
up access and rework user of match data to use the new cached value.

Signed-off-by: Christian Marangi <[email protected]>
---
drivers/net/dsa/qca/qca8k.c | 35 +++++++++++------------------------
drivers/net/dsa/qca/qca8k.h | 1 +
2 files changed, 12 insertions(+), 24 deletions(-)

diff --git a/drivers/net/dsa/qca/qca8k.c b/drivers/net/dsa/qca/qca8k.c
index 1cbb05b0323f..64524a721221 100644
--- a/drivers/net/dsa/qca/qca8k.c
+++ b/drivers/net/dsa/qca/qca8k.c
@@ -1462,8 +1462,8 @@ static int qca8k_find_cpu_port(struct dsa_switch *ds)
static int
qca8k_setup_of_pws_reg(struct qca8k_priv *priv)
{
+ const struct qca8k_match_data *data = priv->info;
struct device_node *node = priv->dev->of_node;
- const struct qca8k_match_data *data;
u32 val = 0;
int ret;

@@ -1472,8 +1472,6 @@ qca8k_setup_of_pws_reg(struct qca8k_priv *priv)
* Should be applied by default but we set this just to make sure.
*/
if (priv->switch_id == QCA8K_ID_QCA8327) {
- data = of_device_get_match_data(priv->dev);
-
/* Set the correct package of 148 pin for QCA8327 */
if (data->reduced_package)
val |= QCA8327_PWS_PACKAGE148_EN;
@@ -1996,23 +1994,19 @@ static void qca8k_setup_pcs(struct qca8k_priv *priv, struct qca8k_pcs *qpcs,
static void
qca8k_get_strings(struct dsa_switch *ds, int port, u32 stringset, uint8_t *data)
{
- const struct qca8k_match_data *match_data;
struct qca8k_priv *priv = ds->priv;
int i;

if (stringset != ETH_SS_STATS)
return;

- match_data = of_device_get_match_data(priv->dev);
-
- for (i = 0; i < match_data->mib_count; i++)
+ for (i = 0; i < priv->info->mib_count; i++)
strncpy(data + i * ETH_GSTRING_LEN, ar8327_mib[i].name,
ETH_GSTRING_LEN);
}

static void qca8k_mib_autocast_handler(struct dsa_switch *ds, struct sk_buff *skb)
{
- const struct qca8k_match_data *match_data;
struct qca8k_mib_eth_data *mib_eth_data;
struct qca8k_priv *priv = ds->priv;
const struct qca8k_mib_desc *mib;
@@ -2031,10 +2025,9 @@ static void qca8k_mib_autocast_handler(struct dsa_switch *ds, struct sk_buff *sk
if (port != mib_eth_data->req_port)
goto exit;

- match_data = device_get_match_data(priv->dev);
data = mib_eth_data->data;

- for (i = 0; i < match_data->mib_count; i++) {
+ for (i = 0; i < priv->info->mib_count; i++) {
mib = &ar8327_mib[i];

/* First 3 mib are present in the skb head */
@@ -2106,7 +2099,6 @@ qca8k_get_ethtool_stats(struct dsa_switch *ds, int port,
uint64_t *data)
{
struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
- const struct qca8k_match_data *match_data;
const struct qca8k_mib_desc *mib;
u32 reg, i, val;
u32 hi = 0;
@@ -2116,9 +2108,7 @@ qca8k_get_ethtool_stats(struct dsa_switch *ds, int port,
qca8k_get_ethtool_stats_eth(ds, port, data) > 0)
return;

- match_data = of_device_get_match_data(priv->dev);
-
- for (i = 0; i < match_data->mib_count; i++) {
+ for (i = 0; i < priv->info->mib_count; i++) {
mib = &ar8327_mib[i];
reg = QCA8K_PORT_MIB_COUNTER(port) + mib->offset;

@@ -2141,15 +2131,12 @@ qca8k_get_ethtool_stats(struct dsa_switch *ds, int port,
static int
qca8k_get_sset_count(struct dsa_switch *ds, int port, int sset)
{
- const struct qca8k_match_data *match_data;
struct qca8k_priv *priv = ds->priv;

if (sset != ETH_SS_STATS)
return 0;

- match_data = of_device_get_match_data(priv->dev);
-
- return match_data->mib_count;
+ return priv->info->mib_count;
}

static int
@@ -3093,14 +3080,11 @@ static const struct dsa_switch_ops qca8k_switch_ops = {

static int qca8k_read_switch_id(struct qca8k_priv *priv)
{
- const struct qca8k_match_data *data;
u32 val;
u8 id;
int ret;

- /* get the switches ID from the compatible */
- data = of_device_get_match_data(priv->dev);
- if (!data)
+ if (!priv->info)
return -ENODEV;

ret = qca8k_read(priv, QCA8K_REG_MASK_CTRL, &val);
@@ -3108,8 +3092,10 @@ static int qca8k_read_switch_id(struct qca8k_priv *priv)
return -ENODEV;

id = QCA8K_MASK_CTRL_DEVICE_ID(val);
- if (id != data->id) {
- dev_err(priv->dev, "Switch id detected %x but expected %x", id, data->id);
+ if (id != priv->info->id) {
+ dev_err(priv->dev,
+ "Switch id detected %x but expected %x",
+ id, priv->info->id);
return -ENODEV;
}

@@ -3134,6 +3120,7 @@ qca8k_sw_probe(struct mdio_device *mdiodev)
if (!priv)
return -ENOMEM;

+ priv->info = of_device_get_match_data(priv->dev);
priv->bus = mdiodev->bus;
priv->dev = &mdiodev->dev;

diff --git a/drivers/net/dsa/qca/qca8k.h b/drivers/net/dsa/qca/qca8k.h
index ec58d0e80a70..0b990b46890a 100644
--- a/drivers/net/dsa/qca/qca8k.h
+++ b/drivers/net/dsa/qca/qca8k.h
@@ -401,6 +401,7 @@ struct qca8k_priv {
struct qca8k_mdio_cache mdio_cache;
struct qca8k_pcs pcs_port_0;
struct qca8k_pcs pcs_port_6;
+ const struct qca8k_match_data *info;
};

struct qca8k_mib_desc {
--
2.36.1

2022-07-27 12:27:01

by Christian Marangi

[permalink] [raw]
Subject: [net-next PATCH v5 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 <[email protected]>
---
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(-)

diff --git a/drivers/net/dsa/qca/qca8k-8xxx.c b/drivers/net/dsa/qca/qca8k-8xxx.c
index 1815863502c9..bf4dd1cd0f9d 100644
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
@@ -441,217 +441,6 @@ static struct regmap_config qca8k_regmap_config = {
.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
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)
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
qca8k_port_mirror_add(struct dsa_switch *ds, int port,
struct dsa_mall_mirror_tc_entry *mirror,
diff --git a/drivers/net/dsa/qca/qca8k-common.c b/drivers/net/dsa/qca/qca8k-common.c
index e25df4b23b9a..8e92837781ee 100644
--- a/drivers/net/dsa/qca/qca8k-common.c
+++ b/drivers/net/dsa/qca/qca8k-common.c
@@ -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 */
-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;

@@ -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 */
-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;
@@ -148,6 +148,211 @@ int qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask)
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 ret;
@@ -369,6 +574,15 @@ void qca8k_port_bridge_leave(struct dsa_switch *ds, int 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)
{
struct qca8k_priv *priv = ds->priv;
@@ -453,3 +667,82 @@ int qca8k_port_max_mtu(struct dsa_switch *ds, int port)
{
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);
+}
diff --git a/drivers/net/dsa/qca/qca8k.h b/drivers/net/dsa/qca/qca8k.h
index e7d4df253b8c..9da7928de83c 100644
--- a/drivers/net/dsa/qca/qca8k.h
+++ b/drivers/net/dsa/qca/qca8k.h
@@ -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_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);
@@ -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);

/* 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,
+ 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 */
--
2.36.1

2022-07-27 12:27:20

by Christian Marangi

[permalink] [raw]
Subject: [net-next PATCH v5 06/14] net: dsa: qca8k: move mib init function to common code

The same mib function is used by drivers based on qca8k family switch.
Move it to common code to make it accessible also by other drivers.

Signed-off-by: Christian Marangi <[email protected]>
---
drivers/net/dsa/qca/qca8k-8xxx.c | 37 ------------------------------
drivers/net/dsa/qca/qca8k-common.c | 35 ++++++++++++++++++++++++++++
drivers/net/dsa/qca/qca8k.h | 4 ++++
3 files changed, 39 insertions(+), 37 deletions(-)

diff --git a/drivers/net/dsa/qca/qca8k-8xxx.c b/drivers/net/dsa/qca/qca8k-8xxx.c
index 8a5529844c7a..b4daa097a7fc 100644
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
@@ -441,15 +441,6 @@ static struct regmap_config qca8k_regmap_config = {
.cache_type = REGCACHE_NONE, /* Explicitly disable CACHE */
};

-static int
-qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask)
-{
- u32 val;
-
- return regmap_read_poll_timeout(priv->regmap, reg, val, !(val & mask), 0,
- QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC);
-}
-
static int
qca8k_fdb_read(struct qca8k_priv *priv, struct qca8k_fdb *fdb)
{
@@ -777,34 +768,6 @@ qca8k_vlan_del(struct qca8k_priv *priv, u8 port, u16 vid)
return ret;
}

-static int
-qca8k_mib_init(struct qca8k_priv *priv)
-{
- int ret;
-
- mutex_lock(&priv->reg_mutex);
- ret = regmap_update_bits(priv->regmap, QCA8K_REG_MIB,
- QCA8K_MIB_FUNC | QCA8K_MIB_BUSY,
- FIELD_PREP(QCA8K_MIB_FUNC, QCA8K_MIB_FLUSH) |
- QCA8K_MIB_BUSY);
- if (ret)
- goto exit;
-
- ret = qca8k_busy_wait(priv, QCA8K_REG_MIB, QCA8K_MIB_BUSY);
- if (ret)
- goto exit;
-
- ret = regmap_set_bits(priv->regmap, QCA8K_REG_MIB, QCA8K_MIB_CPU_KEEP);
- if (ret)
- goto exit;
-
- ret = qca8k_write(priv, QCA8K_REG_MODULE_EN, QCA8K_MODULE_EN_MIB);
-
-exit:
- mutex_unlock(&priv->reg_mutex);
- return ret;
-}
-
static void
qca8k_port_set_status(struct qca8k_priv *priv, int port, int enable)
{
diff --git a/drivers/net/dsa/qca/qca8k-common.c b/drivers/net/dsa/qca/qca8k-common.c
index a47f876033ba..7da3547f9d97 100644
--- a/drivers/net/dsa/qca/qca8k-common.c
+++ b/drivers/net/dsa/qca/qca8k-common.c
@@ -138,3 +138,38 @@ int qca8k_bulk_write(struct qca8k_priv *priv, u32 reg, u32 *val, int len)

return 0;
}
+
+int qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask)
+{
+ u32 val;
+
+ return regmap_read_poll_timeout(priv->regmap, reg, val, !(val & mask), 0,
+ QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC);
+}
+
+int qca8k_mib_init(struct qca8k_priv *priv)
+{
+ int ret;
+
+ mutex_lock(&priv->reg_mutex);
+ ret = regmap_update_bits(priv->regmap, QCA8K_REG_MIB,
+ QCA8K_MIB_FUNC | QCA8K_MIB_BUSY,
+ FIELD_PREP(QCA8K_MIB_FUNC, QCA8K_MIB_FLUSH) |
+ QCA8K_MIB_BUSY);
+ if (ret)
+ goto exit;
+
+ ret = qca8k_busy_wait(priv, QCA8K_REG_MIB, QCA8K_MIB_BUSY);
+ if (ret)
+ goto exit;
+
+ ret = regmap_set_bits(priv->regmap, QCA8K_REG_MIB, QCA8K_MIB_CPU_KEEP);
+ if (ret)
+ goto exit;
+
+ ret = qca8k_write(priv, QCA8K_REG_MODULE_EN, QCA8K_MODULE_EN_MIB);
+
+exit:
+ mutex_unlock(&priv->reg_mutex);
+ return ret;
+}
diff --git a/drivers/net/dsa/qca/qca8k.h b/drivers/net/dsa/qca/qca8k.h
index df32c1e3a797..f55ef97f826f 100644
--- a/drivers/net/dsa/qca/qca8k.h
+++ b/drivers/net/dsa/qca/qca8k.h
@@ -430,6 +430,7 @@ struct qca8k_fdb {
/* Common setup function */
extern const struct qca8k_mib_desc ar8327_mib[];
extern const struct regmap_access_table qca8k_readable_table;
+int qca8k_mib_init(struct qca8k_priv *priv);

/* Common read/write/rmw function */
int qca8k_read(struct qca8k_priv *priv, u32 reg, u32 *val);
@@ -439,4 +440,7 @@ 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);
+
#endif /* __QCA8K_H */
--
2.36.1

2022-07-27 14:55:39

by Vladimir Oltean

[permalink] [raw]
Subject: Re: [net-next PATCH v5 01/14] net: dsa: qca8k: cache match data to speed up access

On Wed, Jul 27, 2022 at 01:35:10PM +0200, Christian Marangi wrote:
> Using of_device_get_match_data is expensive. Cache match data to speed
> up access and rework user of match data to use the new cached value.
>
> Signed-off-by: Christian Marangi <[email protected]>
> ---

Reviewed-by: Vladimir Oltean <[email protected]>

2022-07-27 14:56:27

by Vladimir Oltean

[permalink] [raw]
Subject: Re: [net-next PATCH v5 06/14] net: dsa: qca8k: move mib init function to common code

On Wed, Jul 27, 2022 at 01:35:15PM +0200, Christian Marangi wrote:
> The same mib function is used by drivers based on qca8k family switch.
> Move it to common code to make it accessible also by other drivers.
>
> Signed-off-by: Christian Marangi <[email protected]>
> ---

Reviewed-by: Vladimir Oltean <[email protected]>

2022-07-27 15:05:29

by Vladimir Oltean

[permalink] [raw]
Subject: Re: [net-next PATCH v5 02/14] net: dsa: qca8k: make mib autocast feature optional

On Wed, Jul 27, 2022 at 01:35:11PM +0200, Christian Marangi wrote:
> Some switch may not support mib autocast feature and require the legacy
> way of reading the regs directly.
> Make the mib autocast feature optional and permit to declare support for
> it using match_data struct in a dedicated qca8k_info_ops struct.
>
> Signed-off-by: Christian Marangi <[email protected]>
> ---

Reviewed-by: Vladimir Oltean <[email protected]>

2022-07-27 15:30:23

by Vladimir Oltean

[permalink] [raw]
Subject: Re: [net-next PATCH v5 10/14] net: dsa: qca8k: move port FDB/MDB function to common code

On Wed, Jul 27, 2022 at 01:35:19PM +0200, Christian Marangi wrote:
> 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 <[email protected]>
> ---

Reviewed-by: Vladimir Oltean <[email protected]>

2022-07-29 05:31:23

by patchwork-bot+netdevbpf

[permalink] [raw]
Subject: Re: [net-next PATCH v5 00/14] net: dsa: qca8k: code split for qca8k

Hello:

This series was applied to netdev/net-next.git (master)
by Jakub Kicinski <[email protected]>:

On Wed, 27 Jul 2022 13:35:09 +0200 you wrote:
> This is needed ad ipq4019 SoC have an internal switch that is
> based on qca8k with very minor changes. The general function is equal.
>
> Because of this we split the driver to common and specific code.
>
> As the common function needs to be moved to a different file to be
> reused, we had to convert every remaining user of qca8k_read/write/rmw
> to regmap variant.
> We had also to generilized the special handling for the ethtool_stats
> function that makes use of the autocast mib. (ipq4019 will have a
> different tagger and use mmio so it could be quicker to use mmio instead
> of automib feature)
> And we had to convert the regmap read/write to bulk implementation to
> drop the special function that makes use of it. This will be compatible
> with ipq4019 and at the same time permits normal switch to use the eth
> mgmt way to send the entire ATU table read/write in one go.
>
> [...]

Here is the summary with links:
- [net-next,v5,01/14] net: dsa: qca8k: cache match data to speed up access
https://git.kernel.org/netdev/net-next/c/3bb0844e7bcd
- [net-next,v5,02/14] net: dsa: qca8k: make mib autocast feature optional
https://git.kernel.org/netdev/net-next/c/533c64bca62a
- [net-next,v5,03/14] net: dsa: qca8k: move mib struct to common code
https://git.kernel.org/netdev/net-next/c/027152b83043
- [net-next,v5,04/14] net: dsa: qca8k: move qca8k read/write/rmw and reg table to common code
https://git.kernel.org/netdev/net-next/c/d5f901eab2e9
- [net-next,v5,05/14] net: dsa: qca8k: move qca8k bulk read/write helper to common code
https://git.kernel.org/netdev/net-next/c/910746444313
- [net-next,v5,06/14] net: dsa: qca8k: move mib init function to common code
https://git.kernel.org/netdev/net-next/c/fce1ec0c4e2d
- [net-next,v5,07/14] net: dsa: qca8k: move port set status/eee/ethtool stats function to common code
https://git.kernel.org/netdev/net-next/c/472fcea160f2
- [net-next,v5,08/14] net: dsa: qca8k: move bridge functions to common code
https://git.kernel.org/netdev/net-next/c/fd3cae2f3ac1
- [net-next,v5,09/14] net: dsa: qca8k: move set age/MTU/port enable/disable functions to common code
https://git.kernel.org/netdev/net-next/c/b3a302b171f7
- [net-next,v5,10/14] net: dsa: qca8k: move port FDB/MDB function to common code
https://git.kernel.org/netdev/net-next/c/2e5bd96eea86
- [net-next,v5,11/14] net: dsa: qca8k: move port mirror functions to common code
https://git.kernel.org/netdev/net-next/c/742d37a84d3f
- [net-next,v5,12/14] net: dsa: qca8k: move port VLAN functions to common code
https://git.kernel.org/netdev/net-next/c/c5290f636624
- [net-next,v5,13/14] net: dsa: qca8k: move port LAG functions to common code
https://git.kernel.org/netdev/net-next/c/e9bbf019af44
- [net-next,v5,14/14] net: dsa: qca8k: move read_switch_id function to common code
https://git.kernel.org/netdev/net-next/c/9d1bcb1f293f

You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html


2022-07-29 21:37:25

by Florian Fainelli

[permalink] [raw]
Subject: Re: [net-next PATCH v5 02/14] net: dsa: qca8k: make mib autocast feature optional

On 7/27/22 04:35, Christian Marangi wrote:
> Some switch may not support mib autocast feature and require the legacy
> way of reading the regs directly.
> Make the mib autocast feature optional and permit to declare support for
> it using match_data struct in a dedicated qca8k_info_ops struct.
>
> Signed-off-by: Christian Marangi <[email protected]>

Reviewed-by: Florian Fainelli <[email protected]>
--
Florian

2022-07-29 22:01:49

by Florian Fainelli

[permalink] [raw]
Subject: Re: [net-next PATCH v5 01/14] net: dsa: qca8k: cache match data to speed up access

On 7/27/22 04:35, Christian Marangi wrote:
> Using of_device_get_match_data is expensive. Cache match data to speed
> up access and rework user of match data to use the new cached value.
>
> Signed-off-by: Christian Marangi <[email protected]>

Reviewed-by: Florian Fainelli <[email protected]>
--
Florian

2022-07-29 22:03:00

by Florian Fainelli

[permalink] [raw]
Subject: Re: [net-next PATCH v5 00/14] net: dsa: qca8k: code split for qca8k

On 7/28/22 22:30, [email protected] wrote:
> Hello:
>
> This series was applied to netdev/net-next.git (master)
> by Jakub Kicinski <[email protected]>:
>
> On Wed, 27 Jul 2022 13:35:09 +0200 you wrote:
>> This is needed ad ipq4019 SoC have an internal switch that is
>> based on qca8k with very minor changes. The general function is equal.
>>
>> Because of this we split the driver to common and specific code.
>>
>> As the common function needs to be moved to a different file to be
>> reused, we had to convert every remaining user of qca8k_read/write/rmw
>> to regmap variant.
>> We had also to generilized the special handling for the ethtool_stats
>> function that makes use of the autocast mib. (ipq4019 will have a
>> different tagger and use mmio so it could be quicker to use mmio instead
>> of automib feature)
>> And we had to convert the regmap read/write to bulk implementation to
>> drop the special function that makes use of it. This will be compatible
>> with ipq4019 and at the same time permits normal switch to use the eth
>> mgmt way to send the entire ATU table read/write in one go.
>>
>> [...]
>
> Here is the summary with links:
> - [net-next,v5,01/14] net: dsa: qca8k: cache match data to speed up access
> https://git.kernel.org/netdev/net-next/c/3bb0844e7bcd
> - [net-next,v5,02/14] net: dsa: qca8k: make mib autocast feature optional
> https://git.kernel.org/netdev/net-next/c/533c64bca62a
> - [net-next,v5,03/14] net: dsa: qca8k: move mib struct to common code
> https://git.kernel.org/netdev/net-next/c/027152b83043
> - [net-next,v5,04/14] net: dsa: qca8k: move qca8k read/write/rmw and reg table to common code
> https://git.kernel.org/netdev/net-next/c/d5f901eab2e9
> - [net-next,v5,05/14] net: dsa: qca8k: move qca8k bulk read/write helper to common code
> https://git.kernel.org/netdev/net-next/c/910746444313
> - [net-next,v5,06/14] net: dsa: qca8k: move mib init function to common code
> https://git.kernel.org/netdev/net-next/c/fce1ec0c4e2d
> - [net-next,v5,07/14] net: dsa: qca8k: move port set status/eee/ethtool stats function to common code
> https://git.kernel.org/netdev/net-next/c/472fcea160f2
> - [net-next,v5,08/14] net: dsa: qca8k: move bridge functions to common code
> https://git.kernel.org/netdev/net-next/c/fd3cae2f3ac1
> - [net-next,v5,09/14] net: dsa: qca8k: move set age/MTU/port enable/disable functions to common code
> https://git.kernel.org/netdev/net-next/c/b3a302b171f7
> - [net-next,v5,10/14] net: dsa: qca8k: move port FDB/MDB function to common code
> https://git.kernel.org/netdev/net-next/c/2e5bd96eea86
> - [net-next,v5,11/14] net: dsa: qca8k: move port mirror functions to common code
> https://git.kernel.org/netdev/net-next/c/742d37a84d3f
> - [net-next,v5,12/14] net: dsa: qca8k: move port VLAN functions to common code
> https://git.kernel.org/netdev/net-next/c/c5290f636624
> - [net-next,v5,13/14] net: dsa: qca8k: move port LAG functions to common code
> https://git.kernel.org/netdev/net-next/c/e9bbf019af44
> - [net-next,v5,14/14] net: dsa: qca8k: move read_switch_id function to common code
> https://git.kernel.org/netdev/net-next/c/9d1bcb1f293f
>
> You are awesome, thank you!

Oh well, at least I reviewed the patches :)
--
Florian

2022-07-29 22:04:13

by Florian Fainelli

[permalink] [raw]
Subject: Re: [net-next PATCH v5 06/14] net: dsa: qca8k: move mib init function to common code

On 7/27/22 04:35, Christian Marangi wrote:
> The same mib function is used by drivers based on qca8k family switch.
> Move it to common code to make it accessible also by other drivers.
>
> Signed-off-by: Christian Marangi <[email protected]>

Reviewed-by: Florian Fainelli <[email protected]>
--
Florian

2022-07-29 22:05:26

by Florian Fainelli

[permalink] [raw]
Subject: Re: [net-next PATCH v5 08/14] net: dsa: qca8k: move bridge functions to common code

On 7/27/22 04:35, Christian Marangi wrote:
> The same bridge functions are used by drivers based on qca8k family
> switch. Move them to common code to make them accessible also by other
> drivers.
> While at it also drop unnecessary qca8k_priv cast for void pointers.
>
> Signed-off-by: Christian Marangi <[email protected]>
> Reviewed-by: Vladimir Oltean <[email protected]>

Reviewed-by: Florian Fainelli <[email protected]>
--
Florian

2022-07-29 22:06:03

by Florian Fainelli

[permalink] [raw]
Subject: Re: [net-next PATCH v5 10/14] net: dsa: qca8k: move port FDB/MDB function to common code

On 7/27/22 04:35, Christian Marangi wrote:
> 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 <[email protected]>

Reviewed-by: Florian Fainelli <[email protected]>
--
Florian

2022-09-14 20:50:49

by Pali Rohár

[permalink] [raw]
Subject: Regression: qca8k_sw_probe crashes (Was: Re: [net-next PATCH v5 01/14] net: dsa: qca8k: cache match data to speed up access)

On Wednesday 27 July 2022 13:35:10 Christian Marangi wrote:
> Using of_device_get_match_data is expensive. Cache match data to speed
> up access and rework user of match data to use the new cached value.
>
> Signed-off-by: Christian Marangi <[email protected]>
> ---
> drivers/net/dsa/qca/qca8k.c | 35 +++++++++++------------------------
> drivers/net/dsa/qca/qca8k.h | 1 +
> 2 files changed, 12 insertions(+), 24 deletions(-)
>
> diff --git a/drivers/net/dsa/qca/qca8k.c b/drivers/net/dsa/qca/qca8k.c
> index 1cbb05b0323f..64524a721221 100644

Hello! This commit is causing kernel crash on powerpc P2020 based board
with QCA8337N-AL3C switch.

[ 1.901926] Kernel attempted to read user page (38) - exploit attempt? (uid: 0)
[ 1.909264] BUG: Kernel NULL pointer dereference on read at 0x00000038
[ 1.915793] Faulting instruction address: 0xc079adec
[ 1.920756] Oops: Kernel access of bad area, sig: 11 [#1]
[ 1.926154] BE PAGE_SIZE=4K SMP NR_CPUS=2 P2020RDB-PC
[ 1.931207] Modules linked in:
[ 1.934260] CPU: 1 PID: 1 Comm: swapper/0 Not tainted 6.0.0-rc2-0caacb197b677410bdac81bc34f05235+ #123
[ 1.943576] NIP: c079adec LR: c06b8920 CTR: 00000000
[ 1.948626] REGS: c146f970 TRAP: 0300 Not tainted (6.0.0-rc2-0caacb197b677410bdac81bc34f05235+)
[ 1.957591] MSR: 00029000 <CE,EE,ME> CR: 84228842 XER: 20000000
[ 1.963786] DEAR: 00000038 ESR: 00000000
[ 1.963786] GPR00: c06b8920 c146fa60 c14a8000 00000000 00000000 00000000 c1c957fc 00000004
[ 1.963786] GPR08: c174f6e8 00000000 c1c95700 c18c2e40 84228848 00000000 c0004548 00000000
[ 1.963786] GPR16: 00000000 c174f600 00000000 fffff000 c0c06504 c0c05c3c efff8b9c efff8b9c
[ 1.963786] GPR24: 00000001 efff8bb0 efff8bac 00000000 00000000 c174f600 00000000 c1c95718
[ 2.001278] NIP [c079adec] of_device_get_match_data+0x10/0x38
[ 2.007040] LR [c06b8920] qca8k_sw_probe+0x40/0x224
[ 2.011927] Call Trace:
[ 2.014368] [c146fa60] [c174f600] 0xc174f600 (unreliable)
[ 2.019774] [c146fa70] [c06b8920] qca8k_sw_probe+0x40/0x224
[ 2.025354] [c146faa0] [c06b2ef0] mdio_probe+0x40/0x8c
[ 2.030497] [c146fac0] [c060ddb8] really_probe+0x250/0x340
[ 2.035990] [c146faf0] [c060dfb0] driver_probe_device+0x44/0xfc
[ 2.041916] [c146fb20] [c060e440] __device_attach_driver+0xa4/0x114
[ 2.048190] [c146fb40] [c060b83c] bus_for_each_drv+0x8c/0xe8
[ 2.053855] [c146fb70] [c060db04] __device_attach+0x110/0x164
[ 2.059607] [c146fba0] [c060c8ec] bus_probe_device+0xb0/0xd4
[ 2.065271] [c146fbc0] [c0609654] device_add+0x438/0x8c8
[ 2.070595] [c146fc20] [c06b3018] mdio_device_register+0x48/0x70
[ 2.076608] [c146fc40] [c06b4c98] of_mdiobus_register+0x310/0x398
[ 2.082707] [c146fca0] [c06ba7d4] fsl_pq_mdio_probe+0x1f0/0x374
[ 2.088636] [c146fd10] [c0610708] platform_probe+0x48/0xac
[ 2.094129] [c146fd30] [c060dc40] really_probe+0xd8/0x340
[ 2.099533] [c146fd60] [c060dfb0] driver_probe_device+0x44/0xfc
[ 2.105459] [c146fd90] [c060e534] __driver_attach+0x84/0x154
[ 2.111124] [c146fdb0] [c060b73c] bus_for_each_dev+0x88/0xe0
[ 2.116789] [c146fde0] [c060cc80] bus_add_driver+0x1f0/0x22c
[ 2.122453] [c146fe10] [c060eca8] driver_register+0x88/0x16c
[ 2.128118] [c146fe30] [c0004150] do_one_initcall+0x80/0x284
[ 2.133785] [c146fea0] [c10012d0] kernel_init_freeable+0x1f4/0x2a0
[ 2.139973] [c146fee0] [c000456c] kernel_init+0x24/0x154
[ 2.145289] [c146ff00] [c001426c] ret_from_kernel_thread+0x5c/0x64
[ 2.151479] Instruction dump:
[ 2.154444] 71290020 40820010 7d445378 38210010 4bffe068 38600000 38210010 4e800020
[ 2.162211] 9421fff0 7c0802a6 7c641b78 90010014 <81230038> 80690018 4bffffad 2c030000
[ 2.170156] ---[ end trace 0000000000000000 ]---
[ 2.174770]
[ 3.176268] Kernel panic - not syncing: Fatal exception
[ 3.181497] Rebooting in 1 seconds..


> --- a/drivers/net/dsa/qca/qca8k.c
> +++ b/drivers/net/dsa/qca/qca8k.c

There is line:
priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL);
and after that follows chunk:

> @@ -3134,6 +3120,7 @@ qca8k_sw_probe(struct mdio_device *mdiodev)
> if (!priv)
> return -ENOMEM;
>
> + priv->info = of_device_get_match_data(priv->dev);

So function of_device_get_match_data() takes as its argument NULL
pointer as 'priv' structure is at this stage zeroed, and which cause
above kernel crash. priv->dev is filled lines below:

> priv->bus = mdiodev->bus;
> priv->dev = &mdiodev->dev;
>

I would propose following patch:

diff --git a/drivers/net/dsa/qca/qca8k-8xxx.c b/drivers/net/dsa/qca/qca8k-8xxx.c
index 1d3e7782a71f..614950a5878a 100644
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
@@ -1887,13 +1887,13 @@ qca8k_sw_probe(struct mdio_device *mdiodev)
*/
priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;

+ priv->dev = &mdiodev->dev;
priv->info = of_device_get_match_data(priv->dev);
priv->bus = mdiodev->bus;
- priv->dev = &mdiodev->dev;

priv->reset_gpio = devm_gpiod_get_optional(priv->dev, "reset",
GPIOD_ASIS);
if (IS_ERR(priv->reset_gpio))
return PTR_ERR(priv->reset_gpio);

which fixes above crash.