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()
179 struct sparx5 *sparx5 = port->sparx5; in sparx5_port_bridge_join() local
180 struct net_device *ndev = port->ndev; in sparx5_port_bridge_join()
183 if (bitmap_empty(sparx5->bridge_mask, SPX5_PORTS)) in sparx5_port_bridge_join()
185 sparx5->hw_bridge_dev = bridge; in sparx5_port_bridge_join()
187 if (sparx5->hw_bridge_dev != bridge) in sparx5_port_bridge_join()
191 return -ENODEV; in sparx5_port_bridge_join()
193 set_bit(port->portno, sparx5->bridge_mask); in sparx5_port_bridge_join()
201 sparx5_mact_forget(sparx5, ndev->dev_addr, 0); in sparx5_port_bridge_join()
211 clear_bit(port->portno, sparx5->bridge_mask); in sparx5_port_bridge_join()
218 struct sparx5 *sparx5 = port->sparx5; in sparx5_port_bridge_leave() local
220 switchdev_bridge_port_unoffload(port->ndev, NULL, NULL, NULL); in sparx5_port_bridge_leave()
222 clear_bit(port->portno, sparx5->bridge_mask); in sparx5_port_bridge_leave()
223 if (bitmap_empty(sparx5->bridge_mask, SPX5_PORTS)) in sparx5_port_bridge_leave()
224 sparx5->hw_bridge_dev = NULL; in sparx5_port_bridge_leave()
227 port->vlan_aware = 0; in sparx5_port_bridge_leave()
228 port->pvid = NULL_VID; in sparx5_port_bridge_leave()
229 port->vid = NULL_VID; in sparx5_port_bridge_leave()
232 sparx5_mact_learn(sparx5, sparx5_get_pgid(sparx5, PGID_CPU), in sparx5_port_bridge_leave()
233 port->ndev->dev_addr, 0); in sparx5_port_bridge_leave()
236 __dev_mc_sync(port->ndev, sparx5_mc_sync, sparx5_mc_unsync); in sparx5_port_bridge_leave()
246 extack = netdev_notifier_info_to_extack(&info->info); in sparx5_port_changeupper()
248 if (netif_is_bridge_master(info->upper_dev)) { in sparx5_port_changeupper()
249 if (info->linking) in sparx5_port_changeupper()
250 err = sparx5_port_bridge_join(port, info->upper_dev, in sparx5_port_changeupper()
253 sparx5_port_bridge_leave(port, info->upper_dev); in sparx5_port_changeupper()
255 sparx5_vlan_port_apply(port->sparx5, port); in sparx5_port_changeupper()
264 struct sparx5 *sparx5 = port->sparx5; in sparx5_port_add_addr() local
265 u16 vid = port->pvid; in sparx5_port_add_addr()
268 sparx5_mact_learn(sparx5, sparx5_get_pgid(sparx5, PGID_CPU), in sparx5_port_add_addr()
269 port->ndev->dev_addr, vid); in sparx5_port_add_addr()
271 sparx5_mact_forget(sparx5, port->ndev->dev_addr, vid); in sparx5_port_add_addr()
285 switch (event) { in sparx5_netdevice_port_event()
315 struct net_device *dev = switchdev_work->dev; in sparx5_switchdev_bridge_fdb_event_work()
318 struct sparx5 *sparx5; in sparx5_switchdev_bridge_fdb_event_work() local
325 sparx5 = switchdev_work->sparx5; in sparx5_switchdev_bridge_fdb_event_work()
328 sparx5 = switchdev_work->sparx5; in sparx5_switchdev_bridge_fdb_event_work()
332 fdb_info = &switchdev_work->fdb_info; in sparx5_switchdev_bridge_fdb_event_work()
335 * collision with non-bridged ports. in sparx5_switchdev_bridge_fdb_event_work()
337 if (fdb_info->vid == 0) in sparx5_switchdev_bridge_fdb_event_work()
340 vid = fdb_info->vid; in sparx5_switchdev_bridge_fdb_event_work()
342 switch (switchdev_work->event) { in sparx5_switchdev_bridge_fdb_event_work()
345 sparx5_add_mact_entry(sparx5, dev, in sparx5_switchdev_bridge_fdb_event_work()
346 sparx5_get_pgid(sparx5, PGID_CPU), in sparx5_switchdev_bridge_fdb_event_work()
347 fdb_info->addr, vid); in sparx5_switchdev_bridge_fdb_event_work()
349 sparx5_add_mact_entry(sparx5, port->ndev, port->portno, in sparx5_switchdev_bridge_fdb_event_work()
350 fdb_info->addr, vid); in sparx5_switchdev_bridge_fdb_event_work()
353 sparx5_del_mact_entry(sparx5, fdb_info->addr, vid); in sparx5_switchdev_bridge_fdb_event_work()
358 kfree(switchdev_work->fdb_info.addr); in sparx5_switchdev_bridge_fdb_event_work()
375 struct sparx5 *spx5; in sparx5_switchdev_event()
378 spx5 = container_of(nb, struct sparx5, switchdev_nb); in sparx5_switchdev_event()
380 switch (event) { in sparx5_switchdev_event()
393 switchdev_work->dev = dev; in sparx5_switchdev_event()
394 switchdev_work->event = event; in sparx5_switchdev_event()
395 switchdev_work->sparx5 = spx5; in sparx5_switchdev_event()
400 INIT_WORK(&switchdev_work->work, in sparx5_switchdev_event()
402 memcpy(&switchdev_work->fdb_info, ptr, in sparx5_switchdev_event()
403 sizeof(switchdev_work->fdb_info)); in sparx5_switchdev_event()
404 switchdev_work->fdb_info.addr = kzalloc(ETH_ALEN, GFP_ATOMIC); in sparx5_switchdev_event()
405 if (!switchdev_work->fdb_info.addr) in sparx5_switchdev_event()
408 ether_addr_copy((u8 *)switchdev_work->fdb_info.addr, in sparx5_switchdev_event()
409 fdb_info->addr); in sparx5_switchdev_event()
412 sparx5_schedule_work(&switchdev_work->work); in sparx5_switchdev_event()
429 struct sparx5 *sparx5 = in sparx5_handle_port_vlan_add() local
430 container_of(nb, struct sparx5, in sparx5_handle_port_vlan_add()
434 sparx5_mact_learn(sparx5, sparx5_get_pgid(sparx5, PGID_BCAST), in sparx5_handle_port_vlan_add()
435 dev->broadcast, v->vid); in sparx5_handle_port_vlan_add()
440 return -EOPNOTSUPP; in sparx5_handle_port_vlan_add()
442 return sparx5_vlan_vid_add(port, v->vid, in sparx5_handle_port_vlan_add()
443 v->flags & BRIDGE_VLAN_INFO_PVID, in sparx5_handle_port_vlan_add()
444 v->flags & BRIDGE_VLAN_INFO_UNTAGGED); in sparx5_handle_port_vlan_add()
447 static int sparx5_alloc_mdb_entry(struct sparx5 *sparx5, in sparx5_alloc_mdb_entry() argument
458 return -ENOMEM; in sparx5_alloc_mdb_entry()
460 err = sparx5_pgid_alloc_mcast(sparx5, &pgid_idx); in sparx5_alloc_mdb_entry()
466 memcpy(entry->addr, addr, ETH_ALEN); in sparx5_alloc_mdb_entry()
467 entry->vid = vid; in sparx5_alloc_mdb_entry()
468 entry->pgid_idx = pgid_idx; in sparx5_alloc_mdb_entry()
470 mutex_lock(&sparx5->mdb_lock); in sparx5_alloc_mdb_entry()
471 list_add_tail(&entry->list, &sparx5->mdb_entries); in sparx5_alloc_mdb_entry()
472 mutex_unlock(&sparx5->mdb_lock); in sparx5_alloc_mdb_entry()
478 static void sparx5_free_mdb_entry(struct sparx5 *sparx5, in sparx5_free_mdb_entry() argument
484 mutex_lock(&sparx5->mdb_lock); in sparx5_free_mdb_entry()
485 list_for_each_entry_safe(entry, tmp, &sparx5->mdb_entries, list) { in sparx5_free_mdb_entry()
486 if ((vid == 0 || entry->vid == vid) && in sparx5_free_mdb_entry()
487 ether_addr_equal(addr, entry->addr)) { in sparx5_free_mdb_entry()
488 list_del(&entry->list); in sparx5_free_mdb_entry()
490 sparx5_pgid_free(sparx5, entry->pgid_idx); in sparx5_free_mdb_entry()
497 mutex_unlock(&sparx5->mdb_lock); in sparx5_free_mdb_entry()
500 static struct sparx5_mdb_entry *sparx5_mdb_get_entry(struct sparx5 *sparx5, in sparx5_mdb_get_entry() argument
506 mutex_lock(&sparx5->mdb_lock); in sparx5_mdb_get_entry()
507 list_for_each_entry(e, &sparx5->mdb_entries, list) { in sparx5_mdb_get_entry()
508 if (ether_addr_equal(e->addr, addr) && e->vid == vid) { in sparx5_mdb_get_entry()
515 mutex_unlock(&sparx5->mdb_lock); in sparx5_mdb_get_entry()
519 static void sparx5_cpu_copy_ena(struct sparx5 *spx5, u16 pgid, bool enable) in sparx5_cpu_copy_ena()
531 struct sparx5 *spx5 = port->sparx5; in sparx5_handle_port_mdb_add()
538 return -EOPNOTSUPP; in sparx5_handle_port_mdb_add()
540 is_host = netif_is_bridge_master(v->obj.orig_dev); in sparx5_handle_port_mdb_add()
545 if (!br_vlan_enabled(spx5->hw_bridge_dev)) in sparx5_handle_port_mdb_add()
548 vid = v->vid; in sparx5_handle_port_mdb_add()
551 entry = sparx5_mdb_get_entry(spx5, v->addr, vid); in sparx5_handle_port_mdb_add()
553 err = sparx5_alloc_mdb_entry(spx5, v->addr, vid, &entry); in sparx5_handle_port_mdb_add()
559 mutex_lock(&spx5->mdb_lock); in sparx5_handle_port_mdb_add()
562 if (is_new && ether_addr_is_ip_mcast(v->addr)) in sparx5_handle_port_mdb_add()
563 for (i = 0; i < spx5->data->consts->n_ports; i++) in sparx5_handle_port_mdb_add()
564 if (spx5->ports[i] && spx5->ports[i]->is_mrouter) in sparx5_handle_port_mdb_add()
565 sparx5_pgid_update_mask(spx5->ports[i], in sparx5_handle_port_mdb_add()
566 entry->pgid_idx, in sparx5_handle_port_mdb_add()
569 if (is_host && !entry->cpu_copy) { in sparx5_handle_port_mdb_add()
570 sparx5_cpu_copy_ena(spx5, entry->pgid_idx, true); in sparx5_handle_port_mdb_add()
571 entry->cpu_copy = true; in sparx5_handle_port_mdb_add()
573 sparx5_pgid_update_mask(port, entry->pgid_idx, true); in sparx5_handle_port_mdb_add()
574 set_bit(port->portno, entry->port_mask); in sparx5_handle_port_mdb_add()
576 mutex_unlock(&spx5->mdb_lock); in sparx5_handle_port_mdb_add()
578 sparx5_mact_learn(spx5, entry->pgid_idx, entry->addr, entry->vid); in sparx5_handle_port_mdb_add()
588 struct sparx5 *spx5 = port->sparx5; in sparx5_handle_port_mdb_del()
594 return -EOPNOTSUPP; in sparx5_handle_port_mdb_del()
596 is_host = netif_is_bridge_master(v->obj.orig_dev); in sparx5_handle_port_mdb_del()
598 if (!br_vlan_enabled(spx5->hw_bridge_dev)) in sparx5_handle_port_mdb_del()
601 vid = v->vid; in sparx5_handle_port_mdb_del()
603 entry = sparx5_mdb_get_entry(spx5, v->addr, vid); in sparx5_handle_port_mdb_del()
607 mutex_lock(&spx5->mdb_lock); in sparx5_handle_port_mdb_del()
608 if (is_host && entry->cpu_copy) { in sparx5_handle_port_mdb_del()
609 sparx5_cpu_copy_ena(spx5, entry->pgid_idx, false); in sparx5_handle_port_mdb_del()
610 entry->cpu_copy = false; in sparx5_handle_port_mdb_del()
612 clear_bit(port->portno, entry->port_mask); in sparx5_handle_port_mdb_del()
615 if (!port->is_mrouter || !ether_addr_is_ip_mcast(v->addr)) in sparx5_handle_port_mdb_del()
616 sparx5_pgid_update_mask(port, entry->pgid_idx, false); in sparx5_handle_port_mdb_del()
618 mutex_unlock(&spx5->mdb_lock); in sparx5_handle_port_mdb_del()
620 if (bitmap_empty(entry->port_mask, SPX5_PORTS) && !entry->cpu_copy) { in sparx5_handle_port_mdb_del()
624 sparx5_pgid_clear(spx5, entry->pgid_idx); in sparx5_handle_port_mdb_del()
625 sparx5_mact_forget(spx5, entry->addr, entry->vid); in sparx5_handle_port_mdb_del()
626 sparx5_free_mdb_entry(spx5, entry->addr, entry->vid); in sparx5_handle_port_mdb_del()
635 const struct switchdev_obj *obj = info->obj; in sparx5_handle_port_obj_add()
638 switch (obj->id) { in sparx5_handle_port_obj_add()
649 err = -EOPNOTSUPP; in sparx5_handle_port_obj_add()
653 info->handled = true; in sparx5_handle_port_obj_add()
666 struct sparx5 *sparx5 = in sparx5_handle_port_vlan_del() local
667 container_of(nb, struct sparx5, in sparx5_handle_port_vlan_del()
670 sparx5_mact_forget(sparx5, dev->broadcast, vid); in sparx5_handle_port_vlan_del()
675 return -EOPNOTSUPP; in sparx5_handle_port_vlan_del()
688 const struct switchdev_obj *obj = info->obj; in sparx5_handle_port_obj_del()
691 switch (obj->id) { in sparx5_handle_port_obj_del()
694 SWITCHDEV_OBJ_PORT_VLAN(obj)->vid); in sparx5_handle_port_obj_del()
702 err = -EOPNOTSUPP; in sparx5_handle_port_obj_del()
706 info->handled = true; in sparx5_handle_port_obj_del()
717 switch (event) { in sparx5_switchdev_blocking_event()
734 int sparx5_register_notifier_blocks(struct sparx5 *s5) in sparx5_register_notifier_blocks()
738 s5->netdevice_nb.notifier_call = sparx5_netdevice_event; in sparx5_register_notifier_blocks()
739 err = register_netdevice_notifier(&s5->netdevice_nb); in sparx5_register_notifier_blocks()
743 s5->switchdev_nb.notifier_call = sparx5_switchdev_event; in sparx5_register_notifier_blocks()
744 err = register_switchdev_notifier(&s5->switchdev_nb); in sparx5_register_notifier_blocks()
748 s5->switchdev_blocking_nb.notifier_call = sparx5_switchdev_blocking_event; in sparx5_register_notifier_blocks()
749 err = register_switchdev_blocking_notifier(&s5->switchdev_blocking_nb); in sparx5_register_notifier_blocks()
755 err = -ENOMEM; in sparx5_register_notifier_blocks()
762 unregister_switchdev_notifier(&s5->switchdev_nb); in sparx5_register_notifier_blocks()
764 unregister_netdevice_notifier(&s5->netdevice_nb); in sparx5_register_notifier_blocks()
769 void sparx5_unregister_notifier_blocks(struct sparx5 *s5) in sparx5_unregister_notifier_blocks()
773 unregister_switchdev_blocking_notifier(&s5->switchdev_blocking_nb); in sparx5_unregister_notifier_blocks()
774 unregister_switchdev_notifier(&s5->switchdev_nb); in sparx5_unregister_notifier_blocks()
775 unregister_netdevice_notifier(&s5->netdevice_nb); in sparx5_unregister_notifier_blocks()