23c9bddf07e21bae2a44e2f2d104cfaaf6e106f8
[openwrt/openwrt.git] / target / linux / generic / backport-5.4 / 747-v5.5-net-dsa-mv88e6xxx-Add-support-for-port-mirroring.patch
1 From f0942e00a1abb6404ca4302c66497fc623676c11 Mon Sep 17 00:00:00 2001
2 From: Iwan R Timmer <irtimmer@gmail.com>
3 Date: Thu, 7 Nov 2019 22:11:14 +0100
4 Subject: [PATCH] net: dsa: mv88e6xxx: Add support for port mirroring
5
6 Add support for configuring port mirroring through the cls_matchall
7 classifier. We do a full ingress and/or egress capture towards a
8 capture port. It allows setting a different capture port for ingress
9 and egress traffic.
10
11 It keeps track of the mirrored ports and the destination ports to
12 prevent changes to the capture port while other ports are being
13 mirrored.
14
15 Signed-off-by: Iwan R Timmer <irtimmer@gmail.com>
16 Reviewed-by: Andrew Lunn <andrew@lunn.ch>
17 Signed-off-by: David S. Miller <davem@davemloft.net>
18 ---
19 drivers/net/dsa/mv88e6xxx/chip.c | 76 +++++++++++++++++++++++++++++
20 drivers/net/dsa/mv88e6xxx/chip.h | 6 +++
21 drivers/net/dsa/mv88e6xxx/global1.c | 18 +++++--
22 drivers/net/dsa/mv88e6xxx/port.c | 37 ++++++++++++++
23 drivers/net/dsa/mv88e6xxx/port.h | 3 ++
24 5 files changed, 136 insertions(+), 4 deletions(-)
25
26 --- a/drivers/net/dsa/mv88e6xxx/chip.c
27 +++ b/drivers/net/dsa/mv88e6xxx/chip.c
28 @@ -4921,6 +4921,80 @@ static int mv88e6xxx_port_mdb_del(struct
29 return err;
30 }
31
32 +static int mv88e6xxx_port_mirror_add(struct dsa_switch *ds, int port,
33 + struct dsa_mall_mirror_tc_entry *mirror,
34 + bool ingress)
35 +{
36 + enum mv88e6xxx_egress_direction direction = ingress ?
37 + MV88E6XXX_EGRESS_DIR_INGRESS :
38 + MV88E6XXX_EGRESS_DIR_EGRESS;
39 + struct mv88e6xxx_chip *chip = ds->priv;
40 + bool other_mirrors = false;
41 + int i;
42 + int err;
43 +
44 + if (!chip->info->ops->set_egress_port)
45 + return -EOPNOTSUPP;
46 +
47 + mutex_lock(&chip->reg_lock);
48 + if ((ingress ? chip->ingress_dest_port : chip->egress_dest_port) !=
49 + mirror->to_local_port) {
50 + for (i = 0; i < mv88e6xxx_num_ports(chip); i++)
51 + other_mirrors |= ingress ?
52 + chip->ports[i].mirror_ingress :
53 + chip->ports[i].mirror_egress;
54 +
55 + /* Can't change egress port when other mirror is active */
56 + if (other_mirrors) {
57 + err = -EBUSY;
58 + goto out;
59 + }
60 +
61 + err = chip->info->ops->set_egress_port(chip,
62 + direction,
63 + mirror->to_local_port);
64 + if (err)
65 + goto out;
66 + }
67 +
68 + err = mv88e6xxx_port_set_mirror(chip, port, direction, true);
69 +out:
70 + mutex_unlock(&chip->reg_lock);
71 +
72 + return err;
73 +}
74 +
75 +static void mv88e6xxx_port_mirror_del(struct dsa_switch *ds, int port,
76 + struct dsa_mall_mirror_tc_entry *mirror)
77 +{
78 + enum mv88e6xxx_egress_direction direction = mirror->ingress ?
79 + MV88E6XXX_EGRESS_DIR_INGRESS :
80 + MV88E6XXX_EGRESS_DIR_EGRESS;
81 + struct mv88e6xxx_chip *chip = ds->priv;
82 + bool other_mirrors = false;
83 + int i;
84 +
85 + mutex_lock(&chip->reg_lock);
86 + if (mv88e6xxx_port_set_mirror(chip, port, direction, false))
87 + dev_err(ds->dev, "p%d: failed to disable mirroring\n", port);
88 +
89 + for (i = 0; i < mv88e6xxx_num_ports(chip); i++)
90 + other_mirrors |= mirror->ingress ?
91 + chip->ports[i].mirror_ingress :
92 + chip->ports[i].mirror_egress;
93 +
94 + /* Reset egress port when no other mirror is active */
95 + if (!other_mirrors) {
96 + if (chip->info->ops->set_egress_port(chip,
97 + direction,
98 + dsa_upstream_port(ds,
99 + port)));
100 + dev_err(ds->dev, "failed to set egress port\n");
101 + }
102 +
103 + mutex_unlock(&chip->reg_lock);
104 +}
105 +
106 static int mv88e6xxx_port_egress_floods(struct dsa_switch *ds, int port,
107 bool unicast, bool multicast)
108 {
109 @@ -4975,6 +5049,8 @@ static const struct dsa_switch_ops mv88e
110 .port_mdb_prepare = mv88e6xxx_port_mdb_prepare,
111 .port_mdb_add = mv88e6xxx_port_mdb_add,
112 .port_mdb_del = mv88e6xxx_port_mdb_del,
113 + .port_mirror_add = mv88e6xxx_port_mirror_add,
114 + .port_mirror_del = mv88e6xxx_port_mirror_del,
115 .crosschip_bridge_join = mv88e6xxx_crosschip_bridge_join,
116 .crosschip_bridge_leave = mv88e6xxx_crosschip_bridge_leave,
117 .port_hwtstamp_set = mv88e6xxx_port_hwtstamp_set,
118 --- a/drivers/net/dsa/mv88e6xxx/chip.h
119 +++ b/drivers/net/dsa/mv88e6xxx/chip.h
120 @@ -232,6 +232,8 @@ struct mv88e6xxx_port {
121 u64 vtu_member_violation;
122 u64 vtu_miss_violation;
123 u8 cmode;
124 + bool mirror_ingress;
125 + bool mirror_egress;
126 unsigned int serdes_irq;
127 };
128
129 @@ -315,6 +317,10 @@ struct mv88e6xxx_chip {
130 u16 evcap_config;
131 u16 enable_count;
132
133 + /* Current ingress and egress monitor ports */
134 + int egress_dest_port;
135 + int ingress_dest_port;
136 +
137 /* Per-port timestamping resources. */
138 struct mv88e6xxx_port_hwtstamp port_hwtstamp[DSA_MAX_PORTS];
139
140 --- a/drivers/net/dsa/mv88e6xxx/global1.c
141 +++ b/drivers/net/dsa/mv88e6xxx/global1.c
142 @@ -267,6 +267,7 @@ int mv88e6095_g1_set_egress_port(struct
143 enum mv88e6xxx_egress_direction direction,
144 int port)
145 {
146 + int *dest_port_chip;
147 u16 reg;
148 int err;
149
150 @@ -276,11 +277,13 @@ int mv88e6095_g1_set_egress_port(struct
151
152 switch (direction) {
153 case MV88E6XXX_EGRESS_DIR_INGRESS:
154 + dest_port_chip = &chip->ingress_dest_port;
155 reg &= MV88E6185_G1_MONITOR_CTL_INGRESS_DEST_MASK;
156 reg |= port <<
157 __bf_shf(MV88E6185_G1_MONITOR_CTL_INGRESS_DEST_MASK);
158 break;
159 case MV88E6XXX_EGRESS_DIR_EGRESS:
160 + dest_port_chip = &chip->egress_dest_port;
161 reg &= MV88E6185_G1_MONITOR_CTL_EGRESS_DEST_MASK;
162 reg |= port <<
163 __bf_shf(MV88E6185_G1_MONITOR_CTL_EGRESS_DEST_MASK);
164 @@ -289,7 +292,11 @@ int mv88e6095_g1_set_egress_port(struct
165 return -EINVAL;
166 }
167
168 - return mv88e6xxx_g1_write(chip, MV88E6185_G1_MONITOR_CTL, reg);
169 + err = mv88e6xxx_g1_write(chip, MV88E6185_G1_MONITOR_CTL, reg);
170 + if (!err)
171 + *dest_port_chip = port;
172 +
173 + return err;
174 }
175
176 /* Older generations also call this the ARP destination. It has been
177 @@ -325,14 +332,17 @@ int mv88e6390_g1_set_egress_port(struct
178 enum mv88e6xxx_egress_direction direction,
179 int port)
180 {
181 + int *dest_port_chip;
182 u16 ptr;
183 int err;
184
185 switch (direction) {
186 case MV88E6XXX_EGRESS_DIR_INGRESS:
187 + dest_port_chip = &chip->ingress_dest_port;
188 ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_INGRESS_DEST;
189 break;
190 case MV88E6XXX_EGRESS_DIR_EGRESS:
191 + dest_port_chip = &chip->egress_dest_port;
192 ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_EGRESS_DEST;
193 break;
194 default:
195 @@ -340,10 +350,10 @@ int mv88e6390_g1_set_egress_port(struct
196 }
197
198 err = mv88e6390_g1_monitor_write(chip, ptr, port);
199 - if (err)
200 - return err;
201 + if (!err)
202 + *dest_port_chip = port;
203
204 - return 0;
205 + return err;
206 }
207
208 int mv88e6390_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port)
209 --- a/drivers/net/dsa/mv88e6xxx/port.c
210 +++ b/drivers/net/dsa/mv88e6xxx/port.c
211 @@ -1181,6 +1181,43 @@ int mv88e6095_port_set_upstream_port(str
212 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);
213 }
214
215 +int mv88e6xxx_port_set_mirror(struct mv88e6xxx_chip *chip, int port,
216 + enum mv88e6xxx_egress_direction direction,
217 + bool mirror)
218 +{
219 + bool *mirror_port;
220 + u16 reg;
221 + u16 bit;
222 + int err;
223 +
224 + err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, &reg);
225 + if (err)
226 + return err;
227 +
228 + switch (direction) {
229 + case MV88E6XXX_EGRESS_DIR_INGRESS:
230 + bit = MV88E6XXX_PORT_CTL2_INGRESS_MONITOR;
231 + mirror_port = &chip->ports[port].mirror_ingress;
232 + break;
233 + case MV88E6XXX_EGRESS_DIR_EGRESS:
234 + bit = MV88E6XXX_PORT_CTL2_EGRESS_MONITOR;
235 + mirror_port = &chip->ports[port].mirror_egress;
236 + break;
237 + default:
238 + return -EINVAL;
239 + }
240 +
241 + reg &= ~bit;
242 + if (mirror)
243 + reg |= bit;
244 +
245 + err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);
246 + if (!err)
247 + *mirror_port = mirror;
248 +
249 + return err;
250 +}
251 +
252 int mv88e6xxx_port_set_8021q_mode(struct mv88e6xxx_chip *chip, int port,
253 u16 mode)
254 {
255 --- a/drivers/net/dsa/mv88e6xxx/port.h
256 +++ b/drivers/net/dsa/mv88e6xxx/port.h
257 @@ -368,6 +368,9 @@ int mv88e6352_port_link_state(struct mv8
258 int mv88e6xxx_port_set_map_da(struct mv88e6xxx_chip *chip, int port);
259 int mv88e6095_port_set_upstream_port(struct mv88e6xxx_chip *chip, int port,
260 int upstream_port);
261 +int mv88e6xxx_port_set_mirror(struct mv88e6xxx_chip *chip, int port,
262 + enum mv88e6xxx_egress_direction direction,
263 + bool mirror);
264
265 int mv88e6xxx_port_disable_learn_limit(struct mv88e6xxx_chip *chip, int port);
266 int mv88e6xxx_port_disable_pri_override(struct mv88e6xxx_chip *chip, int port);