blob: 4b4584f8522aa48d8c509eb7880085955a90576e [file] [log] [blame]
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001/*
2 * drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
3 * Copyright (c) 2015 Mellanox Technologies. All rights reserved.
4 * Copyright (c) 2015 Jiri Pirko <jiri@mellanox.com>
5 * Copyright (c) 2015 Ido Schimmel <idosch@mellanox.com>
6 * Copyright (c) 2015 Elad Raz <eladr@mellanox.com>
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the names of the copyright holders nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * Alternatively, this software may be distributed under the terms of the
21 * GNU General Public License ("GPL") version 2 as published by the Free
22 * Software Foundation.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
28 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
35 */
36
37#include <linux/kernel.h>
38#include <linux/types.h>
39#include <linux/netdevice.h>
40#include <linux/etherdevice.h>
41#include <linux/slab.h>
42#include <linux/device.h>
43#include <linux/skbuff.h>
44#include <linux/if_vlan.h>
45#include <linux/if_bridge.h>
46#include <linux/workqueue.h>
47#include <linux/jiffies.h>
Ido Schimmel4f2c6ae2016-01-27 15:16:43 +010048#include <linux/rtnetlink.h>
Ido Schimmel9b63ef882017-10-08 11:57:56 +020049#include <linux/netlink.h>
Jiri Pirko56ade8f2015-10-16 14:01:37 +020050#include <net/switchdev.h>
51
Yotam Gigic4db9532017-10-09 11:15:34 +020052#include "spectrum_router.h"
Jiri Pirko56ade8f2015-10-16 14:01:37 +020053#include "spectrum.h"
54#include "core.h"
55#include "reg.h"
56
Ido Schimmelc57529e2017-05-26 08:37:31 +020057struct mlxsw_sp_bridge_ops;
58
Ido Schimmel5f6935c2017-05-16 19:38:26 +020059struct mlxsw_sp_bridge {
60 struct mlxsw_sp *mlxsw_sp;
61 struct {
62 struct delayed_work dw;
63#define MLXSW_SP_DEFAULT_LEARNING_INTERVAL 100
64 unsigned int interval; /* ms */
65 } fdb_notify;
66#define MLXSW_SP_MIN_AGEING_TIME 10
67#define MLXSW_SP_MAX_AGEING_TIME 1000000
68#define MLXSW_SP_DEFAULT_AGEING_TIME 300
69 u32 ageing_time;
Ido Schimmelc57529e2017-05-26 08:37:31 +020070 bool vlan_enabled_exists;
71 struct list_head bridges_list;
Ido Schimmel5f6935c2017-05-16 19:38:26 +020072 DECLARE_BITMAP(mids_bitmap, MLXSW_SP_MID_MAX);
Ido Schimmelc57529e2017-05-26 08:37:31 +020073 const struct mlxsw_sp_bridge_ops *bridge_8021q_ops;
74 const struct mlxsw_sp_bridge_ops *bridge_8021d_ops;
Ido Schimmel5f6935c2017-05-16 19:38:26 +020075};
76
Ido Schimmelc57529e2017-05-26 08:37:31 +020077struct mlxsw_sp_bridge_device {
78 struct net_device *dev;
79 struct list_head list;
80 struct list_head ports_list;
Nogah Frankelb80888a2017-09-20 16:15:04 +020081 struct list_head mids_list;
Ido Schimmelc57529e2017-05-26 08:37:31 +020082 u8 vlan_enabled:1,
83 multicast_enabled:1;
84 const struct mlxsw_sp_bridge_ops *ops;
85};
Ido Schimmel5f6935c2017-05-16 19:38:26 +020086
Ido Schimmelc57529e2017-05-26 08:37:31 +020087struct mlxsw_sp_bridge_port {
88 struct net_device *dev;
89 struct mlxsw_sp_bridge_device *bridge_device;
90 struct list_head list;
91 struct list_head vlans_list;
92 unsigned int ref_count;
93 u8 stp_state;
94 unsigned long flags;
95 bool mrouter;
96 bool lagged;
97 union {
98 u16 lag_id;
99 u16 system_port;
100 };
101};
Elad Raze4b6f692016-01-10 21:06:27 +0100102
Ido Schimmelc57529e2017-05-26 08:37:31 +0200103struct mlxsw_sp_bridge_vlan {
104 struct list_head list;
105 struct list_head port_vlan_list;
Ido Schimmel54a73202015-12-15 16:03:41 +0100106 u16 vid;
Ido Schimmelc57529e2017-05-26 08:37:31 +0200107};
Ido Schimmel54a73202015-12-15 16:03:41 +0100108
Ido Schimmelc57529e2017-05-26 08:37:31 +0200109struct mlxsw_sp_bridge_ops {
110 int (*port_join)(struct mlxsw_sp_bridge_device *bridge_device,
111 struct mlxsw_sp_bridge_port *bridge_port,
Ido Schimmel9b63ef882017-10-08 11:57:56 +0200112 struct mlxsw_sp_port *mlxsw_sp_port,
113 struct netlink_ext_ack *extack);
Ido Schimmelc57529e2017-05-26 08:37:31 +0200114 void (*port_leave)(struct mlxsw_sp_bridge_device *bridge_device,
115 struct mlxsw_sp_bridge_port *bridge_port,
116 struct mlxsw_sp_port *mlxsw_sp_port);
Ido Schimmela1107482017-05-26 08:37:39 +0200117 struct mlxsw_sp_fid *
118 (*fid_get)(struct mlxsw_sp_bridge_device *bridge_device,
119 u16 vid);
Ido Schimmelc57529e2017-05-26 08:37:31 +0200120};
121
122static int
123mlxsw_sp_bridge_port_fdb_flush(struct mlxsw_sp *mlxsw_sp,
124 struct mlxsw_sp_bridge_port *bridge_port,
125 u16 fid_index);
126
Nogah Frankel2e3496c2017-09-20 16:15:09 +0200127static void
Nogah Frankelbb5355b2017-09-20 16:15:12 +0200128mlxsw_sp_bridge_port_mdb_flush(struct mlxsw_sp_port *mlxsw_sp_port,
129 struct mlxsw_sp_bridge_port *bridge_port);
130
131static void
Nogah Frankel2e3496c2017-09-20 16:15:09 +0200132mlxsw_sp_bridge_mdb_mc_enable_sync(struct mlxsw_sp_port *mlxsw_sp_port,
133 struct mlxsw_sp_bridge_device
134 *bridge_device);
135
Nogah Frankel3ddda112017-09-20 16:15:14 +0200136static void
137mlxsw_sp_port_mrouter_update_mdb(struct mlxsw_sp_port *mlxsw_sp_port,
138 struct mlxsw_sp_bridge_port *bridge_port,
139 bool add);
140
Ido Schimmelc57529e2017-05-26 08:37:31 +0200141static struct mlxsw_sp_bridge_device *
142mlxsw_sp_bridge_device_find(const struct mlxsw_sp_bridge *bridge,
143 const struct net_device *br_dev)
144{
145 struct mlxsw_sp_bridge_device *bridge_device;
146
147 list_for_each_entry(bridge_device, &bridge->bridges_list, list)
148 if (bridge_device->dev == br_dev)
149 return bridge_device;
150
151 return NULL;
152}
153
154static struct mlxsw_sp_bridge_device *
155mlxsw_sp_bridge_device_create(struct mlxsw_sp_bridge *bridge,
156 struct net_device *br_dev)
157{
158 struct device *dev = bridge->mlxsw_sp->bus_info->dev;
159 struct mlxsw_sp_bridge_device *bridge_device;
160 bool vlan_enabled = br_vlan_enabled(br_dev);
161
162 if (vlan_enabled && bridge->vlan_enabled_exists) {
163 dev_err(dev, "Only one VLAN-aware bridge is supported\n");
164 return ERR_PTR(-EINVAL);
Nogah Frankel1e5d9432017-02-09 14:54:48 +0100165 }
166
Ido Schimmelc57529e2017-05-26 08:37:31 +0200167 bridge_device = kzalloc(sizeof(*bridge_device), GFP_KERNEL);
168 if (!bridge_device)
169 return ERR_PTR(-ENOMEM);
Ido Schimmel54a73202015-12-15 16:03:41 +0100170
Ido Schimmelc57529e2017-05-26 08:37:31 +0200171 bridge_device->dev = br_dev;
172 bridge_device->vlan_enabled = vlan_enabled;
173 bridge_device->multicast_enabled = br_multicast_enabled(br_dev);
174 INIT_LIST_HEAD(&bridge_device->ports_list);
175 if (vlan_enabled) {
176 bridge->vlan_enabled_exists = true;
177 bridge_device->ops = bridge->bridge_8021q_ops;
178 } else {
179 bridge_device->ops = bridge->bridge_8021d_ops;
180 }
Nogah Frankelb80888a2017-09-20 16:15:04 +0200181 INIT_LIST_HEAD(&bridge_device->mids_list);
Ido Schimmelc57529e2017-05-26 08:37:31 +0200182 list_add(&bridge_device->list, &bridge->bridges_list);
Ido Schimmel54a73202015-12-15 16:03:41 +0100183
Ido Schimmelc57529e2017-05-26 08:37:31 +0200184 return bridge_device;
185}
186
187static void
188mlxsw_sp_bridge_device_destroy(struct mlxsw_sp_bridge *bridge,
189 struct mlxsw_sp_bridge_device *bridge_device)
190{
191 list_del(&bridge_device->list);
192 if (bridge_device->vlan_enabled)
193 bridge->vlan_enabled_exists = false;
194 WARN_ON(!list_empty(&bridge_device->ports_list));
Nogah Frankelbb5355b2017-09-20 16:15:12 +0200195 WARN_ON(!list_empty(&bridge_device->mids_list));
Ido Schimmelc57529e2017-05-26 08:37:31 +0200196 kfree(bridge_device);
197}
198
199static struct mlxsw_sp_bridge_device *
200mlxsw_sp_bridge_device_get(struct mlxsw_sp_bridge *bridge,
201 struct net_device *br_dev)
202{
203 struct mlxsw_sp_bridge_device *bridge_device;
204
205 bridge_device = mlxsw_sp_bridge_device_find(bridge, br_dev);
206 if (bridge_device)
207 return bridge_device;
208
209 return mlxsw_sp_bridge_device_create(bridge, br_dev);
210}
211
212static void
213mlxsw_sp_bridge_device_put(struct mlxsw_sp_bridge *bridge,
214 struct mlxsw_sp_bridge_device *bridge_device)
215{
216 if (list_empty(&bridge_device->ports_list))
217 mlxsw_sp_bridge_device_destroy(bridge, bridge_device);
218}
219
220static struct mlxsw_sp_bridge_port *
221__mlxsw_sp_bridge_port_find(const struct mlxsw_sp_bridge_device *bridge_device,
222 const struct net_device *brport_dev)
223{
224 struct mlxsw_sp_bridge_port *bridge_port;
225
226 list_for_each_entry(bridge_port, &bridge_device->ports_list, list) {
227 if (bridge_port->dev == brport_dev)
228 return bridge_port;
229 }
230
231 return NULL;
232}
233
234static struct mlxsw_sp_bridge_port *
235mlxsw_sp_bridge_port_find(struct mlxsw_sp_bridge *bridge,
236 struct net_device *brport_dev)
237{
238 struct net_device *br_dev = netdev_master_upper_dev_get(brport_dev);
239 struct mlxsw_sp_bridge_device *bridge_device;
240
241 if (!br_dev)
242 return NULL;
243
244 bridge_device = mlxsw_sp_bridge_device_find(bridge, br_dev);
245 if (!bridge_device)
246 return NULL;
247
248 return __mlxsw_sp_bridge_port_find(bridge_device, brport_dev);
249}
250
251static struct mlxsw_sp_bridge_port *
252mlxsw_sp_bridge_port_create(struct mlxsw_sp_bridge_device *bridge_device,
253 struct net_device *brport_dev)
254{
255 struct mlxsw_sp_bridge_port *bridge_port;
256 struct mlxsw_sp_port *mlxsw_sp_port;
257
258 bridge_port = kzalloc(sizeof(*bridge_port), GFP_KERNEL);
259 if (!bridge_port)
260 return NULL;
261
262 mlxsw_sp_port = mlxsw_sp_port_dev_lower_find(brport_dev);
263 bridge_port->lagged = mlxsw_sp_port->lagged;
264 if (bridge_port->lagged)
265 bridge_port->lag_id = mlxsw_sp_port->lag_id;
266 else
267 bridge_port->system_port = mlxsw_sp_port->local_port;
268 bridge_port->dev = brport_dev;
269 bridge_port->bridge_device = bridge_device;
270 bridge_port->stp_state = BR_STATE_DISABLED;
Nogah Frankel9dad51b2017-09-20 16:15:11 +0200271 bridge_port->flags = BR_LEARNING | BR_FLOOD | BR_LEARNING_SYNC |
272 BR_MCAST_FLOOD;
Ido Schimmelc57529e2017-05-26 08:37:31 +0200273 INIT_LIST_HEAD(&bridge_port->vlans_list);
274 list_add(&bridge_port->list, &bridge_device->ports_list);
275 bridge_port->ref_count = 1;
276
277 return bridge_port;
278}
279
280static void
281mlxsw_sp_bridge_port_destroy(struct mlxsw_sp_bridge_port *bridge_port)
282{
283 list_del(&bridge_port->list);
284 WARN_ON(!list_empty(&bridge_port->vlans_list));
285 kfree(bridge_port);
286}
287
288static bool
289mlxsw_sp_bridge_port_should_destroy(const struct mlxsw_sp_bridge_port *
290 bridge_port)
291{
292 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(bridge_port->dev);
293
294 /* In case ports were pulled from out of a bridged LAG, then
295 * it's possible the reference count isn't zero, yet the bridge
296 * port should be destroyed, as it's no longer an upper of ours.
297 */
298 if (!mlxsw_sp && list_empty(&bridge_port->vlans_list))
299 return true;
300 else if (bridge_port->ref_count == 0)
301 return true;
302 else
303 return false;
304}
305
306static struct mlxsw_sp_bridge_port *
307mlxsw_sp_bridge_port_get(struct mlxsw_sp_bridge *bridge,
308 struct net_device *brport_dev)
309{
310 struct net_device *br_dev = netdev_master_upper_dev_get(brport_dev);
311 struct mlxsw_sp_bridge_device *bridge_device;
312 struct mlxsw_sp_bridge_port *bridge_port;
313 int err;
314
315 bridge_port = mlxsw_sp_bridge_port_find(bridge, brport_dev);
316 if (bridge_port) {
317 bridge_port->ref_count++;
318 return bridge_port;
319 }
320
321 bridge_device = mlxsw_sp_bridge_device_get(bridge, br_dev);
322 if (IS_ERR(bridge_device))
323 return ERR_CAST(bridge_device);
324
325 bridge_port = mlxsw_sp_bridge_port_create(bridge_device, brport_dev);
326 if (!bridge_port) {
327 err = -ENOMEM;
328 goto err_bridge_port_create;
329 }
330
331 return bridge_port;
332
333err_bridge_port_create:
334 mlxsw_sp_bridge_device_put(bridge, bridge_device);
335 return ERR_PTR(err);
336}
337
338static void mlxsw_sp_bridge_port_put(struct mlxsw_sp_bridge *bridge,
339 struct mlxsw_sp_bridge_port *bridge_port)
340{
341 struct mlxsw_sp_bridge_device *bridge_device;
342
343 bridge_port->ref_count--;
344 if (!mlxsw_sp_bridge_port_should_destroy(bridge_port))
345 return;
346 bridge_device = bridge_port->bridge_device;
347 mlxsw_sp_bridge_port_destroy(bridge_port);
348 mlxsw_sp_bridge_device_put(bridge, bridge_device);
349}
350
351static struct mlxsw_sp_port_vlan *
352mlxsw_sp_port_vlan_find_by_bridge(struct mlxsw_sp_port *mlxsw_sp_port,
353 const struct mlxsw_sp_bridge_device *
354 bridge_device,
355 u16 vid)
356{
357 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
358
359 list_for_each_entry(mlxsw_sp_port_vlan, &mlxsw_sp_port->vlans_list,
360 list) {
361 if (!mlxsw_sp_port_vlan->bridge_port)
362 continue;
363 if (mlxsw_sp_port_vlan->bridge_port->bridge_device !=
364 bridge_device)
365 continue;
366 if (bridge_device->vlan_enabled &&
367 mlxsw_sp_port_vlan->vid != vid)
368 continue;
369 return mlxsw_sp_port_vlan;
370 }
371
372 return NULL;
373}
374
375static struct mlxsw_sp_port_vlan*
376mlxsw_sp_port_vlan_find_by_fid(struct mlxsw_sp_port *mlxsw_sp_port,
377 u16 fid_index)
378{
379 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
380
381 list_for_each_entry(mlxsw_sp_port_vlan, &mlxsw_sp_port->vlans_list,
382 list) {
383 struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
384
Ido Schimmela1107482017-05-26 08:37:39 +0200385 if (fid && mlxsw_sp_fid_index(fid) == fid_index)
Ido Schimmelc57529e2017-05-26 08:37:31 +0200386 return mlxsw_sp_port_vlan;
387 }
388
389 return NULL;
390}
391
392static struct mlxsw_sp_bridge_vlan *
393mlxsw_sp_bridge_vlan_find(const struct mlxsw_sp_bridge_port *bridge_port,
394 u16 vid)
395{
396 struct mlxsw_sp_bridge_vlan *bridge_vlan;
397
398 list_for_each_entry(bridge_vlan, &bridge_port->vlans_list, list) {
399 if (bridge_vlan->vid == vid)
400 return bridge_vlan;
401 }
402
403 return NULL;
404}
405
406static struct mlxsw_sp_bridge_vlan *
407mlxsw_sp_bridge_vlan_create(struct mlxsw_sp_bridge_port *bridge_port, u16 vid)
408{
409 struct mlxsw_sp_bridge_vlan *bridge_vlan;
410
411 bridge_vlan = kzalloc(sizeof(*bridge_vlan), GFP_KERNEL);
412 if (!bridge_vlan)
413 return NULL;
414
415 INIT_LIST_HEAD(&bridge_vlan->port_vlan_list);
416 bridge_vlan->vid = vid;
417 list_add(&bridge_vlan->list, &bridge_port->vlans_list);
418
419 return bridge_vlan;
420}
421
422static void
423mlxsw_sp_bridge_vlan_destroy(struct mlxsw_sp_bridge_vlan *bridge_vlan)
424{
425 list_del(&bridge_vlan->list);
426 WARN_ON(!list_empty(&bridge_vlan->port_vlan_list));
427 kfree(bridge_vlan);
428}
429
430static struct mlxsw_sp_bridge_vlan *
431mlxsw_sp_bridge_vlan_get(struct mlxsw_sp_bridge_port *bridge_port, u16 vid)
432{
433 struct mlxsw_sp_bridge_vlan *bridge_vlan;
434
435 bridge_vlan = mlxsw_sp_bridge_vlan_find(bridge_port, vid);
436 if (bridge_vlan)
437 return bridge_vlan;
438
439 return mlxsw_sp_bridge_vlan_create(bridge_port, vid);
440}
441
442static void mlxsw_sp_bridge_vlan_put(struct mlxsw_sp_bridge_vlan *bridge_vlan)
443{
444 if (list_empty(&bridge_vlan->port_vlan_list))
445 mlxsw_sp_bridge_vlan_destroy(bridge_vlan);
446}
447
448static void mlxsw_sp_port_bridge_flags_get(struct mlxsw_sp_bridge *bridge,
449 struct net_device *dev,
450 unsigned long *brport_flags)
451{
452 struct mlxsw_sp_bridge_port *bridge_port;
453
454 bridge_port = mlxsw_sp_bridge_port_find(bridge, dev);
455 if (WARN_ON(!bridge_port))
456 return;
457
458 memcpy(brport_flags, &bridge_port->flags, sizeof(*brport_flags));
Ido Schimmel54a73202015-12-15 16:03:41 +0100459}
460
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200461static int mlxsw_sp_port_attr_get(struct net_device *dev,
462 struct switchdev_attr *attr)
463{
464 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
465 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
466
467 switch (attr->id) {
468 case SWITCHDEV_ATTR_ID_PORT_PARENT_ID:
469 attr->u.ppid.id_len = sizeof(mlxsw_sp->base_mac);
470 memcpy(&attr->u.ppid.id, &mlxsw_sp->base_mac,
471 attr->u.ppid.id_len);
472 break;
473 case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:
Ido Schimmelc57529e2017-05-26 08:37:31 +0200474 mlxsw_sp_port_bridge_flags_get(mlxsw_sp->bridge, attr->orig_dev,
475 &attr->u.brport_flags);
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200476 break;
Arkadi Sharshevskyc7b566c2017-06-08 08:44:17 +0200477 case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS_SUPPORT:
Nogah Frankel9dad51b2017-09-20 16:15:11 +0200478 attr->u.brport_flags_support = BR_LEARNING | BR_FLOOD |
479 BR_MCAST_FLOOD;
Arkadi Sharshevskyc7b566c2017-06-08 08:44:17 +0200480 break;
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200481 default:
482 return -EOPNOTSUPP;
483 }
484
485 return 0;
486}
487
Ido Schimmelc57529e2017-05-26 08:37:31 +0200488static int
489mlxsw_sp_port_bridge_vlan_stp_set(struct mlxsw_sp_port *mlxsw_sp_port,
490 struct mlxsw_sp_bridge_vlan *bridge_vlan,
491 u8 state)
492{
493 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
494
495 list_for_each_entry(mlxsw_sp_port_vlan, &bridge_vlan->port_vlan_list,
496 bridge_vlan_node) {
497 if (mlxsw_sp_port_vlan->mlxsw_sp_port != mlxsw_sp_port)
498 continue;
499 return mlxsw_sp_port_vid_stp_set(mlxsw_sp_port,
500 bridge_vlan->vid, state);
501 }
502
503 return 0;
504}
505
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200506static int mlxsw_sp_port_attr_stp_state_set(struct mlxsw_sp_port *mlxsw_sp_port,
507 struct switchdev_trans *trans,
Ido Schimmelc57529e2017-05-26 08:37:31 +0200508 struct net_device *orig_dev,
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200509 u8 state)
510{
Ido Schimmelc57529e2017-05-26 08:37:31 +0200511 struct mlxsw_sp_bridge_port *bridge_port;
512 struct mlxsw_sp_bridge_vlan *bridge_vlan;
Ido Schimmel45bfe6b2017-05-16 19:38:32 +0200513 int err;
514
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200515 if (switchdev_trans_ph_prepare(trans))
516 return 0;
517
Ido Schimmelc57529e2017-05-26 08:37:31 +0200518 /* It's possible we failed to enslave the port, yet this
519 * operation is executed due to it being deferred.
520 */
521 bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp_port->mlxsw_sp->bridge,
522 orig_dev);
523 if (!bridge_port)
Ido Schimmel45bfe6b2017-05-16 19:38:32 +0200524 return 0;
Ido Schimmelc57529e2017-05-26 08:37:31 +0200525
526 list_for_each_entry(bridge_vlan, &bridge_port->vlans_list, list) {
527 err = mlxsw_sp_port_bridge_vlan_stp_set(mlxsw_sp_port,
528 bridge_vlan, state);
529 if (err)
530 goto err_port_bridge_vlan_stp_set;
Ido Schimmel45bfe6b2017-05-16 19:38:32 +0200531 }
532
Ido Schimmelc57529e2017-05-26 08:37:31 +0200533 bridge_port->stp_state = state;
Ido Schimmel45bfe6b2017-05-16 19:38:32 +0200534
535 return 0;
Ido Schimmelc57529e2017-05-26 08:37:31 +0200536
537err_port_bridge_vlan_stp_set:
538 list_for_each_entry_continue_reverse(bridge_vlan,
539 &bridge_port->vlans_list, list)
540 mlxsw_sp_port_bridge_vlan_stp_set(mlxsw_sp_port, bridge_vlan,
541 bridge_port->stp_state);
542 return err;
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200543}
544
Ido Schimmelc57529e2017-05-26 08:37:31 +0200545static int
546mlxsw_sp_port_bridge_vlan_flood_set(struct mlxsw_sp_port *mlxsw_sp_port,
547 struct mlxsw_sp_bridge_vlan *bridge_vlan,
Ido Schimmela1107482017-05-26 08:37:39 +0200548 enum mlxsw_sp_flood_type packet_type,
Ido Schimmelc57529e2017-05-26 08:37:31 +0200549 bool member)
Nogah Frankeleaa7df32017-02-09 14:54:43 +0100550{
Ido Schimmelc57529e2017-05-26 08:37:31 +0200551 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
Nogah Frankeleaa7df32017-02-09 14:54:43 +0100552
Ido Schimmelc57529e2017-05-26 08:37:31 +0200553 list_for_each_entry(mlxsw_sp_port_vlan, &bridge_vlan->port_vlan_list,
554 bridge_vlan_node) {
555 if (mlxsw_sp_port_vlan->mlxsw_sp_port != mlxsw_sp_port)
556 continue;
Ido Schimmela1107482017-05-26 08:37:39 +0200557 return mlxsw_sp_fid_flood_set(mlxsw_sp_port_vlan->fid,
558 packet_type,
559 mlxsw_sp_port->local_port,
560 member);
Ido Schimmel54a73202015-12-15 16:03:41 +0100561 }
562
Ido Schimmelc57529e2017-05-26 08:37:31 +0200563 return 0;
564}
565
566static int
567mlxsw_sp_bridge_port_flood_table_set(struct mlxsw_sp_port *mlxsw_sp_port,
568 struct mlxsw_sp_bridge_port *bridge_port,
Ido Schimmela1107482017-05-26 08:37:39 +0200569 enum mlxsw_sp_flood_type packet_type,
Ido Schimmelc57529e2017-05-26 08:37:31 +0200570 bool member)
571{
572 struct mlxsw_sp_bridge_vlan *bridge_vlan;
573 int err;
574
575 list_for_each_entry(bridge_vlan, &bridge_port->vlans_list, list) {
576 err = mlxsw_sp_port_bridge_vlan_flood_set(mlxsw_sp_port,
Ido Schimmela1107482017-05-26 08:37:39 +0200577 bridge_vlan,
578 packet_type,
Ido Schimmelc57529e2017-05-26 08:37:31 +0200579 member);
580 if (err)
581 goto err_port_bridge_vlan_flood_set;
Ido Schimmel02930382015-10-28 10:16:58 +0100582 }
583
584 return 0;
585
Ido Schimmelc57529e2017-05-26 08:37:31 +0200586err_port_bridge_vlan_flood_set:
587 list_for_each_entry_continue_reverse(bridge_vlan,
588 &bridge_port->vlans_list, list)
589 mlxsw_sp_port_bridge_vlan_flood_set(mlxsw_sp_port, bridge_vlan,
Ido Schimmela1107482017-05-26 08:37:39 +0200590 packet_type, !member);
Ido Schimmel02930382015-10-28 10:16:58 +0100591 return err;
592}
593
Ido Schimmelc57529e2017-05-26 08:37:31 +0200594static int
595mlxsw_sp_port_bridge_vlan_learning_set(struct mlxsw_sp_port *mlxsw_sp_port,
596 struct mlxsw_sp_bridge_vlan *bridge_vlan,
597 bool set)
Nogah Frankel90e0f0c2017-02-09 14:54:49 +0100598{
Ido Schimmelc57529e2017-05-26 08:37:31 +0200599 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
600 u16 vid = bridge_vlan->vid;
Nogah Frankel90e0f0c2017-02-09 14:54:49 +0100601
Ido Schimmelc57529e2017-05-26 08:37:31 +0200602 list_for_each_entry(mlxsw_sp_port_vlan, &bridge_vlan->port_vlan_list,
603 bridge_vlan_node) {
604 if (mlxsw_sp_port_vlan->mlxsw_sp_port != mlxsw_sp_port)
605 continue;
Ido Schimmel7cbc4272017-05-16 19:38:33 +0200606 return mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, set);
Ido Schimmel89b548f2016-08-24 12:00:27 +0200607 }
608
Ido Schimmelc57529e2017-05-26 08:37:31 +0200609 return 0;
610}
611
612static int
613mlxsw_sp_bridge_port_learning_set(struct mlxsw_sp_port *mlxsw_sp_port,
614 struct mlxsw_sp_bridge_port *bridge_port,
615 bool set)
616{
617 struct mlxsw_sp_bridge_vlan *bridge_vlan;
618 int err;
619
620 list_for_each_entry(bridge_vlan, &bridge_port->vlans_list, list) {
621 err = mlxsw_sp_port_bridge_vlan_learning_set(mlxsw_sp_port,
622 bridge_vlan, set);
Ido Schimmel89b548f2016-08-24 12:00:27 +0200623 if (err)
Ido Schimmelc57529e2017-05-26 08:37:31 +0200624 goto err_port_bridge_vlan_learning_set;
Ido Schimmel89b548f2016-08-24 12:00:27 +0200625 }
626
627 return 0;
628
Ido Schimmelc57529e2017-05-26 08:37:31 +0200629err_port_bridge_vlan_learning_set:
630 list_for_each_entry_continue_reverse(bridge_vlan,
631 &bridge_port->vlans_list, list)
632 mlxsw_sp_port_bridge_vlan_learning_set(mlxsw_sp_port,
633 bridge_vlan, !set);
Ido Schimmel89b548f2016-08-24 12:00:27 +0200634 return err;
635}
636
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200637static int mlxsw_sp_port_attr_br_flags_set(struct mlxsw_sp_port *mlxsw_sp_port,
638 struct switchdev_trans *trans,
Ido Schimmelc57529e2017-05-26 08:37:31 +0200639 struct net_device *orig_dev,
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200640 unsigned long brport_flags)
641{
Ido Schimmelc57529e2017-05-26 08:37:31 +0200642 struct mlxsw_sp_bridge_port *bridge_port;
Ido Schimmel02930382015-10-28 10:16:58 +0100643 int err;
644
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200645 if (switchdev_trans_ph_prepare(trans))
646 return 0;
647
Ido Schimmelc57529e2017-05-26 08:37:31 +0200648 bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp_port->mlxsw_sp->bridge,
649 orig_dev);
Ido Schimmel17b334a2017-08-04 14:12:29 +0200650 if (!bridge_port)
651 return 0;
Ido Schimmel02930382015-10-28 10:16:58 +0100652
Ido Schimmelc57529e2017-05-26 08:37:31 +0200653 err = mlxsw_sp_bridge_port_flood_table_set(mlxsw_sp_port, bridge_port,
Ido Schimmela1107482017-05-26 08:37:39 +0200654 MLXSW_SP_FLOOD_TYPE_UC,
Ido Schimmelc57529e2017-05-26 08:37:31 +0200655 brport_flags & BR_FLOOD);
656 if (err)
657 return err;
Ido Schimmel89b548f2016-08-24 12:00:27 +0200658
Ido Schimmelc57529e2017-05-26 08:37:31 +0200659 err = mlxsw_sp_bridge_port_learning_set(mlxsw_sp_port, bridge_port,
660 brport_flags & BR_LEARNING);
661 if (err)
662 return err;
663
Nogah Frankel9dad51b2017-09-20 16:15:11 +0200664 if (bridge_port->bridge_device->multicast_enabled)
665 goto out;
Ido Schimmel02930382015-10-28 10:16:58 +0100666
Nogah Frankel9dad51b2017-09-20 16:15:11 +0200667 err = mlxsw_sp_bridge_port_flood_table_set(mlxsw_sp_port, bridge_port,
668 MLXSW_SP_FLOOD_TYPE_MC,
669 brport_flags &
670 BR_MCAST_FLOOD);
671 if (err)
672 return err;
673
674out:
675 memcpy(&bridge_port->flags, &brport_flags, sizeof(brport_flags));
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200676 return 0;
677}
678
679static int mlxsw_sp_ageing_set(struct mlxsw_sp *mlxsw_sp, u32 ageing_time)
680{
681 char sfdat_pl[MLXSW_REG_SFDAT_LEN];
682 int err;
683
684 mlxsw_reg_sfdat_pack(sfdat_pl, ageing_time);
685 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfdat), sfdat_pl);
686 if (err)
687 return err;
Ido Schimmel5f6935c2017-05-16 19:38:26 +0200688 mlxsw_sp->bridge->ageing_time = ageing_time;
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200689 return 0;
690}
691
692static int mlxsw_sp_port_attr_br_ageing_set(struct mlxsw_sp_port *mlxsw_sp_port,
693 struct switchdev_trans *trans,
Jiri Pirko135f9ec2015-10-28 10:17:02 +0100694 unsigned long ageing_clock_t)
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200695{
696 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
Jiri Pirko135f9ec2015-10-28 10:17:02 +0100697 unsigned long ageing_jiffies = clock_t_to_jiffies(ageing_clock_t);
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200698 u32 ageing_time = jiffies_to_msecs(ageing_jiffies) / 1000;
699
Ido Schimmel869f63a2016-03-08 12:59:33 -0800700 if (switchdev_trans_ph_prepare(trans)) {
701 if (ageing_time < MLXSW_SP_MIN_AGEING_TIME ||
702 ageing_time > MLXSW_SP_MAX_AGEING_TIME)
703 return -ERANGE;
704 else
705 return 0;
706 }
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200707
708 return mlxsw_sp_ageing_set(mlxsw_sp, ageing_time);
709}
710
Elad Raz26a4ea02016-01-06 13:01:10 +0100711static int mlxsw_sp_port_attr_br_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port,
712 struct switchdev_trans *trans,
713 struct net_device *orig_dev,
714 bool vlan_enabled)
715{
716 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
Ido Schimmelc57529e2017-05-26 08:37:31 +0200717 struct mlxsw_sp_bridge_device *bridge_device;
Elad Raz26a4ea02016-01-06 13:01:10 +0100718
Ido Schimmelc57529e2017-05-26 08:37:31 +0200719 if (!switchdev_trans_ph_prepare(trans))
720 return 0;
721
722 bridge_device = mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, orig_dev);
723 if (WARN_ON(!bridge_device))
Elad Raz26a4ea02016-01-06 13:01:10 +0100724 return -EINVAL;
Elad Raz26a4ea02016-01-06 13:01:10 +0100725
Ido Schimmelc57529e2017-05-26 08:37:31 +0200726 if (bridge_device->vlan_enabled == vlan_enabled)
727 return 0;
728
729 netdev_err(bridge_device->dev, "VLAN filtering can't be changed for existing bridge\n");
730 return -EINVAL;
Elad Raz26a4ea02016-01-06 13:01:10 +0100731}
732
Nogah Frankeldff37b52017-09-20 16:15:01 +0200733static int mlxsw_sp_port_attr_mrouter_set(struct mlxsw_sp_port *mlxsw_sp_port,
734 struct switchdev_trans *trans,
735 struct net_device *orig_dev,
736 bool is_port_mrouter)
Nogah Frankel8ecd4592017-02-09 14:54:47 +0100737{
Ido Schimmelc57529e2017-05-26 08:37:31 +0200738 struct mlxsw_sp_bridge_port *bridge_port;
Nogah Frankel4eb6a3b2017-08-22 10:28:11 +0200739 int err;
Ido Schimmelc57529e2017-05-26 08:37:31 +0200740
Nogah Frankel8ecd4592017-02-09 14:54:47 +0100741 if (switchdev_trans_ph_prepare(trans))
742 return 0;
743
Ido Schimmelc57529e2017-05-26 08:37:31 +0200744 bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp_port->mlxsw_sp->bridge,
745 orig_dev);
Ido Schimmel17b334a2017-08-04 14:12:29 +0200746 if (!bridge_port)
747 return 0;
Ido Schimmelc57529e2017-05-26 08:37:31 +0200748
749 if (!bridge_port->bridge_device->multicast_enabled)
Nogah Frankel4eb6a3b2017-08-22 10:28:11 +0200750 goto out;
Ido Schimmelc57529e2017-05-26 08:37:31 +0200751
Nogah Frankel4eb6a3b2017-08-22 10:28:11 +0200752 err = mlxsw_sp_bridge_port_flood_table_set(mlxsw_sp_port, bridge_port,
753 MLXSW_SP_FLOOD_TYPE_MC,
Nogah Frankeldff37b52017-09-20 16:15:01 +0200754 is_port_mrouter);
Nogah Frankel4eb6a3b2017-08-22 10:28:11 +0200755 if (err)
756 return err;
757
Nogah Frankel3ddda112017-09-20 16:15:14 +0200758 mlxsw_sp_port_mrouter_update_mdb(mlxsw_sp_port, bridge_port,
759 is_port_mrouter);
Nogah Frankel4eb6a3b2017-08-22 10:28:11 +0200760out:
Nogah Frankeldff37b52017-09-20 16:15:01 +0200761 bridge_port->mrouter = is_port_mrouter;
Nogah Frankel4eb6a3b2017-08-22 10:28:11 +0200762 return 0;
Ido Schimmelc57529e2017-05-26 08:37:31 +0200763}
764
Nogah Frankel218a8f82017-09-20 16:15:10 +0200765static bool mlxsw_sp_mc_flood(const struct mlxsw_sp_bridge_port *bridge_port)
766{
767 const struct mlxsw_sp_bridge_device *bridge_device;
768
769 bridge_device = bridge_port->bridge_device;
Nogah Frankel9dad51b2017-09-20 16:15:11 +0200770 return bridge_device->multicast_enabled ? bridge_port->mrouter :
771 bridge_port->flags & BR_MCAST_FLOOD;
Nogah Frankel218a8f82017-09-20 16:15:10 +0200772}
773
Ido Schimmelc57529e2017-05-26 08:37:31 +0200774static int mlxsw_sp_port_mc_disabled_set(struct mlxsw_sp_port *mlxsw_sp_port,
775 struct switchdev_trans *trans,
776 struct net_device *orig_dev,
777 bool mc_disabled)
778{
779 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
780 struct mlxsw_sp_bridge_device *bridge_device;
781 struct mlxsw_sp_bridge_port *bridge_port;
782 int err;
783
784 if (switchdev_trans_ph_prepare(trans))
785 return 0;
786
787 /* It's possible we failed to enslave the port, yet this
788 * operation is executed due to it being deferred.
789 */
790 bridge_device = mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, orig_dev);
791 if (!bridge_device)
792 return 0;
793
Nogah Frankel2e3496c2017-09-20 16:15:09 +0200794 if (bridge_device->multicast_enabled != !mc_disabled) {
795 bridge_device->multicast_enabled = !mc_disabled;
796 mlxsw_sp_bridge_mdb_mc_enable_sync(mlxsw_sp_port,
797 bridge_device);
798 }
799
Ido Schimmelc57529e2017-05-26 08:37:31 +0200800 list_for_each_entry(bridge_port, &bridge_device->ports_list, list) {
Ido Schimmela1107482017-05-26 08:37:39 +0200801 enum mlxsw_sp_flood_type packet_type = MLXSW_SP_FLOOD_TYPE_MC;
Nogah Frankel218a8f82017-09-20 16:15:10 +0200802 bool member = mlxsw_sp_mc_flood(bridge_port);
Ido Schimmelc57529e2017-05-26 08:37:31 +0200803
804 err = mlxsw_sp_bridge_port_flood_table_set(mlxsw_sp_port,
Ido Schimmela1107482017-05-26 08:37:39 +0200805 bridge_port,
806 packet_type, member);
Ido Schimmelc57529e2017-05-26 08:37:31 +0200807 if (err)
808 return err;
809 }
810
811 bridge_device->multicast_enabled = !mc_disabled;
Nogah Frankel8ecd4592017-02-09 14:54:47 +0100812
813 return 0;
814}
815
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200816static int mlxsw_sp_port_attr_set(struct net_device *dev,
817 const struct switchdev_attr *attr,
818 struct switchdev_trans *trans)
819{
820 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
Ido Schimmelc57529e2017-05-26 08:37:31 +0200821 int err;
Ido Schimmel54a73202015-12-15 16:03:41 +0100822
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200823 switch (attr->id) {
824 case SWITCHDEV_ATTR_ID_PORT_STP_STATE:
825 err = mlxsw_sp_port_attr_stp_state_set(mlxsw_sp_port, trans,
Ido Schimmelc57529e2017-05-26 08:37:31 +0200826 attr->orig_dev,
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200827 attr->u.stp_state);
828 break;
829 case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:
830 err = mlxsw_sp_port_attr_br_flags_set(mlxsw_sp_port, trans,
Ido Schimmelc57529e2017-05-26 08:37:31 +0200831 attr->orig_dev,
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200832 attr->u.brport_flags);
833 break;
834 case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME:
835 err = mlxsw_sp_port_attr_br_ageing_set(mlxsw_sp_port, trans,
836 attr->u.ageing_time);
837 break;
Elad Raz26a4ea02016-01-06 13:01:10 +0100838 case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING:
839 err = mlxsw_sp_port_attr_br_vlan_set(mlxsw_sp_port, trans,
840 attr->orig_dev,
841 attr->u.vlan_filtering);
842 break;
Nogah Frankel8ecd4592017-02-09 14:54:47 +0100843 case SWITCHDEV_ATTR_ID_PORT_MROUTER:
Nogah Frankeldff37b52017-09-20 16:15:01 +0200844 err = mlxsw_sp_port_attr_mrouter_set(mlxsw_sp_port, trans,
845 attr->orig_dev,
846 attr->u.mrouter);
Nogah Frankel8ecd4592017-02-09 14:54:47 +0100847 break;
Nogah Frankel90e0f0c2017-02-09 14:54:49 +0100848 case SWITCHDEV_ATTR_ID_BRIDGE_MC_DISABLED:
849 err = mlxsw_sp_port_mc_disabled_set(mlxsw_sp_port, trans,
Ido Schimmelc57529e2017-05-26 08:37:31 +0200850 attr->orig_dev,
Nogah Frankel90e0f0c2017-02-09 14:54:49 +0100851 attr->u.mc_disabled);
852 break;
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200853 default:
854 err = -EOPNOTSUPP;
855 break;
856 }
857
858 return err;
859}
860
Ido Schimmelc57529e2017-05-26 08:37:31 +0200861static int
862mlxsw_sp_port_vlan_fid_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
863 struct mlxsw_sp_bridge_port *bridge_port)
864{
865 struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;
Ido Schimmela1107482017-05-26 08:37:39 +0200866 struct mlxsw_sp_bridge_device *bridge_device;
867 u8 local_port = mlxsw_sp_port->local_port;
Ido Schimmelc57529e2017-05-26 08:37:31 +0200868 u16 vid = mlxsw_sp_port_vlan->vid;
869 struct mlxsw_sp_fid *fid;
870 int err;
871
Ido Schimmela1107482017-05-26 08:37:39 +0200872 bridge_device = bridge_port->bridge_device;
873 fid = bridge_device->ops->fid_get(bridge_device, vid);
Ido Schimmelc57529e2017-05-26 08:37:31 +0200874 if (IS_ERR(fid))
875 return PTR_ERR(fid);
876
Ido Schimmela1107482017-05-26 08:37:39 +0200877 err = mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_UC, local_port,
878 bridge_port->flags & BR_FLOOD);
Ido Schimmelc57529e2017-05-26 08:37:31 +0200879 if (err)
Ido Schimmela1107482017-05-26 08:37:39 +0200880 goto err_fid_uc_flood_set;
Ido Schimmelc57529e2017-05-26 08:37:31 +0200881
Ido Schimmela1107482017-05-26 08:37:39 +0200882 err = mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_MC, local_port,
883 mlxsw_sp_mc_flood(bridge_port));
Ido Schimmelc57529e2017-05-26 08:37:31 +0200884 if (err)
Ido Schimmela1107482017-05-26 08:37:39 +0200885 goto err_fid_mc_flood_set;
Ido Schimmelc57529e2017-05-26 08:37:31 +0200886
Ido Schimmela1107482017-05-26 08:37:39 +0200887 err = mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_BC, local_port,
888 true);
Ido Schimmelc57529e2017-05-26 08:37:31 +0200889 if (err)
Ido Schimmela1107482017-05-26 08:37:39 +0200890 goto err_fid_bc_flood_set;
Ido Schimmelc57529e2017-05-26 08:37:31 +0200891
Ido Schimmela1107482017-05-26 08:37:39 +0200892 err = mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port, vid);
Ido Schimmelc57529e2017-05-26 08:37:31 +0200893 if (err)
Ido Schimmela1107482017-05-26 08:37:39 +0200894 goto err_fid_port_vid_map;
Ido Schimmelc57529e2017-05-26 08:37:31 +0200895
896 mlxsw_sp_port_vlan->fid = fid;
897
898 return 0;
899
Ido Schimmela1107482017-05-26 08:37:39 +0200900err_fid_port_vid_map:
901 mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_BC, local_port, false);
902err_fid_bc_flood_set:
903 mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_MC, local_port, false);
904err_fid_mc_flood_set:
905 mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_UC, local_port, false);
906err_fid_uc_flood_set:
907 mlxsw_sp_fid_put(fid);
Ido Schimmelc57529e2017-05-26 08:37:31 +0200908 return err;
909}
910
911static void
912mlxsw_sp_port_vlan_fid_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
913{
914 struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;
Ido Schimmelc57529e2017-05-26 08:37:31 +0200915 struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
Ido Schimmela1107482017-05-26 08:37:39 +0200916 u8 local_port = mlxsw_sp_port->local_port;
Ido Schimmelc57529e2017-05-26 08:37:31 +0200917 u16 vid = mlxsw_sp_port_vlan->vid;
918
919 mlxsw_sp_port_vlan->fid = NULL;
Ido Schimmela1107482017-05-26 08:37:39 +0200920 mlxsw_sp_fid_port_vid_unmap(fid, mlxsw_sp_port, vid);
921 mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_BC, local_port, false);
922 mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_MC, local_port, false);
923 mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_UC, local_port, false);
924 mlxsw_sp_fid_put(fid);
Ido Schimmel14d39462016-06-20 23:04:15 +0200925}
926
Ido Schimmelfe9ccc72017-05-16 19:38:31 +0200927static u16
928mlxsw_sp_port_pvid_determine(const struct mlxsw_sp_port *mlxsw_sp_port,
929 u16 vid, bool is_pvid)
Ido Schimmel584d73d2016-08-24 12:00:26 +0200930{
Ido Schimmelfe9ccc72017-05-16 19:38:31 +0200931 if (is_pvid)
932 return vid;
933 else if (mlxsw_sp_port->pvid == vid)
934 return 0; /* Dis-allow untagged packets */
935 else
936 return mlxsw_sp_port->pvid;
Ido Schimmel584d73d2016-08-24 12:00:26 +0200937}
938
Ido Schimmelc57529e2017-05-26 08:37:31 +0200939static int
940mlxsw_sp_port_vlan_bridge_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
941 struct mlxsw_sp_bridge_port *bridge_port)
942{
943 struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;
944 struct mlxsw_sp_bridge_vlan *bridge_vlan;
945 u16 vid = mlxsw_sp_port_vlan->vid;
946 int err;
947
948 /* No need to continue if only VLAN flags were changed */
949 if (mlxsw_sp_port_vlan->bridge_port)
950 return 0;
951
952 err = mlxsw_sp_port_vlan_fid_join(mlxsw_sp_port_vlan, bridge_port);
953 if (err)
954 return err;
955
956 err = mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid,
957 bridge_port->flags & BR_LEARNING);
958 if (err)
959 goto err_port_vid_learning_set;
960
961 err = mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, vid,
962 bridge_port->stp_state);
963 if (err)
964 goto err_port_vid_stp_set;
965
966 bridge_vlan = mlxsw_sp_bridge_vlan_get(bridge_port, vid);
967 if (!bridge_vlan) {
968 err = -ENOMEM;
969 goto err_bridge_vlan_get;
970 }
971
972 list_add(&mlxsw_sp_port_vlan->bridge_vlan_node,
973 &bridge_vlan->port_vlan_list);
974
975 mlxsw_sp_bridge_port_get(mlxsw_sp_port->mlxsw_sp->bridge,
976 bridge_port->dev);
977 mlxsw_sp_port_vlan->bridge_port = bridge_port;
978
979 return 0;
980
981err_bridge_vlan_get:
982 mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, vid, BR_STATE_DISABLED);
983err_port_vid_stp_set:
984 mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, false);
985err_port_vid_learning_set:
986 mlxsw_sp_port_vlan_fid_leave(mlxsw_sp_port_vlan);
987 return err;
988}
989
990void
991mlxsw_sp_port_vlan_bridge_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
992{
993 struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;
994 struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
995 struct mlxsw_sp_bridge_vlan *bridge_vlan;
996 struct mlxsw_sp_bridge_port *bridge_port;
997 u16 vid = mlxsw_sp_port_vlan->vid;
Nogah Frankelbb5355b2017-09-20 16:15:12 +0200998 bool last_port, last_vlan;
Ido Schimmelc57529e2017-05-26 08:37:31 +0200999
Ido Schimmela1107482017-05-26 08:37:39 +02001000 if (WARN_ON(mlxsw_sp_fid_type(fid) != MLXSW_SP_FID_TYPE_8021Q &&
1001 mlxsw_sp_fid_type(fid) != MLXSW_SP_FID_TYPE_8021D))
1002 return;
1003
Ido Schimmelc57529e2017-05-26 08:37:31 +02001004 bridge_port = mlxsw_sp_port_vlan->bridge_port;
Nogah Frankelbb5355b2017-09-20 16:15:12 +02001005 last_vlan = list_is_singular(&bridge_port->vlans_list);
Ido Schimmelc57529e2017-05-26 08:37:31 +02001006 bridge_vlan = mlxsw_sp_bridge_vlan_find(bridge_port, vid);
Nogah Frankelbb5355b2017-09-20 16:15:12 +02001007 last_port = list_is_singular(&bridge_vlan->port_vlan_list);
Ido Schimmelc57529e2017-05-26 08:37:31 +02001008
1009 list_del(&mlxsw_sp_port_vlan->bridge_vlan_node);
1010 mlxsw_sp_bridge_vlan_put(bridge_vlan);
1011 mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, vid, BR_STATE_DISABLED);
1012 mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, false);
Nogah Frankelbb5355b2017-09-20 16:15:12 +02001013 if (last_port)
Ido Schimmelc57529e2017-05-26 08:37:31 +02001014 mlxsw_sp_bridge_port_fdb_flush(mlxsw_sp_port->mlxsw_sp,
Ido Schimmela1107482017-05-26 08:37:39 +02001015 bridge_port,
1016 mlxsw_sp_fid_index(fid));
Nogah Frankelbb5355b2017-09-20 16:15:12 +02001017 if (last_vlan)
1018 mlxsw_sp_bridge_port_mdb_flush(mlxsw_sp_port, bridge_port);
1019
Ido Schimmelc57529e2017-05-26 08:37:31 +02001020 mlxsw_sp_port_vlan_fid_leave(mlxsw_sp_port_vlan);
1021
1022 mlxsw_sp_bridge_port_put(mlxsw_sp_port->mlxsw_sp->bridge, bridge_port);
1023 mlxsw_sp_port_vlan->bridge_port = NULL;
1024}
1025
1026static int
1027mlxsw_sp_bridge_port_vlan_add(struct mlxsw_sp_port *mlxsw_sp_port,
1028 struct mlxsw_sp_bridge_port *bridge_port,
1029 u16 vid, bool is_untagged, bool is_pvid)
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001030{
Ido Schimmelfe9ccc72017-05-16 19:38:31 +02001031 u16 pvid = mlxsw_sp_port_pvid_determine(mlxsw_sp_port, vid, is_pvid);
Ido Schimmelc57529e2017-05-26 08:37:31 +02001032 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
Ido Schimmelfe9ccc72017-05-16 19:38:31 +02001033 u16 old_pvid = mlxsw_sp_port->pvid;
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001034 int err;
1035
Ido Schimmelc57529e2017-05-26 08:37:31 +02001036 mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_get(mlxsw_sp_port, vid);
1037 if (IS_ERR(mlxsw_sp_port_vlan))
1038 return PTR_ERR(mlxsw_sp_port_vlan);
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001039
Ido Schimmelfe9ccc72017-05-16 19:38:31 +02001040 err = mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, true,
1041 is_untagged);
1042 if (err)
1043 goto err_port_vlan_set;
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001044
Ido Schimmelfe9ccc72017-05-16 19:38:31 +02001045 err = mlxsw_sp_port_pvid_set(mlxsw_sp_port, pvid);
1046 if (err)
1047 goto err_port_pvid_set;
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001048
Ido Schimmelc57529e2017-05-26 08:37:31 +02001049 err = mlxsw_sp_port_vlan_bridge_join(mlxsw_sp_port_vlan, bridge_port);
Ido Schimmelfe9ccc72017-05-16 19:38:31 +02001050 if (err)
Ido Schimmelc57529e2017-05-26 08:37:31 +02001051 goto err_port_vlan_bridge_join;
Ido Schimmel584d73d2016-08-24 12:00:26 +02001052
Ido Schimmelb07a9662015-11-19 12:27:40 +01001053 return 0;
1054
Ido Schimmelc57529e2017-05-26 08:37:31 +02001055err_port_vlan_bridge_join:
Ido Schimmelfe9ccc72017-05-16 19:38:31 +02001056 mlxsw_sp_port_pvid_set(mlxsw_sp_port, old_pvid);
Ido Schimmelb07a9662015-11-19 12:27:40 +01001057err_port_pvid_set:
Ido Schimmelfe9ccc72017-05-16 19:38:31 +02001058 mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, false, false);
1059err_port_vlan_set:
Ido Schimmelc57529e2017-05-26 08:37:31 +02001060 mlxsw_sp_port_vlan_put(mlxsw_sp_port_vlan);
Ido Schimmelb07a9662015-11-19 12:27:40 +01001061 return err;
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001062}
1063
1064static int mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port,
1065 const struct switchdev_obj_port_vlan *vlan,
1066 struct switchdev_trans *trans)
1067{
Elad Raze4a13052016-01-06 13:01:09 +01001068 bool flag_untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
1069 bool flag_pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
Ido Schimmelc57529e2017-05-26 08:37:31 +02001070 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1071 struct net_device *orig_dev = vlan->obj.orig_dev;
1072 struct mlxsw_sp_bridge_port *bridge_port;
Ido Schimmelfe9ccc72017-05-16 19:38:31 +02001073 u16 vid;
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001074
1075 if (switchdev_trans_ph_prepare(trans))
1076 return 0;
1077
Ido Schimmelc57529e2017-05-26 08:37:31 +02001078 bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp->bridge, orig_dev);
1079 if (WARN_ON(!bridge_port))
1080 return -EINVAL;
1081
1082 if (!bridge_port->bridge_device->vlan_enabled)
1083 return 0;
1084
Ido Schimmelfe9ccc72017-05-16 19:38:31 +02001085 for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) {
1086 int err;
1087
Ido Schimmelc57529e2017-05-26 08:37:31 +02001088 err = mlxsw_sp_bridge_port_vlan_add(mlxsw_sp_port, bridge_port,
1089 vid, flag_untagged,
1090 flag_pvid);
Ido Schimmelfe9ccc72017-05-16 19:38:31 +02001091 if (err)
1092 return err;
1093 }
1094
1095 return 0;
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001096}
1097
Ido Schimmelc57529e2017-05-26 08:37:31 +02001098static enum mlxsw_reg_sfdf_flush_type mlxsw_sp_fdb_flush_type(bool lagged)
1099{
1100 return lagged ? MLXSW_REG_SFDF_FLUSH_PER_LAG_AND_FID :
1101 MLXSW_REG_SFDF_FLUSH_PER_PORT_AND_FID;
1102}
1103
1104static int
1105mlxsw_sp_bridge_port_fdb_flush(struct mlxsw_sp *mlxsw_sp,
1106 struct mlxsw_sp_bridge_port *bridge_port,
1107 u16 fid_index)
1108{
1109 bool lagged = bridge_port->lagged;
1110 char sfdf_pl[MLXSW_REG_SFDF_LEN];
1111 u16 system_port;
1112
1113 system_port = lagged ? bridge_port->lag_id : bridge_port->system_port;
1114 mlxsw_reg_sfdf_pack(sfdf_pl, mlxsw_sp_fdb_flush_type(lagged));
1115 mlxsw_reg_sfdf_fid_set(sfdf_pl, fid_index);
1116 mlxsw_reg_sfdf_port_fid_system_port_set(sfdf_pl, system_port);
1117
1118 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfdf), sfdf_pl);
1119}
1120
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01001121static enum mlxsw_reg_sfd_rec_policy mlxsw_sp_sfd_rec_policy(bool dynamic)
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001122{
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01001123 return dynamic ? MLXSW_REG_SFD_REC_POLICY_DYNAMIC_ENTRY_INGRESS :
1124 MLXSW_REG_SFD_REC_POLICY_STATIC_ENTRY;
1125}
1126
1127static enum mlxsw_reg_sfd_op mlxsw_sp_sfd_op(bool adding)
1128{
1129 return adding ? MLXSW_REG_SFD_OP_WRITE_EDIT :
1130 MLXSW_REG_SFD_OP_WRITE_REMOVE;
1131}
1132
Ido Schimmel6e095fd2016-07-04 08:23:13 +02001133static int __mlxsw_sp_port_fdb_uc_op(struct mlxsw_sp *mlxsw_sp, u8 local_port,
1134 const char *mac, u16 fid, bool adding,
1135 enum mlxsw_reg_sfd_rec_action action,
1136 bool dynamic)
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01001137{
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001138 char *sfd_pl;
1139 int err;
1140
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001141 sfd_pl = kmalloc(MLXSW_REG_SFD_LEN, GFP_KERNEL);
1142 if (!sfd_pl)
1143 return -ENOMEM;
1144
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01001145 mlxsw_reg_sfd_pack(sfd_pl, mlxsw_sp_sfd_op(adding), 0);
1146 mlxsw_reg_sfd_uc_pack(sfd_pl, 0, mlxsw_sp_sfd_rec_policy(dynamic),
Ido Schimmel6e095fd2016-07-04 08:23:13 +02001147 mac, fid, action, local_port);
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01001148 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfd), sfd_pl);
1149 kfree(sfd_pl);
1150
1151 return err;
1152}
1153
Ido Schimmel6e095fd2016-07-04 08:23:13 +02001154static int mlxsw_sp_port_fdb_uc_op(struct mlxsw_sp *mlxsw_sp, u8 local_port,
1155 const char *mac, u16 fid, bool adding,
1156 bool dynamic)
1157{
1158 return __mlxsw_sp_port_fdb_uc_op(mlxsw_sp, local_port, mac, fid, adding,
1159 MLXSW_REG_SFD_REC_ACTION_NOP, dynamic);
1160}
1161
1162int mlxsw_sp_rif_fdb_op(struct mlxsw_sp *mlxsw_sp, const char *mac, u16 fid,
1163 bool adding)
1164{
1165 return __mlxsw_sp_port_fdb_uc_op(mlxsw_sp, 0, mac, fid, adding,
1166 MLXSW_REG_SFD_REC_ACTION_FORWARD_IP_ROUTER,
1167 false);
1168}
1169
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01001170static int mlxsw_sp_port_fdb_uc_lag_op(struct mlxsw_sp *mlxsw_sp, u16 lag_id,
Ido Schimmel64771e32015-12-15 16:03:46 +01001171 const char *mac, u16 fid, u16 lag_vid,
1172 bool adding, bool dynamic)
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01001173{
1174 char *sfd_pl;
1175 int err;
1176
1177 sfd_pl = kmalloc(MLXSW_REG_SFD_LEN, GFP_KERNEL);
1178 if (!sfd_pl)
1179 return -ENOMEM;
1180
1181 mlxsw_reg_sfd_pack(sfd_pl, mlxsw_sp_sfd_op(adding), 0);
1182 mlxsw_reg_sfd_uc_lag_pack(sfd_pl, 0, mlxsw_sp_sfd_rec_policy(dynamic),
Ido Schimmel64771e32015-12-15 16:03:46 +01001183 mac, fid, MLXSW_REG_SFD_REC_ACTION_NOP,
1184 lag_vid, lag_id);
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01001185 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfd), sfd_pl);
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001186 kfree(sfd_pl);
1187
1188 return err;
1189}
1190
1191static int
Arkadi Sharshevskyaf0613782017-06-08 08:44:20 +02001192mlxsw_sp_port_fdb_set(struct mlxsw_sp_port *mlxsw_sp_port,
1193 struct switchdev_notifier_fdb_info *fdb_info, bool adding)
1194{
1195 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1196 struct net_device *orig_dev = fdb_info->info.dev;
1197 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
1198 struct mlxsw_sp_bridge_device *bridge_device;
1199 struct mlxsw_sp_bridge_port *bridge_port;
1200 u16 fid_index, vid;
1201
1202 bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp->bridge, orig_dev);
1203 if (!bridge_port)
1204 return -EINVAL;
1205
1206 bridge_device = bridge_port->bridge_device;
1207 mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_bridge(mlxsw_sp_port,
1208 bridge_device,
1209 fdb_info->vid);
1210 if (!mlxsw_sp_port_vlan)
1211 return 0;
1212
1213 fid_index = mlxsw_sp_fid_index(mlxsw_sp_port_vlan->fid);
1214 vid = mlxsw_sp_port_vlan->vid;
1215
1216 if (!bridge_port->lagged)
1217 return mlxsw_sp_port_fdb_uc_op(mlxsw_sp,
1218 bridge_port->system_port,
1219 fdb_info->addr, fid_index,
1220 adding, false);
1221 else
1222 return mlxsw_sp_port_fdb_uc_lag_op(mlxsw_sp,
1223 bridge_port->lag_id,
1224 fdb_info->addr, fid_index,
1225 vid, adding, false);
1226}
1227
Elad Raz3a49b4f2016-01-10 21:06:28 +01001228static int mlxsw_sp_port_mdb_op(struct mlxsw_sp *mlxsw_sp, const char *addr,
Nogah Frankel5f9abc52017-09-20 16:15:05 +02001229 u16 fid, u16 mid_idx, bool adding)
Elad Raz3a49b4f2016-01-10 21:06:28 +01001230{
1231 char *sfd_pl;
1232 int err;
1233
1234 sfd_pl = kmalloc(MLXSW_REG_SFD_LEN, GFP_KERNEL);
1235 if (!sfd_pl)
1236 return -ENOMEM;
1237
1238 mlxsw_reg_sfd_pack(sfd_pl, mlxsw_sp_sfd_op(adding), 0);
1239 mlxsw_reg_sfd_mc_pack(sfd_pl, 0, addr, fid,
Nogah Frankel5f9abc52017-09-20 16:15:05 +02001240 MLXSW_REG_SFD_REC_ACTION_NOP, mid_idx);
Elad Raz3a49b4f2016-01-10 21:06:28 +01001241 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfd), sfd_pl);
1242 kfree(sfd_pl);
1243 return err;
1244}
1245
Nogah Frankel2e3496c2017-09-20 16:15:09 +02001246static int mlxsw_sp_port_smid_full_entry(struct mlxsw_sp *mlxsw_sp, u16 mid_idx,
Yotam Gigic4db9532017-10-09 11:15:34 +02001247 long *ports_bitmap,
1248 bool set_router_port)
Elad Raz3a49b4f2016-01-10 21:06:28 +01001249{
Elad Raz3a49b4f2016-01-10 21:06:28 +01001250 char *smid_pl;
1251 int err, i;
1252
1253 smid_pl = kmalloc(MLXSW_REG_SMID_LEN, GFP_KERNEL);
1254 if (!smid_pl)
1255 return -ENOMEM;
1256
Nogah Frankel5f9abc52017-09-20 16:15:05 +02001257 mlxsw_reg_smid_pack(smid_pl, mid_idx, 0, false);
1258 for (i = 1; i < mlxsw_core_max_ports(mlxsw_sp->core); i++) {
1259 if (mlxsw_sp->ports[i])
1260 mlxsw_reg_smid_port_mask_set(smid_pl, i, 1);
Elad Raz3a49b4f2016-01-10 21:06:28 +01001261 }
Nogah Frankel5f9abc52017-09-20 16:15:05 +02001262
Yotam Gigic4db9532017-10-09 11:15:34 +02001263 mlxsw_reg_smid_port_mask_set(smid_pl,
1264 mlxsw_sp_router_port(mlxsw_sp), 1);
1265
Nogah Frankel2e3496c2017-09-20 16:15:09 +02001266 for_each_set_bit(i, ports_bitmap, mlxsw_core_max_ports(mlxsw_sp->core))
1267 mlxsw_reg_smid_port_set(smid_pl, i, 1);
1268
Yotam Gigic4db9532017-10-09 11:15:34 +02001269 mlxsw_reg_smid_port_set(smid_pl, mlxsw_sp_router_port(mlxsw_sp),
1270 set_router_port);
1271
Nogah Frankel5f9abc52017-09-20 16:15:05 +02001272 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(smid), smid_pl);
1273 kfree(smid_pl);
1274 return err;
1275}
1276
1277static int mlxsw_sp_port_smid_set(struct mlxsw_sp_port *mlxsw_sp_port,
1278 u16 mid_idx, bool add)
1279{
1280 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1281 char *smid_pl;
1282 int err;
1283
1284 smid_pl = kmalloc(MLXSW_REG_SMID_LEN, GFP_KERNEL);
1285 if (!smid_pl)
1286 return -ENOMEM;
1287
1288 mlxsw_reg_smid_pack(smid_pl, mid_idx, mlxsw_sp_port->local_port, add);
Elad Raz3a49b4f2016-01-10 21:06:28 +01001289 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(smid), smid_pl);
1290 kfree(smid_pl);
1291 return err;
1292}
1293
Nogah Frankelb80888a2017-09-20 16:15:04 +02001294static struct
1295mlxsw_sp_mid *__mlxsw_sp_mc_get(struct mlxsw_sp_bridge_device *bridge_device,
1296 const unsigned char *addr,
1297 u16 fid)
Elad Raz3a49b4f2016-01-10 21:06:28 +01001298{
1299 struct mlxsw_sp_mid *mid;
1300
Nogah Frankelb80888a2017-09-20 16:15:04 +02001301 list_for_each_entry(mid, &bridge_device->mids_list, list) {
Ido Schimmel46d08472016-10-30 10:09:22 +01001302 if (ether_addr_equal(mid->addr, addr) && mid->fid == fid)
Elad Raz3a49b4f2016-01-10 21:06:28 +01001303 return mid;
1304 }
1305 return NULL;
1306}
1307
Nogah Frankel3fba8772017-09-20 16:15:13 +02001308static void
1309mlxsw_sp_bridge_port_get_ports_bitmap(struct mlxsw_sp *mlxsw_sp,
1310 struct mlxsw_sp_bridge_port *bridge_port,
1311 unsigned long *ports_bitmap)
1312{
1313 struct mlxsw_sp_port *mlxsw_sp_port;
1314 u64 max_lag_members, i;
1315 int lag_id;
1316
1317 if (!bridge_port->lagged) {
1318 set_bit(bridge_port->system_port, ports_bitmap);
1319 } else {
1320 max_lag_members = MLXSW_CORE_RES_GET(mlxsw_sp->core,
1321 MAX_LAG_MEMBERS);
1322 lag_id = bridge_port->lag_id;
1323 for (i = 0; i < max_lag_members; i++) {
1324 mlxsw_sp_port = mlxsw_sp_port_lagged_get(mlxsw_sp,
1325 lag_id, i);
1326 if (mlxsw_sp_port)
1327 set_bit(mlxsw_sp_port->local_port,
1328 ports_bitmap);
1329 }
1330 }
1331}
1332
1333static void
1334mlxsw_sp_mc_get_mrouters_bitmap(unsigned long *flood_bitmap,
1335 struct mlxsw_sp_bridge_device *bridge_device,
1336 struct mlxsw_sp *mlxsw_sp)
1337{
1338 struct mlxsw_sp_bridge_port *bridge_port;
1339
1340 list_for_each_entry(bridge_port, &bridge_device->ports_list, list) {
1341 if (bridge_port->mrouter) {
1342 mlxsw_sp_bridge_port_get_ports_bitmap(mlxsw_sp,
1343 bridge_port,
1344 flood_bitmap);
1345 }
1346 }
1347}
1348
Nogah Frankel73b433e2017-09-20 16:15:06 +02001349static bool
1350mlxsw_sp_mc_write_mdb_entry(struct mlxsw_sp *mlxsw_sp,
Nogah Frankel3fba8772017-09-20 16:15:13 +02001351 struct mlxsw_sp_mid *mid,
1352 struct mlxsw_sp_bridge_device *bridge_device)
Nogah Frankel73b433e2017-09-20 16:15:06 +02001353{
Nogah Frankel3fba8772017-09-20 16:15:13 +02001354 long *flood_bitmap;
1355 int num_of_ports;
1356 int alloc_size;
Nogah Frankel73b433e2017-09-20 16:15:06 +02001357 u16 mid_idx;
1358 int err;
1359
1360 mid_idx = find_first_zero_bit(mlxsw_sp->bridge->mids_bitmap,
1361 MLXSW_SP_MID_MAX);
1362 if (mid_idx == MLXSW_SP_MID_MAX)
1363 return false;
1364
Nogah Frankel3fba8772017-09-20 16:15:13 +02001365 num_of_ports = mlxsw_core_max_ports(mlxsw_sp->core);
1366 alloc_size = sizeof(long) * BITS_TO_LONGS(num_of_ports);
1367 flood_bitmap = kzalloc(alloc_size, GFP_KERNEL);
1368 if (!flood_bitmap)
1369 return false;
1370
1371 bitmap_copy(flood_bitmap, mid->ports_in_mid, num_of_ports);
1372 mlxsw_sp_mc_get_mrouters_bitmap(flood_bitmap, bridge_device, mlxsw_sp);
1373
Nogah Frankel73b433e2017-09-20 16:15:06 +02001374 mid->mid = mid_idx;
Yotam Gigic4db9532017-10-09 11:15:34 +02001375 err = mlxsw_sp_port_smid_full_entry(mlxsw_sp, mid_idx, flood_bitmap,
1376 false);
Nogah Frankel3fba8772017-09-20 16:15:13 +02001377 kfree(flood_bitmap);
Nogah Frankel73b433e2017-09-20 16:15:06 +02001378 if (err)
1379 return false;
1380
1381 err = mlxsw_sp_port_mdb_op(mlxsw_sp, mid->addr, mid->fid, mid_idx,
1382 true);
1383 if (err)
1384 return false;
1385
1386 set_bit(mid_idx, mlxsw_sp->bridge->mids_bitmap);
1387 mid->in_hw = true;
1388 return true;
1389}
1390
1391static int mlxsw_sp_mc_remove_mdb_entry(struct mlxsw_sp *mlxsw_sp,
1392 struct mlxsw_sp_mid *mid)
1393{
Nogah Frankel846fd8a2017-09-20 16:15:08 +02001394 if (!mid->in_hw)
1395 return 0;
1396
Nogah Frankel73b433e2017-09-20 16:15:06 +02001397 clear_bit(mid->mid, mlxsw_sp->bridge->mids_bitmap);
1398 mid->in_hw = false;
1399 return mlxsw_sp_port_mdb_op(mlxsw_sp, mid->addr, mid->fid, mid->mid,
1400 false);
1401}
1402
Nogah Frankelb80888a2017-09-20 16:15:04 +02001403static struct
1404mlxsw_sp_mid *__mlxsw_sp_mc_alloc(struct mlxsw_sp *mlxsw_sp,
1405 struct mlxsw_sp_bridge_device *bridge_device,
1406 const unsigned char *addr,
1407 u16 fid)
Elad Raz3a49b4f2016-01-10 21:06:28 +01001408{
1409 struct mlxsw_sp_mid *mid;
Nogah Frankel4cdc35e2017-09-20 16:15:02 +02001410 size_t alloc_size;
Elad Raz3a49b4f2016-01-10 21:06:28 +01001411
1412 mid = kzalloc(sizeof(*mid), GFP_KERNEL);
1413 if (!mid)
1414 return NULL;
1415
Nogah Frankel4cdc35e2017-09-20 16:15:02 +02001416 alloc_size = sizeof(unsigned long) *
1417 BITS_TO_LONGS(mlxsw_core_max_ports(mlxsw_sp->core));
Nogah Frankel4cdc35e2017-09-20 16:15:02 +02001418
Nogah Frankel73b433e2017-09-20 16:15:06 +02001419 mid->ports_in_mid = kzalloc(alloc_size, GFP_KERNEL);
1420 if (!mid->ports_in_mid)
1421 goto err_ports_in_mid_alloc;
1422
Elad Raz3a49b4f2016-01-10 21:06:28 +01001423 ether_addr_copy(mid->addr, addr);
Ido Schimmel46d08472016-10-30 10:09:22 +01001424 mid->fid = fid;
Nogah Frankel73b433e2017-09-20 16:15:06 +02001425 mid->in_hw = false;
Nogah Frankel846fd8a2017-09-20 16:15:08 +02001426
1427 if (!bridge_device->multicast_enabled)
1428 goto out;
1429
Nogah Frankel3fba8772017-09-20 16:15:13 +02001430 if (!mlxsw_sp_mc_write_mdb_entry(mlxsw_sp, mid, bridge_device))
Nogah Frankel73b433e2017-09-20 16:15:06 +02001431 goto err_write_mdb_entry;
1432
Nogah Frankel846fd8a2017-09-20 16:15:08 +02001433out:
Nogah Frankelb80888a2017-09-20 16:15:04 +02001434 list_add_tail(&mid->list, &bridge_device->mids_list);
Elad Raz3a49b4f2016-01-10 21:06:28 +01001435 return mid;
Nogah Frankel73b433e2017-09-20 16:15:06 +02001436
1437err_write_mdb_entry:
1438 kfree(mid->ports_in_mid);
1439err_ports_in_mid_alloc:
1440 kfree(mid);
1441 return NULL;
Elad Raz3a49b4f2016-01-10 21:06:28 +01001442}
1443
Nogah Frankel0161b952017-09-20 16:15:03 +02001444static int mlxsw_sp_port_remove_from_mid(struct mlxsw_sp_port *mlxsw_sp_port,
1445 struct mlxsw_sp_mid *mid)
Elad Raz3a49b4f2016-01-10 21:06:28 +01001446{
Nogah Frankel4cdc35e2017-09-20 16:15:02 +02001447 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
Nogah Frankel73b433e2017-09-20 16:15:06 +02001448 int err = 0;
Nogah Frankel4cdc35e2017-09-20 16:15:02 +02001449
1450 clear_bit(mlxsw_sp_port->local_port, mid->ports_in_mid);
Nogah Frankel0161b952017-09-20 16:15:03 +02001451 if (bitmap_empty(mid->ports_in_mid,
1452 mlxsw_core_max_ports(mlxsw_sp->core))) {
Nogah Frankel73b433e2017-09-20 16:15:06 +02001453 err = mlxsw_sp_mc_remove_mdb_entry(mlxsw_sp, mid);
Elad Raz3a49b4f2016-01-10 21:06:28 +01001454 list_del(&mid->list);
Nogah Frankel4cdc35e2017-09-20 16:15:02 +02001455 kfree(mid->ports_in_mid);
Elad Raz3a49b4f2016-01-10 21:06:28 +01001456 kfree(mid);
Elad Raz3a49b4f2016-01-10 21:06:28 +01001457 }
Nogah Frankel73b433e2017-09-20 16:15:06 +02001458 return err;
Elad Raz3a49b4f2016-01-10 21:06:28 +01001459}
1460
1461static int mlxsw_sp_port_mdb_add(struct mlxsw_sp_port *mlxsw_sp_port,
1462 const struct switchdev_obj_port_mdb *mdb,
1463 struct switchdev_trans *trans)
1464{
1465 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
Ido Schimmelc57529e2017-05-26 08:37:31 +02001466 struct net_device *orig_dev = mdb->obj.orig_dev;
1467 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
Elad Raz3a49b4f2016-01-10 21:06:28 +01001468 struct net_device *dev = mlxsw_sp_port->dev;
Ido Schimmelc57529e2017-05-26 08:37:31 +02001469 struct mlxsw_sp_bridge_device *bridge_device;
1470 struct mlxsw_sp_bridge_port *bridge_port;
Elad Raz3a49b4f2016-01-10 21:06:28 +01001471 struct mlxsw_sp_mid *mid;
Ido Schimmelc57529e2017-05-26 08:37:31 +02001472 u16 fid_index;
Elad Raz3a49b4f2016-01-10 21:06:28 +01001473 int err = 0;
1474
1475 if (switchdev_trans_ph_prepare(trans))
1476 return 0;
1477
Ido Schimmelc57529e2017-05-26 08:37:31 +02001478 bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp->bridge, orig_dev);
Ido Schimmel17b334a2017-08-04 14:12:29 +02001479 if (!bridge_port)
1480 return 0;
Ido Schimmelc57529e2017-05-26 08:37:31 +02001481
1482 bridge_device = bridge_port->bridge_device;
1483 mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_bridge(mlxsw_sp_port,
1484 bridge_device,
1485 mdb->vid);
Ido Schimmel17b334a2017-08-04 14:12:29 +02001486 if (!mlxsw_sp_port_vlan)
1487 return 0;
Ido Schimmelc57529e2017-05-26 08:37:31 +02001488
Ido Schimmela1107482017-05-26 08:37:39 +02001489 fid_index = mlxsw_sp_fid_index(mlxsw_sp_port_vlan->fid);
Ido Schimmelc57529e2017-05-26 08:37:31 +02001490
Nogah Frankelb80888a2017-09-20 16:15:04 +02001491 mid = __mlxsw_sp_mc_get(bridge_device, mdb->addr, fid_index);
Elad Raz3a49b4f2016-01-10 21:06:28 +01001492 if (!mid) {
Nogah Frankelb80888a2017-09-20 16:15:04 +02001493 mid = __mlxsw_sp_mc_alloc(mlxsw_sp, bridge_device, mdb->addr,
1494 fid_index);
Elad Raz3a49b4f2016-01-10 21:06:28 +01001495 if (!mid) {
1496 netdev_err(dev, "Unable to allocate MC group\n");
1497 return -ENOMEM;
1498 }
1499 }
Nogah Frankel4cdc35e2017-09-20 16:15:02 +02001500 set_bit(mlxsw_sp_port->local_port, mid->ports_in_mid);
Elad Raz3a49b4f2016-01-10 21:06:28 +01001501
Nogah Frankel846fd8a2017-09-20 16:15:08 +02001502 if (!bridge_device->multicast_enabled)
1503 return 0;
1504
Nogah Frankelded711c2017-09-20 16:15:16 +02001505 if (bridge_port->mrouter)
1506 return 0;
1507
Nogah Frankel5f9abc52017-09-20 16:15:05 +02001508 err = mlxsw_sp_port_smid_set(mlxsw_sp_port, mid->mid, true);
Elad Raz3a49b4f2016-01-10 21:06:28 +01001509 if (err) {
1510 netdev_err(dev, "Unable to set SMID\n");
1511 goto err_out;
1512 }
1513
Elad Raz3a49b4f2016-01-10 21:06:28 +01001514 return 0;
1515
1516err_out:
Nogah Frankel0161b952017-09-20 16:15:03 +02001517 mlxsw_sp_port_remove_from_mid(mlxsw_sp_port, mid);
Elad Raz3a49b4f2016-01-10 21:06:28 +01001518 return err;
1519}
1520
Nogah Frankel2e3496c2017-09-20 16:15:09 +02001521static void
1522mlxsw_sp_bridge_mdb_mc_enable_sync(struct mlxsw_sp_port *mlxsw_sp_port,
1523 struct mlxsw_sp_bridge_device
1524 *bridge_device)
1525{
1526 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1527 struct mlxsw_sp_mid *mid;
1528 bool mc_enabled;
1529
1530 mc_enabled = bridge_device->multicast_enabled;
1531
1532 list_for_each_entry(mid, &bridge_device->mids_list, list) {
1533 if (mc_enabled)
Nogah Frankel3fba8772017-09-20 16:15:13 +02001534 mlxsw_sp_mc_write_mdb_entry(mlxsw_sp, mid,
1535 bridge_device);
Nogah Frankel2e3496c2017-09-20 16:15:09 +02001536 else
1537 mlxsw_sp_mc_remove_mdb_entry(mlxsw_sp, mid);
1538 }
1539}
1540
Nogah Frankel3ddda112017-09-20 16:15:14 +02001541static void
1542mlxsw_sp_port_mrouter_update_mdb(struct mlxsw_sp_port *mlxsw_sp_port,
1543 struct mlxsw_sp_bridge_port *bridge_port,
1544 bool add)
1545{
1546 struct mlxsw_sp_bridge_device *bridge_device;
1547 struct mlxsw_sp_mid *mid;
1548
1549 bridge_device = bridge_port->bridge_device;
1550
1551 list_for_each_entry(mid, &bridge_device->mids_list, list) {
1552 if (!test_bit(mlxsw_sp_port->local_port, mid->ports_in_mid))
1553 mlxsw_sp_port_smid_set(mlxsw_sp_port, mid->mid, add);
1554 }
1555}
1556
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001557static int mlxsw_sp_port_obj_add(struct net_device *dev,
1558 const struct switchdev_obj *obj,
1559 struct switchdev_trans *trans)
1560{
1561 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
1562 int err = 0;
1563
1564 switch (obj->id) {
1565 case SWITCHDEV_OBJ_ID_PORT_VLAN:
1566 err = mlxsw_sp_port_vlans_add(mlxsw_sp_port,
1567 SWITCHDEV_OBJ_PORT_VLAN(obj),
1568 trans);
1569 break;
Elad Raz3a49b4f2016-01-10 21:06:28 +01001570 case SWITCHDEV_OBJ_ID_PORT_MDB:
1571 err = mlxsw_sp_port_mdb_add(mlxsw_sp_port,
1572 SWITCHDEV_OBJ_PORT_MDB(obj),
1573 trans);
1574 break;
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001575 default:
1576 err = -EOPNOTSUPP;
1577 break;
1578 }
1579
1580 return err;
1581}
1582
Ido Schimmelc57529e2017-05-26 08:37:31 +02001583static void
1584mlxsw_sp_bridge_port_vlan_del(struct mlxsw_sp_port *mlxsw_sp_port,
1585 struct mlxsw_sp_bridge_port *bridge_port, u16 vid)
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001586{
Ido Schimmelfe9ccc72017-05-16 19:38:31 +02001587 u16 pvid = mlxsw_sp_port->pvid == vid ? 0 : vid;
Ido Schimmelc57529e2017-05-26 08:37:31 +02001588 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001589
Ido Schimmelc57529e2017-05-26 08:37:31 +02001590 mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid);
1591 if (WARN_ON(!mlxsw_sp_port_vlan))
1592 return;
1593
1594 mlxsw_sp_port_vlan_bridge_leave(mlxsw_sp_port_vlan);
Ido Schimmelfe9ccc72017-05-16 19:38:31 +02001595 mlxsw_sp_port_pvid_set(mlxsw_sp_port, pvid);
1596 mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, false, false);
Ido Schimmelc57529e2017-05-26 08:37:31 +02001597 mlxsw_sp_port_vlan_put(mlxsw_sp_port_vlan);
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001598}
1599
1600static int mlxsw_sp_port_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port,
1601 const struct switchdev_obj_port_vlan *vlan)
1602{
Ido Schimmelc57529e2017-05-26 08:37:31 +02001603 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1604 struct net_device *orig_dev = vlan->obj.orig_dev;
1605 struct mlxsw_sp_bridge_port *bridge_port;
Ido Schimmelfe9ccc72017-05-16 19:38:31 +02001606 u16 vid;
1607
Ido Schimmelc57529e2017-05-26 08:37:31 +02001608 bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp->bridge, orig_dev);
1609 if (WARN_ON(!bridge_port))
1610 return -EINVAL;
1611
1612 if (!bridge_port->bridge_device->vlan_enabled)
1613 return 0;
1614
Ido Schimmelfe9ccc72017-05-16 19:38:31 +02001615 for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++)
Ido Schimmelc57529e2017-05-26 08:37:31 +02001616 mlxsw_sp_bridge_port_vlan_del(mlxsw_sp_port, bridge_port, vid);
Ido Schimmelfe9ccc72017-05-16 19:38:31 +02001617
1618 return 0;
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001619}
1620
Nogah Frankel061e55b2017-09-20 16:15:07 +02001621static int
1622__mlxsw_sp_port_mdb_del(struct mlxsw_sp_port *mlxsw_sp_port,
1623 struct mlxsw_sp_bridge_port *bridge_port,
1624 struct mlxsw_sp_mid *mid)
1625{
1626 struct net_device *dev = mlxsw_sp_port->dev;
1627 int err;
1628
Nogah Frankel846fd8a2017-09-20 16:15:08 +02001629 if (bridge_port->bridge_device->multicast_enabled) {
Nogah Frankelded711c2017-09-20 16:15:16 +02001630 if (bridge_port->bridge_device->multicast_enabled) {
1631 err = mlxsw_sp_port_smid_set(mlxsw_sp_port, mid->mid,
1632 false);
1633 if (err)
1634 netdev_err(dev, "Unable to remove port from SMID\n");
1635 }
Nogah Frankel846fd8a2017-09-20 16:15:08 +02001636 }
Nogah Frankel061e55b2017-09-20 16:15:07 +02001637
1638 err = mlxsw_sp_port_remove_from_mid(mlxsw_sp_port, mid);
1639 if (err)
1640 netdev_err(dev, "Unable to remove MC SFD\n");
1641
1642 return err;
1643}
1644
Elad Raz3a49b4f2016-01-10 21:06:28 +01001645static int mlxsw_sp_port_mdb_del(struct mlxsw_sp_port *mlxsw_sp_port,
1646 const struct switchdev_obj_port_mdb *mdb)
1647{
1648 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
Ido Schimmelc57529e2017-05-26 08:37:31 +02001649 struct net_device *orig_dev = mdb->obj.orig_dev;
1650 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
1651 struct mlxsw_sp_bridge_device *bridge_device;
Elad Raz3a49b4f2016-01-10 21:06:28 +01001652 struct net_device *dev = mlxsw_sp_port->dev;
Ido Schimmelc57529e2017-05-26 08:37:31 +02001653 struct mlxsw_sp_bridge_port *bridge_port;
Elad Raz3a49b4f2016-01-10 21:06:28 +01001654 struct mlxsw_sp_mid *mid;
Ido Schimmelc57529e2017-05-26 08:37:31 +02001655 u16 fid_index;
Elad Raz3a49b4f2016-01-10 21:06:28 +01001656
Ido Schimmelc57529e2017-05-26 08:37:31 +02001657 bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp->bridge, orig_dev);
Ido Schimmel17b334a2017-08-04 14:12:29 +02001658 if (!bridge_port)
1659 return 0;
Ido Schimmelc57529e2017-05-26 08:37:31 +02001660
1661 bridge_device = bridge_port->bridge_device;
1662 mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_bridge(mlxsw_sp_port,
1663 bridge_device,
1664 mdb->vid);
Ido Schimmel17b334a2017-08-04 14:12:29 +02001665 if (!mlxsw_sp_port_vlan)
1666 return 0;
Ido Schimmelc57529e2017-05-26 08:37:31 +02001667
Ido Schimmela1107482017-05-26 08:37:39 +02001668 fid_index = mlxsw_sp_fid_index(mlxsw_sp_port_vlan->fid);
Ido Schimmelc57529e2017-05-26 08:37:31 +02001669
Nogah Frankelb80888a2017-09-20 16:15:04 +02001670 mid = __mlxsw_sp_mc_get(bridge_device, mdb->addr, fid_index);
Elad Raz3a49b4f2016-01-10 21:06:28 +01001671 if (!mid) {
1672 netdev_err(dev, "Unable to remove port from MC DB\n");
1673 return -EINVAL;
1674 }
1675
Nogah Frankel061e55b2017-09-20 16:15:07 +02001676 return __mlxsw_sp_port_mdb_del(mlxsw_sp_port, bridge_port, mid);
Elad Raz3a49b4f2016-01-10 21:06:28 +01001677}
1678
Nogah Frankelbb5355b2017-09-20 16:15:12 +02001679static void
1680mlxsw_sp_bridge_port_mdb_flush(struct mlxsw_sp_port *mlxsw_sp_port,
1681 struct mlxsw_sp_bridge_port *bridge_port)
1682{
1683 struct mlxsw_sp_bridge_device *bridge_device;
1684 struct mlxsw_sp_mid *mid, *tmp;
1685
1686 bridge_device = bridge_port->bridge_device;
1687
1688 list_for_each_entry_safe(mid, tmp, &bridge_device->mids_list, list) {
1689 if (test_bit(mlxsw_sp_port->local_port, mid->ports_in_mid)) {
1690 __mlxsw_sp_port_mdb_del(mlxsw_sp_port, bridge_port,
1691 mid);
Nogah Frankel01662772017-09-20 16:15:15 +02001692 } else if (bridge_device->multicast_enabled &&
1693 bridge_port->mrouter) {
1694 mlxsw_sp_port_smid_set(mlxsw_sp_port, mid->mid, false);
Nogah Frankelbb5355b2017-09-20 16:15:12 +02001695 }
1696 }
1697}
1698
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001699static int mlxsw_sp_port_obj_del(struct net_device *dev,
1700 const struct switchdev_obj *obj)
1701{
1702 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
1703 int err = 0;
1704
1705 switch (obj->id) {
1706 case SWITCHDEV_OBJ_ID_PORT_VLAN:
1707 err = mlxsw_sp_port_vlans_del(mlxsw_sp_port,
1708 SWITCHDEV_OBJ_PORT_VLAN(obj));
1709 break;
Elad Raz3a49b4f2016-01-10 21:06:28 +01001710 case SWITCHDEV_OBJ_ID_PORT_MDB:
1711 err = mlxsw_sp_port_mdb_del(mlxsw_sp_port,
1712 SWITCHDEV_OBJ_PORT_MDB(obj));
Dan Carpenter00ae40e2016-01-13 15:28:23 +03001713 break;
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001714 default:
1715 err = -EOPNOTSUPP;
1716 break;
1717 }
1718
1719 return err;
1720}
1721
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01001722static struct mlxsw_sp_port *mlxsw_sp_lag_rep_port(struct mlxsw_sp *mlxsw_sp,
1723 u16 lag_id)
1724{
1725 struct mlxsw_sp_port *mlxsw_sp_port;
Jiri Pirkoc1a38312016-10-21 16:07:23 +02001726 u64 max_lag_members;
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01001727 int i;
1728
Jiri Pirkoc1a38312016-10-21 16:07:23 +02001729 max_lag_members = MLXSW_CORE_RES_GET(mlxsw_sp->core,
1730 MAX_LAG_MEMBERS);
1731 for (i = 0; i < max_lag_members; i++) {
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01001732 mlxsw_sp_port = mlxsw_sp_port_lagged_get(mlxsw_sp, lag_id, i);
1733 if (mlxsw_sp_port)
1734 return mlxsw_sp_port;
1735 }
1736 return NULL;
1737}
1738
Jiri Pirkoc7070fc2015-10-28 10:17:05 +01001739static const struct switchdev_ops mlxsw_sp_port_switchdev_ops = {
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001740 .switchdev_port_attr_get = mlxsw_sp_port_attr_get,
1741 .switchdev_port_attr_set = mlxsw_sp_port_attr_set,
1742 .switchdev_port_obj_add = mlxsw_sp_port_obj_add,
1743 .switchdev_port_obj_del = mlxsw_sp_port_obj_del,
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001744};
1745
Ido Schimmelc57529e2017-05-26 08:37:31 +02001746static int
1747mlxsw_sp_bridge_8021q_port_join(struct mlxsw_sp_bridge_device *bridge_device,
1748 struct mlxsw_sp_bridge_port *bridge_port,
Ido Schimmel9b63ef882017-10-08 11:57:56 +02001749 struct mlxsw_sp_port *mlxsw_sp_port,
1750 struct netlink_ext_ack *extack)
Ido Schimmelc57529e2017-05-26 08:37:31 +02001751{
1752 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
1753
Ido Schimmel9b63ef882017-10-08 11:57:56 +02001754 if (is_vlan_dev(bridge_port->dev)) {
1755 NL_SET_ERR_MSG(extack, "spectrum: Can not enslave a VLAN device to a VLAN-aware bridge");
Ido Schimmelc57529e2017-05-26 08:37:31 +02001756 return -EINVAL;
Ido Schimmel9b63ef882017-10-08 11:57:56 +02001757 }
Ido Schimmelc57529e2017-05-26 08:37:31 +02001758
1759 mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, 1);
1760 if (WARN_ON(!mlxsw_sp_port_vlan))
1761 return -EINVAL;
1762
1763 /* Let VLAN-aware bridge take care of its own VLANs */
1764 mlxsw_sp_port_vlan_put(mlxsw_sp_port_vlan);
1765
1766 return 0;
1767}
1768
1769static void
1770mlxsw_sp_bridge_8021q_port_leave(struct mlxsw_sp_bridge_device *bridge_device,
1771 struct mlxsw_sp_bridge_port *bridge_port,
1772 struct mlxsw_sp_port *mlxsw_sp_port)
1773{
1774 mlxsw_sp_port_vlan_get(mlxsw_sp_port, 1);
1775 /* Make sure untagged frames are allowed to ingress */
1776 mlxsw_sp_port_pvid_set(mlxsw_sp_port, 1);
1777}
1778
Ido Schimmela1107482017-05-26 08:37:39 +02001779static struct mlxsw_sp_fid *
1780mlxsw_sp_bridge_8021q_fid_get(struct mlxsw_sp_bridge_device *bridge_device,
1781 u16 vid)
1782{
1783 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(bridge_device->dev);
1784
1785 return mlxsw_sp_fid_8021q_get(mlxsw_sp, vid);
1786}
1787
Ido Schimmelc57529e2017-05-26 08:37:31 +02001788static const struct mlxsw_sp_bridge_ops mlxsw_sp_bridge_8021q_ops = {
1789 .port_join = mlxsw_sp_bridge_8021q_port_join,
1790 .port_leave = mlxsw_sp_bridge_8021q_port_leave,
Ido Schimmela1107482017-05-26 08:37:39 +02001791 .fid_get = mlxsw_sp_bridge_8021q_fid_get,
Ido Schimmelc57529e2017-05-26 08:37:31 +02001792};
1793
1794static bool
1795mlxsw_sp_port_is_br_member(const struct mlxsw_sp_port *mlxsw_sp_port,
1796 const struct net_device *br_dev)
1797{
1798 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
1799
1800 list_for_each_entry(mlxsw_sp_port_vlan, &mlxsw_sp_port->vlans_list,
1801 list) {
1802 if (mlxsw_sp_port_vlan->bridge_port &&
1803 mlxsw_sp_port_vlan->bridge_port->bridge_device->dev ==
1804 br_dev)
1805 return true;
1806 }
1807
1808 return false;
1809}
1810
1811static int
1812mlxsw_sp_bridge_8021d_port_join(struct mlxsw_sp_bridge_device *bridge_device,
1813 struct mlxsw_sp_bridge_port *bridge_port,
Ido Schimmel9b63ef882017-10-08 11:57:56 +02001814 struct mlxsw_sp_port *mlxsw_sp_port,
1815 struct netlink_ext_ack *extack)
Ido Schimmelc57529e2017-05-26 08:37:31 +02001816{
1817 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
Ido Schimmelc57529e2017-05-26 08:37:31 +02001818 u16 vid;
1819
Ido Schimmel9b63ef882017-10-08 11:57:56 +02001820 if (!is_vlan_dev(bridge_port->dev)) {
1821 NL_SET_ERR_MSG(extack, "spectrum: Only VLAN devices can be enslaved to a VLAN-unaware bridge");
Ido Schimmelc57529e2017-05-26 08:37:31 +02001822 return -EINVAL;
Ido Schimmel9b63ef882017-10-08 11:57:56 +02001823 }
Ido Schimmelc57529e2017-05-26 08:37:31 +02001824 vid = vlan_dev_vlan_id(bridge_port->dev);
1825
1826 mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid);
1827 if (WARN_ON(!mlxsw_sp_port_vlan))
1828 return -EINVAL;
Ido Schimmelc57529e2017-05-26 08:37:31 +02001829
1830 if (mlxsw_sp_port_is_br_member(mlxsw_sp_port, bridge_device->dev)) {
Ido Schimmel9b63ef882017-10-08 11:57:56 +02001831 NL_SET_ERR_MSG(extack, "spectrum: Can not bridge VLAN uppers of the same port");
Ido Schimmelc57529e2017-05-26 08:37:31 +02001832 return -EINVAL;
1833 }
1834
1835 /* Port is no longer usable as a router interface */
Ido Schimmela1107482017-05-26 08:37:39 +02001836 if (mlxsw_sp_port_vlan->fid)
1837 mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port_vlan);
Ido Schimmelc57529e2017-05-26 08:37:31 +02001838
1839 return mlxsw_sp_port_vlan_bridge_join(mlxsw_sp_port_vlan, bridge_port);
1840}
1841
1842static void
1843mlxsw_sp_bridge_8021d_port_leave(struct mlxsw_sp_bridge_device *bridge_device,
1844 struct mlxsw_sp_bridge_port *bridge_port,
1845 struct mlxsw_sp_port *mlxsw_sp_port)
1846{
1847 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
1848 u16 vid = vlan_dev_vlan_id(bridge_port->dev);
1849
1850 mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid);
1851 if (WARN_ON(!mlxsw_sp_port_vlan))
1852 return;
1853
1854 mlxsw_sp_port_vlan_bridge_leave(mlxsw_sp_port_vlan);
1855}
1856
Ido Schimmela1107482017-05-26 08:37:39 +02001857static struct mlxsw_sp_fid *
1858mlxsw_sp_bridge_8021d_fid_get(struct mlxsw_sp_bridge_device *bridge_device,
1859 u16 vid)
1860{
1861 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(bridge_device->dev);
1862
1863 return mlxsw_sp_fid_8021d_get(mlxsw_sp, bridge_device->dev->ifindex);
1864}
1865
Ido Schimmelc57529e2017-05-26 08:37:31 +02001866static const struct mlxsw_sp_bridge_ops mlxsw_sp_bridge_8021d_ops = {
1867 .port_join = mlxsw_sp_bridge_8021d_port_join,
1868 .port_leave = mlxsw_sp_bridge_8021d_port_leave,
Ido Schimmela1107482017-05-26 08:37:39 +02001869 .fid_get = mlxsw_sp_bridge_8021d_fid_get,
Ido Schimmelc57529e2017-05-26 08:37:31 +02001870};
1871
1872int mlxsw_sp_port_bridge_join(struct mlxsw_sp_port *mlxsw_sp_port,
1873 struct net_device *brport_dev,
Ido Schimmel9b63ef882017-10-08 11:57:56 +02001874 struct net_device *br_dev,
1875 struct netlink_ext_ack *extack)
Ido Schimmelc57529e2017-05-26 08:37:31 +02001876{
1877 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1878 struct mlxsw_sp_bridge_device *bridge_device;
1879 struct mlxsw_sp_bridge_port *bridge_port;
1880 int err;
1881
1882 bridge_port = mlxsw_sp_bridge_port_get(mlxsw_sp->bridge, brport_dev);
1883 if (IS_ERR(bridge_port))
1884 return PTR_ERR(bridge_port);
1885 bridge_device = bridge_port->bridge_device;
1886
1887 err = bridge_device->ops->port_join(bridge_device, bridge_port,
Ido Schimmel9b63ef882017-10-08 11:57:56 +02001888 mlxsw_sp_port, extack);
Ido Schimmelc57529e2017-05-26 08:37:31 +02001889 if (err)
1890 goto err_port_join;
1891
1892 return 0;
1893
1894err_port_join:
1895 mlxsw_sp_bridge_port_put(mlxsw_sp->bridge, bridge_port);
1896 return err;
1897}
1898
1899void mlxsw_sp_port_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_port,
1900 struct net_device *brport_dev,
1901 struct net_device *br_dev)
1902{
1903 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1904 struct mlxsw_sp_bridge_device *bridge_device;
1905 struct mlxsw_sp_bridge_port *bridge_port;
1906
1907 bridge_device = mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, br_dev);
1908 if (!bridge_device)
1909 return;
1910 bridge_port = __mlxsw_sp_bridge_port_find(bridge_device, brport_dev);
1911 if (!bridge_port)
1912 return;
1913
1914 bridge_device->ops->port_leave(bridge_device, bridge_port,
1915 mlxsw_sp_port);
1916 mlxsw_sp_bridge_port_put(mlxsw_sp->bridge, bridge_port);
1917}
1918
Arkadi Sharshevsky1b40dc32017-06-08 08:44:19 +02001919static void
1920mlxsw_sp_fdb_call_notifiers(enum switchdev_notifier_type type,
1921 const char *mac, u16 vid,
1922 struct net_device *dev)
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01001923{
1924 struct switchdev_notifier_fdb_info info;
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01001925
Arkadi Sharshevskya989cdb2017-06-08 08:44:16 +02001926 info.addr = mac;
1927 info.vid = vid;
Arkadi Sharshevsky1b40dc32017-06-08 08:44:19 +02001928 call_switchdev_notifiers(type, dev, &info.info);
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01001929}
1930
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001931static void mlxsw_sp_fdb_notify_mac_process(struct mlxsw_sp *mlxsw_sp,
1932 char *sfn_pl, int rec_index,
1933 bool adding)
1934{
Ido Schimmelc57529e2017-05-26 08:37:31 +02001935 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
1936 struct mlxsw_sp_bridge_device *bridge_device;
1937 struct mlxsw_sp_bridge_port *bridge_port;
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001938 struct mlxsw_sp_port *mlxsw_sp_port;
Arkadi Sharshevsky1b40dc32017-06-08 08:44:19 +02001939 enum switchdev_notifier_type type;
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001940 char mac[ETH_ALEN];
1941 u8 local_port;
Ido Schimmel9de6a802015-12-15 16:03:40 +01001942 u16 vid, fid;
Jiri Pirko12f15012016-01-07 11:50:30 +01001943 bool do_notification = true;
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001944 int err;
1945
Ido Schimmel9de6a802015-12-15 16:03:40 +01001946 mlxsw_reg_sfn_mac_unpack(sfn_pl, rec_index, mac, &fid, &local_port);
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001947 mlxsw_sp_port = mlxsw_sp->ports[local_port];
1948 if (!mlxsw_sp_port) {
1949 dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Incorrect local port in FDB notification\n");
Jiri Pirko12f15012016-01-07 11:50:30 +01001950 goto just_remove;
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001951 }
1952
Ido Schimmelc57529e2017-05-26 08:37:31 +02001953 mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_fid(mlxsw_sp_port, fid);
1954 if (!mlxsw_sp_port_vlan) {
1955 netdev_err(mlxsw_sp_port->dev, "Failed to find a matching {Port, VID} following FDB notification\n");
1956 goto just_remove;
Ido Schimmelaac78a42015-12-15 16:03:42 +01001957 }
1958
Ido Schimmelc57529e2017-05-26 08:37:31 +02001959 bridge_port = mlxsw_sp_port_vlan->bridge_port;
1960 if (!bridge_port) {
1961 netdev_err(mlxsw_sp_port->dev, "{Port, VID} not associated with a bridge\n");
1962 goto just_remove;
1963 }
1964
1965 bridge_device = bridge_port->bridge_device;
1966 vid = bridge_device->vlan_enabled ? mlxsw_sp_port_vlan->vid : 0;
1967
Jiri Pirko12f15012016-01-07 11:50:30 +01001968do_fdb_op:
Jiri Pirko2fa9d452016-01-07 11:50:29 +01001969 err = mlxsw_sp_port_fdb_uc_op(mlxsw_sp, local_port, mac, fid,
Jiri Pirko12f15012016-01-07 11:50:30 +01001970 adding, true);
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001971 if (err) {
Ido Schimmelc0e01ea2017-05-18 13:03:52 +02001972 dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to set FDB entry\n");
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001973 return;
1974 }
1975
Jiri Pirko12f15012016-01-07 11:50:30 +01001976 if (!do_notification)
1977 return;
Arkadi Sharshevsky1b40dc32017-06-08 08:44:19 +02001978 type = adding ? SWITCHDEV_FDB_ADD_TO_BRIDGE : SWITCHDEV_FDB_DEL_TO_BRIDGE;
1979 mlxsw_sp_fdb_call_notifiers(type, mac, vid, bridge_port->dev);
Arkadi Sharshevskya989cdb2017-06-08 08:44:16 +02001980
Jiri Pirko12f15012016-01-07 11:50:30 +01001981 return;
1982
1983just_remove:
1984 adding = false;
1985 do_notification = false;
1986 goto do_fdb_op;
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01001987}
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001988
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01001989static void mlxsw_sp_fdb_notify_mac_lag_process(struct mlxsw_sp *mlxsw_sp,
1990 char *sfn_pl, int rec_index,
1991 bool adding)
1992{
Ido Schimmelc57529e2017-05-26 08:37:31 +02001993 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
1994 struct mlxsw_sp_bridge_device *bridge_device;
1995 struct mlxsw_sp_bridge_port *bridge_port;
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01001996 struct mlxsw_sp_port *mlxsw_sp_port;
Arkadi Sharshevsky1b40dc32017-06-08 08:44:19 +02001997 enum switchdev_notifier_type type;
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01001998 char mac[ETH_ALEN];
Ido Schimmel64771e32015-12-15 16:03:46 +01001999 u16 lag_vid = 0;
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01002000 u16 lag_id;
Ido Schimmel9de6a802015-12-15 16:03:40 +01002001 u16 vid, fid;
Jiri Pirko12f15012016-01-07 11:50:30 +01002002 bool do_notification = true;
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01002003 int err;
2004
Ido Schimmel9de6a802015-12-15 16:03:40 +01002005 mlxsw_reg_sfn_mac_lag_unpack(sfn_pl, rec_index, mac, &fid, &lag_id);
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01002006 mlxsw_sp_port = mlxsw_sp_lag_rep_port(mlxsw_sp, lag_id);
2007 if (!mlxsw_sp_port) {
2008 dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Cannot find port representor for LAG\n");
Jiri Pirko12f15012016-01-07 11:50:30 +01002009 goto just_remove;
Jiri Pirko56ade8f2015-10-16 14:01:37 +02002010 }
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01002011
Ido Schimmelc57529e2017-05-26 08:37:31 +02002012 mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_fid(mlxsw_sp_port, fid);
2013 if (!mlxsw_sp_port_vlan) {
2014 netdev_err(mlxsw_sp_port->dev, "Failed to find a matching {Port, VID} following FDB notification\n");
2015 goto just_remove;
Ido Schimmelaac78a42015-12-15 16:03:42 +01002016 }
2017
Ido Schimmelc57529e2017-05-26 08:37:31 +02002018 bridge_port = mlxsw_sp_port_vlan->bridge_port;
2019 if (!bridge_port) {
2020 netdev_err(mlxsw_sp_port->dev, "{Port, VID} not associated with a bridge\n");
2021 goto just_remove;
2022 }
2023
2024 bridge_device = bridge_port->bridge_device;
2025 vid = bridge_device->vlan_enabled ? mlxsw_sp_port_vlan->vid : 0;
2026 lag_vid = mlxsw_sp_port_vlan->vid;
2027
Jiri Pirko12f15012016-01-07 11:50:30 +01002028do_fdb_op:
Ido Schimmel64771e32015-12-15 16:03:46 +01002029 err = mlxsw_sp_port_fdb_uc_lag_op(mlxsw_sp, lag_id, mac, fid, lag_vid,
Jiri Pirko12f15012016-01-07 11:50:30 +01002030 adding, true);
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01002031 if (err) {
Ido Schimmelc0e01ea2017-05-18 13:03:52 +02002032 dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to set FDB entry\n");
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01002033 return;
2034 }
2035
Jiri Pirko12f15012016-01-07 11:50:30 +01002036 if (!do_notification)
2037 return;
Arkadi Sharshevsky1b40dc32017-06-08 08:44:19 +02002038 type = adding ? SWITCHDEV_FDB_ADD_TO_BRIDGE : SWITCHDEV_FDB_DEL_TO_BRIDGE;
2039 mlxsw_sp_fdb_call_notifiers(type, mac, vid, bridge_port->dev);
Arkadi Sharshevskya989cdb2017-06-08 08:44:16 +02002040
Jiri Pirko12f15012016-01-07 11:50:30 +01002041 return;
2042
2043just_remove:
2044 adding = false;
2045 do_notification = false;
2046 goto do_fdb_op;
Jiri Pirko56ade8f2015-10-16 14:01:37 +02002047}
2048
2049static void mlxsw_sp_fdb_notify_rec_process(struct mlxsw_sp *mlxsw_sp,
2050 char *sfn_pl, int rec_index)
2051{
2052 switch (mlxsw_reg_sfn_rec_type_get(sfn_pl, rec_index)) {
2053 case MLXSW_REG_SFN_REC_TYPE_LEARNED_MAC:
2054 mlxsw_sp_fdb_notify_mac_process(mlxsw_sp, sfn_pl,
2055 rec_index, true);
2056 break;
2057 case MLXSW_REG_SFN_REC_TYPE_AGED_OUT_MAC:
2058 mlxsw_sp_fdb_notify_mac_process(mlxsw_sp, sfn_pl,
2059 rec_index, false);
2060 break;
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01002061 case MLXSW_REG_SFN_REC_TYPE_LEARNED_MAC_LAG:
2062 mlxsw_sp_fdb_notify_mac_lag_process(mlxsw_sp, sfn_pl,
2063 rec_index, true);
2064 break;
2065 case MLXSW_REG_SFN_REC_TYPE_AGED_OUT_MAC_LAG:
2066 mlxsw_sp_fdb_notify_mac_lag_process(mlxsw_sp, sfn_pl,
2067 rec_index, false);
2068 break;
Jiri Pirko56ade8f2015-10-16 14:01:37 +02002069 }
2070}
2071
2072static void mlxsw_sp_fdb_notify_work_schedule(struct mlxsw_sp *mlxsw_sp)
2073{
Ido Schimmel5f6935c2017-05-16 19:38:26 +02002074 struct mlxsw_sp_bridge *bridge = mlxsw_sp->bridge;
2075
2076 mlxsw_core_schedule_dw(&bridge->fdb_notify.dw,
2077 msecs_to_jiffies(bridge->fdb_notify.interval));
Jiri Pirko56ade8f2015-10-16 14:01:37 +02002078}
2079
2080static void mlxsw_sp_fdb_notify_work(struct work_struct *work)
2081{
Ido Schimmel5f6935c2017-05-16 19:38:26 +02002082 struct mlxsw_sp_bridge *bridge;
Jiri Pirko56ade8f2015-10-16 14:01:37 +02002083 struct mlxsw_sp *mlxsw_sp;
2084 char *sfn_pl;
2085 u8 num_rec;
2086 int i;
2087 int err;
2088
2089 sfn_pl = kmalloc(MLXSW_REG_SFN_LEN, GFP_KERNEL);
2090 if (!sfn_pl)
2091 return;
2092
Ido Schimmel5f6935c2017-05-16 19:38:26 +02002093 bridge = container_of(work, struct mlxsw_sp_bridge, fdb_notify.dw.work);
2094 mlxsw_sp = bridge->mlxsw_sp;
Jiri Pirko56ade8f2015-10-16 14:01:37 +02002095
Ido Schimmel4f2c6ae2016-01-27 15:16:43 +01002096 rtnl_lock();
Ido Schimmel1803e0f2016-08-24 12:00:23 +02002097 mlxsw_reg_sfn_pack(sfn_pl);
2098 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(sfn), sfn_pl);
2099 if (err) {
2100 dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to get FDB notifications\n");
2101 goto out;
2102 }
2103 num_rec = mlxsw_reg_sfn_num_rec_get(sfn_pl);
2104 for (i = 0; i < num_rec; i++)
2105 mlxsw_sp_fdb_notify_rec_process(mlxsw_sp, sfn_pl, i);
Jiri Pirko56ade8f2015-10-16 14:01:37 +02002106
Ido Schimmel1803e0f2016-08-24 12:00:23 +02002107out:
Ido Schimmel4f2c6ae2016-01-27 15:16:43 +01002108 rtnl_unlock();
Jiri Pirko56ade8f2015-10-16 14:01:37 +02002109 kfree(sfn_pl);
2110 mlxsw_sp_fdb_notify_work_schedule(mlxsw_sp);
2111}
2112
Arkadi Sharshevskyaf0613782017-06-08 08:44:20 +02002113struct mlxsw_sp_switchdev_event_work {
2114 struct work_struct work;
2115 struct switchdev_notifier_fdb_info fdb_info;
2116 struct net_device *dev;
2117 unsigned long event;
2118};
2119
2120static void mlxsw_sp_switchdev_event_work(struct work_struct *work)
2121{
2122 struct mlxsw_sp_switchdev_event_work *switchdev_work =
2123 container_of(work, struct mlxsw_sp_switchdev_event_work, work);
2124 struct net_device *dev = switchdev_work->dev;
2125 struct switchdev_notifier_fdb_info *fdb_info;
2126 struct mlxsw_sp_port *mlxsw_sp_port;
2127 int err;
2128
2129 rtnl_lock();
2130 mlxsw_sp_port = mlxsw_sp_port_dev_lower_find(dev);
2131 if (!mlxsw_sp_port)
2132 goto out;
2133
2134 switch (switchdev_work->event) {
2135 case SWITCHDEV_FDB_ADD_TO_DEVICE:
2136 fdb_info = &switchdev_work->fdb_info;
2137 err = mlxsw_sp_port_fdb_set(mlxsw_sp_port, fdb_info, true);
2138 if (err)
2139 break;
2140 mlxsw_sp_fdb_call_notifiers(SWITCHDEV_FDB_OFFLOADED,
2141 fdb_info->addr,
2142 fdb_info->vid, dev);
2143 break;
2144 case SWITCHDEV_FDB_DEL_TO_DEVICE:
2145 fdb_info = &switchdev_work->fdb_info;
2146 mlxsw_sp_port_fdb_set(mlxsw_sp_port, fdb_info, false);
2147 break;
2148 }
2149
2150out:
2151 rtnl_unlock();
2152 kfree(switchdev_work->fdb_info.addr);
2153 kfree(switchdev_work);
2154 dev_put(dev);
2155}
2156
2157/* Called under rcu_read_lock() */
2158static int mlxsw_sp_switchdev_event(struct notifier_block *unused,
2159 unsigned long event, void *ptr)
2160{
2161 struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
2162 struct mlxsw_sp_switchdev_event_work *switchdev_work;
2163 struct switchdev_notifier_fdb_info *fdb_info = ptr;
2164
2165 if (!mlxsw_sp_port_dev_lower_find_rcu(dev))
2166 return NOTIFY_DONE;
2167
2168 switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC);
2169 if (!switchdev_work)
2170 return NOTIFY_BAD;
2171
2172 INIT_WORK(&switchdev_work->work, mlxsw_sp_switchdev_event_work);
2173 switchdev_work->dev = dev;
2174 switchdev_work->event = event;
2175
2176 switch (event) {
2177 case SWITCHDEV_FDB_ADD_TO_DEVICE: /* fall through */
2178 case SWITCHDEV_FDB_DEL_TO_DEVICE:
2179 memcpy(&switchdev_work->fdb_info, ptr,
2180 sizeof(switchdev_work->fdb_info));
2181 switchdev_work->fdb_info.addr = kzalloc(ETH_ALEN, GFP_ATOMIC);
Ido Schimmel6f497932017-07-12 09:12:55 +02002182 if (!switchdev_work->fdb_info.addr)
2183 goto err_addr_alloc;
Arkadi Sharshevskyaf0613782017-06-08 08:44:20 +02002184 ether_addr_copy((u8 *)switchdev_work->fdb_info.addr,
2185 fdb_info->addr);
2186 /* Take a reference on the device. This can be either
2187 * upper device containig mlxsw_sp_port or just a
2188 * mlxsw_sp_port
2189 */
2190 dev_hold(dev);
2191 break;
2192 default:
2193 kfree(switchdev_work);
2194 return NOTIFY_DONE;
2195 }
2196
2197 mlxsw_core_schedule_work(&switchdev_work->work);
2198
2199 return NOTIFY_DONE;
Ido Schimmel6f497932017-07-12 09:12:55 +02002200
2201err_addr_alloc:
2202 kfree(switchdev_work);
2203 return NOTIFY_BAD;
Arkadi Sharshevskyaf0613782017-06-08 08:44:20 +02002204}
2205
2206static struct notifier_block mlxsw_sp_switchdev_notifier = {
2207 .notifier_call = mlxsw_sp_switchdev_event,
2208};
2209
Jiri Pirko56ade8f2015-10-16 14:01:37 +02002210static int mlxsw_sp_fdb_init(struct mlxsw_sp *mlxsw_sp)
2211{
Ido Schimmel5f6935c2017-05-16 19:38:26 +02002212 struct mlxsw_sp_bridge *bridge = mlxsw_sp->bridge;
Jiri Pirko56ade8f2015-10-16 14:01:37 +02002213 int err;
2214
2215 err = mlxsw_sp_ageing_set(mlxsw_sp, MLXSW_SP_DEFAULT_AGEING_TIME);
2216 if (err) {
2217 dev_err(mlxsw_sp->bus_info->dev, "Failed to set default ageing time\n");
2218 return err;
2219 }
Arkadi Sharshevskyaf0613782017-06-08 08:44:20 +02002220
2221 err = register_switchdev_notifier(&mlxsw_sp_switchdev_notifier);
2222 if (err) {
2223 dev_err(mlxsw_sp->bus_info->dev, "Failed to register switchdev notifier\n");
2224 return err;
2225 }
2226
Ido Schimmel5f6935c2017-05-16 19:38:26 +02002227 INIT_DELAYED_WORK(&bridge->fdb_notify.dw, mlxsw_sp_fdb_notify_work);
2228 bridge->fdb_notify.interval = MLXSW_SP_DEFAULT_LEARNING_INTERVAL;
Jiri Pirko56ade8f2015-10-16 14:01:37 +02002229 mlxsw_sp_fdb_notify_work_schedule(mlxsw_sp);
2230 return 0;
2231}
2232
2233static void mlxsw_sp_fdb_fini(struct mlxsw_sp *mlxsw_sp)
2234{
Ido Schimmel5f6935c2017-05-16 19:38:26 +02002235 cancel_delayed_work_sync(&mlxsw_sp->bridge->fdb_notify.dw);
Arkadi Sharshevskyaf0613782017-06-08 08:44:20 +02002236 unregister_switchdev_notifier(&mlxsw_sp_switchdev_notifier);
2237
Jiri Pirko56ade8f2015-10-16 14:01:37 +02002238}
2239
Jiri Pirko56ade8f2015-10-16 14:01:37 +02002240int mlxsw_sp_switchdev_init(struct mlxsw_sp *mlxsw_sp)
2241{
Ido Schimmel5f6935c2017-05-16 19:38:26 +02002242 struct mlxsw_sp_bridge *bridge;
2243
2244 bridge = kzalloc(sizeof(*mlxsw_sp->bridge), GFP_KERNEL);
2245 if (!bridge)
2246 return -ENOMEM;
2247 mlxsw_sp->bridge = bridge;
2248 bridge->mlxsw_sp = mlxsw_sp;
2249
Ido Schimmelc57529e2017-05-26 08:37:31 +02002250 INIT_LIST_HEAD(&mlxsw_sp->bridge->bridges_list);
Ido Schimmel5f6935c2017-05-16 19:38:26 +02002251
Ido Schimmelc57529e2017-05-26 08:37:31 +02002252 bridge->bridge_8021q_ops = &mlxsw_sp_bridge_8021q_ops;
2253 bridge->bridge_8021d_ops = &mlxsw_sp_bridge_8021d_ops;
2254
Jiri Pirko56ade8f2015-10-16 14:01:37 +02002255 return mlxsw_sp_fdb_init(mlxsw_sp);
2256}
2257
2258void mlxsw_sp_switchdev_fini(struct mlxsw_sp *mlxsw_sp)
2259{
2260 mlxsw_sp_fdb_fini(mlxsw_sp);
Ido Schimmelc57529e2017-05-26 08:37:31 +02002261 WARN_ON(!list_empty(&mlxsw_sp->bridge->bridges_list));
Ido Schimmel5f6935c2017-05-16 19:38:26 +02002262 kfree(mlxsw_sp->bridge);
Jiri Pirko56ade8f2015-10-16 14:01:37 +02002263}
2264
Jiri Pirko56ade8f2015-10-16 14:01:37 +02002265void mlxsw_sp_port_switchdev_init(struct mlxsw_sp_port *mlxsw_sp_port)
2266{
2267 mlxsw_sp_port->dev->switchdev_ops = &mlxsw_sp_port_switchdev_ops;
2268}
2269
2270void mlxsw_sp_port_switchdev_fini(struct mlxsw_sp_port *mlxsw_sp_port)
2271{
2272}