kernel: 5.10: backport qca8k feature additions
[openwrt/openwrt.git] / target / linux / generic / backport-5.10 / 797-v5.16-05-net-dsa-qca8k-add-support-for-cpu-port-6.patch
diff --git a/target/linux/generic/backport-5.10/797-v5.16-05-net-dsa-qca8k-add-support-for-cpu-port-6.patch b/target/linux/generic/backport-5.10/797-v5.16-05-net-dsa-qca8k-add-support-for-cpu-port-6.patch
new file mode 100644 (file)
index 0000000..320db8f
--- /dev/null
@@ -0,0 +1,153 @@
+From 3fcf734aa482487df83cf8f18608438fcf59127f Mon Sep 17 00:00:00 2001
+From: Ansuel Smith <ansuelsmth@gmail.com>
+Date: Thu, 14 Oct 2021 00:39:10 +0200
+Subject: net: dsa: qca8k: add support for cpu port 6
+
+Currently CPU port is always hardcoded to port 0. This switch have 2 CPU
+ports. The original intention of this driver seems to be use the
+mac06_exchange bit to swap MAC0 with MAC6 in the strange configuration
+where device have connected only the CPU port 6. To skip the
+introduction of a new binding, rework the driver to address the
+secondary CPU port as primary and drop any reference of hardcoded port.
+With configuration of mac06 exchange, just skip the definition of port0
+and define the CPU port as a secondary. The driver will autoconfigure
+the switch to use that as the primary CPU port.
+
+Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/qca8k.c | 51 ++++++++++++++++++++++++++++++++++---------------
+ drivers/net/dsa/qca8k.h |  2 --
+ 2 files changed, 36 insertions(+), 17 deletions(-)
+
+--- a/drivers/net/dsa/qca8k.c
++++ b/drivers/net/dsa/qca8k.c
+@@ -977,6 +977,22 @@ qca8k_setup_mac_pwr_sel(struct qca8k_pri
+       return ret;
+ }
++static int qca8k_find_cpu_port(struct dsa_switch *ds)
++{
++      struct qca8k_priv *priv = ds->priv;
++
++      /* Find the connected cpu port. Valid port are 0 or 6 */
++      if (dsa_is_cpu_port(ds, 0))
++              return 0;
++
++      dev_dbg(priv->dev, "port 0 is not the CPU port. Checking port 6");
++
++      if (dsa_is_cpu_port(ds, 6))
++              return 6;
++
++      return -EINVAL;
++}
++
+ static int
+ qca8k_parse_port_config(struct qca8k_priv *priv)
+ {
+@@ -1017,13 +1033,13 @@ static int
+ qca8k_setup(struct dsa_switch *ds)
+ {
+       struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
+-      int ret, i;
++      int cpu_port, ret, i;
+       u32 mask;
+-      /* Make sure that port 0 is the cpu port */
+-      if (!dsa_is_cpu_port(ds, 0)) {
+-              dev_err(priv->dev, "port 0 is not the CPU port");
+-              return -EINVAL;
++      cpu_port = qca8k_find_cpu_port(ds);
++      if (cpu_port < 0) {
++              dev_err(priv->dev, "No cpu port configured in both cpu port0 and port6");
++              return cpu_port;
+       }
+       /* Parse CPU port config to be later used in phy_link mac_config */
+@@ -1065,7 +1081,7 @@ qca8k_setup(struct dsa_switch *ds)
+               dev_warn(priv->dev, "mib init failed");
+       /* Enable QCA header mode on the cpu port */
+-      ret = qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(QCA8K_CPU_PORT),
++      ret = qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(cpu_port),
+                         QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_TX_S |
+                         QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_RX_S);
+       if (ret) {
+@@ -1087,10 +1103,10 @@ qca8k_setup(struct dsa_switch *ds)
+       /* Forward all unknown frames to CPU port for Linux processing */
+       ret = qca8k_write(priv, QCA8K_REG_GLOBAL_FW_CTRL1,
+-                        BIT(0) << QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_S |
+-                        BIT(0) << QCA8K_GLOBAL_FW_CTRL1_BC_DP_S |
+-                        BIT(0) << QCA8K_GLOBAL_FW_CTRL1_MC_DP_S |
+-                        BIT(0) << QCA8K_GLOBAL_FW_CTRL1_UC_DP_S);
++                        BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_S |
++                        BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_BC_DP_S |
++                        BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_MC_DP_S |
++                        BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_UC_DP_S);
+       if (ret)
+               return ret;
+@@ -1098,7 +1114,7 @@ qca8k_setup(struct dsa_switch *ds)
+       for (i = 0; i < QCA8K_NUM_PORTS; i++) {
+               /* CPU port gets connected to all user ports of the switch */
+               if (dsa_is_cpu_port(ds, i)) {
+-                      ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(QCA8K_CPU_PORT),
++                      ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(cpu_port),
+                                       QCA8K_PORT_LOOKUP_MEMBER, dsa_user_ports(ds));
+                       if (ret)
+                               return ret;
+@@ -1110,7 +1126,7 @@ qca8k_setup(struct dsa_switch *ds)
+                       ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i),
+                                       QCA8K_PORT_LOOKUP_MEMBER,
+-                                      BIT(QCA8K_CPU_PORT));
++                                      BIT(cpu_port));
+                       if (ret)
+                               return ret;
+@@ -1616,9 +1632,12 @@ static int
+ qca8k_port_bridge_join(struct dsa_switch *ds, int port, struct net_device *br)
+ {
+       struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
+-      int port_mask = BIT(QCA8K_CPU_PORT);
++      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 = 1; i < QCA8K_NUM_PORTS; i++) {
+               if (dsa_to_port(ds, i)->bridge_dev != br)
+                       continue;
+@@ -1645,7 +1664,9 @@ static void
+ qca8k_port_bridge_leave(struct dsa_switch *ds, int port, struct net_device *br)
+ {
+       struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
+-      int i;
++      int cpu_port, i;
++
++      cpu_port = dsa_to_port(ds, port)->cpu_dp->index;
+       for (i = 1; i < QCA8K_NUM_PORTS; i++) {
+               if (dsa_to_port(ds, i)->bridge_dev != br)
+@@ -1662,7 +1683,7 @@ qca8k_port_bridge_leave(struct dsa_switc
+        * this port
+        */
+       qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
+-                QCA8K_PORT_LOOKUP_MEMBER, BIT(QCA8K_CPU_PORT));
++                QCA8K_PORT_LOOKUP_MEMBER, BIT(cpu_port));
+ }
+ static int
+--- a/drivers/net/dsa/qca8k.h
++++ b/drivers/net/dsa/qca8k.h
+@@ -24,8 +24,6 @@
+ #define QCA8K_NUM_FDB_RECORDS                         2048
+-#define QCA8K_CPU_PORT                                        0
+-
+ #define QCA8K_PORT_VID_DEF                            1
+ /* Global control registers */