blob: 79806af87b93e1339dd80f3fd8549115802d6e85 [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>
Jiri Pirko56ade8f2015-10-16 14:01:37 +020049#include <net/switchdev.h>
50
51#include "spectrum.h"
52#include "core.h"
53#include "reg.h"
54
Ido Schimmelc57529e2017-05-26 08:37:31 +020055struct mlxsw_sp_bridge_ops;
56
Ido Schimmel5f6935c2017-05-16 19:38:26 +020057struct mlxsw_sp_bridge {
58 struct mlxsw_sp *mlxsw_sp;
59 struct {
60 struct delayed_work dw;
61#define MLXSW_SP_DEFAULT_LEARNING_INTERVAL 100
62 unsigned int interval; /* ms */
63 } fdb_notify;
64#define MLXSW_SP_MIN_AGEING_TIME 10
65#define MLXSW_SP_MAX_AGEING_TIME 1000000
66#define MLXSW_SP_DEFAULT_AGEING_TIME 300
67 u32 ageing_time;
Ido Schimmelc57529e2017-05-26 08:37:31 +020068 bool vlan_enabled_exists;
69 struct list_head bridges_list;
Ido Schimmel5f6935c2017-05-16 19:38:26 +020070 DECLARE_BITMAP(mids_bitmap, MLXSW_SP_MID_MAX);
Ido Schimmelc57529e2017-05-26 08:37:31 +020071 const struct mlxsw_sp_bridge_ops *bridge_8021q_ops;
72 const struct mlxsw_sp_bridge_ops *bridge_8021d_ops;
Ido Schimmel5f6935c2017-05-16 19:38:26 +020073};
74
Ido Schimmelc57529e2017-05-26 08:37:31 +020075struct mlxsw_sp_bridge_device {
76 struct net_device *dev;
77 struct list_head list;
78 struct list_head ports_list;
Nogah Frankelb80888a2017-09-20 16:15:04 +020079 struct list_head mids_list;
Ido Schimmelc57529e2017-05-26 08:37:31 +020080 u8 vlan_enabled:1,
81 multicast_enabled:1;
82 const struct mlxsw_sp_bridge_ops *ops;
83};
Ido Schimmel5f6935c2017-05-16 19:38:26 +020084
Ido Schimmelc57529e2017-05-26 08:37:31 +020085struct mlxsw_sp_bridge_port {
86 struct net_device *dev;
87 struct mlxsw_sp_bridge_device *bridge_device;
88 struct list_head list;
89 struct list_head vlans_list;
90 unsigned int ref_count;
91 u8 stp_state;
92 unsigned long flags;
93 bool mrouter;
94 bool lagged;
95 union {
96 u16 lag_id;
97 u16 system_port;
98 };
99};
Elad Raze4b6f692016-01-10 21:06:27 +0100100
Ido Schimmelc57529e2017-05-26 08:37:31 +0200101struct mlxsw_sp_bridge_vlan {
102 struct list_head list;
103 struct list_head port_vlan_list;
Ido Schimmel54a73202015-12-15 16:03:41 +0100104 u16 vid;
Ido Schimmelc57529e2017-05-26 08:37:31 +0200105};
Ido Schimmel54a73202015-12-15 16:03:41 +0100106
Ido Schimmelc57529e2017-05-26 08:37:31 +0200107struct mlxsw_sp_bridge_ops {
108 int (*port_join)(struct mlxsw_sp_bridge_device *bridge_device,
109 struct mlxsw_sp_bridge_port *bridge_port,
110 struct mlxsw_sp_port *mlxsw_sp_port);
111 void (*port_leave)(struct mlxsw_sp_bridge_device *bridge_device,
112 struct mlxsw_sp_bridge_port *bridge_port,
113 struct mlxsw_sp_port *mlxsw_sp_port);
Ido Schimmela1107482017-05-26 08:37:39 +0200114 struct mlxsw_sp_fid *
115 (*fid_get)(struct mlxsw_sp_bridge_device *bridge_device,
116 u16 vid);
Ido Schimmelc57529e2017-05-26 08:37:31 +0200117};
118
119static int
120mlxsw_sp_bridge_port_fdb_flush(struct mlxsw_sp *mlxsw_sp,
121 struct mlxsw_sp_bridge_port *bridge_port,
122 u16 fid_index);
123
Nogah Frankel2e3496c2017-09-20 16:15:09 +0200124static void
125mlxsw_sp_bridge_mdb_mc_enable_sync(struct mlxsw_sp_port *mlxsw_sp_port,
126 struct mlxsw_sp_bridge_device
127 *bridge_device);
128
Ido Schimmelc57529e2017-05-26 08:37:31 +0200129static struct mlxsw_sp_bridge_device *
130mlxsw_sp_bridge_device_find(const struct mlxsw_sp_bridge *bridge,
131 const struct net_device *br_dev)
132{
133 struct mlxsw_sp_bridge_device *bridge_device;
134
135 list_for_each_entry(bridge_device, &bridge->bridges_list, list)
136 if (bridge_device->dev == br_dev)
137 return bridge_device;
138
139 return NULL;
140}
141
142static struct mlxsw_sp_bridge_device *
143mlxsw_sp_bridge_device_create(struct mlxsw_sp_bridge *bridge,
144 struct net_device *br_dev)
145{
146 struct device *dev = bridge->mlxsw_sp->bus_info->dev;
147 struct mlxsw_sp_bridge_device *bridge_device;
148 bool vlan_enabled = br_vlan_enabled(br_dev);
149
150 if (vlan_enabled && bridge->vlan_enabled_exists) {
151 dev_err(dev, "Only one VLAN-aware bridge is supported\n");
152 return ERR_PTR(-EINVAL);
Nogah Frankel1e5d9432017-02-09 14:54:48 +0100153 }
154
Ido Schimmelc57529e2017-05-26 08:37:31 +0200155 bridge_device = kzalloc(sizeof(*bridge_device), GFP_KERNEL);
156 if (!bridge_device)
157 return ERR_PTR(-ENOMEM);
Ido Schimmel54a73202015-12-15 16:03:41 +0100158
Ido Schimmelc57529e2017-05-26 08:37:31 +0200159 bridge_device->dev = br_dev;
160 bridge_device->vlan_enabled = vlan_enabled;
161 bridge_device->multicast_enabled = br_multicast_enabled(br_dev);
162 INIT_LIST_HEAD(&bridge_device->ports_list);
163 if (vlan_enabled) {
164 bridge->vlan_enabled_exists = true;
165 bridge_device->ops = bridge->bridge_8021q_ops;
166 } else {
167 bridge_device->ops = bridge->bridge_8021d_ops;
168 }
Nogah Frankelb80888a2017-09-20 16:15:04 +0200169 INIT_LIST_HEAD(&bridge_device->mids_list);
Ido Schimmelc57529e2017-05-26 08:37:31 +0200170 list_add(&bridge_device->list, &bridge->bridges_list);
Ido Schimmel54a73202015-12-15 16:03:41 +0100171
Ido Schimmelc57529e2017-05-26 08:37:31 +0200172 return bridge_device;
173}
174
175static void
176mlxsw_sp_bridge_device_destroy(struct mlxsw_sp_bridge *bridge,
177 struct mlxsw_sp_bridge_device *bridge_device)
178{
Nogah Frankelb80888a2017-09-20 16:15:04 +0200179 struct mlxsw_sp_mid *mid, *tmp;
180
Ido Schimmelc57529e2017-05-26 08:37:31 +0200181 list_del(&bridge_device->list);
182 if (bridge_device->vlan_enabled)
183 bridge->vlan_enabled_exists = false;
184 WARN_ON(!list_empty(&bridge_device->ports_list));
Nogah Frankelb80888a2017-09-20 16:15:04 +0200185 list_for_each_entry_safe(mid, tmp, &bridge_device->mids_list, list) {
186 list_del(&mid->list);
187 clear_bit(mid->mid, bridge->mids_bitmap);
188 kfree(mid);
189 }
Ido Schimmelc57529e2017-05-26 08:37:31 +0200190 kfree(bridge_device);
191}
192
193static struct mlxsw_sp_bridge_device *
194mlxsw_sp_bridge_device_get(struct mlxsw_sp_bridge *bridge,
195 struct net_device *br_dev)
196{
197 struct mlxsw_sp_bridge_device *bridge_device;
198
199 bridge_device = mlxsw_sp_bridge_device_find(bridge, br_dev);
200 if (bridge_device)
201 return bridge_device;
202
203 return mlxsw_sp_bridge_device_create(bridge, br_dev);
204}
205
206static void
207mlxsw_sp_bridge_device_put(struct mlxsw_sp_bridge *bridge,
208 struct mlxsw_sp_bridge_device *bridge_device)
209{
210 if (list_empty(&bridge_device->ports_list))
211 mlxsw_sp_bridge_device_destroy(bridge, bridge_device);
212}
213
214static struct mlxsw_sp_bridge_port *
215__mlxsw_sp_bridge_port_find(const struct mlxsw_sp_bridge_device *bridge_device,
216 const struct net_device *brport_dev)
217{
218 struct mlxsw_sp_bridge_port *bridge_port;
219
220 list_for_each_entry(bridge_port, &bridge_device->ports_list, list) {
221 if (bridge_port->dev == brport_dev)
222 return bridge_port;
223 }
224
225 return NULL;
226}
227
228static struct mlxsw_sp_bridge_port *
229mlxsw_sp_bridge_port_find(struct mlxsw_sp_bridge *bridge,
230 struct net_device *brport_dev)
231{
232 struct net_device *br_dev = netdev_master_upper_dev_get(brport_dev);
233 struct mlxsw_sp_bridge_device *bridge_device;
234
235 if (!br_dev)
236 return NULL;
237
238 bridge_device = mlxsw_sp_bridge_device_find(bridge, br_dev);
239 if (!bridge_device)
240 return NULL;
241
242 return __mlxsw_sp_bridge_port_find(bridge_device, brport_dev);
243}
244
245static struct mlxsw_sp_bridge_port *
246mlxsw_sp_bridge_port_create(struct mlxsw_sp_bridge_device *bridge_device,
247 struct net_device *brport_dev)
248{
249 struct mlxsw_sp_bridge_port *bridge_port;
250 struct mlxsw_sp_port *mlxsw_sp_port;
251
252 bridge_port = kzalloc(sizeof(*bridge_port), GFP_KERNEL);
253 if (!bridge_port)
254 return NULL;
255
256 mlxsw_sp_port = mlxsw_sp_port_dev_lower_find(brport_dev);
257 bridge_port->lagged = mlxsw_sp_port->lagged;
258 if (bridge_port->lagged)
259 bridge_port->lag_id = mlxsw_sp_port->lag_id;
260 else
261 bridge_port->system_port = mlxsw_sp_port->local_port;
262 bridge_port->dev = brport_dev;
263 bridge_port->bridge_device = bridge_device;
264 bridge_port->stp_state = BR_STATE_DISABLED;
265 bridge_port->flags = BR_LEARNING | BR_FLOOD | BR_LEARNING_SYNC;
266 INIT_LIST_HEAD(&bridge_port->vlans_list);
267 list_add(&bridge_port->list, &bridge_device->ports_list);
268 bridge_port->ref_count = 1;
269
270 return bridge_port;
271}
272
273static void
274mlxsw_sp_bridge_port_destroy(struct mlxsw_sp_bridge_port *bridge_port)
275{
276 list_del(&bridge_port->list);
277 WARN_ON(!list_empty(&bridge_port->vlans_list));
278 kfree(bridge_port);
279}
280
281static bool
282mlxsw_sp_bridge_port_should_destroy(const struct mlxsw_sp_bridge_port *
283 bridge_port)
284{
285 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(bridge_port->dev);
286
287 /* In case ports were pulled from out of a bridged LAG, then
288 * it's possible the reference count isn't zero, yet the bridge
289 * port should be destroyed, as it's no longer an upper of ours.
290 */
291 if (!mlxsw_sp && list_empty(&bridge_port->vlans_list))
292 return true;
293 else if (bridge_port->ref_count == 0)
294 return true;
295 else
296 return false;
297}
298
299static struct mlxsw_sp_bridge_port *
300mlxsw_sp_bridge_port_get(struct mlxsw_sp_bridge *bridge,
301 struct net_device *brport_dev)
302{
303 struct net_device *br_dev = netdev_master_upper_dev_get(brport_dev);
304 struct mlxsw_sp_bridge_device *bridge_device;
305 struct mlxsw_sp_bridge_port *bridge_port;
306 int err;
307
308 bridge_port = mlxsw_sp_bridge_port_find(bridge, brport_dev);
309 if (bridge_port) {
310 bridge_port->ref_count++;
311 return bridge_port;
312 }
313
314 bridge_device = mlxsw_sp_bridge_device_get(bridge, br_dev);
315 if (IS_ERR(bridge_device))
316 return ERR_CAST(bridge_device);
317
318 bridge_port = mlxsw_sp_bridge_port_create(bridge_device, brport_dev);
319 if (!bridge_port) {
320 err = -ENOMEM;
321 goto err_bridge_port_create;
322 }
323
324 return bridge_port;
325
326err_bridge_port_create:
327 mlxsw_sp_bridge_device_put(bridge, bridge_device);
328 return ERR_PTR(err);
329}
330
331static void mlxsw_sp_bridge_port_put(struct mlxsw_sp_bridge *bridge,
332 struct mlxsw_sp_bridge_port *bridge_port)
333{
334 struct mlxsw_sp_bridge_device *bridge_device;
335
336 bridge_port->ref_count--;
337 if (!mlxsw_sp_bridge_port_should_destroy(bridge_port))
338 return;
339 bridge_device = bridge_port->bridge_device;
340 mlxsw_sp_bridge_port_destroy(bridge_port);
341 mlxsw_sp_bridge_device_put(bridge, bridge_device);
342}
343
344static struct mlxsw_sp_port_vlan *
345mlxsw_sp_port_vlan_find_by_bridge(struct mlxsw_sp_port *mlxsw_sp_port,
346 const struct mlxsw_sp_bridge_device *
347 bridge_device,
348 u16 vid)
349{
350 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
351
352 list_for_each_entry(mlxsw_sp_port_vlan, &mlxsw_sp_port->vlans_list,
353 list) {
354 if (!mlxsw_sp_port_vlan->bridge_port)
355 continue;
356 if (mlxsw_sp_port_vlan->bridge_port->bridge_device !=
357 bridge_device)
358 continue;
359 if (bridge_device->vlan_enabled &&
360 mlxsw_sp_port_vlan->vid != vid)
361 continue;
362 return mlxsw_sp_port_vlan;
363 }
364
365 return NULL;
366}
367
368static struct mlxsw_sp_port_vlan*
369mlxsw_sp_port_vlan_find_by_fid(struct mlxsw_sp_port *mlxsw_sp_port,
370 u16 fid_index)
371{
372 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
373
374 list_for_each_entry(mlxsw_sp_port_vlan, &mlxsw_sp_port->vlans_list,
375 list) {
376 struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
377
Ido Schimmela1107482017-05-26 08:37:39 +0200378 if (fid && mlxsw_sp_fid_index(fid) == fid_index)
Ido Schimmelc57529e2017-05-26 08:37:31 +0200379 return mlxsw_sp_port_vlan;
380 }
381
382 return NULL;
383}
384
385static struct mlxsw_sp_bridge_vlan *
386mlxsw_sp_bridge_vlan_find(const struct mlxsw_sp_bridge_port *bridge_port,
387 u16 vid)
388{
389 struct mlxsw_sp_bridge_vlan *bridge_vlan;
390
391 list_for_each_entry(bridge_vlan, &bridge_port->vlans_list, list) {
392 if (bridge_vlan->vid == vid)
393 return bridge_vlan;
394 }
395
396 return NULL;
397}
398
399static struct mlxsw_sp_bridge_vlan *
400mlxsw_sp_bridge_vlan_create(struct mlxsw_sp_bridge_port *bridge_port, u16 vid)
401{
402 struct mlxsw_sp_bridge_vlan *bridge_vlan;
403
404 bridge_vlan = kzalloc(sizeof(*bridge_vlan), GFP_KERNEL);
405 if (!bridge_vlan)
406 return NULL;
407
408 INIT_LIST_HEAD(&bridge_vlan->port_vlan_list);
409 bridge_vlan->vid = vid;
410 list_add(&bridge_vlan->list, &bridge_port->vlans_list);
411
412 return bridge_vlan;
413}
414
415static void
416mlxsw_sp_bridge_vlan_destroy(struct mlxsw_sp_bridge_vlan *bridge_vlan)
417{
418 list_del(&bridge_vlan->list);
419 WARN_ON(!list_empty(&bridge_vlan->port_vlan_list));
420 kfree(bridge_vlan);
421}
422
423static struct mlxsw_sp_bridge_vlan *
424mlxsw_sp_bridge_vlan_get(struct mlxsw_sp_bridge_port *bridge_port, u16 vid)
425{
426 struct mlxsw_sp_bridge_vlan *bridge_vlan;
427
428 bridge_vlan = mlxsw_sp_bridge_vlan_find(bridge_port, vid);
429 if (bridge_vlan)
430 return bridge_vlan;
431
432 return mlxsw_sp_bridge_vlan_create(bridge_port, vid);
433}
434
435static void mlxsw_sp_bridge_vlan_put(struct mlxsw_sp_bridge_vlan *bridge_vlan)
436{
437 if (list_empty(&bridge_vlan->port_vlan_list))
438 mlxsw_sp_bridge_vlan_destroy(bridge_vlan);
439}
440
441static void mlxsw_sp_port_bridge_flags_get(struct mlxsw_sp_bridge *bridge,
442 struct net_device *dev,
443 unsigned long *brport_flags)
444{
445 struct mlxsw_sp_bridge_port *bridge_port;
446
447 bridge_port = mlxsw_sp_bridge_port_find(bridge, dev);
448 if (WARN_ON(!bridge_port))
449 return;
450
451 memcpy(brport_flags, &bridge_port->flags, sizeof(*brport_flags));
Ido Schimmel54a73202015-12-15 16:03:41 +0100452}
453
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200454static int mlxsw_sp_port_attr_get(struct net_device *dev,
455 struct switchdev_attr *attr)
456{
457 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
458 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
459
460 switch (attr->id) {
461 case SWITCHDEV_ATTR_ID_PORT_PARENT_ID:
462 attr->u.ppid.id_len = sizeof(mlxsw_sp->base_mac);
463 memcpy(&attr->u.ppid.id, &mlxsw_sp->base_mac,
464 attr->u.ppid.id_len);
465 break;
466 case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:
Ido Schimmelc57529e2017-05-26 08:37:31 +0200467 mlxsw_sp_port_bridge_flags_get(mlxsw_sp->bridge, attr->orig_dev,
468 &attr->u.brport_flags);
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200469 break;
Arkadi Sharshevskyc7b566c2017-06-08 08:44:17 +0200470 case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS_SUPPORT:
471 attr->u.brport_flags_support = BR_LEARNING | BR_FLOOD;
472 break;
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200473 default:
474 return -EOPNOTSUPP;
475 }
476
477 return 0;
478}
479
Ido Schimmelc57529e2017-05-26 08:37:31 +0200480static int
481mlxsw_sp_port_bridge_vlan_stp_set(struct mlxsw_sp_port *mlxsw_sp_port,
482 struct mlxsw_sp_bridge_vlan *bridge_vlan,
483 u8 state)
484{
485 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
486
487 list_for_each_entry(mlxsw_sp_port_vlan, &bridge_vlan->port_vlan_list,
488 bridge_vlan_node) {
489 if (mlxsw_sp_port_vlan->mlxsw_sp_port != mlxsw_sp_port)
490 continue;
491 return mlxsw_sp_port_vid_stp_set(mlxsw_sp_port,
492 bridge_vlan->vid, state);
493 }
494
495 return 0;
496}
497
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200498static int mlxsw_sp_port_attr_stp_state_set(struct mlxsw_sp_port *mlxsw_sp_port,
499 struct switchdev_trans *trans,
Ido Schimmelc57529e2017-05-26 08:37:31 +0200500 struct net_device *orig_dev,
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200501 u8 state)
502{
Ido Schimmelc57529e2017-05-26 08:37:31 +0200503 struct mlxsw_sp_bridge_port *bridge_port;
504 struct mlxsw_sp_bridge_vlan *bridge_vlan;
Ido Schimmel45bfe6b2017-05-16 19:38:32 +0200505 int err;
506
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200507 if (switchdev_trans_ph_prepare(trans))
508 return 0;
509
Ido Schimmelc57529e2017-05-26 08:37:31 +0200510 /* It's possible we failed to enslave the port, yet this
511 * operation is executed due to it being deferred.
512 */
513 bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp_port->mlxsw_sp->bridge,
514 orig_dev);
515 if (!bridge_port)
Ido Schimmel45bfe6b2017-05-16 19:38:32 +0200516 return 0;
Ido Schimmelc57529e2017-05-26 08:37:31 +0200517
518 list_for_each_entry(bridge_vlan, &bridge_port->vlans_list, list) {
519 err = mlxsw_sp_port_bridge_vlan_stp_set(mlxsw_sp_port,
520 bridge_vlan, state);
521 if (err)
522 goto err_port_bridge_vlan_stp_set;
Ido Schimmel45bfe6b2017-05-16 19:38:32 +0200523 }
524
Ido Schimmelc57529e2017-05-26 08:37:31 +0200525 bridge_port->stp_state = state;
Ido Schimmel45bfe6b2017-05-16 19:38:32 +0200526
527 return 0;
Ido Schimmelc57529e2017-05-26 08:37:31 +0200528
529err_port_bridge_vlan_stp_set:
530 list_for_each_entry_continue_reverse(bridge_vlan,
531 &bridge_port->vlans_list, list)
532 mlxsw_sp_port_bridge_vlan_stp_set(mlxsw_sp_port, bridge_vlan,
533 bridge_port->stp_state);
534 return err;
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200535}
536
Ido Schimmelc57529e2017-05-26 08:37:31 +0200537static int
538mlxsw_sp_port_bridge_vlan_flood_set(struct mlxsw_sp_port *mlxsw_sp_port,
539 struct mlxsw_sp_bridge_vlan *bridge_vlan,
Ido Schimmela1107482017-05-26 08:37:39 +0200540 enum mlxsw_sp_flood_type packet_type,
Ido Schimmelc57529e2017-05-26 08:37:31 +0200541 bool member)
Nogah Frankeleaa7df32017-02-09 14:54:43 +0100542{
Ido Schimmelc57529e2017-05-26 08:37:31 +0200543 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
Nogah Frankeleaa7df32017-02-09 14:54:43 +0100544
Ido Schimmelc57529e2017-05-26 08:37:31 +0200545 list_for_each_entry(mlxsw_sp_port_vlan, &bridge_vlan->port_vlan_list,
546 bridge_vlan_node) {
547 if (mlxsw_sp_port_vlan->mlxsw_sp_port != mlxsw_sp_port)
548 continue;
Ido Schimmela1107482017-05-26 08:37:39 +0200549 return mlxsw_sp_fid_flood_set(mlxsw_sp_port_vlan->fid,
550 packet_type,
551 mlxsw_sp_port->local_port,
552 member);
Ido Schimmel54a73202015-12-15 16:03:41 +0100553 }
554
Ido Schimmelc57529e2017-05-26 08:37:31 +0200555 return 0;
556}
557
558static int
559mlxsw_sp_bridge_port_flood_table_set(struct mlxsw_sp_port *mlxsw_sp_port,
560 struct mlxsw_sp_bridge_port *bridge_port,
Ido Schimmela1107482017-05-26 08:37:39 +0200561 enum mlxsw_sp_flood_type packet_type,
Ido Schimmelc57529e2017-05-26 08:37:31 +0200562 bool member)
563{
564 struct mlxsw_sp_bridge_vlan *bridge_vlan;
565 int err;
566
567 list_for_each_entry(bridge_vlan, &bridge_port->vlans_list, list) {
568 err = mlxsw_sp_port_bridge_vlan_flood_set(mlxsw_sp_port,
Ido Schimmela1107482017-05-26 08:37:39 +0200569 bridge_vlan,
570 packet_type,
Ido Schimmelc57529e2017-05-26 08:37:31 +0200571 member);
572 if (err)
573 goto err_port_bridge_vlan_flood_set;
Ido Schimmel02930382015-10-28 10:16:58 +0100574 }
575
576 return 0;
577
Ido Schimmelc57529e2017-05-26 08:37:31 +0200578err_port_bridge_vlan_flood_set:
579 list_for_each_entry_continue_reverse(bridge_vlan,
580 &bridge_port->vlans_list, list)
581 mlxsw_sp_port_bridge_vlan_flood_set(mlxsw_sp_port, bridge_vlan,
Ido Schimmela1107482017-05-26 08:37:39 +0200582 packet_type, !member);
Ido Schimmel02930382015-10-28 10:16:58 +0100583 return err;
584}
585
Ido Schimmelc57529e2017-05-26 08:37:31 +0200586static int
587mlxsw_sp_port_bridge_vlan_learning_set(struct mlxsw_sp_port *mlxsw_sp_port,
588 struct mlxsw_sp_bridge_vlan *bridge_vlan,
589 bool set)
Nogah Frankel90e0f0c2017-02-09 14:54:49 +0100590{
Ido Schimmelc57529e2017-05-26 08:37:31 +0200591 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
592 u16 vid = bridge_vlan->vid;
Nogah Frankel90e0f0c2017-02-09 14:54:49 +0100593
Ido Schimmelc57529e2017-05-26 08:37:31 +0200594 list_for_each_entry(mlxsw_sp_port_vlan, &bridge_vlan->port_vlan_list,
595 bridge_vlan_node) {
596 if (mlxsw_sp_port_vlan->mlxsw_sp_port != mlxsw_sp_port)
597 continue;
Ido Schimmel7cbc4272017-05-16 19:38:33 +0200598 return mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, set);
Ido Schimmel89b548f2016-08-24 12:00:27 +0200599 }
600
Ido Schimmelc57529e2017-05-26 08:37:31 +0200601 return 0;
602}
603
604static int
605mlxsw_sp_bridge_port_learning_set(struct mlxsw_sp_port *mlxsw_sp_port,
606 struct mlxsw_sp_bridge_port *bridge_port,
607 bool set)
608{
609 struct mlxsw_sp_bridge_vlan *bridge_vlan;
610 int err;
611
612 list_for_each_entry(bridge_vlan, &bridge_port->vlans_list, list) {
613 err = mlxsw_sp_port_bridge_vlan_learning_set(mlxsw_sp_port,
614 bridge_vlan, set);
Ido Schimmel89b548f2016-08-24 12:00:27 +0200615 if (err)
Ido Schimmelc57529e2017-05-26 08:37:31 +0200616 goto err_port_bridge_vlan_learning_set;
Ido Schimmel89b548f2016-08-24 12:00:27 +0200617 }
618
619 return 0;
620
Ido Schimmelc57529e2017-05-26 08:37:31 +0200621err_port_bridge_vlan_learning_set:
622 list_for_each_entry_continue_reverse(bridge_vlan,
623 &bridge_port->vlans_list, list)
624 mlxsw_sp_port_bridge_vlan_learning_set(mlxsw_sp_port,
625 bridge_vlan, !set);
Ido Schimmel89b548f2016-08-24 12:00:27 +0200626 return err;
627}
628
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200629static int mlxsw_sp_port_attr_br_flags_set(struct mlxsw_sp_port *mlxsw_sp_port,
630 struct switchdev_trans *trans,
Ido Schimmelc57529e2017-05-26 08:37:31 +0200631 struct net_device *orig_dev,
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200632 unsigned long brport_flags)
633{
Ido Schimmelc57529e2017-05-26 08:37:31 +0200634 struct mlxsw_sp_bridge_port *bridge_port;
Ido Schimmel02930382015-10-28 10:16:58 +0100635 int err;
636
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200637 if (switchdev_trans_ph_prepare(trans))
638 return 0;
639
Ido Schimmelc57529e2017-05-26 08:37:31 +0200640 bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp_port->mlxsw_sp->bridge,
641 orig_dev);
Ido Schimmel17b334a2017-08-04 14:12:29 +0200642 if (!bridge_port)
643 return 0;
Ido Schimmel02930382015-10-28 10:16:58 +0100644
Ido Schimmelc57529e2017-05-26 08:37:31 +0200645 err = mlxsw_sp_bridge_port_flood_table_set(mlxsw_sp_port, bridge_port,
Ido Schimmela1107482017-05-26 08:37:39 +0200646 MLXSW_SP_FLOOD_TYPE_UC,
Ido Schimmelc57529e2017-05-26 08:37:31 +0200647 brport_flags & BR_FLOOD);
648 if (err)
649 return err;
Ido Schimmel89b548f2016-08-24 12:00:27 +0200650
Ido Schimmelc57529e2017-05-26 08:37:31 +0200651 err = mlxsw_sp_bridge_port_learning_set(mlxsw_sp_port, bridge_port,
652 brport_flags & BR_LEARNING);
653 if (err)
654 return err;
655
656 memcpy(&bridge_port->flags, &brport_flags, sizeof(brport_flags));
Ido Schimmel02930382015-10-28 10:16:58 +0100657
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200658 return 0;
659}
660
661static int mlxsw_sp_ageing_set(struct mlxsw_sp *mlxsw_sp, u32 ageing_time)
662{
663 char sfdat_pl[MLXSW_REG_SFDAT_LEN];
664 int err;
665
666 mlxsw_reg_sfdat_pack(sfdat_pl, ageing_time);
667 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfdat), sfdat_pl);
668 if (err)
669 return err;
Ido Schimmel5f6935c2017-05-16 19:38:26 +0200670 mlxsw_sp->bridge->ageing_time = ageing_time;
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200671 return 0;
672}
673
674static int mlxsw_sp_port_attr_br_ageing_set(struct mlxsw_sp_port *mlxsw_sp_port,
675 struct switchdev_trans *trans,
Jiri Pirko135f9ec2015-10-28 10:17:02 +0100676 unsigned long ageing_clock_t)
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200677{
678 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
Jiri Pirko135f9ec2015-10-28 10:17:02 +0100679 unsigned long ageing_jiffies = clock_t_to_jiffies(ageing_clock_t);
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200680 u32 ageing_time = jiffies_to_msecs(ageing_jiffies) / 1000;
681
Ido Schimmel869f63a2016-03-08 12:59:33 -0800682 if (switchdev_trans_ph_prepare(trans)) {
683 if (ageing_time < MLXSW_SP_MIN_AGEING_TIME ||
684 ageing_time > MLXSW_SP_MAX_AGEING_TIME)
685 return -ERANGE;
686 else
687 return 0;
688 }
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200689
690 return mlxsw_sp_ageing_set(mlxsw_sp, ageing_time);
691}
692
Elad Raz26a4ea02016-01-06 13:01:10 +0100693static int mlxsw_sp_port_attr_br_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port,
694 struct switchdev_trans *trans,
695 struct net_device *orig_dev,
696 bool vlan_enabled)
697{
698 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
Ido Schimmelc57529e2017-05-26 08:37:31 +0200699 struct mlxsw_sp_bridge_device *bridge_device;
Elad Raz26a4ea02016-01-06 13:01:10 +0100700
Ido Schimmelc57529e2017-05-26 08:37:31 +0200701 if (!switchdev_trans_ph_prepare(trans))
702 return 0;
703
704 bridge_device = mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, orig_dev);
705 if (WARN_ON(!bridge_device))
Elad Raz26a4ea02016-01-06 13:01:10 +0100706 return -EINVAL;
Elad Raz26a4ea02016-01-06 13:01:10 +0100707
Ido Schimmelc57529e2017-05-26 08:37:31 +0200708 if (bridge_device->vlan_enabled == vlan_enabled)
709 return 0;
710
711 netdev_err(bridge_device->dev, "VLAN filtering can't be changed for existing bridge\n");
712 return -EINVAL;
Elad Raz26a4ea02016-01-06 13:01:10 +0100713}
714
Nogah Frankeldff37b52017-09-20 16:15:01 +0200715static int mlxsw_sp_port_attr_mrouter_set(struct mlxsw_sp_port *mlxsw_sp_port,
716 struct switchdev_trans *trans,
717 struct net_device *orig_dev,
718 bool is_port_mrouter)
Nogah Frankel8ecd4592017-02-09 14:54:47 +0100719{
Ido Schimmelc57529e2017-05-26 08:37:31 +0200720 struct mlxsw_sp_bridge_port *bridge_port;
Nogah Frankel4eb6a3b2017-08-22 10:28:11 +0200721 int err;
Ido Schimmelc57529e2017-05-26 08:37:31 +0200722
Nogah Frankel8ecd4592017-02-09 14:54:47 +0100723 if (switchdev_trans_ph_prepare(trans))
724 return 0;
725
Ido Schimmelc57529e2017-05-26 08:37:31 +0200726 bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp_port->mlxsw_sp->bridge,
727 orig_dev);
Ido Schimmel17b334a2017-08-04 14:12:29 +0200728 if (!bridge_port)
729 return 0;
Ido Schimmelc57529e2017-05-26 08:37:31 +0200730
731 if (!bridge_port->bridge_device->multicast_enabled)
Nogah Frankel4eb6a3b2017-08-22 10:28:11 +0200732 goto out;
Ido Schimmelc57529e2017-05-26 08:37:31 +0200733
Nogah Frankel4eb6a3b2017-08-22 10:28:11 +0200734 err = mlxsw_sp_bridge_port_flood_table_set(mlxsw_sp_port, bridge_port,
735 MLXSW_SP_FLOOD_TYPE_MC,
Nogah Frankeldff37b52017-09-20 16:15:01 +0200736 is_port_mrouter);
Nogah Frankel4eb6a3b2017-08-22 10:28:11 +0200737 if (err)
738 return err;
739
740out:
Nogah Frankeldff37b52017-09-20 16:15:01 +0200741 bridge_port->mrouter = is_port_mrouter;
Nogah Frankel4eb6a3b2017-08-22 10:28:11 +0200742 return 0;
Ido Schimmelc57529e2017-05-26 08:37:31 +0200743}
744
745static int mlxsw_sp_port_mc_disabled_set(struct mlxsw_sp_port *mlxsw_sp_port,
746 struct switchdev_trans *trans,
747 struct net_device *orig_dev,
748 bool mc_disabled)
749{
750 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
751 struct mlxsw_sp_bridge_device *bridge_device;
752 struct mlxsw_sp_bridge_port *bridge_port;
753 int err;
754
755 if (switchdev_trans_ph_prepare(trans))
756 return 0;
757
758 /* It's possible we failed to enslave the port, yet this
759 * operation is executed due to it being deferred.
760 */
761 bridge_device = mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, orig_dev);
762 if (!bridge_device)
763 return 0;
764
Nogah Frankel2e3496c2017-09-20 16:15:09 +0200765 if (bridge_device->multicast_enabled != !mc_disabled) {
766 bridge_device->multicast_enabled = !mc_disabled;
767 mlxsw_sp_bridge_mdb_mc_enable_sync(mlxsw_sp_port,
768 bridge_device);
769 }
770
Ido Schimmelc57529e2017-05-26 08:37:31 +0200771 list_for_each_entry(bridge_port, &bridge_device->ports_list, list) {
Ido Schimmela1107482017-05-26 08:37:39 +0200772 enum mlxsw_sp_flood_type packet_type = MLXSW_SP_FLOOD_TYPE_MC;
Ido Schimmelc57529e2017-05-26 08:37:31 +0200773 bool member = mc_disabled ? true : bridge_port->mrouter;
774
775 err = mlxsw_sp_bridge_port_flood_table_set(mlxsw_sp_port,
Ido Schimmela1107482017-05-26 08:37:39 +0200776 bridge_port,
777 packet_type, member);
Ido Schimmelc57529e2017-05-26 08:37:31 +0200778 if (err)
779 return err;
780 }
781
782 bridge_device->multicast_enabled = !mc_disabled;
Nogah Frankel8ecd4592017-02-09 14:54:47 +0100783
784 return 0;
785}
786
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200787static int mlxsw_sp_port_attr_set(struct net_device *dev,
788 const struct switchdev_attr *attr,
789 struct switchdev_trans *trans)
790{
791 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
Ido Schimmelc57529e2017-05-26 08:37:31 +0200792 int err;
Ido Schimmel54a73202015-12-15 16:03:41 +0100793
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200794 switch (attr->id) {
795 case SWITCHDEV_ATTR_ID_PORT_STP_STATE:
796 err = mlxsw_sp_port_attr_stp_state_set(mlxsw_sp_port, trans,
Ido Schimmelc57529e2017-05-26 08:37:31 +0200797 attr->orig_dev,
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200798 attr->u.stp_state);
799 break;
800 case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:
801 err = mlxsw_sp_port_attr_br_flags_set(mlxsw_sp_port, trans,
Ido Schimmelc57529e2017-05-26 08:37:31 +0200802 attr->orig_dev,
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200803 attr->u.brport_flags);
804 break;
805 case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME:
806 err = mlxsw_sp_port_attr_br_ageing_set(mlxsw_sp_port, trans,
807 attr->u.ageing_time);
808 break;
Elad Raz26a4ea02016-01-06 13:01:10 +0100809 case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING:
810 err = mlxsw_sp_port_attr_br_vlan_set(mlxsw_sp_port, trans,
811 attr->orig_dev,
812 attr->u.vlan_filtering);
813 break;
Nogah Frankel8ecd4592017-02-09 14:54:47 +0100814 case SWITCHDEV_ATTR_ID_PORT_MROUTER:
Nogah Frankeldff37b52017-09-20 16:15:01 +0200815 err = mlxsw_sp_port_attr_mrouter_set(mlxsw_sp_port, trans,
816 attr->orig_dev,
817 attr->u.mrouter);
Nogah Frankel8ecd4592017-02-09 14:54:47 +0100818 break;
Nogah Frankel90e0f0c2017-02-09 14:54:49 +0100819 case SWITCHDEV_ATTR_ID_BRIDGE_MC_DISABLED:
820 err = mlxsw_sp_port_mc_disabled_set(mlxsw_sp_port, trans,
Ido Schimmelc57529e2017-05-26 08:37:31 +0200821 attr->orig_dev,
Nogah Frankel90e0f0c2017-02-09 14:54:49 +0100822 attr->u.mc_disabled);
823 break;
Jiri Pirko56ade8f2015-10-16 14:01:37 +0200824 default:
825 err = -EOPNOTSUPP;
826 break;
827 }
828
829 return err;
830}
831
Ido Schimmelc57529e2017-05-26 08:37:31 +0200832static bool mlxsw_sp_mc_flood(const struct mlxsw_sp_bridge_port *bridge_port)
833{
834 const struct mlxsw_sp_bridge_device *bridge_device;
835
836 bridge_device = bridge_port->bridge_device;
837 return !bridge_device->multicast_enabled ? true : bridge_port->mrouter;
838}
839
Ido Schimmelc57529e2017-05-26 08:37:31 +0200840static int
841mlxsw_sp_port_vlan_fid_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
842 struct mlxsw_sp_bridge_port *bridge_port)
843{
844 struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;
Ido Schimmela1107482017-05-26 08:37:39 +0200845 struct mlxsw_sp_bridge_device *bridge_device;
846 u8 local_port = mlxsw_sp_port->local_port;
Ido Schimmelc57529e2017-05-26 08:37:31 +0200847 u16 vid = mlxsw_sp_port_vlan->vid;
848 struct mlxsw_sp_fid *fid;
849 int err;
850
Ido Schimmela1107482017-05-26 08:37:39 +0200851 bridge_device = bridge_port->bridge_device;
852 fid = bridge_device->ops->fid_get(bridge_device, vid);
Ido Schimmelc57529e2017-05-26 08:37:31 +0200853 if (IS_ERR(fid))
854 return PTR_ERR(fid);
855
Ido Schimmela1107482017-05-26 08:37:39 +0200856 err = mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_UC, local_port,
857 bridge_port->flags & BR_FLOOD);
Ido Schimmelc57529e2017-05-26 08:37:31 +0200858 if (err)
Ido Schimmela1107482017-05-26 08:37:39 +0200859 goto err_fid_uc_flood_set;
Ido Schimmelc57529e2017-05-26 08:37:31 +0200860
Ido Schimmela1107482017-05-26 08:37:39 +0200861 err = mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_MC, local_port,
862 mlxsw_sp_mc_flood(bridge_port));
Ido Schimmelc57529e2017-05-26 08:37:31 +0200863 if (err)
Ido Schimmela1107482017-05-26 08:37:39 +0200864 goto err_fid_mc_flood_set;
Ido Schimmelc57529e2017-05-26 08:37:31 +0200865
Ido Schimmela1107482017-05-26 08:37:39 +0200866 err = mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_BC, local_port,
867 true);
Ido Schimmelc57529e2017-05-26 08:37:31 +0200868 if (err)
Ido Schimmela1107482017-05-26 08:37:39 +0200869 goto err_fid_bc_flood_set;
Ido Schimmelc57529e2017-05-26 08:37:31 +0200870
Ido Schimmela1107482017-05-26 08:37:39 +0200871 err = mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port, vid);
Ido Schimmelc57529e2017-05-26 08:37:31 +0200872 if (err)
Ido Schimmela1107482017-05-26 08:37:39 +0200873 goto err_fid_port_vid_map;
Ido Schimmelc57529e2017-05-26 08:37:31 +0200874
875 mlxsw_sp_port_vlan->fid = fid;
876
877 return 0;
878
Ido Schimmela1107482017-05-26 08:37:39 +0200879err_fid_port_vid_map:
880 mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_BC, local_port, false);
881err_fid_bc_flood_set:
882 mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_MC, local_port, false);
883err_fid_mc_flood_set:
884 mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_UC, local_port, false);
885err_fid_uc_flood_set:
886 mlxsw_sp_fid_put(fid);
Ido Schimmelc57529e2017-05-26 08:37:31 +0200887 return err;
888}
889
890static void
891mlxsw_sp_port_vlan_fid_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
892{
893 struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;
Ido Schimmelc57529e2017-05-26 08:37:31 +0200894 struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
Ido Schimmela1107482017-05-26 08:37:39 +0200895 u8 local_port = mlxsw_sp_port->local_port;
Ido Schimmelc57529e2017-05-26 08:37:31 +0200896 u16 vid = mlxsw_sp_port_vlan->vid;
897
898 mlxsw_sp_port_vlan->fid = NULL;
Ido Schimmela1107482017-05-26 08:37:39 +0200899 mlxsw_sp_fid_port_vid_unmap(fid, mlxsw_sp_port, vid);
900 mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_BC, local_port, false);
901 mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_MC, local_port, false);
902 mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_UC, local_port, false);
903 mlxsw_sp_fid_put(fid);
Ido Schimmel14d39462016-06-20 23:04:15 +0200904}
905
Ido Schimmelfe9ccc72017-05-16 19:38:31 +0200906static u16
907mlxsw_sp_port_pvid_determine(const struct mlxsw_sp_port *mlxsw_sp_port,
908 u16 vid, bool is_pvid)
Ido Schimmel584d73d2016-08-24 12:00:26 +0200909{
Ido Schimmelfe9ccc72017-05-16 19:38:31 +0200910 if (is_pvid)
911 return vid;
912 else if (mlxsw_sp_port->pvid == vid)
913 return 0; /* Dis-allow untagged packets */
914 else
915 return mlxsw_sp_port->pvid;
Ido Schimmel584d73d2016-08-24 12:00:26 +0200916}
917
Ido Schimmelc57529e2017-05-26 08:37:31 +0200918static int
919mlxsw_sp_port_vlan_bridge_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
920 struct mlxsw_sp_bridge_port *bridge_port)
921{
922 struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;
923 struct mlxsw_sp_bridge_vlan *bridge_vlan;
924 u16 vid = mlxsw_sp_port_vlan->vid;
925 int err;
926
927 /* No need to continue if only VLAN flags were changed */
928 if (mlxsw_sp_port_vlan->bridge_port)
929 return 0;
930
931 err = mlxsw_sp_port_vlan_fid_join(mlxsw_sp_port_vlan, bridge_port);
932 if (err)
933 return err;
934
935 err = mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid,
936 bridge_port->flags & BR_LEARNING);
937 if (err)
938 goto err_port_vid_learning_set;
939
940 err = mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, vid,
941 bridge_port->stp_state);
942 if (err)
943 goto err_port_vid_stp_set;
944
945 bridge_vlan = mlxsw_sp_bridge_vlan_get(bridge_port, vid);
946 if (!bridge_vlan) {
947 err = -ENOMEM;
948 goto err_bridge_vlan_get;
949 }
950
951 list_add(&mlxsw_sp_port_vlan->bridge_vlan_node,
952 &bridge_vlan->port_vlan_list);
953
954 mlxsw_sp_bridge_port_get(mlxsw_sp_port->mlxsw_sp->bridge,
955 bridge_port->dev);
956 mlxsw_sp_port_vlan->bridge_port = bridge_port;
957
958 return 0;
959
960err_bridge_vlan_get:
961 mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, vid, BR_STATE_DISABLED);
962err_port_vid_stp_set:
963 mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, false);
964err_port_vid_learning_set:
965 mlxsw_sp_port_vlan_fid_leave(mlxsw_sp_port_vlan);
966 return err;
967}
968
969void
970mlxsw_sp_port_vlan_bridge_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
971{
972 struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;
973 struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
974 struct mlxsw_sp_bridge_vlan *bridge_vlan;
975 struct mlxsw_sp_bridge_port *bridge_port;
976 u16 vid = mlxsw_sp_port_vlan->vid;
977 bool last;
978
Ido Schimmela1107482017-05-26 08:37:39 +0200979 if (WARN_ON(mlxsw_sp_fid_type(fid) != MLXSW_SP_FID_TYPE_8021Q &&
980 mlxsw_sp_fid_type(fid) != MLXSW_SP_FID_TYPE_8021D))
981 return;
982
Ido Schimmelc57529e2017-05-26 08:37:31 +0200983 bridge_port = mlxsw_sp_port_vlan->bridge_port;
984 bridge_vlan = mlxsw_sp_bridge_vlan_find(bridge_port, vid);
985 last = list_is_singular(&bridge_vlan->port_vlan_list);
986
987 list_del(&mlxsw_sp_port_vlan->bridge_vlan_node);
988 mlxsw_sp_bridge_vlan_put(bridge_vlan);
989 mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, vid, BR_STATE_DISABLED);
990 mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, false);
991 if (last)
992 mlxsw_sp_bridge_port_fdb_flush(mlxsw_sp_port->mlxsw_sp,
Ido Schimmela1107482017-05-26 08:37:39 +0200993 bridge_port,
994 mlxsw_sp_fid_index(fid));
Ido Schimmelc57529e2017-05-26 08:37:31 +0200995 mlxsw_sp_port_vlan_fid_leave(mlxsw_sp_port_vlan);
996
997 mlxsw_sp_bridge_port_put(mlxsw_sp_port->mlxsw_sp->bridge, bridge_port);
998 mlxsw_sp_port_vlan->bridge_port = NULL;
999}
1000
1001static int
1002mlxsw_sp_bridge_port_vlan_add(struct mlxsw_sp_port *mlxsw_sp_port,
1003 struct mlxsw_sp_bridge_port *bridge_port,
1004 u16 vid, bool is_untagged, bool is_pvid)
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001005{
Ido Schimmelfe9ccc72017-05-16 19:38:31 +02001006 u16 pvid = mlxsw_sp_port_pvid_determine(mlxsw_sp_port, vid, is_pvid);
Ido Schimmelc57529e2017-05-26 08:37:31 +02001007 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
Ido Schimmelfe9ccc72017-05-16 19:38:31 +02001008 u16 old_pvid = mlxsw_sp_port->pvid;
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001009 int err;
1010
Ido Schimmelc57529e2017-05-26 08:37:31 +02001011 mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_get(mlxsw_sp_port, vid);
1012 if (IS_ERR(mlxsw_sp_port_vlan))
1013 return PTR_ERR(mlxsw_sp_port_vlan);
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001014
Ido Schimmelfe9ccc72017-05-16 19:38:31 +02001015 err = mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, true,
1016 is_untagged);
1017 if (err)
1018 goto err_port_vlan_set;
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001019
Ido Schimmelfe9ccc72017-05-16 19:38:31 +02001020 err = mlxsw_sp_port_pvid_set(mlxsw_sp_port, pvid);
1021 if (err)
1022 goto err_port_pvid_set;
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001023
Ido Schimmelc57529e2017-05-26 08:37:31 +02001024 err = mlxsw_sp_port_vlan_bridge_join(mlxsw_sp_port_vlan, bridge_port);
Ido Schimmelfe9ccc72017-05-16 19:38:31 +02001025 if (err)
Ido Schimmelc57529e2017-05-26 08:37:31 +02001026 goto err_port_vlan_bridge_join;
Ido Schimmel584d73d2016-08-24 12:00:26 +02001027
Ido Schimmelb07a9662015-11-19 12:27:40 +01001028 return 0;
1029
Ido Schimmelc57529e2017-05-26 08:37:31 +02001030err_port_vlan_bridge_join:
Ido Schimmelfe9ccc72017-05-16 19:38:31 +02001031 mlxsw_sp_port_pvid_set(mlxsw_sp_port, old_pvid);
Ido Schimmelb07a9662015-11-19 12:27:40 +01001032err_port_pvid_set:
Ido Schimmelfe9ccc72017-05-16 19:38:31 +02001033 mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, false, false);
1034err_port_vlan_set:
Ido Schimmelc57529e2017-05-26 08:37:31 +02001035 mlxsw_sp_port_vlan_put(mlxsw_sp_port_vlan);
Ido Schimmelb07a9662015-11-19 12:27:40 +01001036 return err;
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001037}
1038
1039static int mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port,
1040 const struct switchdev_obj_port_vlan *vlan,
1041 struct switchdev_trans *trans)
1042{
Elad Raze4a13052016-01-06 13:01:09 +01001043 bool flag_untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
1044 bool flag_pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
Ido Schimmelc57529e2017-05-26 08:37:31 +02001045 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1046 struct net_device *orig_dev = vlan->obj.orig_dev;
1047 struct mlxsw_sp_bridge_port *bridge_port;
Ido Schimmelfe9ccc72017-05-16 19:38:31 +02001048 u16 vid;
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001049
1050 if (switchdev_trans_ph_prepare(trans))
1051 return 0;
1052
Ido Schimmelc57529e2017-05-26 08:37:31 +02001053 bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp->bridge, orig_dev);
1054 if (WARN_ON(!bridge_port))
1055 return -EINVAL;
1056
1057 if (!bridge_port->bridge_device->vlan_enabled)
1058 return 0;
1059
Ido Schimmelfe9ccc72017-05-16 19:38:31 +02001060 for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) {
1061 int err;
1062
Ido Schimmelc57529e2017-05-26 08:37:31 +02001063 err = mlxsw_sp_bridge_port_vlan_add(mlxsw_sp_port, bridge_port,
1064 vid, flag_untagged,
1065 flag_pvid);
Ido Schimmelfe9ccc72017-05-16 19:38:31 +02001066 if (err)
1067 return err;
1068 }
1069
1070 return 0;
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001071}
1072
Ido Schimmelc57529e2017-05-26 08:37:31 +02001073static enum mlxsw_reg_sfdf_flush_type mlxsw_sp_fdb_flush_type(bool lagged)
1074{
1075 return lagged ? MLXSW_REG_SFDF_FLUSH_PER_LAG_AND_FID :
1076 MLXSW_REG_SFDF_FLUSH_PER_PORT_AND_FID;
1077}
1078
1079static int
1080mlxsw_sp_bridge_port_fdb_flush(struct mlxsw_sp *mlxsw_sp,
1081 struct mlxsw_sp_bridge_port *bridge_port,
1082 u16 fid_index)
1083{
1084 bool lagged = bridge_port->lagged;
1085 char sfdf_pl[MLXSW_REG_SFDF_LEN];
1086 u16 system_port;
1087
1088 system_port = lagged ? bridge_port->lag_id : bridge_port->system_port;
1089 mlxsw_reg_sfdf_pack(sfdf_pl, mlxsw_sp_fdb_flush_type(lagged));
1090 mlxsw_reg_sfdf_fid_set(sfdf_pl, fid_index);
1091 mlxsw_reg_sfdf_port_fid_system_port_set(sfdf_pl, system_port);
1092
1093 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfdf), sfdf_pl);
1094}
1095
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01001096static enum mlxsw_reg_sfd_rec_policy mlxsw_sp_sfd_rec_policy(bool dynamic)
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001097{
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01001098 return dynamic ? MLXSW_REG_SFD_REC_POLICY_DYNAMIC_ENTRY_INGRESS :
1099 MLXSW_REG_SFD_REC_POLICY_STATIC_ENTRY;
1100}
1101
1102static enum mlxsw_reg_sfd_op mlxsw_sp_sfd_op(bool adding)
1103{
1104 return adding ? MLXSW_REG_SFD_OP_WRITE_EDIT :
1105 MLXSW_REG_SFD_OP_WRITE_REMOVE;
1106}
1107
Ido Schimmel6e095fd2016-07-04 08:23:13 +02001108static int __mlxsw_sp_port_fdb_uc_op(struct mlxsw_sp *mlxsw_sp, u8 local_port,
1109 const char *mac, u16 fid, bool adding,
1110 enum mlxsw_reg_sfd_rec_action action,
1111 bool dynamic)
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01001112{
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001113 char *sfd_pl;
1114 int err;
1115
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001116 sfd_pl = kmalloc(MLXSW_REG_SFD_LEN, GFP_KERNEL);
1117 if (!sfd_pl)
1118 return -ENOMEM;
1119
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01001120 mlxsw_reg_sfd_pack(sfd_pl, mlxsw_sp_sfd_op(adding), 0);
1121 mlxsw_reg_sfd_uc_pack(sfd_pl, 0, mlxsw_sp_sfd_rec_policy(dynamic),
Ido Schimmel6e095fd2016-07-04 08:23:13 +02001122 mac, fid, action, local_port);
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01001123 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfd), sfd_pl);
1124 kfree(sfd_pl);
1125
1126 return err;
1127}
1128
Ido Schimmel6e095fd2016-07-04 08:23:13 +02001129static int mlxsw_sp_port_fdb_uc_op(struct mlxsw_sp *mlxsw_sp, u8 local_port,
1130 const char *mac, u16 fid, bool adding,
1131 bool dynamic)
1132{
1133 return __mlxsw_sp_port_fdb_uc_op(mlxsw_sp, local_port, mac, fid, adding,
1134 MLXSW_REG_SFD_REC_ACTION_NOP, dynamic);
1135}
1136
1137int mlxsw_sp_rif_fdb_op(struct mlxsw_sp *mlxsw_sp, const char *mac, u16 fid,
1138 bool adding)
1139{
1140 return __mlxsw_sp_port_fdb_uc_op(mlxsw_sp, 0, mac, fid, adding,
1141 MLXSW_REG_SFD_REC_ACTION_FORWARD_IP_ROUTER,
1142 false);
1143}
1144
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01001145static int mlxsw_sp_port_fdb_uc_lag_op(struct mlxsw_sp *mlxsw_sp, u16 lag_id,
Ido Schimmel64771e32015-12-15 16:03:46 +01001146 const char *mac, u16 fid, u16 lag_vid,
1147 bool adding, bool dynamic)
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01001148{
1149 char *sfd_pl;
1150 int err;
1151
1152 sfd_pl = kmalloc(MLXSW_REG_SFD_LEN, GFP_KERNEL);
1153 if (!sfd_pl)
1154 return -ENOMEM;
1155
1156 mlxsw_reg_sfd_pack(sfd_pl, mlxsw_sp_sfd_op(adding), 0);
1157 mlxsw_reg_sfd_uc_lag_pack(sfd_pl, 0, mlxsw_sp_sfd_rec_policy(dynamic),
Ido Schimmel64771e32015-12-15 16:03:46 +01001158 mac, fid, MLXSW_REG_SFD_REC_ACTION_NOP,
1159 lag_vid, lag_id);
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01001160 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfd), sfd_pl);
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001161 kfree(sfd_pl);
1162
1163 return err;
1164}
1165
1166static int
Arkadi Sharshevskyaf0613782017-06-08 08:44:20 +02001167mlxsw_sp_port_fdb_set(struct mlxsw_sp_port *mlxsw_sp_port,
1168 struct switchdev_notifier_fdb_info *fdb_info, bool adding)
1169{
1170 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1171 struct net_device *orig_dev = fdb_info->info.dev;
1172 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
1173 struct mlxsw_sp_bridge_device *bridge_device;
1174 struct mlxsw_sp_bridge_port *bridge_port;
1175 u16 fid_index, vid;
1176
1177 bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp->bridge, orig_dev);
1178 if (!bridge_port)
1179 return -EINVAL;
1180
1181 bridge_device = bridge_port->bridge_device;
1182 mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_bridge(mlxsw_sp_port,
1183 bridge_device,
1184 fdb_info->vid);
1185 if (!mlxsw_sp_port_vlan)
1186 return 0;
1187
1188 fid_index = mlxsw_sp_fid_index(mlxsw_sp_port_vlan->fid);
1189 vid = mlxsw_sp_port_vlan->vid;
1190
1191 if (!bridge_port->lagged)
1192 return mlxsw_sp_port_fdb_uc_op(mlxsw_sp,
1193 bridge_port->system_port,
1194 fdb_info->addr, fid_index,
1195 adding, false);
1196 else
1197 return mlxsw_sp_port_fdb_uc_lag_op(mlxsw_sp,
1198 bridge_port->lag_id,
1199 fdb_info->addr, fid_index,
1200 vid, adding, false);
1201}
1202
Elad Raz3a49b4f2016-01-10 21:06:28 +01001203static int mlxsw_sp_port_mdb_op(struct mlxsw_sp *mlxsw_sp, const char *addr,
Nogah Frankel5f9abc52017-09-20 16:15:05 +02001204 u16 fid, u16 mid_idx, bool adding)
Elad Raz3a49b4f2016-01-10 21:06:28 +01001205{
1206 char *sfd_pl;
1207 int err;
1208
1209 sfd_pl = kmalloc(MLXSW_REG_SFD_LEN, GFP_KERNEL);
1210 if (!sfd_pl)
1211 return -ENOMEM;
1212
1213 mlxsw_reg_sfd_pack(sfd_pl, mlxsw_sp_sfd_op(adding), 0);
1214 mlxsw_reg_sfd_mc_pack(sfd_pl, 0, addr, fid,
Nogah Frankel5f9abc52017-09-20 16:15:05 +02001215 MLXSW_REG_SFD_REC_ACTION_NOP, mid_idx);
Elad Raz3a49b4f2016-01-10 21:06:28 +01001216 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfd), sfd_pl);
1217 kfree(sfd_pl);
1218 return err;
1219}
1220
Nogah Frankel2e3496c2017-09-20 16:15:09 +02001221static int mlxsw_sp_port_smid_full_entry(struct mlxsw_sp *mlxsw_sp, u16 mid_idx,
1222 long *ports_bitmap)
Elad Raz3a49b4f2016-01-10 21:06:28 +01001223{
Elad Raz3a49b4f2016-01-10 21:06:28 +01001224 char *smid_pl;
1225 int err, i;
1226
1227 smid_pl = kmalloc(MLXSW_REG_SMID_LEN, GFP_KERNEL);
1228 if (!smid_pl)
1229 return -ENOMEM;
1230
Nogah Frankel5f9abc52017-09-20 16:15:05 +02001231 mlxsw_reg_smid_pack(smid_pl, mid_idx, 0, false);
1232 for (i = 1; i < mlxsw_core_max_ports(mlxsw_sp->core); i++) {
1233 if (mlxsw_sp->ports[i])
1234 mlxsw_reg_smid_port_mask_set(smid_pl, i, 1);
Elad Raz3a49b4f2016-01-10 21:06:28 +01001235 }
Nogah Frankel5f9abc52017-09-20 16:15:05 +02001236
Nogah Frankel2e3496c2017-09-20 16:15:09 +02001237 for_each_set_bit(i, ports_bitmap, mlxsw_core_max_ports(mlxsw_sp->core))
1238 mlxsw_reg_smid_port_set(smid_pl, i, 1);
1239
Nogah Frankel5f9abc52017-09-20 16:15:05 +02001240 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(smid), smid_pl);
1241 kfree(smid_pl);
1242 return err;
1243}
1244
1245static int mlxsw_sp_port_smid_set(struct mlxsw_sp_port *mlxsw_sp_port,
1246 u16 mid_idx, bool add)
1247{
1248 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1249 char *smid_pl;
1250 int err;
1251
1252 smid_pl = kmalloc(MLXSW_REG_SMID_LEN, GFP_KERNEL);
1253 if (!smid_pl)
1254 return -ENOMEM;
1255
1256 mlxsw_reg_smid_pack(smid_pl, mid_idx, mlxsw_sp_port->local_port, add);
Elad Raz3a49b4f2016-01-10 21:06:28 +01001257 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(smid), smid_pl);
1258 kfree(smid_pl);
1259 return err;
1260}
1261
Nogah Frankelb80888a2017-09-20 16:15:04 +02001262static struct
1263mlxsw_sp_mid *__mlxsw_sp_mc_get(struct mlxsw_sp_bridge_device *bridge_device,
1264 const unsigned char *addr,
1265 u16 fid)
Elad Raz3a49b4f2016-01-10 21:06:28 +01001266{
1267 struct mlxsw_sp_mid *mid;
1268
Nogah Frankelb80888a2017-09-20 16:15:04 +02001269 list_for_each_entry(mid, &bridge_device->mids_list, list) {
Ido Schimmel46d08472016-10-30 10:09:22 +01001270 if (ether_addr_equal(mid->addr, addr) && mid->fid == fid)
Elad Raz3a49b4f2016-01-10 21:06:28 +01001271 return mid;
1272 }
1273 return NULL;
1274}
1275
Nogah Frankel73b433e2017-09-20 16:15:06 +02001276static bool
1277mlxsw_sp_mc_write_mdb_entry(struct mlxsw_sp *mlxsw_sp,
1278 struct mlxsw_sp_mid *mid)
1279{
1280 u16 mid_idx;
1281 int err;
1282
1283 mid_idx = find_first_zero_bit(mlxsw_sp->bridge->mids_bitmap,
1284 MLXSW_SP_MID_MAX);
1285 if (mid_idx == MLXSW_SP_MID_MAX)
1286 return false;
1287
1288 mid->mid = mid_idx;
Nogah Frankel2e3496c2017-09-20 16:15:09 +02001289 err = mlxsw_sp_port_smid_full_entry(mlxsw_sp, mid_idx,
1290 mid->ports_in_mid);
Nogah Frankel73b433e2017-09-20 16:15:06 +02001291 if (err)
1292 return false;
1293
1294 err = mlxsw_sp_port_mdb_op(mlxsw_sp, mid->addr, mid->fid, mid_idx,
1295 true);
1296 if (err)
1297 return false;
1298
1299 set_bit(mid_idx, mlxsw_sp->bridge->mids_bitmap);
1300 mid->in_hw = true;
1301 return true;
1302}
1303
1304static int mlxsw_sp_mc_remove_mdb_entry(struct mlxsw_sp *mlxsw_sp,
1305 struct mlxsw_sp_mid *mid)
1306{
Nogah Frankel846fd8a2017-09-20 16:15:08 +02001307 if (!mid->in_hw)
1308 return 0;
1309
Nogah Frankel73b433e2017-09-20 16:15:06 +02001310 clear_bit(mid->mid, mlxsw_sp->bridge->mids_bitmap);
1311 mid->in_hw = false;
1312 return mlxsw_sp_port_mdb_op(mlxsw_sp, mid->addr, mid->fid, mid->mid,
1313 false);
1314}
1315
Nogah Frankelb80888a2017-09-20 16:15:04 +02001316static struct
1317mlxsw_sp_mid *__mlxsw_sp_mc_alloc(struct mlxsw_sp *mlxsw_sp,
1318 struct mlxsw_sp_bridge_device *bridge_device,
1319 const unsigned char *addr,
1320 u16 fid)
Elad Raz3a49b4f2016-01-10 21:06:28 +01001321{
1322 struct mlxsw_sp_mid *mid;
Nogah Frankel4cdc35e2017-09-20 16:15:02 +02001323 size_t alloc_size;
Elad Raz3a49b4f2016-01-10 21:06:28 +01001324
1325 mid = kzalloc(sizeof(*mid), GFP_KERNEL);
1326 if (!mid)
1327 return NULL;
1328
Nogah Frankel4cdc35e2017-09-20 16:15:02 +02001329 alloc_size = sizeof(unsigned long) *
1330 BITS_TO_LONGS(mlxsw_core_max_ports(mlxsw_sp->core));
Nogah Frankel4cdc35e2017-09-20 16:15:02 +02001331
Nogah Frankel73b433e2017-09-20 16:15:06 +02001332 mid->ports_in_mid = kzalloc(alloc_size, GFP_KERNEL);
1333 if (!mid->ports_in_mid)
1334 goto err_ports_in_mid_alloc;
1335
Elad Raz3a49b4f2016-01-10 21:06:28 +01001336 ether_addr_copy(mid->addr, addr);
Ido Schimmel46d08472016-10-30 10:09:22 +01001337 mid->fid = fid;
Nogah Frankel73b433e2017-09-20 16:15:06 +02001338 mid->in_hw = false;
Nogah Frankel846fd8a2017-09-20 16:15:08 +02001339
1340 if (!bridge_device->multicast_enabled)
1341 goto out;
1342
Nogah Frankel73b433e2017-09-20 16:15:06 +02001343 if (!mlxsw_sp_mc_write_mdb_entry(mlxsw_sp, mid))
1344 goto err_write_mdb_entry;
1345
Nogah Frankel846fd8a2017-09-20 16:15:08 +02001346out:
Nogah Frankelb80888a2017-09-20 16:15:04 +02001347 list_add_tail(&mid->list, &bridge_device->mids_list);
Elad Raz3a49b4f2016-01-10 21:06:28 +01001348 return mid;
Nogah Frankel73b433e2017-09-20 16:15:06 +02001349
1350err_write_mdb_entry:
1351 kfree(mid->ports_in_mid);
1352err_ports_in_mid_alloc:
1353 kfree(mid);
1354 return NULL;
Elad Raz3a49b4f2016-01-10 21:06:28 +01001355}
1356
Nogah Frankel0161b952017-09-20 16:15:03 +02001357static int mlxsw_sp_port_remove_from_mid(struct mlxsw_sp_port *mlxsw_sp_port,
1358 struct mlxsw_sp_mid *mid)
Elad Raz3a49b4f2016-01-10 21:06:28 +01001359{
Nogah Frankel4cdc35e2017-09-20 16:15:02 +02001360 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
Nogah Frankel73b433e2017-09-20 16:15:06 +02001361 int err = 0;
Nogah Frankel4cdc35e2017-09-20 16:15:02 +02001362
1363 clear_bit(mlxsw_sp_port->local_port, mid->ports_in_mid);
Nogah Frankel0161b952017-09-20 16:15:03 +02001364 if (bitmap_empty(mid->ports_in_mid,
1365 mlxsw_core_max_ports(mlxsw_sp->core))) {
Nogah Frankel73b433e2017-09-20 16:15:06 +02001366 err = mlxsw_sp_mc_remove_mdb_entry(mlxsw_sp, mid);
Elad Raz3a49b4f2016-01-10 21:06:28 +01001367 list_del(&mid->list);
Nogah Frankel4cdc35e2017-09-20 16:15:02 +02001368 kfree(mid->ports_in_mid);
Elad Raz3a49b4f2016-01-10 21:06:28 +01001369 kfree(mid);
Elad Raz3a49b4f2016-01-10 21:06:28 +01001370 }
Nogah Frankel73b433e2017-09-20 16:15:06 +02001371 return err;
Elad Raz3a49b4f2016-01-10 21:06:28 +01001372}
1373
1374static int mlxsw_sp_port_mdb_add(struct mlxsw_sp_port *mlxsw_sp_port,
1375 const struct switchdev_obj_port_mdb *mdb,
1376 struct switchdev_trans *trans)
1377{
1378 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
Ido Schimmelc57529e2017-05-26 08:37:31 +02001379 struct net_device *orig_dev = mdb->obj.orig_dev;
1380 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
Elad Raz3a49b4f2016-01-10 21:06:28 +01001381 struct net_device *dev = mlxsw_sp_port->dev;
Ido Schimmelc57529e2017-05-26 08:37:31 +02001382 struct mlxsw_sp_bridge_device *bridge_device;
1383 struct mlxsw_sp_bridge_port *bridge_port;
Elad Raz3a49b4f2016-01-10 21:06:28 +01001384 struct mlxsw_sp_mid *mid;
Ido Schimmelc57529e2017-05-26 08:37:31 +02001385 u16 fid_index;
Elad Raz3a49b4f2016-01-10 21:06:28 +01001386 int err = 0;
1387
1388 if (switchdev_trans_ph_prepare(trans))
1389 return 0;
1390
Ido Schimmelc57529e2017-05-26 08:37:31 +02001391 bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp->bridge, orig_dev);
Ido Schimmel17b334a2017-08-04 14:12:29 +02001392 if (!bridge_port)
1393 return 0;
Ido Schimmelc57529e2017-05-26 08:37:31 +02001394
1395 bridge_device = bridge_port->bridge_device;
1396 mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_bridge(mlxsw_sp_port,
1397 bridge_device,
1398 mdb->vid);
Ido Schimmel17b334a2017-08-04 14:12:29 +02001399 if (!mlxsw_sp_port_vlan)
1400 return 0;
Ido Schimmelc57529e2017-05-26 08:37:31 +02001401
Ido Schimmela1107482017-05-26 08:37:39 +02001402 fid_index = mlxsw_sp_fid_index(mlxsw_sp_port_vlan->fid);
Ido Schimmelc57529e2017-05-26 08:37:31 +02001403
Nogah Frankelb80888a2017-09-20 16:15:04 +02001404 mid = __mlxsw_sp_mc_get(bridge_device, mdb->addr, fid_index);
Elad Raz3a49b4f2016-01-10 21:06:28 +01001405 if (!mid) {
Nogah Frankelb80888a2017-09-20 16:15:04 +02001406 mid = __mlxsw_sp_mc_alloc(mlxsw_sp, bridge_device, mdb->addr,
1407 fid_index);
Elad Raz3a49b4f2016-01-10 21:06:28 +01001408 if (!mid) {
1409 netdev_err(dev, "Unable to allocate MC group\n");
1410 return -ENOMEM;
1411 }
1412 }
Nogah Frankel4cdc35e2017-09-20 16:15:02 +02001413 set_bit(mlxsw_sp_port->local_port, mid->ports_in_mid);
Elad Raz3a49b4f2016-01-10 21:06:28 +01001414
Nogah Frankel846fd8a2017-09-20 16:15:08 +02001415 if (!bridge_device->multicast_enabled)
1416 return 0;
1417
Nogah Frankel5f9abc52017-09-20 16:15:05 +02001418 err = mlxsw_sp_port_smid_set(mlxsw_sp_port, mid->mid, true);
Elad Raz3a49b4f2016-01-10 21:06:28 +01001419 if (err) {
1420 netdev_err(dev, "Unable to set SMID\n");
1421 goto err_out;
1422 }
1423
Elad Raz3a49b4f2016-01-10 21:06:28 +01001424 return 0;
1425
1426err_out:
Nogah Frankel0161b952017-09-20 16:15:03 +02001427 mlxsw_sp_port_remove_from_mid(mlxsw_sp_port, mid);
Elad Raz3a49b4f2016-01-10 21:06:28 +01001428 return err;
1429}
1430
Nogah Frankel2e3496c2017-09-20 16:15:09 +02001431static void
1432mlxsw_sp_bridge_mdb_mc_enable_sync(struct mlxsw_sp_port *mlxsw_sp_port,
1433 struct mlxsw_sp_bridge_device
1434 *bridge_device)
1435{
1436 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1437 struct mlxsw_sp_mid *mid;
1438 bool mc_enabled;
1439
1440 mc_enabled = bridge_device->multicast_enabled;
1441
1442 list_for_each_entry(mid, &bridge_device->mids_list, list) {
1443 if (mc_enabled)
1444 mlxsw_sp_mc_write_mdb_entry(mlxsw_sp, mid);
1445 else
1446 mlxsw_sp_mc_remove_mdb_entry(mlxsw_sp, mid);
1447 }
1448}
1449
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001450static int mlxsw_sp_port_obj_add(struct net_device *dev,
1451 const struct switchdev_obj *obj,
1452 struct switchdev_trans *trans)
1453{
1454 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
1455 int err = 0;
1456
1457 switch (obj->id) {
1458 case SWITCHDEV_OBJ_ID_PORT_VLAN:
1459 err = mlxsw_sp_port_vlans_add(mlxsw_sp_port,
1460 SWITCHDEV_OBJ_PORT_VLAN(obj),
1461 trans);
1462 break;
Elad Raz3a49b4f2016-01-10 21:06:28 +01001463 case SWITCHDEV_OBJ_ID_PORT_MDB:
1464 err = mlxsw_sp_port_mdb_add(mlxsw_sp_port,
1465 SWITCHDEV_OBJ_PORT_MDB(obj),
1466 trans);
1467 break;
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001468 default:
1469 err = -EOPNOTSUPP;
1470 break;
1471 }
1472
1473 return err;
1474}
1475
Ido Schimmelc57529e2017-05-26 08:37:31 +02001476static void
1477mlxsw_sp_bridge_port_vlan_del(struct mlxsw_sp_port *mlxsw_sp_port,
1478 struct mlxsw_sp_bridge_port *bridge_port, u16 vid)
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001479{
Ido Schimmelfe9ccc72017-05-16 19:38:31 +02001480 u16 pvid = mlxsw_sp_port->pvid == vid ? 0 : vid;
Ido Schimmelc57529e2017-05-26 08:37:31 +02001481 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001482
Ido Schimmelc57529e2017-05-26 08:37:31 +02001483 mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid);
1484 if (WARN_ON(!mlxsw_sp_port_vlan))
1485 return;
1486
1487 mlxsw_sp_port_vlan_bridge_leave(mlxsw_sp_port_vlan);
Ido Schimmelfe9ccc72017-05-16 19:38:31 +02001488 mlxsw_sp_port_pvid_set(mlxsw_sp_port, pvid);
1489 mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, false, false);
Ido Schimmelc57529e2017-05-26 08:37:31 +02001490 mlxsw_sp_port_vlan_put(mlxsw_sp_port_vlan);
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001491}
1492
1493static int mlxsw_sp_port_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port,
1494 const struct switchdev_obj_port_vlan *vlan)
1495{
Ido Schimmelc57529e2017-05-26 08:37:31 +02001496 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1497 struct net_device *orig_dev = vlan->obj.orig_dev;
1498 struct mlxsw_sp_bridge_port *bridge_port;
Ido Schimmelfe9ccc72017-05-16 19:38:31 +02001499 u16 vid;
1500
Ido Schimmelc57529e2017-05-26 08:37:31 +02001501 bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp->bridge, orig_dev);
1502 if (WARN_ON(!bridge_port))
1503 return -EINVAL;
1504
1505 if (!bridge_port->bridge_device->vlan_enabled)
1506 return 0;
1507
Ido Schimmelfe9ccc72017-05-16 19:38:31 +02001508 for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++)
Ido Schimmelc57529e2017-05-26 08:37:31 +02001509 mlxsw_sp_bridge_port_vlan_del(mlxsw_sp_port, bridge_port, vid);
Ido Schimmelfe9ccc72017-05-16 19:38:31 +02001510
1511 return 0;
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001512}
1513
Nogah Frankel061e55b2017-09-20 16:15:07 +02001514static int
1515__mlxsw_sp_port_mdb_del(struct mlxsw_sp_port *mlxsw_sp_port,
1516 struct mlxsw_sp_bridge_port *bridge_port,
1517 struct mlxsw_sp_mid *mid)
1518{
1519 struct net_device *dev = mlxsw_sp_port->dev;
1520 int err;
1521
Nogah Frankel846fd8a2017-09-20 16:15:08 +02001522 if (bridge_port->bridge_device->multicast_enabled) {
1523 err = mlxsw_sp_port_smid_set(mlxsw_sp_port, mid->mid, false);
1524
1525 if (err)
1526 netdev_err(dev, "Unable to remove port from SMID\n");
1527 }
Nogah Frankel061e55b2017-09-20 16:15:07 +02001528
1529 err = mlxsw_sp_port_remove_from_mid(mlxsw_sp_port, mid);
1530 if (err)
1531 netdev_err(dev, "Unable to remove MC SFD\n");
1532
1533 return err;
1534}
1535
Elad Raz3a49b4f2016-01-10 21:06:28 +01001536static int mlxsw_sp_port_mdb_del(struct mlxsw_sp_port *mlxsw_sp_port,
1537 const struct switchdev_obj_port_mdb *mdb)
1538{
1539 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
Ido Schimmelc57529e2017-05-26 08:37:31 +02001540 struct net_device *orig_dev = mdb->obj.orig_dev;
1541 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
1542 struct mlxsw_sp_bridge_device *bridge_device;
Elad Raz3a49b4f2016-01-10 21:06:28 +01001543 struct net_device *dev = mlxsw_sp_port->dev;
Ido Schimmelc57529e2017-05-26 08:37:31 +02001544 struct mlxsw_sp_bridge_port *bridge_port;
Elad Raz3a49b4f2016-01-10 21:06:28 +01001545 struct mlxsw_sp_mid *mid;
Ido Schimmelc57529e2017-05-26 08:37:31 +02001546 u16 fid_index;
Elad Raz3a49b4f2016-01-10 21:06:28 +01001547
Ido Schimmelc57529e2017-05-26 08:37:31 +02001548 bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp->bridge, orig_dev);
Ido Schimmel17b334a2017-08-04 14:12:29 +02001549 if (!bridge_port)
1550 return 0;
Ido Schimmelc57529e2017-05-26 08:37:31 +02001551
1552 bridge_device = bridge_port->bridge_device;
1553 mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_bridge(mlxsw_sp_port,
1554 bridge_device,
1555 mdb->vid);
Ido Schimmel17b334a2017-08-04 14:12:29 +02001556 if (!mlxsw_sp_port_vlan)
1557 return 0;
Ido Schimmelc57529e2017-05-26 08:37:31 +02001558
Ido Schimmela1107482017-05-26 08:37:39 +02001559 fid_index = mlxsw_sp_fid_index(mlxsw_sp_port_vlan->fid);
Ido Schimmelc57529e2017-05-26 08:37:31 +02001560
Nogah Frankelb80888a2017-09-20 16:15:04 +02001561 mid = __mlxsw_sp_mc_get(bridge_device, mdb->addr, fid_index);
Elad Raz3a49b4f2016-01-10 21:06:28 +01001562 if (!mid) {
1563 netdev_err(dev, "Unable to remove port from MC DB\n");
1564 return -EINVAL;
1565 }
1566
Nogah Frankel061e55b2017-09-20 16:15:07 +02001567 return __mlxsw_sp_port_mdb_del(mlxsw_sp_port, bridge_port, mid);
Elad Raz3a49b4f2016-01-10 21:06:28 +01001568}
1569
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001570static int mlxsw_sp_port_obj_del(struct net_device *dev,
1571 const struct switchdev_obj *obj)
1572{
1573 struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
1574 int err = 0;
1575
1576 switch (obj->id) {
1577 case SWITCHDEV_OBJ_ID_PORT_VLAN:
1578 err = mlxsw_sp_port_vlans_del(mlxsw_sp_port,
1579 SWITCHDEV_OBJ_PORT_VLAN(obj));
1580 break;
Elad Raz3a49b4f2016-01-10 21:06:28 +01001581 case SWITCHDEV_OBJ_ID_PORT_MDB:
1582 err = mlxsw_sp_port_mdb_del(mlxsw_sp_port,
1583 SWITCHDEV_OBJ_PORT_MDB(obj));
Dan Carpenter00ae40e2016-01-13 15:28:23 +03001584 break;
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001585 default:
1586 err = -EOPNOTSUPP;
1587 break;
1588 }
1589
1590 return err;
1591}
1592
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01001593static struct mlxsw_sp_port *mlxsw_sp_lag_rep_port(struct mlxsw_sp *mlxsw_sp,
1594 u16 lag_id)
1595{
1596 struct mlxsw_sp_port *mlxsw_sp_port;
Jiri Pirkoc1a38312016-10-21 16:07:23 +02001597 u64 max_lag_members;
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01001598 int i;
1599
Jiri Pirkoc1a38312016-10-21 16:07:23 +02001600 max_lag_members = MLXSW_CORE_RES_GET(mlxsw_sp->core,
1601 MAX_LAG_MEMBERS);
1602 for (i = 0; i < max_lag_members; i++) {
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01001603 mlxsw_sp_port = mlxsw_sp_port_lagged_get(mlxsw_sp, lag_id, i);
1604 if (mlxsw_sp_port)
1605 return mlxsw_sp_port;
1606 }
1607 return NULL;
1608}
1609
Jiri Pirkoc7070fc2015-10-28 10:17:05 +01001610static const struct switchdev_ops mlxsw_sp_port_switchdev_ops = {
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001611 .switchdev_port_attr_get = mlxsw_sp_port_attr_get,
1612 .switchdev_port_attr_set = mlxsw_sp_port_attr_set,
1613 .switchdev_port_obj_add = mlxsw_sp_port_obj_add,
1614 .switchdev_port_obj_del = mlxsw_sp_port_obj_del,
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001615};
1616
Ido Schimmelc57529e2017-05-26 08:37:31 +02001617static int
1618mlxsw_sp_bridge_8021q_port_join(struct mlxsw_sp_bridge_device *bridge_device,
1619 struct mlxsw_sp_bridge_port *bridge_port,
1620 struct mlxsw_sp_port *mlxsw_sp_port)
1621{
1622 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
1623
1624 if (is_vlan_dev(bridge_port->dev))
1625 return -EINVAL;
1626
1627 mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, 1);
1628 if (WARN_ON(!mlxsw_sp_port_vlan))
1629 return -EINVAL;
1630
1631 /* Let VLAN-aware bridge take care of its own VLANs */
1632 mlxsw_sp_port_vlan_put(mlxsw_sp_port_vlan);
1633
1634 return 0;
1635}
1636
1637static void
1638mlxsw_sp_bridge_8021q_port_leave(struct mlxsw_sp_bridge_device *bridge_device,
1639 struct mlxsw_sp_bridge_port *bridge_port,
1640 struct mlxsw_sp_port *mlxsw_sp_port)
1641{
1642 mlxsw_sp_port_vlan_get(mlxsw_sp_port, 1);
1643 /* Make sure untagged frames are allowed to ingress */
1644 mlxsw_sp_port_pvid_set(mlxsw_sp_port, 1);
1645}
1646
Ido Schimmela1107482017-05-26 08:37:39 +02001647static struct mlxsw_sp_fid *
1648mlxsw_sp_bridge_8021q_fid_get(struct mlxsw_sp_bridge_device *bridge_device,
1649 u16 vid)
1650{
1651 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(bridge_device->dev);
1652
1653 return mlxsw_sp_fid_8021q_get(mlxsw_sp, vid);
1654}
1655
Ido Schimmelc57529e2017-05-26 08:37:31 +02001656static const struct mlxsw_sp_bridge_ops mlxsw_sp_bridge_8021q_ops = {
1657 .port_join = mlxsw_sp_bridge_8021q_port_join,
1658 .port_leave = mlxsw_sp_bridge_8021q_port_leave,
Ido Schimmela1107482017-05-26 08:37:39 +02001659 .fid_get = mlxsw_sp_bridge_8021q_fid_get,
Ido Schimmelc57529e2017-05-26 08:37:31 +02001660};
1661
1662static bool
1663mlxsw_sp_port_is_br_member(const struct mlxsw_sp_port *mlxsw_sp_port,
1664 const struct net_device *br_dev)
1665{
1666 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
1667
1668 list_for_each_entry(mlxsw_sp_port_vlan, &mlxsw_sp_port->vlans_list,
1669 list) {
1670 if (mlxsw_sp_port_vlan->bridge_port &&
1671 mlxsw_sp_port_vlan->bridge_port->bridge_device->dev ==
1672 br_dev)
1673 return true;
1674 }
1675
1676 return false;
1677}
1678
1679static int
1680mlxsw_sp_bridge_8021d_port_join(struct mlxsw_sp_bridge_device *bridge_device,
1681 struct mlxsw_sp_bridge_port *bridge_port,
1682 struct mlxsw_sp_port *mlxsw_sp_port)
1683{
1684 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
Ido Schimmelc57529e2017-05-26 08:37:31 +02001685 u16 vid;
1686
1687 if (!is_vlan_dev(bridge_port->dev))
1688 return -EINVAL;
1689 vid = vlan_dev_vlan_id(bridge_port->dev);
1690
1691 mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid);
1692 if (WARN_ON(!mlxsw_sp_port_vlan))
1693 return -EINVAL;
Ido Schimmelc57529e2017-05-26 08:37:31 +02001694
1695 if (mlxsw_sp_port_is_br_member(mlxsw_sp_port, bridge_device->dev)) {
1696 netdev_err(mlxsw_sp_port->dev, "Can't bridge VLAN uppers of the same port\n");
1697 return -EINVAL;
1698 }
1699
1700 /* Port is no longer usable as a router interface */
Ido Schimmela1107482017-05-26 08:37:39 +02001701 if (mlxsw_sp_port_vlan->fid)
1702 mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port_vlan);
Ido Schimmelc57529e2017-05-26 08:37:31 +02001703
1704 return mlxsw_sp_port_vlan_bridge_join(mlxsw_sp_port_vlan, bridge_port);
1705}
1706
1707static void
1708mlxsw_sp_bridge_8021d_port_leave(struct mlxsw_sp_bridge_device *bridge_device,
1709 struct mlxsw_sp_bridge_port *bridge_port,
1710 struct mlxsw_sp_port *mlxsw_sp_port)
1711{
1712 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
1713 u16 vid = vlan_dev_vlan_id(bridge_port->dev);
1714
1715 mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid);
1716 if (WARN_ON(!mlxsw_sp_port_vlan))
1717 return;
1718
1719 mlxsw_sp_port_vlan_bridge_leave(mlxsw_sp_port_vlan);
1720}
1721
Ido Schimmela1107482017-05-26 08:37:39 +02001722static struct mlxsw_sp_fid *
1723mlxsw_sp_bridge_8021d_fid_get(struct mlxsw_sp_bridge_device *bridge_device,
1724 u16 vid)
1725{
1726 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(bridge_device->dev);
1727
1728 return mlxsw_sp_fid_8021d_get(mlxsw_sp, bridge_device->dev->ifindex);
1729}
1730
Ido Schimmelc57529e2017-05-26 08:37:31 +02001731static const struct mlxsw_sp_bridge_ops mlxsw_sp_bridge_8021d_ops = {
1732 .port_join = mlxsw_sp_bridge_8021d_port_join,
1733 .port_leave = mlxsw_sp_bridge_8021d_port_leave,
Ido Schimmela1107482017-05-26 08:37:39 +02001734 .fid_get = mlxsw_sp_bridge_8021d_fid_get,
Ido Schimmelc57529e2017-05-26 08:37:31 +02001735};
1736
1737int mlxsw_sp_port_bridge_join(struct mlxsw_sp_port *mlxsw_sp_port,
1738 struct net_device *brport_dev,
1739 struct net_device *br_dev)
1740{
1741 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1742 struct mlxsw_sp_bridge_device *bridge_device;
1743 struct mlxsw_sp_bridge_port *bridge_port;
1744 int err;
1745
1746 bridge_port = mlxsw_sp_bridge_port_get(mlxsw_sp->bridge, brport_dev);
1747 if (IS_ERR(bridge_port))
1748 return PTR_ERR(bridge_port);
1749 bridge_device = bridge_port->bridge_device;
1750
1751 err = bridge_device->ops->port_join(bridge_device, bridge_port,
1752 mlxsw_sp_port);
1753 if (err)
1754 goto err_port_join;
1755
1756 return 0;
1757
1758err_port_join:
1759 mlxsw_sp_bridge_port_put(mlxsw_sp->bridge, bridge_port);
1760 return err;
1761}
1762
1763void mlxsw_sp_port_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_port,
1764 struct net_device *brport_dev,
1765 struct net_device *br_dev)
1766{
1767 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1768 struct mlxsw_sp_bridge_device *bridge_device;
1769 struct mlxsw_sp_bridge_port *bridge_port;
1770
1771 bridge_device = mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, br_dev);
1772 if (!bridge_device)
1773 return;
1774 bridge_port = __mlxsw_sp_bridge_port_find(bridge_device, brport_dev);
1775 if (!bridge_port)
1776 return;
1777
1778 bridge_device->ops->port_leave(bridge_device, bridge_port,
1779 mlxsw_sp_port);
1780 mlxsw_sp_bridge_port_put(mlxsw_sp->bridge, bridge_port);
1781}
1782
Arkadi Sharshevsky1b40dc32017-06-08 08:44:19 +02001783static void
1784mlxsw_sp_fdb_call_notifiers(enum switchdev_notifier_type type,
1785 const char *mac, u16 vid,
1786 struct net_device *dev)
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01001787{
1788 struct switchdev_notifier_fdb_info info;
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01001789
Arkadi Sharshevskya989cdb2017-06-08 08:44:16 +02001790 info.addr = mac;
1791 info.vid = vid;
Arkadi Sharshevsky1b40dc32017-06-08 08:44:19 +02001792 call_switchdev_notifiers(type, dev, &info.info);
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01001793}
1794
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001795static void mlxsw_sp_fdb_notify_mac_process(struct mlxsw_sp *mlxsw_sp,
1796 char *sfn_pl, int rec_index,
1797 bool adding)
1798{
Ido Schimmelc57529e2017-05-26 08:37:31 +02001799 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
1800 struct mlxsw_sp_bridge_device *bridge_device;
1801 struct mlxsw_sp_bridge_port *bridge_port;
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001802 struct mlxsw_sp_port *mlxsw_sp_port;
Arkadi Sharshevsky1b40dc32017-06-08 08:44:19 +02001803 enum switchdev_notifier_type type;
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001804 char mac[ETH_ALEN];
1805 u8 local_port;
Ido Schimmel9de6a802015-12-15 16:03:40 +01001806 u16 vid, fid;
Jiri Pirko12f15012016-01-07 11:50:30 +01001807 bool do_notification = true;
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001808 int err;
1809
Ido Schimmel9de6a802015-12-15 16:03:40 +01001810 mlxsw_reg_sfn_mac_unpack(sfn_pl, rec_index, mac, &fid, &local_port);
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001811 mlxsw_sp_port = mlxsw_sp->ports[local_port];
1812 if (!mlxsw_sp_port) {
1813 dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Incorrect local port in FDB notification\n");
Jiri Pirko12f15012016-01-07 11:50:30 +01001814 goto just_remove;
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001815 }
1816
Ido Schimmelc57529e2017-05-26 08:37:31 +02001817 mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_fid(mlxsw_sp_port, fid);
1818 if (!mlxsw_sp_port_vlan) {
1819 netdev_err(mlxsw_sp_port->dev, "Failed to find a matching {Port, VID} following FDB notification\n");
1820 goto just_remove;
Ido Schimmelaac78a42015-12-15 16:03:42 +01001821 }
1822
Ido Schimmelc57529e2017-05-26 08:37:31 +02001823 bridge_port = mlxsw_sp_port_vlan->bridge_port;
1824 if (!bridge_port) {
1825 netdev_err(mlxsw_sp_port->dev, "{Port, VID} not associated with a bridge\n");
1826 goto just_remove;
1827 }
1828
1829 bridge_device = bridge_port->bridge_device;
1830 vid = bridge_device->vlan_enabled ? mlxsw_sp_port_vlan->vid : 0;
1831
Jiri Pirko12f15012016-01-07 11:50:30 +01001832do_fdb_op:
Jiri Pirko2fa9d452016-01-07 11:50:29 +01001833 err = mlxsw_sp_port_fdb_uc_op(mlxsw_sp, local_port, mac, fid,
Jiri Pirko12f15012016-01-07 11:50:30 +01001834 adding, true);
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001835 if (err) {
Ido Schimmelc0e01ea2017-05-18 13:03:52 +02001836 dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to set FDB entry\n");
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001837 return;
1838 }
1839
Jiri Pirko12f15012016-01-07 11:50:30 +01001840 if (!do_notification)
1841 return;
Arkadi Sharshevsky1b40dc32017-06-08 08:44:19 +02001842 type = adding ? SWITCHDEV_FDB_ADD_TO_BRIDGE : SWITCHDEV_FDB_DEL_TO_BRIDGE;
1843 mlxsw_sp_fdb_call_notifiers(type, mac, vid, bridge_port->dev);
Arkadi Sharshevskya989cdb2017-06-08 08:44:16 +02001844
Jiri Pirko12f15012016-01-07 11:50:30 +01001845 return;
1846
1847just_remove:
1848 adding = false;
1849 do_notification = false;
1850 goto do_fdb_op;
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01001851}
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001852
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01001853static void mlxsw_sp_fdb_notify_mac_lag_process(struct mlxsw_sp *mlxsw_sp,
1854 char *sfn_pl, int rec_index,
1855 bool adding)
1856{
Ido Schimmelc57529e2017-05-26 08:37:31 +02001857 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
1858 struct mlxsw_sp_bridge_device *bridge_device;
1859 struct mlxsw_sp_bridge_port *bridge_port;
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01001860 struct mlxsw_sp_port *mlxsw_sp_port;
Arkadi Sharshevsky1b40dc32017-06-08 08:44:19 +02001861 enum switchdev_notifier_type type;
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01001862 char mac[ETH_ALEN];
Ido Schimmel64771e32015-12-15 16:03:46 +01001863 u16 lag_vid = 0;
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01001864 u16 lag_id;
Ido Schimmel9de6a802015-12-15 16:03:40 +01001865 u16 vid, fid;
Jiri Pirko12f15012016-01-07 11:50:30 +01001866 bool do_notification = true;
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01001867 int err;
1868
Ido Schimmel9de6a802015-12-15 16:03:40 +01001869 mlxsw_reg_sfn_mac_lag_unpack(sfn_pl, rec_index, mac, &fid, &lag_id);
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01001870 mlxsw_sp_port = mlxsw_sp_lag_rep_port(mlxsw_sp, lag_id);
1871 if (!mlxsw_sp_port) {
1872 dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Cannot find port representor for LAG\n");
Jiri Pirko12f15012016-01-07 11:50:30 +01001873 goto just_remove;
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001874 }
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01001875
Ido Schimmelc57529e2017-05-26 08:37:31 +02001876 mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_fid(mlxsw_sp_port, fid);
1877 if (!mlxsw_sp_port_vlan) {
1878 netdev_err(mlxsw_sp_port->dev, "Failed to find a matching {Port, VID} following FDB notification\n");
1879 goto just_remove;
Ido Schimmelaac78a42015-12-15 16:03:42 +01001880 }
1881
Ido Schimmelc57529e2017-05-26 08:37:31 +02001882 bridge_port = mlxsw_sp_port_vlan->bridge_port;
1883 if (!bridge_port) {
1884 netdev_err(mlxsw_sp_port->dev, "{Port, VID} not associated with a bridge\n");
1885 goto just_remove;
1886 }
1887
1888 bridge_device = bridge_port->bridge_device;
1889 vid = bridge_device->vlan_enabled ? mlxsw_sp_port_vlan->vid : 0;
1890 lag_vid = mlxsw_sp_port_vlan->vid;
1891
Jiri Pirko12f15012016-01-07 11:50:30 +01001892do_fdb_op:
Ido Schimmel64771e32015-12-15 16:03:46 +01001893 err = mlxsw_sp_port_fdb_uc_lag_op(mlxsw_sp, lag_id, mac, fid, lag_vid,
Jiri Pirko12f15012016-01-07 11:50:30 +01001894 adding, true);
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01001895 if (err) {
Ido Schimmelc0e01ea2017-05-18 13:03:52 +02001896 dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to set FDB entry\n");
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01001897 return;
1898 }
1899
Jiri Pirko12f15012016-01-07 11:50:30 +01001900 if (!do_notification)
1901 return;
Arkadi Sharshevsky1b40dc32017-06-08 08:44:19 +02001902 type = adding ? SWITCHDEV_FDB_ADD_TO_BRIDGE : SWITCHDEV_FDB_DEL_TO_BRIDGE;
1903 mlxsw_sp_fdb_call_notifiers(type, mac, vid, bridge_port->dev);
Arkadi Sharshevskya989cdb2017-06-08 08:44:16 +02001904
Jiri Pirko12f15012016-01-07 11:50:30 +01001905 return;
1906
1907just_remove:
1908 adding = false;
1909 do_notification = false;
1910 goto do_fdb_op;
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001911}
1912
1913static void mlxsw_sp_fdb_notify_rec_process(struct mlxsw_sp *mlxsw_sp,
1914 char *sfn_pl, int rec_index)
1915{
1916 switch (mlxsw_reg_sfn_rec_type_get(sfn_pl, rec_index)) {
1917 case MLXSW_REG_SFN_REC_TYPE_LEARNED_MAC:
1918 mlxsw_sp_fdb_notify_mac_process(mlxsw_sp, sfn_pl,
1919 rec_index, true);
1920 break;
1921 case MLXSW_REG_SFN_REC_TYPE_AGED_OUT_MAC:
1922 mlxsw_sp_fdb_notify_mac_process(mlxsw_sp, sfn_pl,
1923 rec_index, false);
1924 break;
Jiri Pirko8a1ab5d2015-12-03 12:12:29 +01001925 case MLXSW_REG_SFN_REC_TYPE_LEARNED_MAC_LAG:
1926 mlxsw_sp_fdb_notify_mac_lag_process(mlxsw_sp, sfn_pl,
1927 rec_index, true);
1928 break;
1929 case MLXSW_REG_SFN_REC_TYPE_AGED_OUT_MAC_LAG:
1930 mlxsw_sp_fdb_notify_mac_lag_process(mlxsw_sp, sfn_pl,
1931 rec_index, false);
1932 break;
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001933 }
1934}
1935
1936static void mlxsw_sp_fdb_notify_work_schedule(struct mlxsw_sp *mlxsw_sp)
1937{
Ido Schimmel5f6935c2017-05-16 19:38:26 +02001938 struct mlxsw_sp_bridge *bridge = mlxsw_sp->bridge;
1939
1940 mlxsw_core_schedule_dw(&bridge->fdb_notify.dw,
1941 msecs_to_jiffies(bridge->fdb_notify.interval));
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001942}
1943
1944static void mlxsw_sp_fdb_notify_work(struct work_struct *work)
1945{
Ido Schimmel5f6935c2017-05-16 19:38:26 +02001946 struct mlxsw_sp_bridge *bridge;
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001947 struct mlxsw_sp *mlxsw_sp;
1948 char *sfn_pl;
1949 u8 num_rec;
1950 int i;
1951 int err;
1952
1953 sfn_pl = kmalloc(MLXSW_REG_SFN_LEN, GFP_KERNEL);
1954 if (!sfn_pl)
1955 return;
1956
Ido Schimmel5f6935c2017-05-16 19:38:26 +02001957 bridge = container_of(work, struct mlxsw_sp_bridge, fdb_notify.dw.work);
1958 mlxsw_sp = bridge->mlxsw_sp;
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001959
Ido Schimmel4f2c6ae2016-01-27 15:16:43 +01001960 rtnl_lock();
Ido Schimmel1803e0f2016-08-24 12:00:23 +02001961 mlxsw_reg_sfn_pack(sfn_pl);
1962 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(sfn), sfn_pl);
1963 if (err) {
1964 dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to get FDB notifications\n");
1965 goto out;
1966 }
1967 num_rec = mlxsw_reg_sfn_num_rec_get(sfn_pl);
1968 for (i = 0; i < num_rec; i++)
1969 mlxsw_sp_fdb_notify_rec_process(mlxsw_sp, sfn_pl, i);
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001970
Ido Schimmel1803e0f2016-08-24 12:00:23 +02001971out:
Ido Schimmel4f2c6ae2016-01-27 15:16:43 +01001972 rtnl_unlock();
Jiri Pirko56ade8f2015-10-16 14:01:37 +02001973 kfree(sfn_pl);
1974 mlxsw_sp_fdb_notify_work_schedule(mlxsw_sp);
1975}
1976
Arkadi Sharshevskyaf0613782017-06-08 08:44:20 +02001977struct mlxsw_sp_switchdev_event_work {
1978 struct work_struct work;
1979 struct switchdev_notifier_fdb_info fdb_info;
1980 struct net_device *dev;
1981 unsigned long event;
1982};
1983
1984static void mlxsw_sp_switchdev_event_work(struct work_struct *work)
1985{
1986 struct mlxsw_sp_switchdev_event_work *switchdev_work =
1987 container_of(work, struct mlxsw_sp_switchdev_event_work, work);
1988 struct net_device *dev = switchdev_work->dev;
1989 struct switchdev_notifier_fdb_info *fdb_info;
1990 struct mlxsw_sp_port *mlxsw_sp_port;
1991 int err;
1992
1993 rtnl_lock();
1994 mlxsw_sp_port = mlxsw_sp_port_dev_lower_find(dev);
1995 if (!mlxsw_sp_port)
1996 goto out;
1997
1998 switch (switchdev_work->event) {
1999 case SWITCHDEV_FDB_ADD_TO_DEVICE:
2000 fdb_info = &switchdev_work->fdb_info;
2001 err = mlxsw_sp_port_fdb_set(mlxsw_sp_port, fdb_info, true);
2002 if (err)
2003 break;
2004 mlxsw_sp_fdb_call_notifiers(SWITCHDEV_FDB_OFFLOADED,
2005 fdb_info->addr,
2006 fdb_info->vid, dev);
2007 break;
2008 case SWITCHDEV_FDB_DEL_TO_DEVICE:
2009 fdb_info = &switchdev_work->fdb_info;
2010 mlxsw_sp_port_fdb_set(mlxsw_sp_port, fdb_info, false);
2011 break;
2012 }
2013
2014out:
2015 rtnl_unlock();
2016 kfree(switchdev_work->fdb_info.addr);
2017 kfree(switchdev_work);
2018 dev_put(dev);
2019}
2020
2021/* Called under rcu_read_lock() */
2022static int mlxsw_sp_switchdev_event(struct notifier_block *unused,
2023 unsigned long event, void *ptr)
2024{
2025 struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
2026 struct mlxsw_sp_switchdev_event_work *switchdev_work;
2027 struct switchdev_notifier_fdb_info *fdb_info = ptr;
2028
2029 if (!mlxsw_sp_port_dev_lower_find_rcu(dev))
2030 return NOTIFY_DONE;
2031
2032 switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC);
2033 if (!switchdev_work)
2034 return NOTIFY_BAD;
2035
2036 INIT_WORK(&switchdev_work->work, mlxsw_sp_switchdev_event_work);
2037 switchdev_work->dev = dev;
2038 switchdev_work->event = event;
2039
2040 switch (event) {
2041 case SWITCHDEV_FDB_ADD_TO_DEVICE: /* fall through */
2042 case SWITCHDEV_FDB_DEL_TO_DEVICE:
2043 memcpy(&switchdev_work->fdb_info, ptr,
2044 sizeof(switchdev_work->fdb_info));
2045 switchdev_work->fdb_info.addr = kzalloc(ETH_ALEN, GFP_ATOMIC);
Ido Schimmel6f497932017-07-12 09:12:55 +02002046 if (!switchdev_work->fdb_info.addr)
2047 goto err_addr_alloc;
Arkadi Sharshevskyaf0613782017-06-08 08:44:20 +02002048 ether_addr_copy((u8 *)switchdev_work->fdb_info.addr,
2049 fdb_info->addr);
2050 /* Take a reference on the device. This can be either
2051 * upper device containig mlxsw_sp_port or just a
2052 * mlxsw_sp_port
2053 */
2054 dev_hold(dev);
2055 break;
2056 default:
2057 kfree(switchdev_work);
2058 return NOTIFY_DONE;
2059 }
2060
2061 mlxsw_core_schedule_work(&switchdev_work->work);
2062
2063 return NOTIFY_DONE;
Ido Schimmel6f497932017-07-12 09:12:55 +02002064
2065err_addr_alloc:
2066 kfree(switchdev_work);
2067 return NOTIFY_BAD;
Arkadi Sharshevskyaf0613782017-06-08 08:44:20 +02002068}
2069
2070static struct notifier_block mlxsw_sp_switchdev_notifier = {
2071 .notifier_call = mlxsw_sp_switchdev_event,
2072};
2073
Jiri Pirko56ade8f2015-10-16 14:01:37 +02002074static int mlxsw_sp_fdb_init(struct mlxsw_sp *mlxsw_sp)
2075{
Ido Schimmel5f6935c2017-05-16 19:38:26 +02002076 struct mlxsw_sp_bridge *bridge = mlxsw_sp->bridge;
Jiri Pirko56ade8f2015-10-16 14:01:37 +02002077 int err;
2078
2079 err = mlxsw_sp_ageing_set(mlxsw_sp, MLXSW_SP_DEFAULT_AGEING_TIME);
2080 if (err) {
2081 dev_err(mlxsw_sp->bus_info->dev, "Failed to set default ageing time\n");
2082 return err;
2083 }
Arkadi Sharshevskyaf0613782017-06-08 08:44:20 +02002084
2085 err = register_switchdev_notifier(&mlxsw_sp_switchdev_notifier);
2086 if (err) {
2087 dev_err(mlxsw_sp->bus_info->dev, "Failed to register switchdev notifier\n");
2088 return err;
2089 }
2090
Ido Schimmel5f6935c2017-05-16 19:38:26 +02002091 INIT_DELAYED_WORK(&bridge->fdb_notify.dw, mlxsw_sp_fdb_notify_work);
2092 bridge->fdb_notify.interval = MLXSW_SP_DEFAULT_LEARNING_INTERVAL;
Jiri Pirko56ade8f2015-10-16 14:01:37 +02002093 mlxsw_sp_fdb_notify_work_schedule(mlxsw_sp);
2094 return 0;
2095}
2096
2097static void mlxsw_sp_fdb_fini(struct mlxsw_sp *mlxsw_sp)
2098{
Ido Schimmel5f6935c2017-05-16 19:38:26 +02002099 cancel_delayed_work_sync(&mlxsw_sp->bridge->fdb_notify.dw);
Arkadi Sharshevskyaf0613782017-06-08 08:44:20 +02002100 unregister_switchdev_notifier(&mlxsw_sp_switchdev_notifier);
2101
Jiri Pirko56ade8f2015-10-16 14:01:37 +02002102}
2103
Jiri Pirko56ade8f2015-10-16 14:01:37 +02002104int mlxsw_sp_switchdev_init(struct mlxsw_sp *mlxsw_sp)
2105{
Ido Schimmel5f6935c2017-05-16 19:38:26 +02002106 struct mlxsw_sp_bridge *bridge;
2107
2108 bridge = kzalloc(sizeof(*mlxsw_sp->bridge), GFP_KERNEL);
2109 if (!bridge)
2110 return -ENOMEM;
2111 mlxsw_sp->bridge = bridge;
2112 bridge->mlxsw_sp = mlxsw_sp;
2113
Ido Schimmelc57529e2017-05-26 08:37:31 +02002114 INIT_LIST_HEAD(&mlxsw_sp->bridge->bridges_list);
Ido Schimmel5f6935c2017-05-16 19:38:26 +02002115
Ido Schimmelc57529e2017-05-26 08:37:31 +02002116 bridge->bridge_8021q_ops = &mlxsw_sp_bridge_8021q_ops;
2117 bridge->bridge_8021d_ops = &mlxsw_sp_bridge_8021d_ops;
2118
Jiri Pirko56ade8f2015-10-16 14:01:37 +02002119 return mlxsw_sp_fdb_init(mlxsw_sp);
2120}
2121
2122void mlxsw_sp_switchdev_fini(struct mlxsw_sp *mlxsw_sp)
2123{
2124 mlxsw_sp_fdb_fini(mlxsw_sp);
Ido Schimmelc57529e2017-05-26 08:37:31 +02002125 WARN_ON(!list_empty(&mlxsw_sp->bridge->bridges_list));
Ido Schimmel5f6935c2017-05-16 19:38:26 +02002126 kfree(mlxsw_sp->bridge);
Jiri Pirko56ade8f2015-10-16 14:01:37 +02002127}
2128
Jiri Pirko56ade8f2015-10-16 14:01:37 +02002129void mlxsw_sp_port_switchdev_init(struct mlxsw_sp_port *mlxsw_sp_port)
2130{
2131 mlxsw_sp_port->dev->switchdev_ops = &mlxsw_sp_port_switchdev_ops;
2132}
2133
2134void mlxsw_sp_port_switchdev_fini(struct mlxsw_sp_port *mlxsw_sp_port)
2135{
2136}