665 lines · c
1// SPDX-License-Identifier: GPL-2.0+2 3#include <linux/if_bridge.h>4#include <net/switchdev.h>5 6#include "lan966x_main.h"7 8static struct notifier_block lan966x_netdevice_nb __read_mostly;9 10static void lan966x_port_set_mcast_ip_flood(struct lan966x_port *port,11 u32 pgid_ip)12{13 struct lan966x *lan966x = port->lan966x;14 u32 flood_mask_ip;15 16 flood_mask_ip = lan_rd(lan966x, ANA_PGID(pgid_ip));17 flood_mask_ip = ANA_PGID_PGID_GET(flood_mask_ip);18 19 /* If mcast snooping is not enabled then use mcast flood mask20 * to decide to enable multicast flooding or not.21 */22 if (!port->mcast_ena) {23 u32 flood_mask;24 25 flood_mask = lan_rd(lan966x, ANA_PGID(PGID_MC));26 flood_mask = ANA_PGID_PGID_GET(flood_mask);27 28 if (flood_mask & BIT(port->chip_port))29 flood_mask_ip |= BIT(port->chip_port);30 else31 flood_mask_ip &= ~BIT(port->chip_port);32 } else {33 flood_mask_ip &= ~BIT(port->chip_port);34 }35 36 lan_rmw(ANA_PGID_PGID_SET(flood_mask_ip),37 ANA_PGID_PGID,38 lan966x, ANA_PGID(pgid_ip));39}40 41static void lan966x_port_set_mcast_flood(struct lan966x_port *port,42 bool enabled)43{44 u32 val = lan_rd(port->lan966x, ANA_PGID(PGID_MC));45 46 val = ANA_PGID_PGID_GET(val);47 if (enabled)48 val |= BIT(port->chip_port);49 else50 val &= ~BIT(port->chip_port);51 52 lan_rmw(ANA_PGID_PGID_SET(val),53 ANA_PGID_PGID,54 port->lan966x, ANA_PGID(PGID_MC));55 56 if (!port->mcast_ena) {57 lan966x_port_set_mcast_ip_flood(port, PGID_MCIPV4);58 lan966x_port_set_mcast_ip_flood(port, PGID_MCIPV6);59 }60}61 62static void lan966x_port_set_ucast_flood(struct lan966x_port *port,63 bool enabled)64{65 u32 val = lan_rd(port->lan966x, ANA_PGID(PGID_UC));66 67 val = ANA_PGID_PGID_GET(val);68 if (enabled)69 val |= BIT(port->chip_port);70 else71 val &= ~BIT(port->chip_port);72 73 lan_rmw(ANA_PGID_PGID_SET(val),74 ANA_PGID_PGID,75 port->lan966x, ANA_PGID(PGID_UC));76}77 78static void lan966x_port_set_bcast_flood(struct lan966x_port *port,79 bool enabled)80{81 u32 val = lan_rd(port->lan966x, ANA_PGID(PGID_BC));82 83 val = ANA_PGID_PGID_GET(val);84 if (enabled)85 val |= BIT(port->chip_port);86 else87 val &= ~BIT(port->chip_port);88 89 lan_rmw(ANA_PGID_PGID_SET(val),90 ANA_PGID_PGID,91 port->lan966x, ANA_PGID(PGID_BC));92}93 94static void lan966x_port_set_learning(struct lan966x_port *port, bool enabled)95{96 lan_rmw(ANA_PORT_CFG_LEARN_ENA_SET(enabled),97 ANA_PORT_CFG_LEARN_ENA,98 port->lan966x, ANA_PORT_CFG(port->chip_port));99 100 port->learn_ena = enabled;101}102 103static void lan966x_port_bridge_flags(struct lan966x_port *port,104 struct switchdev_brport_flags flags)105{106 if (flags.mask & BR_MCAST_FLOOD)107 lan966x_port_set_mcast_flood(port,108 !!(flags.val & BR_MCAST_FLOOD));109 110 if (flags.mask & BR_FLOOD)111 lan966x_port_set_ucast_flood(port,112 !!(flags.val & BR_FLOOD));113 114 if (flags.mask & BR_BCAST_FLOOD)115 lan966x_port_set_bcast_flood(port,116 !!(flags.val & BR_BCAST_FLOOD));117 118 if (flags.mask & BR_LEARNING)119 lan966x_port_set_learning(port,120 !!(flags.val & BR_LEARNING));121}122 123static int lan966x_port_pre_bridge_flags(struct lan966x_port *port,124 struct switchdev_brport_flags flags)125{126 if (flags.mask & ~(BR_MCAST_FLOOD | BR_FLOOD | BR_BCAST_FLOOD |127 BR_LEARNING))128 return -EINVAL;129 130 return 0;131}132 133void lan966x_update_fwd_mask(struct lan966x *lan966x)134{135 int i;136 137 for (i = 0; i < lan966x->num_phys_ports; i++) {138 struct lan966x_port *port = lan966x->ports[i];139 unsigned long mask = 0;140 141 if (port && lan966x->bridge_fwd_mask & BIT(i)) {142 mask = lan966x->bridge_fwd_mask & ~BIT(i);143 144 if (port->bond)145 mask &= ~lan966x_lag_get_mask(lan966x,146 port->bond);147 }148 149 mask |= BIT(CPU_PORT);150 151 lan_wr(ANA_PGID_PGID_SET(mask),152 lan966x, ANA_PGID(PGID_SRC + i));153 }154}155 156void lan966x_port_stp_state_set(struct lan966x_port *port, u8 state)157{158 struct lan966x *lan966x = port->lan966x;159 bool learn_ena = false;160 161 if ((state == BR_STATE_FORWARDING || state == BR_STATE_LEARNING) &&162 port->learn_ena)163 learn_ena = true;164 165 if (state == BR_STATE_FORWARDING)166 lan966x->bridge_fwd_mask |= BIT(port->chip_port);167 else168 lan966x->bridge_fwd_mask &= ~BIT(port->chip_port);169 170 lan_rmw(ANA_PORT_CFG_LEARN_ENA_SET(learn_ena),171 ANA_PORT_CFG_LEARN_ENA,172 lan966x, ANA_PORT_CFG(port->chip_port));173 174 lan966x_update_fwd_mask(lan966x);175}176 177void lan966x_port_ageing_set(struct lan966x_port *port,178 unsigned long ageing_clock_t)179{180 unsigned long ageing_jiffies = clock_t_to_jiffies(ageing_clock_t);181 u32 ageing_time = jiffies_to_msecs(ageing_jiffies) / 1000;182 183 lan966x_mac_set_ageing(port->lan966x, ageing_time);184}185 186static void lan966x_port_mc_set(struct lan966x_port *port, bool mcast_ena)187{188 struct lan966x *lan966x = port->lan966x;189 190 port->mcast_ena = mcast_ena;191 if (mcast_ena)192 lan966x_mdb_restore_entries(lan966x);193 else194 lan966x_mdb_clear_entries(lan966x);195 196 lan_rmw(ANA_CPU_FWD_CFG_IGMP_REDIR_ENA_SET(mcast_ena) |197 ANA_CPU_FWD_CFG_MLD_REDIR_ENA_SET(mcast_ena) |198 ANA_CPU_FWD_CFG_IPMC_CTRL_COPY_ENA_SET(mcast_ena),199 ANA_CPU_FWD_CFG_IGMP_REDIR_ENA |200 ANA_CPU_FWD_CFG_MLD_REDIR_ENA |201 ANA_CPU_FWD_CFG_IPMC_CTRL_COPY_ENA,202 lan966x, ANA_CPU_FWD_CFG(port->chip_port));203 204 lan966x_port_set_mcast_ip_flood(port, PGID_MCIPV4);205 lan966x_port_set_mcast_ip_flood(port, PGID_MCIPV6);206}207 208static int lan966x_port_attr_set(struct net_device *dev, const void *ctx,209 const struct switchdev_attr *attr,210 struct netlink_ext_ack *extack)211{212 struct lan966x_port *port = netdev_priv(dev);213 int err = 0;214 215 if (ctx && ctx != port)216 return 0;217 218 switch (attr->id) {219 case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:220 lan966x_port_bridge_flags(port, attr->u.brport_flags);221 break;222 case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS:223 err = lan966x_port_pre_bridge_flags(port, attr->u.brport_flags);224 break;225 case SWITCHDEV_ATTR_ID_PORT_STP_STATE:226 lan966x_port_stp_state_set(port, attr->u.stp_state);227 break;228 case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME:229 lan966x_port_ageing_set(port, attr->u.ageing_time);230 break;231 case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING:232 lan966x_vlan_port_set_vlan_aware(port, attr->u.vlan_filtering);233 lan966x_vlan_port_apply(port);234 break;235 case SWITCHDEV_ATTR_ID_BRIDGE_MC_DISABLED:236 lan966x_port_mc_set(port, !attr->u.mc_disabled);237 break;238 default:239 err = -EOPNOTSUPP;240 break;241 }242 243 return err;244}245 246static int lan966x_port_bridge_join(struct lan966x_port *port,247 struct net_device *brport_dev,248 struct net_device *bridge,249 struct netlink_ext_ack *extack)250{251 struct switchdev_brport_flags flags = {0};252 struct lan966x *lan966x = port->lan966x;253 struct net_device *dev = port->dev;254 int err;255 256 if (!lan966x->bridge_mask) {257 lan966x->bridge = bridge;258 } else {259 if (lan966x->bridge != bridge) {260 NL_SET_ERR_MSG_MOD(extack, "Not allow to add port to different bridge");261 return -ENODEV;262 }263 }264 265 err = switchdev_bridge_port_offload(brport_dev, dev, port,266 &lan966x_switchdev_nb,267 &lan966x_switchdev_blocking_nb,268 false, extack);269 if (err)270 return err;271 272 lan966x->bridge_mask |= BIT(port->chip_port);273 274 flags.mask = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD;275 flags.val = flags.mask;276 lan966x_port_bridge_flags(port, flags);277 278 return 0;279}280 281static void lan966x_port_bridge_leave(struct lan966x_port *port,282 struct net_device *bridge)283{284 struct switchdev_brport_flags flags = {0};285 struct lan966x *lan966x = port->lan966x;286 287 flags.mask = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD;288 flags.val = flags.mask & ~BR_LEARNING;289 lan966x_port_bridge_flags(port, flags);290 291 lan966x->bridge_mask &= ~BIT(port->chip_port);292 293 if (!lan966x->bridge_mask)294 lan966x->bridge = NULL;295 296 /* Set the port back to host mode */297 lan966x_vlan_port_set_vlan_aware(port, false);298 lan966x_vlan_port_set_vid(port, HOST_PVID, false, false);299 lan966x_vlan_port_apply(port);300}301 302int lan966x_port_changeupper(struct net_device *dev,303 struct net_device *brport_dev,304 struct netdev_notifier_changeupper_info *info)305{306 struct lan966x_port *port = netdev_priv(dev);307 struct netlink_ext_ack *extack;308 int err = 0;309 310 extack = netdev_notifier_info_to_extack(&info->info);311 312 if (netif_is_bridge_master(info->upper_dev)) {313 if (info->linking)314 err = lan966x_port_bridge_join(port, brport_dev,315 info->upper_dev,316 extack);317 else318 lan966x_port_bridge_leave(port, info->upper_dev);319 }320 321 if (netif_is_lag_master(info->upper_dev)) {322 if (info->linking)323 err = lan966x_lag_port_join(port, info->upper_dev,324 info->upper_dev,325 extack);326 else327 lan966x_lag_port_leave(port, info->upper_dev);328 }329 330 return err;331}332 333int lan966x_port_prechangeupper(struct net_device *dev,334 struct net_device *brport_dev,335 struct netdev_notifier_changeupper_info *info)336{337 struct lan966x_port *port = netdev_priv(dev);338 int err = NOTIFY_DONE;339 340 if (netif_is_bridge_master(info->upper_dev) && !info->linking) {341 switchdev_bridge_port_unoffload(port->dev, port, NULL, NULL);342 lan966x_fdb_flush_workqueue(port->lan966x);343 }344 345 if (netif_is_lag_master(info->upper_dev)) {346 err = lan966x_lag_port_prechangeupper(dev, info);347 if (err || info->linking)348 return err;349 350 switchdev_bridge_port_unoffload(brport_dev, port, NULL, NULL);351 lan966x_fdb_flush_workqueue(port->lan966x);352 }353 354 return err;355}356 357static int lan966x_foreign_bridging_check(struct net_device *upper,358 bool *has_foreign,359 bool *seen_lan966x,360 struct netlink_ext_ack *extack)361{362 struct lan966x *lan966x = NULL;363 struct net_device *dev;364 struct list_head *iter;365 366 if (!netif_is_bridge_master(upper) &&367 !netif_is_lag_master(upper))368 return 0;369 370 netdev_for_each_lower_dev(upper, dev, iter) {371 if (lan966x_netdevice_check(dev)) {372 struct lan966x_port *port = netdev_priv(dev);373 374 if (lan966x) {375 /* Upper already has at least one port of a376 * lan966x switch inside it, check that it's377 * the same instance of the driver.378 */379 if (port->lan966x != lan966x) {380 NL_SET_ERR_MSG_MOD(extack,381 "Bridging between multiple lan966x switches disallowed");382 return -EINVAL;383 }384 } else {385 /* This is the first lan966x port inside this386 * upper device387 */388 lan966x = port->lan966x;389 *seen_lan966x = true;390 }391 } else if (netif_is_lag_master(dev)) {392 /* Allow to have bond interfaces that have only lan966x393 * devices394 */395 if (lan966x_foreign_bridging_check(dev, has_foreign,396 seen_lan966x,397 extack))398 return -EINVAL;399 } else {400 *has_foreign = true;401 }402 403 if (*seen_lan966x && *has_foreign) {404 NL_SET_ERR_MSG_MOD(extack,405 "Bridging lan966x ports with foreign interfaces disallowed");406 return -EINVAL;407 }408 }409 410 return 0;411}412 413static int lan966x_bridge_check(struct net_device *dev,414 struct netdev_notifier_changeupper_info *info)415{416 bool has_foreign = false;417 bool seen_lan966x = false;418 419 return lan966x_foreign_bridging_check(info->upper_dev,420 &has_foreign,421 &seen_lan966x,422 info->info.extack);423}424 425static int lan966x_netdevice_port_event(struct net_device *dev,426 struct notifier_block *nb,427 unsigned long event, void *ptr)428{429 int err = 0;430 431 if (!lan966x_netdevice_check(dev)) {432 switch (event) {433 case NETDEV_CHANGEUPPER:434 case NETDEV_PRECHANGEUPPER:435 err = lan966x_bridge_check(dev, ptr);436 if (err)437 return err;438 439 if (netif_is_lag_master(dev)) {440 if (event == NETDEV_CHANGEUPPER)441 err = lan966x_lag_netdev_changeupper(dev,442 ptr);443 else444 err = lan966x_lag_netdev_prechangeupper(dev,445 ptr);446 447 return err;448 }449 break;450 default:451 return 0;452 }453 454 return 0;455 }456 457 switch (event) {458 case NETDEV_PRECHANGEUPPER:459 err = lan966x_port_prechangeupper(dev, dev, ptr);460 break;461 case NETDEV_CHANGEUPPER:462 err = lan966x_bridge_check(dev, ptr);463 if (err)464 return err;465 466 err = lan966x_port_changeupper(dev, dev, ptr);467 break;468 case NETDEV_CHANGELOWERSTATE:469 err = lan966x_lag_port_changelowerstate(dev, ptr);470 break;471 }472 473 return err;474}475 476static int lan966x_netdevice_event(struct notifier_block *nb,477 unsigned long event, void *ptr)478{479 struct net_device *dev = netdev_notifier_info_to_dev(ptr);480 int ret;481 482 ret = lan966x_netdevice_port_event(dev, nb, event, ptr);483 484 return notifier_from_errno(ret);485}486 487static bool lan966x_foreign_dev_check(const struct net_device *dev,488 const struct net_device *foreign_dev)489{490 struct lan966x_port *port = netdev_priv(dev);491 struct lan966x *lan966x = port->lan966x;492 int i;493 494 if (netif_is_bridge_master(foreign_dev))495 if (lan966x->bridge == foreign_dev)496 return false;497 498 if (netif_is_lag_master(foreign_dev))499 for (i = 0; i < lan966x->num_phys_ports; ++i)500 if (lan966x->ports[i] &&501 lan966x->ports[i]->bond == foreign_dev)502 return false;503 504 return true;505}506 507static int lan966x_switchdev_event(struct notifier_block *nb,508 unsigned long event, void *ptr)509{510 struct net_device *dev = switchdev_notifier_info_to_dev(ptr);511 int err;512 513 switch (event) {514 case SWITCHDEV_PORT_ATTR_SET:515 err = switchdev_handle_port_attr_set(dev, ptr,516 lan966x_netdevice_check,517 lan966x_port_attr_set);518 return notifier_from_errno(err);519 case SWITCHDEV_FDB_ADD_TO_DEVICE:520 case SWITCHDEV_FDB_DEL_TO_DEVICE:521 err = switchdev_handle_fdb_event_to_device(dev, event, ptr,522 lan966x_netdevice_check,523 lan966x_foreign_dev_check,524 lan966x_handle_fdb);525 return notifier_from_errno(err);526 }527 528 return NOTIFY_DONE;529}530 531static int lan966x_handle_port_vlan_add(struct lan966x_port *port,532 const struct switchdev_obj *obj)533{534 const struct switchdev_obj_port_vlan *v = SWITCHDEV_OBJ_PORT_VLAN(obj);535 struct lan966x *lan966x = port->lan966x;536 537 if (!netif_is_bridge_master(obj->orig_dev))538 lan966x_vlan_port_add_vlan(port, v->vid,539 v->flags & BRIDGE_VLAN_INFO_PVID,540 v->flags & BRIDGE_VLAN_INFO_UNTAGGED);541 else542 lan966x_vlan_cpu_add_vlan(lan966x, v->vid);543 544 return 0;545}546 547static int lan966x_handle_port_obj_add(struct net_device *dev, const void *ctx,548 const struct switchdev_obj *obj,549 struct netlink_ext_ack *extack)550{551 struct lan966x_port *port = netdev_priv(dev);552 int err;553 554 if (ctx && ctx != port)555 return 0;556 557 switch (obj->id) {558 case SWITCHDEV_OBJ_ID_PORT_VLAN:559 err = lan966x_handle_port_vlan_add(port, obj);560 break;561 case SWITCHDEV_OBJ_ID_PORT_MDB:562 case SWITCHDEV_OBJ_ID_HOST_MDB:563 err = lan966x_handle_port_mdb_add(port, obj);564 break;565 default:566 err = -EOPNOTSUPP;567 break;568 }569 570 return err;571}572 573static int lan966x_handle_port_vlan_del(struct lan966x_port *port,574 const struct switchdev_obj *obj)575{576 const struct switchdev_obj_port_vlan *v = SWITCHDEV_OBJ_PORT_VLAN(obj);577 struct lan966x *lan966x = port->lan966x;578 579 if (!netif_is_bridge_master(obj->orig_dev))580 lan966x_vlan_port_del_vlan(port, v->vid);581 else582 lan966x_vlan_cpu_del_vlan(lan966x, v->vid);583 584 return 0;585}586 587static int lan966x_handle_port_obj_del(struct net_device *dev, const void *ctx,588 const struct switchdev_obj *obj)589{590 struct lan966x_port *port = netdev_priv(dev);591 int err;592 593 if (ctx && ctx != port)594 return 0;595 596 switch (obj->id) {597 case SWITCHDEV_OBJ_ID_PORT_VLAN:598 err = lan966x_handle_port_vlan_del(port, obj);599 break;600 case SWITCHDEV_OBJ_ID_PORT_MDB:601 case SWITCHDEV_OBJ_ID_HOST_MDB:602 err = lan966x_handle_port_mdb_del(port, obj);603 break;604 default:605 err = -EOPNOTSUPP;606 break;607 }608 609 return err;610}611 612static int lan966x_switchdev_blocking_event(struct notifier_block *nb,613 unsigned long event,614 void *ptr)615{616 struct net_device *dev = switchdev_notifier_info_to_dev(ptr);617 int err;618 619 switch (event) {620 case SWITCHDEV_PORT_OBJ_ADD:621 err = switchdev_handle_port_obj_add(dev, ptr,622 lan966x_netdevice_check,623 lan966x_handle_port_obj_add);624 return notifier_from_errno(err);625 case SWITCHDEV_PORT_OBJ_DEL:626 err = switchdev_handle_port_obj_del(dev, ptr,627 lan966x_netdevice_check,628 lan966x_handle_port_obj_del);629 return notifier_from_errno(err);630 case SWITCHDEV_PORT_ATTR_SET:631 err = switchdev_handle_port_attr_set(dev, ptr,632 lan966x_netdevice_check,633 lan966x_port_attr_set);634 return notifier_from_errno(err);635 }636 637 return NOTIFY_DONE;638}639 640static struct notifier_block lan966x_netdevice_nb __read_mostly = {641 .notifier_call = lan966x_netdevice_event,642};643 644struct notifier_block lan966x_switchdev_nb __read_mostly = {645 .notifier_call = lan966x_switchdev_event,646};647 648struct notifier_block lan966x_switchdev_blocking_nb __read_mostly = {649 .notifier_call = lan966x_switchdev_blocking_event,650};651 652void lan966x_register_notifier_blocks(void)653{654 register_netdevice_notifier(&lan966x_netdevice_nb);655 register_switchdev_notifier(&lan966x_switchdev_nb);656 register_switchdev_blocking_notifier(&lan966x_switchdev_blocking_nb);657}658 659void lan966x_unregister_notifier_blocks(void)660{661 unregister_switchdev_blocking_notifier(&lan966x_switchdev_blocking_nb);662 unregister_switchdev_notifier(&lan966x_switchdev_nb);663 unregister_netdevice_notifier(&lan966x_netdevice_nb);664}665