File Index
Files and directories
Sign in
FILE

sparx5_switchdev.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/microchip/sparx5/sparx5_switchdev.c C
  1// SPDX-License-Identifier: GPL-2.0+
  2/* Microchip Sparx5 Switch driver
  3 *
  4 * Copyright (c) 2021 Microchip Technology Inc. and its subsidiaries.
  5 */
  6
  7#include <linux/if_bridge.h>
  8#include <net/switchdev.h>
  9
 10#include "sparx5_main_regs.h"
 11#include "sparx5_main.h"
 12
 13static struct workqueue_struct *sparx5_owq;
 14
 15struct sparx5_switchdev_event_work {
 16	struct work_struct work;
 17	struct switchdev_notifier_fdb_info fdb_info;
 18	struct net_device *dev;
 19	struct sparx5 *sparx5;
 20	unsigned long event;
 21};
 22
 23static int sparx5_port_attr_pre_bridge_flags(struct sparx5_port *port,
 24					     struct switchdev_brport_flags flags)
 25{
 26	if (flags.mask & ~(BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD))
 27		return -EINVAL;
 28
 29	return 0;
 30}
 31
 32static void sparx5_port_update_mcast_ip_flood(struct sparx5_port *port, bool flood_flag)
 33{
 34	bool should_flood = flood_flag || port->is_mrouter;
 35	struct sparx5 *sparx5 = port->sparx5;
 36	int pgid;
 37
 38	for (pgid = sparx5_get_pgid(sparx5, PGID_IPV4_MC_DATA);
 39	     pgid <= sparx5_get_pgid(sparx5, PGID_IPV6_MC_CTRL); pgid++)
 40		sparx5_pgid_update_mask(port, pgid, should_flood);
 41}
 42
 43static void sparx5_port_attr_bridge_flags(struct sparx5_port *port,
 44					  struct switchdev_brport_flags flags)
 45{
 46	struct sparx5 *sparx5 = port->sparx5;
 47
 48	if (flags.mask & BR_MCAST_FLOOD) {
 49		sparx5_pgid_update_mask(port,
 50					sparx5_get_pgid(sparx5, PGID_MC_FLOOD),
 51					!!(flags.val & BR_MCAST_FLOOD));
 52		sparx5_port_update_mcast_ip_flood(port, !!(flags.val & BR_MCAST_FLOOD));
 53	}
 54
 55	if (flags.mask & BR_FLOOD)
 56		sparx5_pgid_update_mask(port,
 57					sparx5_get_pgid(sparx5, PGID_UC_FLOOD),
 58					!!(flags.val & BR_FLOOD));
 59	if (flags.mask & BR_BCAST_FLOOD)
 60		sparx5_pgid_update_mask(port,
 61					sparx5_get_pgid(sparx5, PGID_BCAST),
 62					!!(flags.val & BR_BCAST_FLOOD));
 63}
 64
 65static void sparx5_attr_stp_state_set(struct sparx5_port *port,
 66				      u8 state)
 67{
 68	struct sparx5 *sparx5 = port->sparx5;
 69
 70	if (!test_bit(port->portno, sparx5->bridge_mask)) {
 71		netdev_err(port->ndev,
 72			   "Controlling non-bridged port %d?\n", port->portno);
 73		return;
 74	}
 75
 76	switch (state) {
 77	case BR_STATE_FORWARDING:
 78		set_bit(port->portno, sparx5->bridge_fwd_mask);
 79		fallthrough;
 80	case BR_STATE_LEARNING:
 81		set_bit(port->portno, sparx5->bridge_lrn_mask);
 82		break;
 83
 84	default:
 85		/* All other states treated as blocking */
 86		clear_bit(port->portno, sparx5->bridge_fwd_mask);
 87		clear_bit(port->portno, sparx5->bridge_lrn_mask);
 88		break;
 89	}
 90
 91	/* apply the bridge_fwd_mask to all the ports */
 92	sparx5_update_fwd(sparx5);
 93}
 94
 95static void sparx5_port_attr_ageing_set(struct sparx5_port *port,
 96					unsigned long ageing_clock_t)
 97{
 98	unsigned long ageing_jiffies = clock_t_to_jiffies(ageing_clock_t);
 99	u32 ageing_time = jiffies_to_msecs(ageing_jiffies);
100
101	sparx5_set_ageing(port->sparx5, ageing_time);
102}
103
104static void sparx5_port_attr_mrouter_set(struct sparx5_port *port,
105					 struct net_device *orig_dev,
106					 bool enable)
107{
108	struct sparx5 *sparx5 = port->sparx5;
109	struct sparx5_mdb_entry *e;
110	bool flood_flag;
111
112	if ((enable && port->is_mrouter) || (!enable && !port->is_mrouter))
113		return;
114
115	/* Add/del mrouter port on all active mdb entries in HW.
116	 * Don't change entry port mask, since that represents
117	 * ports that actually joined that group.
118	 */
119	mutex_lock(&sparx5->mdb_lock);
120	list_for_each_entry(e, &sparx5->mdb_entries, list) {
121		if (!test_bit(port->portno, e->port_mask) &&
122		    ether_addr_is_ip_mcast(e->addr))
123			sparx5_pgid_update_mask(port, e->pgid_idx, enable);
124	}
125	mutex_unlock(&sparx5->mdb_lock);
126
127	/* Enable/disable flooding depending on if port is mrouter port
128	 * or if mcast flood is enabled.
129	 */
130	port->is_mrouter = enable;
131	flood_flag = br_port_flag_is_set(port->ndev, BR_MCAST_FLOOD);
132	sparx5_port_update_mcast_ip_flood(port, flood_flag);
133}
134
135static int sparx5_port_attr_set(struct net_device *dev, const void *ctx,
136				const struct switchdev_attr *attr,
137				struct netlink_ext_ack *extack)
138{
139	struct sparx5_port *port = netdev_priv(dev);
140
141	switch (attr->id) {
142	case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS:
143		return sparx5_port_attr_pre_bridge_flags(port,
144							 attr->u.brport_flags);
145	case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:
146		sparx5_port_attr_bridge_flags(port, attr->u.brport_flags);
147		break;
148	case SWITCHDEV_ATTR_ID_PORT_STP_STATE:
149		sparx5_attr_stp_state_set(port, attr->u.stp_state);
150		break;
151	case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME:
152		sparx5_port_attr_ageing_set(port, attr->u.ageing_time);
153		break;
154	case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING:
155		/* Used PVID 1 when default_pvid is 0, to avoid
156		 * collision with non-bridged ports.
157		 */
158		if (port->pvid == 0)
159			port->pvid = 1;
160		port->vlan_aware = attr->u.vlan_filtering;
161		sparx5_vlan_port_apply(port->sparx5, port);
162		break;
163	case SWITCHDEV_ATTR_ID_PORT_MROUTER:
164		sparx5_port_attr_mrouter_set(port,
165					     attr->orig_dev,
166					     attr->u.mrouter);
167		break;
168	default:
169		return -EOPNOTSUPP;
170	}
171
172	return 0;
173}
174
175static int sparx5_port_bridge_join(struct sparx5_port *port,
176				   struct net_device *bridge,
177				   struct netlink_ext_ack *extack)
178{
179	struct switchdev_brport_flags flags = {0};
180	struct sparx5 *sparx5 = port->sparx5;
181	struct net_device *ndev = port->ndev;
182	int err;
183
184	if (bitmap_empty(sparx5->bridge_mask, SPX5_PORTS))
185		/* First bridged port */
186		sparx5->hw_bridge_dev = bridge;
187	else
188		if (sparx5->hw_bridge_dev != bridge)
189			/* This is adding the port to a second bridge, this is
190			 * unsupported
191			 */
192			return -ENODEV;
193
194	set_bit(port->portno, sparx5->bridge_mask);
195
196	err = switchdev_bridge_port_offload(ndev, ndev, NULL, NULL, NULL,
197					    false, extack);
198	if (err)
199		goto err_switchdev_offload;
200
201	/* Remove standalone port entry */
202	sparx5_mact_forget(sparx5, ndev->dev_addr, 0);
203
204	/* Port enters in bridge mode therefore don't need to copy to CPU
205	 * frames for multicast in case the bridge is not requesting them
206	 */
207	__dev_mc_unsync(ndev, sparx5_mc_unsync);
208
209	/* Enable uc/mc/bc flooding */
210	flags.mask = BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD;
211	flags.val = flags.mask;
212	sparx5_port_attr_bridge_flags(port, flags);
213
214	return 0;
215
216err_switchdev_offload:
217	clear_bit(port->portno, sparx5->bridge_mask);
218	return err;
219}
220
221static void sparx5_port_bridge_leave(struct sparx5_port *port,
222				     struct net_device *bridge)
223{
224	struct switchdev_brport_flags flags = {0};
225	struct sparx5 *sparx5 = port->sparx5;
226
227	switchdev_bridge_port_unoffload(port->ndev, NULL, NULL, NULL);
228
229	clear_bit(port->portno, sparx5->bridge_mask);
230	if (bitmap_empty(sparx5->bridge_mask, SPX5_PORTS))
231		sparx5->hw_bridge_dev = NULL;
232
233	/* Clear bridge vlan settings before updating the port settings */
234	port->vlan_aware = 0;
235	port->pvid = NULL_VID;
236	port->vid = NULL_VID;
237
238	/* Forward frames to CPU */
239	sparx5_mact_learn(sparx5, sparx5_get_pgid(sparx5, PGID_CPU),
240			  port->ndev->dev_addr, 0);
241
242	/* Port enters in host more therefore restore mc list */
243	__dev_mc_sync(port->ndev, sparx5_mc_sync, sparx5_mc_unsync);
244
245	/* Disable uc/mc/bc flooding */
246	flags.mask = BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD;
247	flags.val = 0;
248	sparx5_port_attr_bridge_flags(port, flags);
249}
250
251static int sparx5_port_changeupper(struct net_device *dev,
252				   struct netdev_notifier_changeupper_info *info)
253{
254	struct sparx5_port *port = netdev_priv(dev);
255	struct netlink_ext_ack *extack;
256	int err = 0;
257
258	extack = netdev_notifier_info_to_extack(&info->info);
259
260	if (netif_is_bridge_master(info->upper_dev)) {
261		if (info->linking)
262			err = sparx5_port_bridge_join(port, info->upper_dev,
263						      extack);
264		else
265			sparx5_port_bridge_leave(port, info->upper_dev);
266
267		sparx5_vlan_port_apply(port->sparx5, port);
268	}
269
270	return err;
271}
272
273static int sparx5_port_add_addr(struct net_device *dev, bool up)
274{
275	struct sparx5_port *port = netdev_priv(dev);
276	struct sparx5 *sparx5 = port->sparx5;
277	u16 vid = port->pvid;
278
279	if (up)
280		sparx5_mact_learn(sparx5, sparx5_get_pgid(sparx5, PGID_CPU),
281				  port->ndev->dev_addr, vid);
282	else
283		sparx5_mact_forget(sparx5, port->ndev->dev_addr, vid);
284
285	return 0;
286}
287
288static int sparx5_netdevice_port_event(struct net_device *dev,
289				       struct notifier_block *nb,
290				       unsigned long event, void *ptr)
291{
292	int err = 0;
293
294	if (!sparx5_netdevice_check(dev))
295		return 0;
296
297	switch (event) {
298	case NETDEV_CHANGEUPPER:
299		err = sparx5_port_changeupper(dev, ptr);
300		break;
301	case NETDEV_PRE_UP:
302		err = sparx5_port_add_addr(dev, true);
303		break;
304	case NETDEV_DOWN:
305		err = sparx5_port_add_addr(dev, false);
306		break;
307	}
308
309	return err;
310}
311
312static int sparx5_netdevice_event(struct notifier_block *nb,
313				  unsigned long event, void *ptr)
314{
315	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
316	int ret = 0;
317
318	ret = sparx5_netdevice_port_event(dev, nb, event, ptr);
319
320	return notifier_from_errno(ret);
321}
322
323static void sparx5_switchdev_bridge_fdb_event_work(struct work_struct *work)
324{
325	struct sparx5_switchdev_event_work *switchdev_work =
326		container_of(work, struct sparx5_switchdev_event_work, work);
327	struct net_device *dev = switchdev_work->dev;
328	struct switchdev_notifier_fdb_info *fdb_info;
329	struct sparx5_port *port;
330	struct sparx5 *sparx5;
331	bool host_addr;
332	u16 vid;
333
334	rtnl_lock();
335	if (!sparx5_netdevice_check(dev)) {
336		host_addr = true;
337		sparx5 = switchdev_work->sparx5;
338	} else {
339		host_addr = false;
340		sparx5 = switchdev_work->sparx5;
341		port = netdev_priv(dev);
342	}
343
344	fdb_info = &switchdev_work->fdb_info;
345
346	/* Used PVID 1 when default_pvid is 0, to avoid
347	 * collision with non-bridged ports.
348	 */
349	if (fdb_info->vid == 0)
350		vid = 1;
351	else
352		vid = fdb_info->vid;
353
354	switch (switchdev_work->event) {
355	case SWITCHDEV_FDB_ADD_TO_DEVICE:
356		if (host_addr)
357			sparx5_add_mact_entry(sparx5, dev,
358					      sparx5_get_pgid(sparx5, PGID_CPU),
359					      fdb_info->addr, vid);
360		else
361			sparx5_add_mact_entry(sparx5, port->ndev, port->portno,
362					      fdb_info->addr, vid);
363		break;
364	case SWITCHDEV_FDB_DEL_TO_DEVICE:
365		sparx5_del_mact_entry(sparx5, fdb_info->addr, vid);
366		break;
367	}
368
369	rtnl_unlock();
370	kfree(switchdev_work->fdb_info.addr);
371	kfree(switchdev_work);
372	dev_put(dev);
373}
374
375static void sparx5_schedule_work(struct work_struct *work)
376{
377	queue_work(sparx5_owq, work);
378}
379
380static int sparx5_switchdev_event(struct notifier_block *nb,
381				  unsigned long event, void *ptr)
382{
383	struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
384	struct sparx5_switchdev_event_work *switchdev_work;
385	struct switchdev_notifier_fdb_info *fdb_info;
386	struct switchdev_notifier_info *info = ptr;
387	struct sparx5 *spx5;
388	int err;
389
390	spx5 = container_of(nb, struct sparx5, switchdev_nb);
391
392	switch (event) {
393	case SWITCHDEV_PORT_ATTR_SET:
394		err = switchdev_handle_port_attr_set(dev, ptr,
395						     sparx5_netdevice_check,
396						     sparx5_port_attr_set);
397		return notifier_from_errno(err);
398	case SWITCHDEV_FDB_ADD_TO_DEVICE:
399		fallthrough;
400	case SWITCHDEV_FDB_DEL_TO_DEVICE:
401		switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC);
402		if (!switchdev_work)
403			return NOTIFY_BAD;
404
405		switchdev_work->dev = dev;
406		switchdev_work->event = event;
407		switchdev_work->sparx5 = spx5;
408
409		fdb_info = container_of(info,
410					struct switchdev_notifier_fdb_info,
411					info);
412		INIT_WORK(&switchdev_work->work,
413			  sparx5_switchdev_bridge_fdb_event_work);
414		memcpy(&switchdev_work->fdb_info, ptr,
415		       sizeof(switchdev_work->fdb_info));
416		switchdev_work->fdb_info.addr = kzalloc(ETH_ALEN, GFP_ATOMIC);
417		if (!switchdev_work->fdb_info.addr)
418			goto err_addr_alloc;
419
420		ether_addr_copy((u8 *)switchdev_work->fdb_info.addr,
421				fdb_info->addr);
422		dev_hold(dev);
423
424		sparx5_schedule_work(&switchdev_work->work);
425		break;
426	}
427
428	return NOTIFY_DONE;
429err_addr_alloc:
430	kfree(switchdev_work);
431	return NOTIFY_BAD;
432}
433
434static int sparx5_handle_port_vlan_add(struct net_device *dev,
435				       struct notifier_block *nb,
436				       const struct switchdev_obj_port_vlan *v)
437{
438	struct sparx5_port *port = netdev_priv(dev);
439
440	if (netif_is_bridge_master(dev)) {
441		struct sparx5 *sparx5 =
442			container_of(nb, struct sparx5,
443				     switchdev_blocking_nb);
444
445		/* Flood broadcast to CPU */
446		sparx5_mact_learn(sparx5, sparx5_get_pgid(sparx5, PGID_BCAST),
447				  dev->broadcast, v->vid);
448		return 0;
449	}
450
451	if (!sparx5_netdevice_check(dev))
452		return -EOPNOTSUPP;
453
454	return sparx5_vlan_vid_add(port, v->vid,
455				  v->flags & BRIDGE_VLAN_INFO_PVID,
456				  v->flags & BRIDGE_VLAN_INFO_UNTAGGED);
457}
458
459static int sparx5_alloc_mdb_entry(struct sparx5 *sparx5,
460				  const unsigned char *addr,
461				  u16 vid,
462				  struct sparx5_mdb_entry **entry_out)
463{
464	struct sparx5_mdb_entry *entry;
465	u16 pgid_idx;
466	int err;
467
468	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
469	if (!entry)
470		return -ENOMEM;
471
472	err = sparx5_pgid_alloc_mcast(sparx5, &pgid_idx);
473	if (err) {
474		kfree(entry);
475		return err;
476	}
477
478	memcpy(entry->addr, addr, ETH_ALEN);
479	entry->vid = vid;
480	entry->pgid_idx = pgid_idx;
481
482	mutex_lock(&sparx5->mdb_lock);
483	list_add_tail(&entry->list, &sparx5->mdb_entries);
484	mutex_unlock(&sparx5->mdb_lock);
485
486	*entry_out = entry;
487	return 0;
488}
489
490static void sparx5_free_mdb_entry(struct sparx5 *sparx5,
491				  const unsigned char *addr,
492				  u16 vid)
493{
494	struct sparx5_mdb_entry *entry, *tmp;
495
496	mutex_lock(&sparx5->mdb_lock);
497	list_for_each_entry_safe(entry, tmp, &sparx5->mdb_entries, list) {
498		if ((vid == 0 || entry->vid == vid) &&
499		    ether_addr_equal(addr, entry->addr)) {
500			list_del(&entry->list);
501
502			sparx5_pgid_free(sparx5, entry->pgid_idx);
503			kfree(entry);
504			goto out;
505		}
506	}
507
508out:
509	mutex_unlock(&sparx5->mdb_lock);
510}
511
512static struct sparx5_mdb_entry *sparx5_mdb_get_entry(struct sparx5 *sparx5,
513						     const unsigned char *addr,
514						     u16 vid)
515{
516	struct sparx5_mdb_entry *e, *found = NULL;
517
518	mutex_lock(&sparx5->mdb_lock);
519	list_for_each_entry(e, &sparx5->mdb_entries, list) {
520		if (ether_addr_equal(e->addr, addr) && e->vid == vid) {
521			found = e;
522			goto out;
523		}
524	}
525
526out:
527	mutex_unlock(&sparx5->mdb_lock);
528	return found;
529}
530
531static void sparx5_cpu_copy_ena(struct sparx5 *spx5, u16 pgid, bool enable)
532{
533	spx5_rmw(ANA_AC_PGID_MISC_CFG_PGID_CPU_COPY_ENA_SET(enable),
534		 ANA_AC_PGID_MISC_CFG_PGID_CPU_COPY_ENA, spx5,
535		 ANA_AC_PGID_MISC_CFG(pgid));
536}
537
538static int sparx5_handle_port_mdb_add(struct net_device *dev,
539				      struct notifier_block *nb,
540				      const struct switchdev_obj_port_mdb *v)
541{
542	struct sparx5_port *port = netdev_priv(dev);
543	struct sparx5 *spx5 = port->sparx5;
544	struct sparx5_mdb_entry *entry;
545	bool is_host, is_new;
546	int err, i;
547	u16 vid;
548
549	if (!sparx5_netdevice_check(dev))
550		return -EOPNOTSUPP;
551
552	is_host = netif_is_bridge_master(v->obj.orig_dev);
553
554	/* When VLAN unaware the vlan value is not parsed and we receive vid 0.
555	 * Fall back to bridge vid 1.
556	 */
557	if (!br_vlan_enabled(spx5->hw_bridge_dev))
558		vid = 1;
559	else
560		vid = v->vid;
561
562	is_new = false;
563	entry = sparx5_mdb_get_entry(spx5, v->addr, vid);
564	if (!entry) {
565		err = sparx5_alloc_mdb_entry(spx5, v->addr, vid, &entry);
566		is_new = true;
567		if (err)
568			return err;
569	}
570
571	mutex_lock(&spx5->mdb_lock);
572
573	/* Add any mrouter ports to the new entry */
574	if (is_new && ether_addr_is_ip_mcast(v->addr))
575		for (i = 0; i < spx5->data->consts->n_ports; i++)
576			if (spx5->ports[i] && spx5->ports[i]->is_mrouter)
577				sparx5_pgid_update_mask(spx5->ports[i],
578							entry->pgid_idx,
579							true);
580
581	if (is_host && !entry->cpu_copy) {
582		sparx5_cpu_copy_ena(spx5, entry->pgid_idx, true);
583		entry->cpu_copy = true;
584	} else if (!is_host) {
585		sparx5_pgid_update_mask(port, entry->pgid_idx, true);
586		set_bit(port->portno, entry->port_mask);
587	}
588	mutex_unlock(&spx5->mdb_lock);
589
590	sparx5_mact_learn(spx5, entry->pgid_idx, entry->addr, entry->vid);
591
592	return 0;
593}
594
595static int sparx5_handle_port_mdb_del(struct net_device *dev,
596				      struct notifier_block *nb,
597				      const struct switchdev_obj_port_mdb *v)
598{
599	struct sparx5_port *port = netdev_priv(dev);
600	struct sparx5 *spx5 = port->sparx5;
601	struct sparx5_mdb_entry *entry;
602	bool is_host;
603	u16 vid;
604
605	if (!sparx5_netdevice_check(dev))
606		return -EOPNOTSUPP;
607
608	is_host = netif_is_bridge_master(v->obj.orig_dev);
609
610	if (!br_vlan_enabled(spx5->hw_bridge_dev))
611		vid = 1;
612	else
613		vid = v->vid;
614
615	entry = sparx5_mdb_get_entry(spx5, v->addr, vid);
616	if (!entry)
617		return 0;
618
619	mutex_lock(&spx5->mdb_lock);
620	if (is_host && entry->cpu_copy) {
621		sparx5_cpu_copy_ena(spx5, entry->pgid_idx, false);
622		entry->cpu_copy = false;
623	} else if (!is_host) {
624		clear_bit(port->portno, entry->port_mask);
625
626		/* Port not mrouter port or addr is L2 mcast, remove port from mask. */
627		if (!port->is_mrouter || !ether_addr_is_ip_mcast(v->addr))
628			sparx5_pgid_update_mask(port, entry->pgid_idx, false);
629	}
630	mutex_unlock(&spx5->mdb_lock);
631
632	if (bitmap_empty(entry->port_mask, SPX5_PORTS) && !entry->cpu_copy) {
633		 /* Clear pgid in case mrouter ports exists
634		  * that are not part of the group.
635		  */
636		sparx5_pgid_clear(spx5, entry->pgid_idx);
637		sparx5_mact_forget(spx5, entry->addr, entry->vid);
638		sparx5_free_mdb_entry(spx5, entry->addr, entry->vid);
639	}
640	return 0;
641}
642
643static int sparx5_handle_port_obj_add(struct net_device *dev,
644				      struct notifier_block *nb,
645				      struct switchdev_notifier_port_obj_info *info)
646{
647	const struct switchdev_obj *obj = info->obj;
648	int err;
649
650	switch (obj->id) {
651	case SWITCHDEV_OBJ_ID_PORT_VLAN:
652		err = sparx5_handle_port_vlan_add(dev, nb,
653						  SWITCHDEV_OBJ_PORT_VLAN(obj));
654		break;
655	case SWITCHDEV_OBJ_ID_PORT_MDB:
656	case SWITCHDEV_OBJ_ID_HOST_MDB:
657		err = sparx5_handle_port_mdb_add(dev, nb,
658						 SWITCHDEV_OBJ_PORT_MDB(obj));
659		break;
660	default:
661		err = -EOPNOTSUPP;
662		break;
663	}
664
665	info->handled = true;
666	return err;
667}
668
669static int sparx5_handle_port_vlan_del(struct net_device *dev,
670				       struct notifier_block *nb,
671				       u16 vid)
672{
673	struct sparx5_port *port = netdev_priv(dev);
674	int ret;
675
676	/* Master bridge? */
677	if (netif_is_bridge_master(dev)) {
678		struct sparx5 *sparx5 =
679			container_of(nb, struct sparx5,
680				     switchdev_blocking_nb);
681
682		sparx5_mact_forget(sparx5, dev->broadcast, vid);
683		return 0;
684	}
685
686	if (!sparx5_netdevice_check(dev))
687		return -EOPNOTSUPP;
688
689	ret = sparx5_vlan_vid_del(port, vid);
690	if (ret)
691		return ret;
692
693	return 0;
694}
695
696static int sparx5_handle_port_obj_del(struct net_device *dev,
697				      struct notifier_block *nb,
698				      struct switchdev_notifier_port_obj_info *info)
699{
700	const struct switchdev_obj *obj = info->obj;
701	int err;
702
703	switch (obj->id) {
704	case SWITCHDEV_OBJ_ID_PORT_VLAN:
705		err = sparx5_handle_port_vlan_del(dev, nb,
706						  SWITCHDEV_OBJ_PORT_VLAN(obj)->vid);
707		break;
708	case SWITCHDEV_OBJ_ID_PORT_MDB:
709	case SWITCHDEV_OBJ_ID_HOST_MDB:
710		err = sparx5_handle_port_mdb_del(dev, nb,
711						 SWITCHDEV_OBJ_PORT_MDB(obj));
712		break;
713	default:
714		err = -EOPNOTSUPP;
715		break;
716	}
717
718	info->handled = true;
719	return err;
720}
721
722static int sparx5_switchdev_blocking_event(struct notifier_block *nb,
723					   unsigned long event,
724					   void *ptr)
725{
726	struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
727	int err;
728
729	switch (event) {
730	case SWITCHDEV_PORT_OBJ_ADD:
731		err = sparx5_handle_port_obj_add(dev, nb, ptr);
732		return notifier_from_errno(err);
733	case SWITCHDEV_PORT_OBJ_DEL:
734		err = sparx5_handle_port_obj_del(dev, nb, ptr);
735		return notifier_from_errno(err);
736	case SWITCHDEV_PORT_ATTR_SET:
737		err = switchdev_handle_port_attr_set(dev, ptr,
738						     sparx5_netdevice_check,
739						     sparx5_port_attr_set);
740		return notifier_from_errno(err);
741	}
742
743	return NOTIFY_DONE;
744}
745
746int sparx5_register_notifier_blocks(struct sparx5 *s5)
747{
748	int err;
749
750	s5->netdevice_nb.notifier_call = sparx5_netdevice_event;
751	err = register_netdevice_notifier(&s5->netdevice_nb);
752	if (err)
753		return err;
754
755	s5->switchdev_nb.notifier_call = sparx5_switchdev_event;
756	err = register_switchdev_notifier(&s5->switchdev_nb);
757	if (err)
758		goto err_switchdev_nb;
759
760	s5->switchdev_blocking_nb.notifier_call = sparx5_switchdev_blocking_event;
761	err = register_switchdev_blocking_notifier(&s5->switchdev_blocking_nb);
762	if (err)
763		goto err_switchdev_blocking_nb;
764
765	sparx5_owq = alloc_ordered_workqueue("sparx5_order", 0);
766	if (!sparx5_owq) {
767		err = -ENOMEM;
768		goto err_switchdev_blocking_nb;
769	}
770
771	return 0;
772
773err_switchdev_blocking_nb:
774	unregister_switchdev_notifier(&s5->switchdev_nb);
775err_switchdev_nb:
776	unregister_netdevice_notifier(&s5->netdevice_nb);
777
778	return err;
779}
780
781void sparx5_unregister_notifier_blocks(struct sparx5 *s5)
782{
783	destroy_workqueue(sparx5_owq);
784
785	unregister_switchdev_blocking_notifier(&s5->switchdev_blocking_nb);
786	unregister_switchdev_notifier(&s5->switchdev_nb);
787	unregister_netdevice_notifier(&s5->netdevice_nb);
788}
~/ Read-only file preview.