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()
35 struct sparx5 *sparx5 = port->sparx5; in sparx5_port_update_mcast_ip_flood() local
38 for (pgid = sparx5_get_pgid(sparx5, PGID_IPV4_MC_DATA); in sparx5_port_update_mcast_ip_flood()
39 pgid <= sparx5_get_pgid(sparx5, PGID_IPV6_MC_CTRL); pgid++) in sparx5_port_update_mcast_ip_flood()
46 struct sparx5 *sparx5 = port->sparx5; in sparx5_port_attr_bridge_flags() local
50 sparx5_get_pgid(sparx5, PGID_MC_FLOOD), in sparx5_port_attr_bridge_flags()
57 sparx5_get_pgid(sparx5, PGID_UC_FLOOD), in sparx5_port_attr_bridge_flags()
61 sparx5_get_pgid(sparx5, PGID_BCAST), in sparx5_port_attr_bridge_flags()
68 struct sparx5 *sparx5 = port->sparx5; in sparx5_attr_stp_state_set() local
70 if (!test_bit(port->portno, sparx5->bridge_mask)) { in sparx5_attr_stp_state_set()
71 netdev_err(port->ndev, in sparx5_attr_stp_state_set()
72 "Controlling non-bridged port %d?\n", port->portno); in sparx5_attr_stp_state_set()
76 switch (state) { in sparx5_attr_stp_state_set()
78 set_bit(port->portno, sparx5->bridge_fwd_mask); in sparx5_attr_stp_state_set()
81 set_bit(port->portno, sparx5->bridge_lrn_mask); in sparx5_attr_stp_state_set()
86 clear_bit(port->portno, sparx5->bridge_fwd_mask); in sparx5_attr_stp_state_set()
87 clear_bit(port->portno, sparx5->bridge_lrn_mask); in sparx5_attr_stp_state_set()
92 sparx5_update_fwd(sparx5); in sparx5_attr_stp_state_set()
101 sparx5_set_ageing(port->sparx5, ageing_time); in sparx5_port_attr_ageing_set()
108 struct sparx5 *sparx5 = port->sparx5; in sparx5_port_attr_mrouter_set() local
112 if ((enable && port->is_mrouter) || (!enable && !port->is_mrouter)) in sparx5_port_attr_mrouter_set()
119 mutex_lock(&sparx5->mdb_lock); in sparx5_port_attr_mrouter_set()
120 list_for_each_entry(e, &sparx5->mdb_entries, list) { in sparx5_port_attr_mrouter_set()
121 if (!test_bit(port->portno, e->port_mask) && in sparx5_port_attr_mrouter_set()
122 ether_addr_is_ip_mcast(e->addr)) in sparx5_port_attr_mrouter_set()
123 sparx5_pgid_update_mask(port, e->pgid_idx, enable); in sparx5_port_attr_mrouter_set()
125 mutex_unlock(&sparx5->mdb_lock); in sparx5_port_attr_mrouter_set()
130 port->is_mrouter = enable; in sparx5_port_attr_mrouter_set()
131 flood_flag = br_port_flag_is_set(port->ndev, BR_MCAST_FLOOD); in sparx5_port_attr_mrouter_set()
141 switch (attr->id) { in sparx5_port_attr_set()
144 attr->u.brport_flags); in sparx5_port_attr_set()
146 sparx5_port_attr_bridge_flags(port, attr->u.brport_flags); in sparx5_port_attr_set()
149 sparx5_attr_stp_state_set(port, attr->u.stp_state); in sparx5_port_attr_set()
152 sparx5_port_attr_ageing_set(port, attr->u.ageing_time); in sparx5_port_attr_set()
156 * collision with non-bridged ports. in sparx5_port_attr_set()
158 if (port->pvid == 0) in sparx5_port_attr_set()
159 port->pvid = 1; in sparx5_port_attr_set()
160 port->vlan_aware = attr->u.vlan_filtering; in sparx5_port_attr_set()
161 sparx5_vlan_port_apply(port->sparx5, port); in sparx5_port_attr_set()
165 attr->orig_dev, in sparx5_port_attr_set()
166 attr->u.mrouter); in sparx5_port_attr_set()
169 return -EOPNOTSUPP; in sparx5_port_attr_set()
180 struct sparx5 *sparx5 = port->sparx5; in sparx5_port_bridge_join() local
181 struct net_device *ndev = port->ndev; in sparx5_port_bridge_join()
184 if (bitmap_empty(sparx5->bridge_mask, SPX5_PORTS)) in sparx5_port_bridge_join()
186 sparx5->hw_bridge_dev = bridge; in sparx5_port_bridge_join()
188 if (sparx5->hw_bridge_dev != bridge) in sparx5_port_bridge_join()
192 return -ENODEV; in sparx5_port_bridge_join()
194 set_bit(port->portno, sparx5->bridge_mask); in sparx5_port_bridge_join()
202 sparx5_mact_forget(sparx5, ndev->dev_addr, 0); in sparx5_port_bridge_join()
217 clear_bit(port->portno, sparx5->bridge_mask); in sparx5_port_bridge_join()
225 struct sparx5 *sparx5 = port->sparx5; in sparx5_port_bridge_leave() local
227 switchdev_bridge_port_unoffload(port->ndev, NULL, NULL, NULL); in sparx5_port_bridge_leave()
229 clear_bit(port->portno, sparx5->bridge_mask); in sparx5_port_bridge_leave()
230 if (bitmap_empty(sparx5->bridge_mask, SPX5_PORTS)) in sparx5_port_bridge_leave()
231 sparx5->hw_bridge_dev = NULL; in sparx5_port_bridge_leave()
234 port->vlan_aware = 0; in sparx5_port_bridge_leave()
235 port->pvid = NULL_VID; in sparx5_port_bridge_leave()
236 port->vid = NULL_VID; in sparx5_port_bridge_leave()
239 sparx5_mact_learn(sparx5, sparx5_get_pgid(sparx5, PGID_CPU), in sparx5_port_bridge_leave()
240 port->ndev->dev_addr, 0); in sparx5_port_bridge_leave()
243 __dev_mc_sync(port->ndev, sparx5_mc_sync, sparx5_mc_unsync); in sparx5_port_bridge_leave()
258 extack = netdev_notifier_info_to_extack(&info->info); in sparx5_port_changeupper()
260 if (netif_is_bridge_master(info->upper_dev)) { in sparx5_port_changeupper()
261 if (info->linking) in sparx5_port_changeupper()
262 err = sparx5_port_bridge_join(port, info->upper_dev, in sparx5_port_changeupper()
265 sparx5_port_bridge_leave(port, info->upper_dev); in sparx5_port_changeupper()
267 sparx5_vlan_port_apply(port->sparx5, port); in sparx5_port_changeupper()
276 struct sparx5 *sparx5 = port->sparx5; in sparx5_port_add_addr() local
277 u16 vid = port->pvid; in sparx5_port_add_addr()
280 sparx5_mact_learn(sparx5, sparx5_get_pgid(sparx5, PGID_CPU), in sparx5_port_add_addr()
281 port->ndev->dev_addr, vid); in sparx5_port_add_addr()
283 sparx5_mact_forget(sparx5, port->ndev->dev_addr, vid); in sparx5_port_add_addr()
297 switch (event) { in sparx5_netdevice_port_event()
327 struct net_device *dev = switchdev_work->dev; in sparx5_switchdev_bridge_fdb_event_work()
330 struct sparx5 *sparx5; in sparx5_switchdev_bridge_fdb_event_work() local
337 sparx5 = switchdev_work->sparx5; in sparx5_switchdev_bridge_fdb_event_work()
340 sparx5 = switchdev_work->sparx5; in sparx5_switchdev_bridge_fdb_event_work()
344 fdb_info = &switchdev_work->fdb_info; in sparx5_switchdev_bridge_fdb_event_work()
347 * collision with non-bridged ports. in sparx5_switchdev_bridge_fdb_event_work()
349 if (fdb_info->vid == 0) in sparx5_switchdev_bridge_fdb_event_work()
352 vid = fdb_info->vid; in sparx5_switchdev_bridge_fdb_event_work()
354 switch (switchdev_work->event) { in sparx5_switchdev_bridge_fdb_event_work()
357 sparx5_add_mact_entry(sparx5, dev, in sparx5_switchdev_bridge_fdb_event_work()
358 sparx5_get_pgid(sparx5, PGID_CPU), in sparx5_switchdev_bridge_fdb_event_work()
359 fdb_info->addr, vid); in sparx5_switchdev_bridge_fdb_event_work()
361 sparx5_add_mact_entry(sparx5, port->ndev, port->portno, in sparx5_switchdev_bridge_fdb_event_work()
362 fdb_info->addr, vid); in sparx5_switchdev_bridge_fdb_event_work()
365 sparx5_del_mact_entry(sparx5, fdb_info->addr, vid); in sparx5_switchdev_bridge_fdb_event_work()
370 kfree(switchdev_work->fdb_info.addr); in sparx5_switchdev_bridge_fdb_event_work()
387 struct sparx5 *spx5; in sparx5_switchdev_event()
390 spx5 = container_of(nb, struct sparx5, switchdev_nb); in sparx5_switchdev_event()
392 switch (event) { in sparx5_switchdev_event()
405 switchdev_work->dev = dev; in sparx5_switchdev_event()
406 switchdev_work->event = event; in sparx5_switchdev_event()
407 switchdev_work->sparx5 = spx5; in sparx5_switchdev_event()
412 INIT_WORK(&switchdev_work->work, in sparx5_switchdev_event()
414 memcpy(&switchdev_work->fdb_info, ptr, in sparx5_switchdev_event()
415 sizeof(switchdev_work->fdb_info)); in sparx5_switchdev_event()
416 switchdev_work->fdb_info.addr = kzalloc(ETH_ALEN, GFP_ATOMIC); in sparx5_switchdev_event()
417 if (!switchdev_work->fdb_info.addr) in sparx5_switchdev_event()
420 ether_addr_copy((u8 *)switchdev_work->fdb_info.addr, in sparx5_switchdev_event()
421 fdb_info->addr); in sparx5_switchdev_event()
424 sparx5_schedule_work(&switchdev_work->work); in sparx5_switchdev_event()
441 struct sparx5 *sparx5 = in sparx5_handle_port_vlan_add() local
442 container_of(nb, struct sparx5, in sparx5_handle_port_vlan_add()
446 sparx5_mact_learn(sparx5, sparx5_get_pgid(sparx5, PGID_BCAST), in sparx5_handle_port_vlan_add()
447 dev->broadcast, v->vid); in sparx5_handle_port_vlan_add()
452 return -EOPNOTSUPP; in sparx5_handle_port_vlan_add()
454 return sparx5_vlan_vid_add(port, v->vid, in sparx5_handle_port_vlan_add()
455 v->flags & BRIDGE_VLAN_INFO_PVID, in sparx5_handle_port_vlan_add()
456 v->flags & BRIDGE_VLAN_INFO_UNTAGGED); in sparx5_handle_port_vlan_add()
459 static int sparx5_alloc_mdb_entry(struct sparx5 *sparx5, in sparx5_alloc_mdb_entry() argument
470 return -ENOMEM; in sparx5_alloc_mdb_entry()
472 err = sparx5_pgid_alloc_mcast(sparx5, &pgid_idx); in sparx5_alloc_mdb_entry()
478 memcpy(entry->addr, addr, ETH_ALEN); in sparx5_alloc_mdb_entry()
479 entry->vid = vid; in sparx5_alloc_mdb_entry()
480 entry->pgid_idx = pgid_idx; in sparx5_alloc_mdb_entry()
482 mutex_lock(&sparx5->mdb_lock); in sparx5_alloc_mdb_entry()
483 list_add_tail(&entry->list, &sparx5->mdb_entries); in sparx5_alloc_mdb_entry()
484 mutex_unlock(&sparx5->mdb_lock); in sparx5_alloc_mdb_entry()
490 static void sparx5_free_mdb_entry(struct sparx5 *sparx5, in sparx5_free_mdb_entry() argument
496 mutex_lock(&sparx5->mdb_lock); in sparx5_free_mdb_entry()
497 list_for_each_entry_safe(entry, tmp, &sparx5->mdb_entries, list) { in sparx5_free_mdb_entry()
498 if ((vid == 0 || entry->vid == vid) && in sparx5_free_mdb_entry()
499 ether_addr_equal(addr, entry->addr)) { in sparx5_free_mdb_entry()
500 list_del(&entry->list); in sparx5_free_mdb_entry()
502 sparx5_pgid_free(sparx5, entry->pgid_idx); in sparx5_free_mdb_entry()
509 mutex_unlock(&sparx5->mdb_lock); in sparx5_free_mdb_entry()
512 static struct sparx5_mdb_entry *sparx5_mdb_get_entry(struct sparx5 *sparx5, in sparx5_mdb_get_entry() argument
518 mutex_lock(&sparx5->mdb_lock); in sparx5_mdb_get_entry()
519 list_for_each_entry(e, &sparx5->mdb_entries, list) { in sparx5_mdb_get_entry()
520 if (ether_addr_equal(e->addr, addr) && e->vid == vid) { in sparx5_mdb_get_entry()
527 mutex_unlock(&sparx5->mdb_lock); in sparx5_mdb_get_entry()
531 static void sparx5_cpu_copy_ena(struct sparx5 *spx5, u16 pgid, bool enable) in sparx5_cpu_copy_ena()
543 struct sparx5 *spx5 = port->sparx5; in sparx5_handle_port_mdb_add()
550 return -EOPNOTSUPP; in sparx5_handle_port_mdb_add()
552 is_host = netif_is_bridge_master(v->obj.orig_dev); in sparx5_handle_port_mdb_add()
557 if (!br_vlan_enabled(spx5->hw_bridge_dev)) in sparx5_handle_port_mdb_add()
560 vid = v->vid; in sparx5_handle_port_mdb_add()
563 entry = sparx5_mdb_get_entry(spx5, v->addr, vid); in sparx5_handle_port_mdb_add()
565 err = sparx5_alloc_mdb_entry(spx5, v->addr, vid, &entry); in sparx5_handle_port_mdb_add()
571 mutex_lock(&spx5->mdb_lock); in sparx5_handle_port_mdb_add()
574 if (is_new && ether_addr_is_ip_mcast(v->addr)) in sparx5_handle_port_mdb_add()
575 for (i = 0; i < spx5->data->consts->n_ports; i++) in sparx5_handle_port_mdb_add()
576 if (spx5->ports[i] && spx5->ports[i]->is_mrouter) in sparx5_handle_port_mdb_add()
577 sparx5_pgid_update_mask(spx5->ports[i], in sparx5_handle_port_mdb_add()
578 entry->pgid_idx, in sparx5_handle_port_mdb_add()
581 if (is_host && !entry->cpu_copy) { in sparx5_handle_port_mdb_add()
582 sparx5_cpu_copy_ena(spx5, entry->pgid_idx, true); in sparx5_handle_port_mdb_add()
583 entry->cpu_copy = true; in sparx5_handle_port_mdb_add()
585 sparx5_pgid_update_mask(port, entry->pgid_idx, true); in sparx5_handle_port_mdb_add()
586 set_bit(port->portno, entry->port_mask); in sparx5_handle_port_mdb_add()
588 mutex_unlock(&spx5->mdb_lock); in sparx5_handle_port_mdb_add()
590 sparx5_mact_learn(spx5, entry->pgid_idx, entry->addr, entry->vid); in sparx5_handle_port_mdb_add()
600 struct sparx5 *spx5 = port->sparx5; in sparx5_handle_port_mdb_del()
606 return -EOPNOTSUPP; in sparx5_handle_port_mdb_del()
608 is_host = netif_is_bridge_master(v->obj.orig_dev); in sparx5_handle_port_mdb_del()
610 if (!br_vlan_enabled(spx5->hw_bridge_dev)) in sparx5_handle_port_mdb_del()
613 vid = v->vid; in sparx5_handle_port_mdb_del()
615 entry = sparx5_mdb_get_entry(spx5, v->addr, vid); in sparx5_handle_port_mdb_del()
619 mutex_lock(&spx5->mdb_lock); in sparx5_handle_port_mdb_del()
620 if (is_host && entry->cpu_copy) { in sparx5_handle_port_mdb_del()
621 sparx5_cpu_copy_ena(spx5, entry->pgid_idx, false); in sparx5_handle_port_mdb_del()
622 entry->cpu_copy = false; in sparx5_handle_port_mdb_del()
624 clear_bit(port->portno, entry->port_mask); in sparx5_handle_port_mdb_del()
627 if (!port->is_mrouter || !ether_addr_is_ip_mcast(v->addr)) in sparx5_handle_port_mdb_del()
628 sparx5_pgid_update_mask(port, entry->pgid_idx, false); in sparx5_handle_port_mdb_del()
630 mutex_unlock(&spx5->mdb_lock); in sparx5_handle_port_mdb_del()
632 if (bitmap_empty(entry->port_mask, SPX5_PORTS) && !entry->cpu_copy) { in sparx5_handle_port_mdb_del()
636 sparx5_pgid_clear(spx5, entry->pgid_idx); in sparx5_handle_port_mdb_del()
637 sparx5_mact_forget(spx5, entry->addr, entry->vid); in sparx5_handle_port_mdb_del()
638 sparx5_free_mdb_entry(spx5, entry->addr, entry->vid); in sparx5_handle_port_mdb_del()
647 const struct switchdev_obj *obj = info->obj; in sparx5_handle_port_obj_add()
650 switch (obj->id) { in sparx5_handle_port_obj_add()
661 err = -EOPNOTSUPP; in sparx5_handle_port_obj_add()
665 info->handled = true; in sparx5_handle_port_obj_add()
678 struct sparx5 *sparx5 = in sparx5_handle_port_vlan_del() local
679 container_of(nb, struct sparx5, in sparx5_handle_port_vlan_del()
682 sparx5_mact_forget(sparx5, dev->broadcast, vid); in sparx5_handle_port_vlan_del()
687 return -EOPNOTSUPP; in sparx5_handle_port_vlan_del()
700 const struct switchdev_obj *obj = info->obj; in sparx5_handle_port_obj_del()
703 switch (obj->id) { in sparx5_handle_port_obj_del()
706 SWITCHDEV_OBJ_PORT_VLAN(obj)->vid); in sparx5_handle_port_obj_del()
714 err = -EOPNOTSUPP; in sparx5_handle_port_obj_del()
718 info->handled = true; in sparx5_handle_port_obj_del()
729 switch (event) { in sparx5_switchdev_blocking_event()
746 int sparx5_register_notifier_blocks(struct sparx5 *s5) in sparx5_register_notifier_blocks()
750 s5->netdevice_nb.notifier_call = sparx5_netdevice_event; in sparx5_register_notifier_blocks()
751 err = register_netdevice_notifier(&s5->netdevice_nb); in sparx5_register_notifier_blocks()
755 s5->switchdev_nb.notifier_call = sparx5_switchdev_event; in sparx5_register_notifier_blocks()
756 err = register_switchdev_notifier(&s5->switchdev_nb); in sparx5_register_notifier_blocks()
760 s5->switchdev_blocking_nb.notifier_call = sparx5_switchdev_blocking_event; in sparx5_register_notifier_blocks()
761 err = register_switchdev_blocking_notifier(&s5->switchdev_blocking_nb); in sparx5_register_notifier_blocks()
767 err = -ENOMEM; in sparx5_register_notifier_blocks()
774 unregister_switchdev_notifier(&s5->switchdev_nb); in sparx5_register_notifier_blocks()
776 unregister_netdevice_notifier(&s5->netdevice_nb); in sparx5_register_notifier_blocks()
781 void sparx5_unregister_notifier_blocks(struct sparx5 *s5) in sparx5_unregister_notifier_blocks()
785 unregister_switchdev_blocking_notifier(&s5->switchdev_blocking_nb); in sparx5_unregister_notifier_blocks()
786 unregister_switchdev_notifier(&s5->switchdev_nb); in sparx5_unregister_notifier_blocks()
787 unregister_netdevice_notifier(&s5->netdevice_nb); in sparx5_unregister_notifier_blocks()