Linux Audio

Check our new training course

Loading...
v5.14.15
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * Handling of a single switch chip, part of a switch fabric
  4 *
  5 * Copyright (c) 2017 Savoir-faire Linux Inc.
  6 *	Vivien Didelot <vivien.didelot@savoirfairelinux.com>
 
 
 
 
 
  7 */
  8
  9#include <linux/if_bridge.h>
 10#include <linux/netdevice.h>
 11#include <linux/notifier.h>
 12#include <linux/if_vlan.h>
 13#include <net/switchdev.h>
 14
 15#include "dsa_priv.h"
 16
 17static unsigned int dsa_switch_fastest_ageing_time(struct dsa_switch *ds,
 18						   unsigned int ageing_time)
 19{
 20	int i;
 21
 22	for (i = 0; i < ds->num_ports; ++i) {
 23		struct dsa_port *dp = dsa_to_port(ds, i);
 24
 25		if (dp->ageing_time && dp->ageing_time < ageing_time)
 26			ageing_time = dp->ageing_time;
 27	}
 28
 29	return ageing_time;
 30}
 31
 32static int dsa_switch_ageing_time(struct dsa_switch *ds,
 33				  struct dsa_notifier_ageing_time_info *info)
 34{
 35	unsigned int ageing_time = info->ageing_time;
 
 36
 37	if (ds->ageing_time_min && ageing_time < ds->ageing_time_min)
 38		return -ERANGE;
 39
 40	if (ds->ageing_time_max && ageing_time > ds->ageing_time_max)
 41		return -ERANGE;
 
 
 42
 43	/* Program the fastest ageing time in case of multiple bridges */
 44	ageing_time = dsa_switch_fastest_ageing_time(ds, ageing_time);
 45
 46	if (ds->ops->set_ageing_time)
 47		return ds->ops->set_ageing_time(ds, ageing_time);
 48
 49	return 0;
 50}
 51
 52static bool dsa_switch_mtu_match(struct dsa_switch *ds, int port,
 53				 struct dsa_notifier_mtu_info *info)
 54{
 55	if (ds->index == info->sw_index && port == info->port)
 56		return true;
 57
 58	/* Do not propagate to other switches in the tree if the notifier was
 59	 * targeted for a single switch.
 60	 */
 61	if (info->targeted_match)
 62		return false;
 63
 64	if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port))
 65		return true;
 66
 67	return false;
 68}
 69
 70static int dsa_switch_mtu(struct dsa_switch *ds,
 71			  struct dsa_notifier_mtu_info *info)
 72{
 73	int port, ret;
 74
 75	if (!ds->ops->port_change_mtu)
 76		return -EOPNOTSUPP;
 77
 78	for (port = 0; port < ds->num_ports; port++) {
 79		if (dsa_switch_mtu_match(ds, port, info)) {
 80			ret = ds->ops->port_change_mtu(ds, port, info->mtu);
 81			if (ret)
 82				return ret;
 83		}
 84	}
 85
 86	return 0;
 87}
 88
 89static int dsa_switch_bridge_join(struct dsa_switch *ds,
 90				  struct dsa_notifier_bridge_info *info)
 91{
 92	struct dsa_switch_tree *dst = ds->dst;
 93
 94	if (dst->index == info->tree_index && ds->index == info->sw_index &&
 95	    ds->ops->port_bridge_join)
 96		return ds->ops->port_bridge_join(ds, info->port, info->br);
 97
 98	if ((dst->index != info->tree_index || ds->index != info->sw_index) &&
 99	    ds->ops->crosschip_bridge_join)
100		return ds->ops->crosschip_bridge_join(ds, info->tree_index,
101						      info->sw_index,
102						      info->port, info->br);
103
104	return 0;
105}
106
107static int dsa_switch_bridge_leave(struct dsa_switch *ds,
108				   struct dsa_notifier_bridge_info *info)
109{
110	bool unset_vlan_filtering = br_vlan_enabled(info->br);
111	struct dsa_switch_tree *dst = ds->dst;
112	struct netlink_ext_ack extack = {0};
113	int err, port;
114
115	if (dst->index == info->tree_index && ds->index == info->sw_index &&
116	    ds->ops->port_bridge_leave)
117		ds->ops->port_bridge_leave(ds, info->port, info->br);
118
119	if ((dst->index != info->tree_index || ds->index != info->sw_index) &&
120	    ds->ops->crosschip_bridge_leave)
121		ds->ops->crosschip_bridge_leave(ds, info->tree_index,
122						info->sw_index, info->port,
123						info->br);
124
125	/* If the bridge was vlan_filtering, the bridge core doesn't trigger an
126	 * event for changing vlan_filtering setting upon slave ports leaving
127	 * it. That is a good thing, because that lets us handle it and also
128	 * handle the case where the switch's vlan_filtering setting is global
129	 * (not per port). When that happens, the correct moment to trigger the
130	 * vlan_filtering callback is only when the last port leaves the last
131	 * VLAN-aware bridge.
132	 */
133	if (unset_vlan_filtering && ds->vlan_filtering_is_global) {
134		for (port = 0; port < ds->num_ports; port++) {
135			struct net_device *bridge_dev;
136
137			bridge_dev = dsa_to_port(ds, port)->bridge_dev;
138
139			if (bridge_dev && br_vlan_enabled(bridge_dev)) {
140				unset_vlan_filtering = false;
141				break;
142			}
143		}
144	}
145	if (unset_vlan_filtering) {
146		err = dsa_port_vlan_filtering(dsa_to_port(ds, info->port),
147					      false, &extack);
148		if (extack._msg)
149			dev_err(ds->dev, "port %d: %s\n", info->port,
150				extack._msg);
151		if (err && err != -EOPNOTSUPP)
152			return err;
153	}
154	return 0;
155}
156
157/* Matches for all upstream-facing ports (the CPU port and all upstream-facing
158 * DSA links) that sit between the targeted port on which the notifier was
159 * emitted and its dedicated CPU port.
160 */
161static bool dsa_switch_host_address_match(struct dsa_switch *ds, int port,
162					  int info_sw_index, int info_port)
163{
164	struct dsa_port *targeted_dp, *cpu_dp;
165	struct dsa_switch *targeted_ds;
166
167	targeted_ds = dsa_switch_find(ds->dst->index, info_sw_index);
168	targeted_dp = dsa_to_port(targeted_ds, info_port);
169	cpu_dp = targeted_dp->cpu_dp;
170
171	if (dsa_switch_is_upstream_of(ds, targeted_ds))
172		return port == dsa_towards_port(ds, cpu_dp->ds->index,
173						cpu_dp->index);
174
175	return false;
176}
177
178static struct dsa_mac_addr *dsa_mac_addr_find(struct list_head *addr_list,
179					      const unsigned char *addr,
180					      u16 vid)
181{
182	struct dsa_mac_addr *a;
183
184	list_for_each_entry(a, addr_list, list)
185		if (ether_addr_equal(a->addr, addr) && a->vid == vid)
186			return a;
187
188	return NULL;
189}
190
191static int dsa_switch_do_mdb_add(struct dsa_switch *ds, int port,
192				 const struct switchdev_obj_port_mdb *mdb)
193{
194	struct dsa_port *dp = dsa_to_port(ds, port);
195	struct dsa_mac_addr *a;
196	int err;
197
198	/* No need to bother with refcounting for user ports */
199	if (!(dsa_port_is_cpu(dp) || dsa_port_is_dsa(dp)))
200		return ds->ops->port_mdb_add(ds, port, mdb);
201
202	a = dsa_mac_addr_find(&dp->mdbs, mdb->addr, mdb->vid);
203	if (a) {
204		refcount_inc(&a->refcount);
205		return 0;
206	}
207
208	a = kzalloc(sizeof(*a), GFP_KERNEL);
209	if (!a)
210		return -ENOMEM;
211
212	err = ds->ops->port_mdb_add(ds, port, mdb);
213	if (err) {
214		kfree(a);
215		return err;
216	}
217
218	ether_addr_copy(a->addr, mdb->addr);
219	a->vid = mdb->vid;
220	refcount_set(&a->refcount, 1);
221	list_add_tail(&a->list, &dp->mdbs);
222
223	return 0;
224}
225
226static int dsa_switch_do_mdb_del(struct dsa_switch *ds, int port,
227				 const struct switchdev_obj_port_mdb *mdb)
228{
229	struct dsa_port *dp = dsa_to_port(ds, port);
230	struct dsa_mac_addr *a;
231	int err;
232
233	/* No need to bother with refcounting for user ports */
234	if (!(dsa_port_is_cpu(dp) || dsa_port_is_dsa(dp)))
235		return ds->ops->port_mdb_del(ds, port, mdb);
236
237	a = dsa_mac_addr_find(&dp->mdbs, mdb->addr, mdb->vid);
238	if (!a)
239		return -ENOENT;
240
241	if (!refcount_dec_and_test(&a->refcount))
242		return 0;
243
244	err = ds->ops->port_mdb_del(ds, port, mdb);
245	if (err) {
246		refcount_inc(&a->refcount);
247		return err;
248	}
249
250	list_del(&a->list);
251	kfree(a);
252
253	return 0;
254}
255
256static int dsa_switch_do_fdb_add(struct dsa_switch *ds, int port,
257				 const unsigned char *addr, u16 vid)
258{
259	struct dsa_port *dp = dsa_to_port(ds, port);
260	struct dsa_mac_addr *a;
261	int err;
262
263	/* No need to bother with refcounting for user ports */
264	if (!(dsa_port_is_cpu(dp) || dsa_port_is_dsa(dp)))
265		return ds->ops->port_fdb_add(ds, port, addr, vid);
266
267	a = dsa_mac_addr_find(&dp->fdbs, addr, vid);
268	if (a) {
269		refcount_inc(&a->refcount);
270		return 0;
271	}
272
273	a = kzalloc(sizeof(*a), GFP_KERNEL);
274	if (!a)
275		return -ENOMEM;
276
277	err = ds->ops->port_fdb_add(ds, port, addr, vid);
278	if (err) {
279		kfree(a);
280		return err;
281	}
282
283	ether_addr_copy(a->addr, addr);
284	a->vid = vid;
285	refcount_set(&a->refcount, 1);
286	list_add_tail(&a->list, &dp->fdbs);
287
288	return 0;
289}
290
291static int dsa_switch_do_fdb_del(struct dsa_switch *ds, int port,
292				 const unsigned char *addr, u16 vid)
293{
294	struct dsa_port *dp = dsa_to_port(ds, port);
295	struct dsa_mac_addr *a;
296	int err;
297
298	/* No need to bother with refcounting for user ports */
299	if (!(dsa_port_is_cpu(dp) || dsa_port_is_dsa(dp)))
300		return ds->ops->port_fdb_del(ds, port, addr, vid);
301
302	a = dsa_mac_addr_find(&dp->fdbs, addr, vid);
303	if (!a)
304		return -ENOENT;
305
306	if (!refcount_dec_and_test(&a->refcount))
307		return 0;
308
309	err = ds->ops->port_fdb_del(ds, port, addr, vid);
310	if (err) {
311		refcount_inc(&a->refcount);
312		return err;
313	}
314
315	list_del(&a->list);
316	kfree(a);
317
318	return 0;
319}
320
321static int dsa_switch_host_fdb_add(struct dsa_switch *ds,
322				   struct dsa_notifier_fdb_info *info)
323{
324	int err = 0;
325	int port;
326
327	if (!ds->ops->port_fdb_add)
328		return -EOPNOTSUPP;
329
330	for (port = 0; port < ds->num_ports; port++) {
331		if (dsa_switch_host_address_match(ds, port, info->sw_index,
332						  info->port)) {
333			err = dsa_switch_do_fdb_add(ds, port, info->addr,
334						    info->vid);
335			if (err)
336				break;
337		}
338	}
339
340	return err;
341}
342
343static int dsa_switch_host_fdb_del(struct dsa_switch *ds,
344				   struct dsa_notifier_fdb_info *info)
345{
346	int err = 0;
347	int port;
348
349	if (!ds->ops->port_fdb_del)
350		return -EOPNOTSUPP;
351
352	for (port = 0; port < ds->num_ports; port++) {
353		if (dsa_switch_host_address_match(ds, port, info->sw_index,
354						  info->port)) {
355			err = dsa_switch_do_fdb_del(ds, port, info->addr,
356						    info->vid);
357			if (err)
358				break;
359		}
360	}
361
362	return err;
363}
364
365static int dsa_switch_fdb_add(struct dsa_switch *ds,
366			      struct dsa_notifier_fdb_info *info)
367{
368	int port = dsa_towards_port(ds, info->sw_index, info->port);
369
370	if (!ds->ops->port_fdb_add)
371		return -EOPNOTSUPP;
372
373	return dsa_switch_do_fdb_add(ds, port, info->addr, info->vid);
374}
375
376static int dsa_switch_fdb_del(struct dsa_switch *ds,
377			      struct dsa_notifier_fdb_info *info)
378{
379	int port = dsa_towards_port(ds, info->sw_index, info->port);
380
381	if (!ds->ops->port_fdb_del)
382		return -EOPNOTSUPP;
383
384	return dsa_switch_do_fdb_del(ds, port, info->addr, info->vid);
385}
386
387static int dsa_switch_hsr_join(struct dsa_switch *ds,
388			       struct dsa_notifier_hsr_info *info)
389{
390	if (ds->index == info->sw_index && ds->ops->port_hsr_join)
391		return ds->ops->port_hsr_join(ds, info->port, info->hsr);
392
393	return -EOPNOTSUPP;
394}
395
396static int dsa_switch_hsr_leave(struct dsa_switch *ds,
397				struct dsa_notifier_hsr_info *info)
398{
399	if (ds->index == info->sw_index && ds->ops->port_hsr_leave)
400		return ds->ops->port_hsr_leave(ds, info->port, info->hsr);
401
402	return -EOPNOTSUPP;
403}
404
405static int dsa_switch_lag_change(struct dsa_switch *ds,
406				 struct dsa_notifier_lag_info *info)
407{
408	if (ds->index == info->sw_index && ds->ops->port_lag_change)
409		return ds->ops->port_lag_change(ds, info->port);
410
411	if (ds->index != info->sw_index && ds->ops->crosschip_lag_change)
412		return ds->ops->crosschip_lag_change(ds, info->sw_index,
413						     info->port);
 
 
414
415	return 0;
416}
417
418static int dsa_switch_lag_join(struct dsa_switch *ds,
419			       struct dsa_notifier_lag_info *info)
 
420{
421	if (ds->index == info->sw_index && ds->ops->port_lag_join)
422		return ds->ops->port_lag_join(ds, info->port, info->lag,
423					      info->info);
424
425	if (ds->index != info->sw_index && ds->ops->crosschip_lag_join)
426		return ds->ops->crosschip_lag_join(ds, info->sw_index,
427						   info->port, info->lag,
428						   info->info);
429
430	return -EOPNOTSUPP;
431}
432
433static int dsa_switch_lag_leave(struct dsa_switch *ds,
434				struct dsa_notifier_lag_info *info)
435{
436	if (ds->index == info->sw_index && ds->ops->port_lag_leave)
437		return ds->ops->port_lag_leave(ds, info->port, info->lag);
438
439	if (ds->index != info->sw_index && ds->ops->crosschip_lag_leave)
440		return ds->ops->crosschip_lag_leave(ds, info->sw_index,
441						    info->port, info->lag);
442
443	return -EOPNOTSUPP;
 
444}
445
446static int dsa_switch_mdb_add(struct dsa_switch *ds,
447			      struct dsa_notifier_mdb_info *info)
448{
449	int port = dsa_towards_port(ds, info->sw_index, info->port);
450
451	if (!ds->ops->port_mdb_add)
452		return -EOPNOTSUPP;
453
454	return dsa_switch_do_mdb_add(ds, port, info->mdb);
455}
456
457static int dsa_switch_mdb_del(struct dsa_switch *ds,
458			      struct dsa_notifier_mdb_info *info)
459{
460	int port = dsa_towards_port(ds, info->sw_index, info->port);
461
462	if (!ds->ops->port_mdb_del)
463		return -EOPNOTSUPP;
464
465	return dsa_switch_do_mdb_del(ds, port, info->mdb);
466}
467
468static int dsa_switch_host_mdb_add(struct dsa_switch *ds,
469				   struct dsa_notifier_mdb_info *info)
470{
471	int err = 0;
472	int port;
473
474	if (!ds->ops->port_mdb_add)
475		return -EOPNOTSUPP;
476
477	for (port = 0; port < ds->num_ports; port++) {
478		if (dsa_switch_host_address_match(ds, port, info->sw_index,
479						  info->port)) {
480			err = dsa_switch_do_mdb_add(ds, port, info->mdb);
481			if (err)
482				break;
483		}
484	}
485
486	return err;
487}
488
489static int dsa_switch_host_mdb_del(struct dsa_switch *ds,
490				   struct dsa_notifier_mdb_info *info)
491{
492	int err = 0;
493	int port;
494
495	if (!ds->ops->port_mdb_del)
496		return -EOPNOTSUPP;
497
498	for (port = 0; port < ds->num_ports; port++) {
499		if (dsa_switch_host_address_match(ds, port, info->sw_index,
500						  info->port)) {
501			err = dsa_switch_do_mdb_del(ds, port, info->mdb);
502			if (err)
503				break;
504		}
505	}
506
507	return err;
508}
509
510static bool dsa_switch_vlan_match(struct dsa_switch *ds, int port,
511				  struct dsa_notifier_vlan_info *info)
512{
513	if (ds->index == info->sw_index && port == info->port)
514		return true;
515
516	if (dsa_is_dsa_port(ds, port))
517		return true;
518
519	return false;
520}
521
522static int dsa_switch_vlan_add(struct dsa_switch *ds,
523			       struct dsa_notifier_vlan_info *info)
524{
525	int port, err;
526
527	if (!ds->ops->port_vlan_add)
528		return -EOPNOTSUPP;
529
530	for (port = 0; port < ds->num_ports; port++) {
531		if (dsa_switch_vlan_match(ds, port, info)) {
532			err = ds->ops->port_vlan_add(ds, port, info->vlan,
533						     info->extack);
534			if (err)
535				return err;
536		}
537	}
538
539	return 0;
540}
541
542static int dsa_switch_vlan_del(struct dsa_switch *ds,
543			       struct dsa_notifier_vlan_info *info)
544{
545	if (!ds->ops->port_vlan_del)
 
 
546		return -EOPNOTSUPP;
547
548	if (ds->index == info->sw_index)
549		return ds->ops->port_vlan_del(ds, info->port, info->vlan);
550
551	/* Do not deprogram the DSA links as they may be used as conduit
552	 * for other VLAN members in the fabric.
553	 */
554	return 0;
555}
556
557static int dsa_switch_change_tag_proto(struct dsa_switch *ds,
558				       struct dsa_notifier_tag_proto_info *info)
 
 
559{
560	const struct dsa_device_ops *tag_ops = info->tag_ops;
561	int port, err;
562
563	if (!ds->ops->change_tag_protocol)
564		return -EOPNOTSUPP;
565
566	ASSERT_RTNL();
567
568	for (port = 0; port < ds->num_ports; port++) {
569		if (!dsa_is_cpu_port(ds, port))
570			continue;
571
572		err = ds->ops->change_tag_protocol(ds, port, tag_ops->proto);
573		if (err)
574			return err;
575
576		dsa_port_set_tag_protocol(dsa_to_port(ds, port), tag_ops);
577	}
578
579	/* Now that changing the tag protocol can no longer fail, let's update
580	 * the remaining bits which are "duplicated for faster access", and the
581	 * bits that depend on the tagger, such as the MTU.
582	 */
583	for (port = 0; port < ds->num_ports; port++) {
584		if (dsa_is_user_port(ds, port)) {
585			struct net_device *slave;
586
587			slave = dsa_to_port(ds, port)->slave;
588			dsa_slave_setup_tagger(slave);
589
590			/* rtnl_mutex is held in dsa_tree_change_tag_proto */
591			dsa_slave_change_mtu(slave, slave->mtu);
592		}
593	}
594
595	return 0;
596}
597
598static int dsa_switch_mrp_add(struct dsa_switch *ds,
599			      struct dsa_notifier_mrp_info *info)
 
 
600{
601	if (!ds->ops->port_mrp_add)
602		return -EOPNOTSUPP;
603
604	if (ds->index == info->sw_index)
605		return ds->ops->port_mrp_add(ds, info->port, info->mrp);
606
607	return 0;
 
608}
609
610static int dsa_switch_mrp_del(struct dsa_switch *ds,
611			      struct dsa_notifier_mrp_info *info)
612{
613	if (!ds->ops->port_mrp_del)
614		return -EOPNOTSUPP;
 
 
615
 
 
616	if (ds->index == info->sw_index)
617		return ds->ops->port_mrp_del(ds, info->port, info->mrp);
 
 
 
618
619	return 0;
620}
621
622static int
623dsa_switch_mrp_add_ring_role(struct dsa_switch *ds,
624			     struct dsa_notifier_mrp_ring_role_info *info)
625{
626	if (!ds->ops->port_mrp_add)
627		return -EOPNOTSUPP;
628
629	if (ds->index == info->sw_index)
630		return ds->ops->port_mrp_add_ring_role(ds, info->port,
631						       info->mrp);
632
633	return 0;
634}
635
636static int
637dsa_switch_mrp_del_ring_role(struct dsa_switch *ds,
638			     struct dsa_notifier_mrp_ring_role_info *info)
639{
640	if (!ds->ops->port_mrp_del)
 
 
641		return -EOPNOTSUPP;
642
643	if (ds->index == info->sw_index)
644		return ds->ops->port_mrp_del_ring_role(ds, info->port,
645						       info->mrp);
646
647	return 0;
648}
649
650static int dsa_switch_event(struct notifier_block *nb,
651			    unsigned long event, void *info)
652{
653	struct dsa_switch *ds = container_of(nb, struct dsa_switch, nb);
654	int err;
655
656	switch (event) {
657	case DSA_NOTIFIER_AGEING_TIME:
658		err = dsa_switch_ageing_time(ds, info);
659		break;
660	case DSA_NOTIFIER_BRIDGE_JOIN:
661		err = dsa_switch_bridge_join(ds, info);
662		break;
663	case DSA_NOTIFIER_BRIDGE_LEAVE:
664		err = dsa_switch_bridge_leave(ds, info);
665		break;
666	case DSA_NOTIFIER_FDB_ADD:
667		err = dsa_switch_fdb_add(ds, info);
668		break;
669	case DSA_NOTIFIER_FDB_DEL:
670		err = dsa_switch_fdb_del(ds, info);
671		break;
672	case DSA_NOTIFIER_HOST_FDB_ADD:
673		err = dsa_switch_host_fdb_add(ds, info);
674		break;
675	case DSA_NOTIFIER_HOST_FDB_DEL:
676		err = dsa_switch_host_fdb_del(ds, info);
677		break;
678	case DSA_NOTIFIER_HSR_JOIN:
679		err = dsa_switch_hsr_join(ds, info);
680		break;
681	case DSA_NOTIFIER_HSR_LEAVE:
682		err = dsa_switch_hsr_leave(ds, info);
683		break;
684	case DSA_NOTIFIER_LAG_CHANGE:
685		err = dsa_switch_lag_change(ds, info);
686		break;
687	case DSA_NOTIFIER_LAG_JOIN:
688		err = dsa_switch_lag_join(ds, info);
689		break;
690	case DSA_NOTIFIER_LAG_LEAVE:
691		err = dsa_switch_lag_leave(ds, info);
692		break;
693	case DSA_NOTIFIER_MDB_ADD:
694		err = dsa_switch_mdb_add(ds, info);
695		break;
696	case DSA_NOTIFIER_MDB_DEL:
697		err = dsa_switch_mdb_del(ds, info);
698		break;
699	case DSA_NOTIFIER_HOST_MDB_ADD:
700		err = dsa_switch_host_mdb_add(ds, info);
701		break;
702	case DSA_NOTIFIER_HOST_MDB_DEL:
703		err = dsa_switch_host_mdb_del(ds, info);
704		break;
705	case DSA_NOTIFIER_VLAN_ADD:
706		err = dsa_switch_vlan_add(ds, info);
707		break;
708	case DSA_NOTIFIER_VLAN_DEL:
709		err = dsa_switch_vlan_del(ds, info);
710		break;
711	case DSA_NOTIFIER_MTU:
712		err = dsa_switch_mtu(ds, info);
713		break;
714	case DSA_NOTIFIER_TAG_PROTO:
715		err = dsa_switch_change_tag_proto(ds, info);
716		break;
717	case DSA_NOTIFIER_MRP_ADD:
718		err = dsa_switch_mrp_add(ds, info);
719		break;
720	case DSA_NOTIFIER_MRP_DEL:
721		err = dsa_switch_mrp_del(ds, info);
722		break;
723	case DSA_NOTIFIER_MRP_ADD_RING_ROLE:
724		err = dsa_switch_mrp_add_ring_role(ds, info);
725		break;
726	case DSA_NOTIFIER_MRP_DEL_RING_ROLE:
727		err = dsa_switch_mrp_del_ring_role(ds, info);
728		break;
729	default:
730		err = -EOPNOTSUPP;
731		break;
732	}
733
 
 
 
 
734	if (err)
735		dev_dbg(ds->dev, "breaking chain for DSA event %lu (%d)\n",
736			event, err);
737
738	return notifier_from_errno(err);
739}
740
741int dsa_switch_register_notifier(struct dsa_switch *ds)
742{
743	ds->nb.notifier_call = dsa_switch_event;
744
745	return raw_notifier_chain_register(&ds->dst->nh, &ds->nb);
746}
747
748void dsa_switch_unregister_notifier(struct dsa_switch *ds)
749{
750	int err;
751
752	err = raw_notifier_chain_unregister(&ds->dst->nh, &ds->nb);
753	if (err)
754		dev_err(ds->dev, "failed to unregister notifier (%d)\n", err);
755}
v4.17
 
  1/*
  2 * Handling of a single switch chip, part of a switch fabric
  3 *
  4 * Copyright (c) 2017 Savoir-faire Linux Inc.
  5 *	Vivien Didelot <vivien.didelot@savoirfairelinux.com>
  6 *
  7 * This program is free software; you can redistribute it and/or modify
  8 * it under the terms of the GNU General Public License as published by
  9 * the Free Software Foundation; either version 2 of the License, or
 10 * (at your option) any later version.
 11 */
 12
 
 13#include <linux/netdevice.h>
 14#include <linux/notifier.h>
 
 15#include <net/switchdev.h>
 16
 17#include "dsa_priv.h"
 18
 19static unsigned int dsa_switch_fastest_ageing_time(struct dsa_switch *ds,
 20						   unsigned int ageing_time)
 21{
 22	int i;
 23
 24	for (i = 0; i < ds->num_ports; ++i) {
 25		struct dsa_port *dp = &ds->ports[i];
 26
 27		if (dp->ageing_time && dp->ageing_time < ageing_time)
 28			ageing_time = dp->ageing_time;
 29	}
 30
 31	return ageing_time;
 32}
 33
 34static int dsa_switch_ageing_time(struct dsa_switch *ds,
 35				  struct dsa_notifier_ageing_time_info *info)
 36{
 37	unsigned int ageing_time = info->ageing_time;
 38	struct switchdev_trans *trans = info->trans;
 39
 40	if (switchdev_trans_ph_prepare(trans)) {
 41		if (ds->ageing_time_min && ageing_time < ds->ageing_time_min)
 42			return -ERANGE;
 43		if (ds->ageing_time_max && ageing_time > ds->ageing_time_max)
 44			return -ERANGE;
 45		return 0;
 46	}
 47
 48	/* Program the fastest ageing time in case of multiple bridges */
 49	ageing_time = dsa_switch_fastest_ageing_time(ds, ageing_time);
 50
 51	if (ds->ops->set_ageing_time)
 52		return ds->ops->set_ageing_time(ds, ageing_time);
 53
 54	return 0;
 55}
 56
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 57static int dsa_switch_bridge_join(struct dsa_switch *ds,
 58				  struct dsa_notifier_bridge_info *info)
 59{
 60	if (ds->index == info->sw_index && ds->ops->port_bridge_join)
 
 
 
 61		return ds->ops->port_bridge_join(ds, info->port, info->br);
 62
 63	if (ds->index != info->sw_index && ds->ops->crosschip_bridge_join)
 64		return ds->ops->crosschip_bridge_join(ds, info->sw_index,
 
 
 65						      info->port, info->br);
 66
 67	return 0;
 68}
 69
 70static int dsa_switch_bridge_leave(struct dsa_switch *ds,
 71				   struct dsa_notifier_bridge_info *info)
 72{
 73	if (ds->index == info->sw_index && ds->ops->port_bridge_leave)
 
 
 
 
 
 
 74		ds->ops->port_bridge_leave(ds, info->port, info->br);
 75
 76	if (ds->index != info->sw_index && ds->ops->crosschip_bridge_leave)
 77		ds->ops->crosschip_bridge_leave(ds, info->sw_index, info->port,
 
 
 78						info->br);
 79
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 80	return 0;
 81}
 82
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 83static int dsa_switch_fdb_add(struct dsa_switch *ds,
 84			      struct dsa_notifier_fdb_info *info)
 85{
 86	int port = dsa_towards_port(ds, info->sw_index, info->port);
 87
 88	if (!ds->ops->port_fdb_add)
 89		return -EOPNOTSUPP;
 90
 91	return ds->ops->port_fdb_add(ds, port, info->addr, info->vid);
 92}
 93
 94static int dsa_switch_fdb_del(struct dsa_switch *ds,
 95			      struct dsa_notifier_fdb_info *info)
 96{
 97	int port = dsa_towards_port(ds, info->sw_index, info->port);
 98
 99	if (!ds->ops->port_fdb_del)
100		return -EOPNOTSUPP;
101
102	return ds->ops->port_fdb_del(ds, port, info->addr, info->vid);
103}
104
105static int
106dsa_switch_mdb_prepare_bitmap(struct dsa_switch *ds,
107			      const struct switchdev_obj_port_mdb *mdb,
108			      const unsigned long *bitmap)
 
 
 
 
 
 
 
109{
110	int port, err;
 
 
 
 
111
112	if (!ds->ops->port_mdb_prepare || !ds->ops->port_mdb_add)
113		return -EOPNOTSUPP;
 
 
 
114
115	for_each_set_bit(port, bitmap, ds->num_ports) {
116		err = ds->ops->port_mdb_prepare(ds, port, mdb);
117		if (err)
118			return err;
119	}
120
121	return 0;
122}
123
124static void dsa_switch_mdb_add_bitmap(struct dsa_switch *ds,
125				      const struct switchdev_obj_port_mdb *mdb,
126				      const unsigned long *bitmap)
127{
128	int port;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
129
130	for_each_set_bit(port, bitmap, ds->num_ports)
131		ds->ops->port_mdb_add(ds, port, mdb);
132}
133
134static int dsa_switch_mdb_add(struct dsa_switch *ds,
135			      struct dsa_notifier_mdb_info *info)
136{
137	const struct switchdev_obj_port_mdb *mdb = info->mdb;
138	struct switchdev_trans *trans = info->trans;
139	DECLARE_BITMAP(group, ds->num_ports);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
140	int port;
141
142	/* Build a mask of Multicast group members */
143	bitmap_zero(group, ds->num_ports);
144	if (ds->index == info->sw_index)
145		set_bit(info->port, group);
146	for (port = 0; port < ds->num_ports; port++)
147		if (dsa_is_dsa_port(ds, port))
148			set_bit(port, group);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
149
150	if (switchdev_trans_ph_prepare(trans))
151		return dsa_switch_mdb_prepare_bitmap(ds, mdb, group);
152
153	dsa_switch_mdb_add_bitmap(ds, mdb, group);
 
 
 
 
 
 
 
154
155	return 0;
156}
157
158static int dsa_switch_mdb_del(struct dsa_switch *ds,
159			      struct dsa_notifier_mdb_info *info)
160{
161	const struct switchdev_obj_port_mdb *mdb = info->mdb;
162
163	if (!ds->ops->port_mdb_del)
164		return -EOPNOTSUPP;
165
166	if (ds->index == info->sw_index)
167		return ds->ops->port_mdb_del(ds, info->port, mdb);
168
 
 
 
169	return 0;
170}
171
172static int
173dsa_switch_vlan_prepare_bitmap(struct dsa_switch *ds,
174			       const struct switchdev_obj_port_vlan *vlan,
175			       const unsigned long *bitmap)
176{
 
177	int port, err;
178
179	if (!ds->ops->port_vlan_prepare || !ds->ops->port_vlan_add)
180		return -EOPNOTSUPP;
181
182	for_each_set_bit(port, bitmap, ds->num_ports) {
183		err = ds->ops->port_vlan_prepare(ds, port, vlan);
 
 
 
 
 
184		if (err)
185			return err;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
186	}
187
188	return 0;
189}
190
191static void
192dsa_switch_vlan_add_bitmap(struct dsa_switch *ds,
193			   const struct switchdev_obj_port_vlan *vlan,
194			   const unsigned long *bitmap)
195{
196	int port;
 
 
 
 
197
198	for_each_set_bit(port, bitmap, ds->num_ports)
199		ds->ops->port_vlan_add(ds, port, vlan);
200}
201
202static int dsa_switch_vlan_add(struct dsa_switch *ds,
203			       struct dsa_notifier_vlan_info *info)
204{
205	const struct switchdev_obj_port_vlan *vlan = info->vlan;
206	struct switchdev_trans *trans = info->trans;
207	DECLARE_BITMAP(members, ds->num_ports);
208	int port;
209
210	/* Build a mask of VLAN members */
211	bitmap_zero(members, ds->num_ports);
212	if (ds->index == info->sw_index)
213		set_bit(info->port, members);
214	for (port = 0; port < ds->num_ports; port++)
215		if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
216			set_bit(port, members);
217
218	if (switchdev_trans_ph_prepare(trans))
219		return dsa_switch_vlan_prepare_bitmap(ds, vlan, members);
220
221	dsa_switch_vlan_add_bitmap(ds, vlan, members);
 
 
 
 
 
 
 
 
 
222
223	return 0;
224}
225
226static int dsa_switch_vlan_del(struct dsa_switch *ds,
227			       struct dsa_notifier_vlan_info *info)
 
228{
229	const struct switchdev_obj_port_vlan *vlan = info->vlan;
230
231	if (!ds->ops->port_vlan_del)
232		return -EOPNOTSUPP;
233
234	if (ds->index == info->sw_index)
235		return ds->ops->port_vlan_del(ds, info->port, vlan);
 
236
237	return 0;
238}
239
240static int dsa_switch_event(struct notifier_block *nb,
241			    unsigned long event, void *info)
242{
243	struct dsa_switch *ds = container_of(nb, struct dsa_switch, nb);
244	int err;
245
246	switch (event) {
247	case DSA_NOTIFIER_AGEING_TIME:
248		err = dsa_switch_ageing_time(ds, info);
249		break;
250	case DSA_NOTIFIER_BRIDGE_JOIN:
251		err = dsa_switch_bridge_join(ds, info);
252		break;
253	case DSA_NOTIFIER_BRIDGE_LEAVE:
254		err = dsa_switch_bridge_leave(ds, info);
255		break;
256	case DSA_NOTIFIER_FDB_ADD:
257		err = dsa_switch_fdb_add(ds, info);
258		break;
259	case DSA_NOTIFIER_FDB_DEL:
260		err = dsa_switch_fdb_del(ds, info);
261		break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
262	case DSA_NOTIFIER_MDB_ADD:
263		err = dsa_switch_mdb_add(ds, info);
264		break;
265	case DSA_NOTIFIER_MDB_DEL:
266		err = dsa_switch_mdb_del(ds, info);
267		break;
 
 
 
 
 
 
268	case DSA_NOTIFIER_VLAN_ADD:
269		err = dsa_switch_vlan_add(ds, info);
270		break;
271	case DSA_NOTIFIER_VLAN_DEL:
272		err = dsa_switch_vlan_del(ds, info);
273		break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
274	default:
275		err = -EOPNOTSUPP;
276		break;
277	}
278
279	/* Non-switchdev operations cannot be rolled back. If a DSA driver
280	 * returns an error during the chained call, switch chips may be in an
281	 * inconsistent state.
282	 */
283	if (err)
284		dev_dbg(ds->dev, "breaking chain for DSA event %lu (%d)\n",
285			event, err);
286
287	return notifier_from_errno(err);
288}
289
290int dsa_switch_register_notifier(struct dsa_switch *ds)
291{
292	ds->nb.notifier_call = dsa_switch_event;
293
294	return raw_notifier_chain_register(&ds->dst->nh, &ds->nb);
295}
296
297void dsa_switch_unregister_notifier(struct dsa_switch *ds)
298{
299	int err;
300
301	err = raw_notifier_chain_unregister(&ds->dst->nh, &ds->nb);
302	if (err)
303		dev_err(ds->dev, "failed to unregister notifier (%d)\n", err);
304}