1*19e9bfa0SVlad Buslov // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2*19e9bfa0SVlad Buslov /* Copyright (c) 2021 Mellanox Technologies. */ 3*19e9bfa0SVlad Buslov 4*19e9bfa0SVlad Buslov #include <linux/netdevice.h> 5*19e9bfa0SVlad Buslov #include <net/netevent.h> 6*19e9bfa0SVlad Buslov #include <net/switchdev.h> 7*19e9bfa0SVlad Buslov #include "bridge.h" 8*19e9bfa0SVlad Buslov #include "esw/bridge.h" 9*19e9bfa0SVlad Buslov #include "en_rep.h" 10*19e9bfa0SVlad Buslov 11*19e9bfa0SVlad Buslov static int mlx5_esw_bridge_port_changeupper(struct notifier_block *nb, void *ptr) 12*19e9bfa0SVlad Buslov { 13*19e9bfa0SVlad Buslov struct mlx5_esw_bridge_offloads *br_offloads = container_of(nb, 14*19e9bfa0SVlad Buslov struct mlx5_esw_bridge_offloads, 15*19e9bfa0SVlad Buslov netdev_nb); 16*19e9bfa0SVlad Buslov struct net_device *dev = netdev_notifier_info_to_dev(ptr); 17*19e9bfa0SVlad Buslov struct netdev_notifier_changeupper_info *info = ptr; 18*19e9bfa0SVlad Buslov struct netlink_ext_ack *extack; 19*19e9bfa0SVlad Buslov struct mlx5e_rep_priv *rpriv; 20*19e9bfa0SVlad Buslov struct mlx5_eswitch *esw; 21*19e9bfa0SVlad Buslov struct mlx5_vport *vport; 22*19e9bfa0SVlad Buslov struct net_device *upper; 23*19e9bfa0SVlad Buslov struct mlx5e_priv *priv; 24*19e9bfa0SVlad Buslov u16 vport_num; 25*19e9bfa0SVlad Buslov 26*19e9bfa0SVlad Buslov if (!mlx5e_eswitch_rep(dev)) 27*19e9bfa0SVlad Buslov return 0; 28*19e9bfa0SVlad Buslov 29*19e9bfa0SVlad Buslov upper = info->upper_dev; 30*19e9bfa0SVlad Buslov if (!netif_is_bridge_master(upper)) 31*19e9bfa0SVlad Buslov return 0; 32*19e9bfa0SVlad Buslov 33*19e9bfa0SVlad Buslov esw = br_offloads->esw; 34*19e9bfa0SVlad Buslov priv = netdev_priv(dev); 35*19e9bfa0SVlad Buslov if (esw != priv->mdev->priv.eswitch) 36*19e9bfa0SVlad Buslov return 0; 37*19e9bfa0SVlad Buslov 38*19e9bfa0SVlad Buslov rpriv = priv->ppriv; 39*19e9bfa0SVlad Buslov vport_num = rpriv->rep->vport; 40*19e9bfa0SVlad Buslov vport = mlx5_eswitch_get_vport(esw, vport_num); 41*19e9bfa0SVlad Buslov if (IS_ERR(vport)) 42*19e9bfa0SVlad Buslov return PTR_ERR(vport); 43*19e9bfa0SVlad Buslov 44*19e9bfa0SVlad Buslov extack = netdev_notifier_info_to_extack(&info->info); 45*19e9bfa0SVlad Buslov 46*19e9bfa0SVlad Buslov return info->linking ? 47*19e9bfa0SVlad Buslov mlx5_esw_bridge_vport_link(upper->ifindex, br_offloads, vport, extack) : 48*19e9bfa0SVlad Buslov mlx5_esw_bridge_vport_unlink(upper->ifindex, br_offloads, vport, extack); 49*19e9bfa0SVlad Buslov } 50*19e9bfa0SVlad Buslov 51*19e9bfa0SVlad Buslov static int mlx5_esw_bridge_switchdev_port_event(struct notifier_block *nb, 52*19e9bfa0SVlad Buslov unsigned long event, void *ptr) 53*19e9bfa0SVlad Buslov { 54*19e9bfa0SVlad Buslov int err = 0; 55*19e9bfa0SVlad Buslov 56*19e9bfa0SVlad Buslov switch (event) { 57*19e9bfa0SVlad Buslov case NETDEV_PRECHANGEUPPER: 58*19e9bfa0SVlad Buslov break; 59*19e9bfa0SVlad Buslov 60*19e9bfa0SVlad Buslov case NETDEV_CHANGEUPPER: 61*19e9bfa0SVlad Buslov err = mlx5_esw_bridge_port_changeupper(nb, ptr); 62*19e9bfa0SVlad Buslov break; 63*19e9bfa0SVlad Buslov } 64*19e9bfa0SVlad Buslov 65*19e9bfa0SVlad Buslov return notifier_from_errno(err); 66*19e9bfa0SVlad Buslov } 67*19e9bfa0SVlad Buslov 68*19e9bfa0SVlad Buslov void mlx5e_rep_bridge_init(struct mlx5e_priv *priv) 69*19e9bfa0SVlad Buslov { 70*19e9bfa0SVlad Buslov struct mlx5_esw_bridge_offloads *br_offloads; 71*19e9bfa0SVlad Buslov struct mlx5_core_dev *mdev = priv->mdev; 72*19e9bfa0SVlad Buslov struct mlx5_eswitch *esw = 73*19e9bfa0SVlad Buslov mdev->priv.eswitch; 74*19e9bfa0SVlad Buslov int err; 75*19e9bfa0SVlad Buslov 76*19e9bfa0SVlad Buslov rtnl_lock(); 77*19e9bfa0SVlad Buslov br_offloads = mlx5_esw_bridge_init(esw); 78*19e9bfa0SVlad Buslov rtnl_unlock(); 79*19e9bfa0SVlad Buslov if (IS_ERR(br_offloads)) { 80*19e9bfa0SVlad Buslov esw_warn(mdev, "Failed to init esw bridge (err=%ld)\n", PTR_ERR(br_offloads)); 81*19e9bfa0SVlad Buslov return; 82*19e9bfa0SVlad Buslov } 83*19e9bfa0SVlad Buslov 84*19e9bfa0SVlad Buslov br_offloads->netdev_nb.notifier_call = mlx5_esw_bridge_switchdev_port_event; 85*19e9bfa0SVlad Buslov err = register_netdevice_notifier(&br_offloads->netdev_nb); 86*19e9bfa0SVlad Buslov if (err) { 87*19e9bfa0SVlad Buslov esw_warn(mdev, "Failed to register bridge offloads netdevice notifier (err=%d)\n", 88*19e9bfa0SVlad Buslov err); 89*19e9bfa0SVlad Buslov mlx5_esw_bridge_cleanup(esw); 90*19e9bfa0SVlad Buslov } 91*19e9bfa0SVlad Buslov } 92*19e9bfa0SVlad Buslov 93*19e9bfa0SVlad Buslov void mlx5e_rep_bridge_cleanup(struct mlx5e_priv *priv) 94*19e9bfa0SVlad Buslov { 95*19e9bfa0SVlad Buslov struct mlx5_esw_bridge_offloads *br_offloads; 96*19e9bfa0SVlad Buslov struct mlx5_core_dev *mdev = priv->mdev; 97*19e9bfa0SVlad Buslov struct mlx5_eswitch *esw = 98*19e9bfa0SVlad Buslov mdev->priv.eswitch; 99*19e9bfa0SVlad Buslov 100*19e9bfa0SVlad Buslov br_offloads = esw->br_offloads; 101*19e9bfa0SVlad Buslov if (!br_offloads) 102*19e9bfa0SVlad Buslov return; 103*19e9bfa0SVlad Buslov 104*19e9bfa0SVlad Buslov unregister_netdevice_notifier(&br_offloads->netdev_nb); 105*19e9bfa0SVlad Buslov rtnl_lock(); 106*19e9bfa0SVlad Buslov mlx5_esw_bridge_cleanup(esw); 107*19e9bfa0SVlad Buslov rtnl_unlock(); 108*19e9bfa0SVlad Buslov } 109