d31789370e8c6b7642ae76f692984eec7751ba0f
[openwrt/staging/neocturne.git] /
1 From 23cfc7172e5297d0bee49ac6f6f8248d1cf0820d Mon Sep 17 00:00:00 2001
2 From: Christian Marangi <ansuelsmth@gmail.com>
3 Date: Sun, 30 Jul 2023 09:41:10 +0200
4 Subject: [PATCH 1/4] net: dsa: qca8k: make learning configurable and keep off
5 if standalone
6
7 Address learning should initially be turned off by the driver for port
8 operation in standalone mode, then the DSA core handles changes to it
9 via ds->ops->port_bridge_flags().
10
11 Currently this is not the case for qca8k where learning is enabled
12 unconditionally in qca8k_setup for every user port.
13
14 Handle ports configured in standalone mode by making the learning
15 configurable and not enabling it by default.
16
17 Implement .port_pre_bridge_flags and .port_bridge_flags dsa ops to
18 enable learning for bridge that request it and tweak
19 .port_stp_state_set to correctly disable learning when port is
20 configured in standalone mode.
21
22 Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
23 Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
24 Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
25 Link: https://lore.kernel.org/r/20230730074113.21889-2-ansuelsmth@gmail.com
26 Signed-off-by: Paolo Abeni <pabeni@redhat.com>
27 ---
28 drivers/net/dsa/qca/qca8k-8xxx.c | 7 +++--
29 drivers/net/dsa/qca/qca8k-common.c | 48 ++++++++++++++++++++++++++++++
30 drivers/net/dsa/qca/qca8k.h | 6 ++++
31 3 files changed, 58 insertions(+), 3 deletions(-)
32
33 --- a/drivers/net/dsa/qca/qca8k-8xxx.c
34 +++ b/drivers/net/dsa/qca/qca8k-8xxx.c
35 @@ -1905,9 +1905,8 @@ qca8k_setup(struct dsa_switch *ds)
36 if (ret)
37 return ret;
38
39 - /* Enable ARP Auto-learning by default */
40 - ret = regmap_set_bits(priv->regmap, QCA8K_PORT_LOOKUP_CTRL(i),
41 - QCA8K_PORT_LOOKUP_LEARN);
42 + ret = regmap_clear_bits(priv->regmap, QCA8K_PORT_LOOKUP_CTRL(i),
43 + QCA8K_PORT_LOOKUP_LEARN);
44 if (ret)
45 return ret;
46
47 @@ -2013,6 +2012,8 @@ static const struct dsa_switch_ops qca8k
48 .port_change_mtu = qca8k_port_change_mtu,
49 .port_max_mtu = qca8k_port_max_mtu,
50 .port_stp_state_set = qca8k_port_stp_state_set,
51 + .port_pre_bridge_flags = qca8k_port_pre_bridge_flags,
52 + .port_bridge_flags = qca8k_port_bridge_flags,
53 .port_bridge_join = qca8k_port_bridge_join,
54 .port_bridge_leave = qca8k_port_bridge_leave,
55 .port_fast_age = qca8k_port_fast_age,
56 --- a/drivers/net/dsa/qca/qca8k-common.c
57 +++ b/drivers/net/dsa/qca/qca8k-common.c
58 @@ -565,9 +565,26 @@ int qca8k_get_mac_eee(struct dsa_switch
59 return 0;
60 }
61
62 +static int qca8k_port_configure_learning(struct dsa_switch *ds, int port,
63 + bool learning)
64 +{
65 + struct qca8k_priv *priv = ds->priv;
66 +
67 + if (learning)
68 + return regmap_set_bits(priv->regmap,
69 + QCA8K_PORT_LOOKUP_CTRL(port),
70 + QCA8K_PORT_LOOKUP_LEARN);
71 + else
72 + return regmap_clear_bits(priv->regmap,
73 + QCA8K_PORT_LOOKUP_CTRL(port),
74 + QCA8K_PORT_LOOKUP_LEARN);
75 +}
76 +
77 void qca8k_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
78 {
79 + struct dsa_port *dp = dsa_to_port(ds, port);
80 struct qca8k_priv *priv = ds->priv;
81 + bool learning = false;
82 u32 stp_state;
83
84 switch (state) {
85 @@ -582,8 +599,11 @@ void qca8k_port_stp_state_set(struct dsa
86 break;
87 case BR_STATE_LEARNING:
88 stp_state = QCA8K_PORT_LOOKUP_STATE_LEARNING;
89 + learning = dp->learning;
90 break;
91 case BR_STATE_FORWARDING:
92 + learning = dp->learning;
93 + fallthrough;
94 default:
95 stp_state = QCA8K_PORT_LOOKUP_STATE_FORWARD;
96 break;
97 @@ -591,6 +611,34 @@ void qca8k_port_stp_state_set(struct dsa
98
99 qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
100 QCA8K_PORT_LOOKUP_STATE_MASK, stp_state);
101 +
102 + qca8k_port_configure_learning(ds, port, learning);
103 +}
104 +
105 +int qca8k_port_pre_bridge_flags(struct dsa_switch *ds, int port,
106 + struct switchdev_brport_flags flags,
107 + struct netlink_ext_ack *extack)
108 +{
109 + if (flags.mask & ~BR_LEARNING)
110 + return -EINVAL;
111 +
112 + return 0;
113 +}
114 +
115 +int qca8k_port_bridge_flags(struct dsa_switch *ds, int port,
116 + struct switchdev_brport_flags flags,
117 + struct netlink_ext_ack *extack)
118 +{
119 + int ret;
120 +
121 + if (flags.mask & BR_LEARNING) {
122 + ret = qca8k_port_configure_learning(ds, port,
123 + flags.val & BR_LEARNING);
124 + if (ret)
125 + return ret;
126 + }
127 +
128 + return 0;
129 }
130
131 int qca8k_port_bridge_join(struct dsa_switch *ds, int port,
132 --- a/drivers/net/dsa/qca/qca8k.h
133 +++ b/drivers/net/dsa/qca/qca8k.h
134 @@ -448,6 +448,12 @@ int qca8k_get_mac_eee(struct dsa_switch
135
136 /* Common bridge function */
137 void qca8k_port_stp_state_set(struct dsa_switch *ds, int port, u8 state);
138 +int qca8k_port_pre_bridge_flags(struct dsa_switch *ds, int port,
139 + struct switchdev_brport_flags flags,
140 + struct netlink_ext_ack *extack);
141 +int qca8k_port_bridge_flags(struct dsa_switch *ds, int port,
142 + struct switchdev_brport_flags flags,
143 + struct netlink_ext_ack *extack);
144 int qca8k_port_bridge_join(struct dsa_switch *ds, int port,
145 struct dsa_bridge bridge,
146 bool *tx_fwd_offload,