Lines Matching +full:sparx5 +full:- +full:switch
1 // SPDX-License-Identifier: GPL-2.0+
2 /* Microchip Sparx5 Switch driver
19 struct sparx5 *sparx5; member
27 return -EINVAL; in sparx5_port_attr_pre_bridge_flags()
34 bool should_flood = flood_flag || port->is_mrouter; in sparx5_port_update_mcast_ip_flood()
58 struct sparx5 *sparx5 = port->sparx5; in sparx5_attr_stp_state_set() local
60 if (!test_bit(port->portno, sparx5->bridge_mask)) { in sparx5_attr_stp_state_set()
61 netdev_err(port->ndev, in sparx5_attr_stp_state_set()
62 "Controlling non-bridged port %d?\n", port->portno); in sparx5_attr_stp_state_set()
66 switch (state) { in sparx5_attr_stp_state_set()
68 set_bit(port->portno, sparx5->bridge_fwd_mask); in sparx5_attr_stp_state_set()
71 set_bit(port->portno, sparx5->bridge_lrn_mask); in sparx5_attr_stp_state_set()
76 clear_bit(port->portno, sparx5->bridge_fwd_mask); in sparx5_attr_stp_state_set()
77 clear_bit(port->portno, sparx5->bridge_lrn_mask); in sparx5_attr_stp_state_set()
82 sparx5_update_fwd(sparx5); in sparx5_attr_stp_state_set()
91 sparx5_set_ageing(port->sparx5, ageing_time); in sparx5_port_attr_ageing_set()
98 struct sparx5 *sparx5 = port->sparx5; in sparx5_port_attr_mrouter_set() local
102 if ((enable && port->is_mrouter) || (!enable && !port->is_mrouter)) in sparx5_port_attr_mrouter_set()
109 mutex_lock(&sparx5->mdb_lock); in sparx5_port_attr_mrouter_set()
110 list_for_each_entry(e, &sparx5->mdb_entries, list) { in sparx5_port_attr_mrouter_set()
111 if (!test_bit(port->portno, e->port_mask) && in sparx5_port_attr_mrouter_set()
112 ether_addr_is_ip_mcast(e->addr)) in sparx5_port_attr_mrouter_set()
113 sparx5_pgid_update_mask(port, e->pgid_idx, enable); in sparx5_port_attr_mrouter_set()
115 mutex_unlock(&sparx5->mdb_lock); in sparx5_port_attr_mrouter_set()
120 port->is_mrouter = enable; in sparx5_port_attr_mrouter_set()
121 flood_flag = br_port_flag_is_set(port->ndev, BR_MCAST_FLOOD); in sparx5_port_attr_mrouter_set()
131 switch (attr->id) { in sparx5_port_attr_set()
134 attr->u.brport_flags); in sparx5_port_attr_set()
136 sparx5_port_attr_bridge_flags(port, attr->u.brport_flags); in sparx5_port_attr_set()
139 sparx5_attr_stp_state_set(port, attr->u.stp_state); in sparx5_port_attr_set()
142 sparx5_port_attr_ageing_set(port, attr->u.ageing_time); in sparx5_port_attr_set()
146 * collision with non-bridged ports. in sparx5_port_attr_set()
148 if (port->pvid == 0) in sparx5_port_attr_set()
149 port->pvid = 1; in sparx5_port_attr_set()
150 port->vlan_aware = attr->u.vlan_filtering; in sparx5_port_attr_set()
151 sparx5_vlan_port_apply(port->sparx5, port); in sparx5_port_attr_set()
155 attr->orig_dev, in sparx5_port_attr_set()
156 attr->u.mrouter); in sparx5_port_attr_set()
159 return -EOPNOTSUPP; in sparx5_port_attr_set()
169 struct sparx5 *sparx5 = port->sparx5; in sparx5_port_bridge_join() local
170 struct net_device *ndev = port->ndev; in sparx5_port_bridge_join()
173 if (bitmap_empty(sparx5->bridge_mask, SPX5_PORTS)) in sparx5_port_bridge_join()
175 sparx5->hw_bridge_dev = bridge; in sparx5_port_bridge_join()
177 if (sparx5->hw_bridge_dev != bridge) in sparx5_port_bridge_join()
181 return -ENODEV; in sparx5_port_bridge_join()
183 set_bit(port->portno, sparx5->bridge_mask); in sparx5_port_bridge_join()
191 sparx5_mact_forget(sparx5, ndev->dev_addr, 0); in sparx5_port_bridge_join()
201 clear_bit(port->portno, sparx5->bridge_mask); in sparx5_port_bridge_join()
208 struct sparx5 *sparx5 = port->sparx5; in sparx5_port_bridge_leave() local
210 switchdev_bridge_port_unoffload(port->ndev, NULL, NULL, NULL); in sparx5_port_bridge_leave()
212 clear_bit(port->portno, sparx5->bridge_mask); in sparx5_port_bridge_leave()
213 if (bitmap_empty(sparx5->bridge_mask, SPX5_PORTS)) in sparx5_port_bridge_leave()
214 sparx5->hw_bridge_dev = NULL; in sparx5_port_bridge_leave()
217 port->vlan_aware = 0; in sparx5_port_bridge_leave()
218 port->pvid = NULL_VID; in sparx5_port_bridge_leave()
219 port->vid = NULL_VID; in sparx5_port_bridge_leave()
222 sparx5_mact_learn(sparx5, PGID_CPU, port->ndev->dev_addr, 0); in sparx5_port_bridge_leave()
225 __dev_mc_sync(port->ndev, sparx5_mc_sync, sparx5_mc_unsync); in sparx5_port_bridge_leave()
235 extack = netdev_notifier_info_to_extack(&info->info); in sparx5_port_changeupper()
237 if (netif_is_bridge_master(info->upper_dev)) { in sparx5_port_changeupper()
238 if (info->linking) in sparx5_port_changeupper()
239 err = sparx5_port_bridge_join(port, info->upper_dev, in sparx5_port_changeupper()
242 sparx5_port_bridge_leave(port, info->upper_dev); in sparx5_port_changeupper()
244 sparx5_vlan_port_apply(port->sparx5, port); in sparx5_port_changeupper()
253 struct sparx5 *sparx5 = port->sparx5; in sparx5_port_add_addr() local
254 u16 vid = port->pvid; in sparx5_port_add_addr()
257 sparx5_mact_learn(sparx5, PGID_CPU, port->ndev->dev_addr, vid); in sparx5_port_add_addr()
259 sparx5_mact_forget(sparx5, port->ndev->dev_addr, vid); in sparx5_port_add_addr()
273 switch (event) { in sparx5_netdevice_port_event()
303 struct net_device *dev = switchdev_work->dev; in sparx5_switchdev_bridge_fdb_event_work()
306 struct sparx5 *sparx5; in sparx5_switchdev_bridge_fdb_event_work() local
313 sparx5 = switchdev_work->sparx5; in sparx5_switchdev_bridge_fdb_event_work()
316 sparx5 = switchdev_work->sparx5; in sparx5_switchdev_bridge_fdb_event_work()
320 fdb_info = &switchdev_work->fdb_info; in sparx5_switchdev_bridge_fdb_event_work()
323 * collision with non-bridged ports. in sparx5_switchdev_bridge_fdb_event_work()
325 if (fdb_info->vid == 0) in sparx5_switchdev_bridge_fdb_event_work()
328 vid = fdb_info->vid; in sparx5_switchdev_bridge_fdb_event_work()
330 switch (switchdev_work->event) { in sparx5_switchdev_bridge_fdb_event_work()
333 sparx5_add_mact_entry(sparx5, dev, PGID_CPU, in sparx5_switchdev_bridge_fdb_event_work()
334 fdb_info->addr, vid); in sparx5_switchdev_bridge_fdb_event_work()
336 sparx5_add_mact_entry(sparx5, port->ndev, port->portno, in sparx5_switchdev_bridge_fdb_event_work()
337 fdb_info->addr, vid); in sparx5_switchdev_bridge_fdb_event_work()
340 sparx5_del_mact_entry(sparx5, fdb_info->addr, vid); in sparx5_switchdev_bridge_fdb_event_work()
345 kfree(switchdev_work->fdb_info.addr); in sparx5_switchdev_bridge_fdb_event_work()
362 struct sparx5 *spx5; in sparx5_switchdev_event()
365 spx5 = container_of(nb, struct sparx5, switchdev_nb); in sparx5_switchdev_event()
367 switch (event) { in sparx5_switchdev_event()
380 switchdev_work->dev = dev; in sparx5_switchdev_event()
381 switchdev_work->event = event; in sparx5_switchdev_event()
382 switchdev_work->sparx5 = spx5; in sparx5_switchdev_event()
387 INIT_WORK(&switchdev_work->work, in sparx5_switchdev_event()
389 memcpy(&switchdev_work->fdb_info, ptr, in sparx5_switchdev_event()
390 sizeof(switchdev_work->fdb_info)); in sparx5_switchdev_event()
391 switchdev_work->fdb_info.addr = kzalloc(ETH_ALEN, GFP_ATOMIC); in sparx5_switchdev_event()
392 if (!switchdev_work->fdb_info.addr) in sparx5_switchdev_event()
395 ether_addr_copy((u8 *)switchdev_work->fdb_info.addr, in sparx5_switchdev_event()
396 fdb_info->addr); in sparx5_switchdev_event()
399 sparx5_schedule_work(&switchdev_work->work); in sparx5_switchdev_event()
416 struct sparx5 *sparx5 = in sparx5_handle_port_vlan_add() local
417 container_of(nb, struct sparx5, in sparx5_handle_port_vlan_add()
421 sparx5_mact_learn(sparx5, PGID_BCAST, dev->broadcast, in sparx5_handle_port_vlan_add()
422 v->vid); in sparx5_handle_port_vlan_add()
427 return -EOPNOTSUPP; in sparx5_handle_port_vlan_add()
429 return sparx5_vlan_vid_add(port, v->vid, in sparx5_handle_port_vlan_add()
430 v->flags & BRIDGE_VLAN_INFO_PVID, in sparx5_handle_port_vlan_add()
431 v->flags & BRIDGE_VLAN_INFO_UNTAGGED); in sparx5_handle_port_vlan_add()
434 static int sparx5_alloc_mdb_entry(struct sparx5 *sparx5, in sparx5_alloc_mdb_entry() argument
445 return -ENOMEM; in sparx5_alloc_mdb_entry()
447 err = sparx5_pgid_alloc_mcast(sparx5, &pgid_idx); in sparx5_alloc_mdb_entry()
453 memcpy(entry->addr, addr, ETH_ALEN); in sparx5_alloc_mdb_entry()
454 entry->vid = vid; in sparx5_alloc_mdb_entry()
455 entry->pgid_idx = pgid_idx; in sparx5_alloc_mdb_entry()
457 mutex_lock(&sparx5->mdb_lock); in sparx5_alloc_mdb_entry()
458 list_add_tail(&entry->list, &sparx5->mdb_entries); in sparx5_alloc_mdb_entry()
459 mutex_unlock(&sparx5->mdb_lock); in sparx5_alloc_mdb_entry()
465 static void sparx5_free_mdb_entry(struct sparx5 *sparx5, in sparx5_free_mdb_entry() argument
471 mutex_lock(&sparx5->mdb_lock); in sparx5_free_mdb_entry()
472 list_for_each_entry_safe(entry, tmp, &sparx5->mdb_entries, list) { in sparx5_free_mdb_entry()
473 if ((vid == 0 || entry->vid == vid) && in sparx5_free_mdb_entry()
474 ether_addr_equal(addr, entry->addr)) { in sparx5_free_mdb_entry()
475 list_del(&entry->list); in sparx5_free_mdb_entry()
477 sparx5_pgid_free(sparx5, entry->pgid_idx); in sparx5_free_mdb_entry()
484 mutex_unlock(&sparx5->mdb_lock); in sparx5_free_mdb_entry()
487 static struct sparx5_mdb_entry *sparx5_mdb_get_entry(struct sparx5 *sparx5, in sparx5_mdb_get_entry() argument
493 mutex_lock(&sparx5->mdb_lock); in sparx5_mdb_get_entry()
494 list_for_each_entry(e, &sparx5->mdb_entries, list) { in sparx5_mdb_get_entry()
495 if (ether_addr_equal(e->addr, addr) && e->vid == vid) { in sparx5_mdb_get_entry()
502 mutex_unlock(&sparx5->mdb_lock); in sparx5_mdb_get_entry()
506 static void sparx5_cpu_copy_ena(struct sparx5 *spx5, u16 pgid, bool enable) in sparx5_cpu_copy_ena()
518 struct sparx5 *spx5 = port->sparx5; in sparx5_handle_port_mdb_add()
525 return -EOPNOTSUPP; in sparx5_handle_port_mdb_add()
527 is_host = netif_is_bridge_master(v->obj.orig_dev); in sparx5_handle_port_mdb_add()
532 if (!br_vlan_enabled(spx5->hw_bridge_dev)) in sparx5_handle_port_mdb_add()
535 vid = v->vid; in sparx5_handle_port_mdb_add()
538 entry = sparx5_mdb_get_entry(spx5, v->addr, vid); in sparx5_handle_port_mdb_add()
540 err = sparx5_alloc_mdb_entry(spx5, v->addr, vid, &entry); in sparx5_handle_port_mdb_add()
546 mutex_lock(&spx5->mdb_lock); in sparx5_handle_port_mdb_add()
549 if (is_new && ether_addr_is_ip_mcast(v->addr)) in sparx5_handle_port_mdb_add()
551 if (spx5->ports[i] && spx5->ports[i]->is_mrouter) in sparx5_handle_port_mdb_add()
552 sparx5_pgid_update_mask(spx5->ports[i], in sparx5_handle_port_mdb_add()
553 entry->pgid_idx, in sparx5_handle_port_mdb_add()
556 if (is_host && !entry->cpu_copy) { in sparx5_handle_port_mdb_add()
557 sparx5_cpu_copy_ena(spx5, entry->pgid_idx, true); in sparx5_handle_port_mdb_add()
558 entry->cpu_copy = true; in sparx5_handle_port_mdb_add()
560 sparx5_pgid_update_mask(port, entry->pgid_idx, true); in sparx5_handle_port_mdb_add()
561 set_bit(port->portno, entry->port_mask); in sparx5_handle_port_mdb_add()
563 mutex_unlock(&spx5->mdb_lock); in sparx5_handle_port_mdb_add()
565 sparx5_mact_learn(spx5, entry->pgid_idx, entry->addr, entry->vid); in sparx5_handle_port_mdb_add()
575 struct sparx5 *spx5 = port->sparx5; in sparx5_handle_port_mdb_del()
581 return -EOPNOTSUPP; in sparx5_handle_port_mdb_del()
583 is_host = netif_is_bridge_master(v->obj.orig_dev); in sparx5_handle_port_mdb_del()
585 if (!br_vlan_enabled(spx5->hw_bridge_dev)) in sparx5_handle_port_mdb_del()
588 vid = v->vid; in sparx5_handle_port_mdb_del()
590 entry = sparx5_mdb_get_entry(spx5, v->addr, vid); in sparx5_handle_port_mdb_del()
594 mutex_lock(&spx5->mdb_lock); in sparx5_handle_port_mdb_del()
595 if (is_host && entry->cpu_copy) { in sparx5_handle_port_mdb_del()
596 sparx5_cpu_copy_ena(spx5, entry->pgid_idx, false); in sparx5_handle_port_mdb_del()
597 entry->cpu_copy = false; in sparx5_handle_port_mdb_del()
599 clear_bit(port->portno, entry->port_mask); in sparx5_handle_port_mdb_del()
602 if (!port->is_mrouter || !ether_addr_is_ip_mcast(v->addr)) in sparx5_handle_port_mdb_del()
603 sparx5_pgid_update_mask(port, entry->pgid_idx, false); in sparx5_handle_port_mdb_del()
605 mutex_unlock(&spx5->mdb_lock); in sparx5_handle_port_mdb_del()
607 if (bitmap_empty(entry->port_mask, SPX5_PORTS) && !entry->cpu_copy) { in sparx5_handle_port_mdb_del()
611 sparx5_pgid_clear(spx5, entry->pgid_idx); in sparx5_handle_port_mdb_del()
612 sparx5_mact_forget(spx5, entry->addr, entry->vid); in sparx5_handle_port_mdb_del()
613 sparx5_free_mdb_entry(spx5, entry->addr, entry->vid); in sparx5_handle_port_mdb_del()
622 const struct switchdev_obj *obj = info->obj; in sparx5_handle_port_obj_add()
625 switch (obj->id) { in sparx5_handle_port_obj_add()
636 err = -EOPNOTSUPP; in sparx5_handle_port_obj_add()
640 info->handled = true; in sparx5_handle_port_obj_add()
653 struct sparx5 *sparx5 = in sparx5_handle_port_vlan_del() local
654 container_of(nb, struct sparx5, in sparx5_handle_port_vlan_del()
657 sparx5_mact_forget(sparx5, dev->broadcast, vid); in sparx5_handle_port_vlan_del()
662 return -EOPNOTSUPP; in sparx5_handle_port_vlan_del()
675 const struct switchdev_obj *obj = info->obj; in sparx5_handle_port_obj_del()
678 switch (obj->id) { in sparx5_handle_port_obj_del()
681 SWITCHDEV_OBJ_PORT_VLAN(obj)->vid); in sparx5_handle_port_obj_del()
689 err = -EOPNOTSUPP; in sparx5_handle_port_obj_del()
693 info->handled = true; in sparx5_handle_port_obj_del()
704 switch (event) { in sparx5_switchdev_blocking_event()
721 int sparx5_register_notifier_blocks(struct sparx5 *s5) in sparx5_register_notifier_blocks()
725 s5->netdevice_nb.notifier_call = sparx5_netdevice_event; in sparx5_register_notifier_blocks()
726 err = register_netdevice_notifier(&s5->netdevice_nb); in sparx5_register_notifier_blocks()
730 s5->switchdev_nb.notifier_call = sparx5_switchdev_event; in sparx5_register_notifier_blocks()
731 err = register_switchdev_notifier(&s5->switchdev_nb); in sparx5_register_notifier_blocks()
735 s5->switchdev_blocking_nb.notifier_call = sparx5_switchdev_blocking_event; in sparx5_register_notifier_blocks()
736 err = register_switchdev_blocking_notifier(&s5->switchdev_blocking_nb); in sparx5_register_notifier_blocks()
742 err = -ENOMEM; in sparx5_register_notifier_blocks()
749 unregister_switchdev_notifier(&s5->switchdev_nb); in sparx5_register_notifier_blocks()
751 unregister_netdevice_notifier(&s5->netdevice_nb); in sparx5_register_notifier_blocks()
756 void sparx5_unregister_notifier_blocks(struct sparx5 *s5) in sparx5_unregister_notifier_blocks()
760 unregister_switchdev_blocking_notifier(&s5->switchdev_blocking_nb); in sparx5_unregister_notifier_blocks()
761 unregister_switchdev_notifier(&s5->switchdev_nb); in sparx5_unregister_notifier_blocks()
762 unregister_netdevice_notifier(&s5->netdevice_nb); in sparx5_unregister_notifier_blocks()