119e9bfa0SVlad Buslov // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 219e9bfa0SVlad Buslov /* Copyright (c) 2021 Mellanox Technologies. */ 319e9bfa0SVlad Buslov 419e9bfa0SVlad Buslov #include <linux/netdevice.h> 5c636a0f0SVlad Buslov #include <linux/if_bridge.h> 619e9bfa0SVlad Buslov #include <net/netevent.h> 719e9bfa0SVlad Buslov #include <net/switchdev.h> 819e9bfa0SVlad Buslov #include "bridge.h" 919e9bfa0SVlad Buslov #include "esw/bridge.h" 1019e9bfa0SVlad Buslov #include "en_rep.h" 1119e9bfa0SVlad Buslov 12c636a0f0SVlad Buslov #define MLX5_ESW_BRIDGE_UPDATE_INTERVAL 1000 13c636a0f0SVlad Buslov 147cd6a54aSVlad Buslov struct mlx5_bridge_switchdev_fdb_work { 157cd6a54aSVlad Buslov struct work_struct work; 167cd6a54aSVlad Buslov struct switchdev_notifier_fdb_info fdb_info; 177cd6a54aSVlad Buslov struct net_device *dev; 187cd6a54aSVlad Buslov bool add; 197cd6a54aSVlad Buslov }; 207cd6a54aSVlad Buslov 21*3ee6233eSVlad Buslov static bool mlx5_esw_bridge_dev_same_esw(struct net_device *dev, struct mlx5_eswitch *esw) 22*3ee6233eSVlad Buslov { 23*3ee6233eSVlad Buslov struct mlx5e_priv *priv = netdev_priv(dev); 24*3ee6233eSVlad Buslov 25*3ee6233eSVlad Buslov return esw == priv->mdev->priv.eswitch; 26*3ee6233eSVlad Buslov } 27*3ee6233eSVlad Buslov 28*3ee6233eSVlad Buslov static int mlx5_esw_bridge_vport_num_vhca_id_get(struct net_device *dev, struct mlx5_eswitch *esw, 29*3ee6233eSVlad Buslov u16 *vport_num, u16 *esw_owner_vhca_id) 30*3ee6233eSVlad Buslov { 31*3ee6233eSVlad Buslov struct mlx5e_rep_priv *rpriv; 32*3ee6233eSVlad Buslov struct mlx5e_priv *priv; 33*3ee6233eSVlad Buslov 34*3ee6233eSVlad Buslov if (!mlx5e_eswitch_rep(dev) || !mlx5_esw_bridge_dev_same_esw(dev, esw)) 35*3ee6233eSVlad Buslov return -ENODEV; 36*3ee6233eSVlad Buslov 37*3ee6233eSVlad Buslov priv = netdev_priv(dev); 38*3ee6233eSVlad Buslov rpriv = priv->ppriv; 39*3ee6233eSVlad Buslov *vport_num = rpriv->rep->vport; 40*3ee6233eSVlad Buslov *esw_owner_vhca_id = MLX5_CAP_GEN(priv->mdev, vhca_id); 41*3ee6233eSVlad Buslov return 0; 42*3ee6233eSVlad Buslov } 43*3ee6233eSVlad Buslov 44*3ee6233eSVlad Buslov static int 45*3ee6233eSVlad Buslov mlx5_esw_bridge_lower_rep_vport_num_vhca_id_get(struct net_device *dev, struct mlx5_eswitch *esw, 46*3ee6233eSVlad Buslov u16 *vport_num, u16 *esw_owner_vhca_id) 47*3ee6233eSVlad Buslov { 48*3ee6233eSVlad Buslov struct net_device *lower_dev; 49*3ee6233eSVlad Buslov struct list_head *iter; 50*3ee6233eSVlad Buslov 51*3ee6233eSVlad Buslov if (mlx5e_eswitch_rep(dev) && mlx5_esw_bridge_dev_same_esw(dev, esw)) 52*3ee6233eSVlad Buslov return mlx5_esw_bridge_vport_num_vhca_id_get(dev, esw, vport_num, 53*3ee6233eSVlad Buslov esw_owner_vhca_id); 54*3ee6233eSVlad Buslov 55*3ee6233eSVlad Buslov netdev_for_each_lower_dev(dev, lower_dev, iter) { 56*3ee6233eSVlad Buslov int err; 57*3ee6233eSVlad Buslov 58*3ee6233eSVlad Buslov if (netif_is_bridge_master(lower_dev)) 59*3ee6233eSVlad Buslov continue; 60*3ee6233eSVlad Buslov 61*3ee6233eSVlad Buslov err = mlx5_esw_bridge_lower_rep_vport_num_vhca_id_get(lower_dev, esw, vport_num, 62*3ee6233eSVlad Buslov esw_owner_vhca_id); 63*3ee6233eSVlad Buslov if (!err) 64*3ee6233eSVlad Buslov return 0; 65*3ee6233eSVlad Buslov } 66*3ee6233eSVlad Buslov 67*3ee6233eSVlad Buslov return -ENODEV; 68*3ee6233eSVlad Buslov } 69*3ee6233eSVlad Buslov 7019e9bfa0SVlad Buslov static int mlx5_esw_bridge_port_changeupper(struct notifier_block *nb, void *ptr) 7119e9bfa0SVlad Buslov { 7219e9bfa0SVlad Buslov struct mlx5_esw_bridge_offloads *br_offloads = container_of(nb, 7319e9bfa0SVlad Buslov struct mlx5_esw_bridge_offloads, 7419e9bfa0SVlad Buslov netdev_nb); 7519e9bfa0SVlad Buslov struct net_device *dev = netdev_notifier_info_to_dev(ptr); 7619e9bfa0SVlad Buslov struct netdev_notifier_changeupper_info *info = ptr; 77*3ee6233eSVlad Buslov struct net_device *upper = info->upper_dev; 78*3ee6233eSVlad Buslov u16 vport_num, esw_owner_vhca_id; 7919e9bfa0SVlad Buslov struct netlink_ext_ack *extack; 80*3ee6233eSVlad Buslov int ifindex = upper->ifindex; 81*3ee6233eSVlad Buslov int err; 8219e9bfa0SVlad Buslov 8319e9bfa0SVlad Buslov if (!netif_is_bridge_master(upper)) 8419e9bfa0SVlad Buslov return 0; 8519e9bfa0SVlad Buslov 86*3ee6233eSVlad Buslov err = mlx5_esw_bridge_vport_num_vhca_id_get(dev, br_offloads->esw, &vport_num, 87*3ee6233eSVlad Buslov &esw_owner_vhca_id); 88*3ee6233eSVlad Buslov if (err) 8919e9bfa0SVlad Buslov return 0; 9019e9bfa0SVlad Buslov 9119e9bfa0SVlad Buslov extack = netdev_notifier_info_to_extack(&info->info); 9219e9bfa0SVlad Buslov 9319e9bfa0SVlad Buslov return info->linking ? 94*3ee6233eSVlad Buslov mlx5_esw_bridge_vport_link(ifindex, vport_num, esw_owner_vhca_id, br_offloads, 95*3ee6233eSVlad Buslov extack) : 96*3ee6233eSVlad Buslov mlx5_esw_bridge_vport_unlink(ifindex, vport_num, esw_owner_vhca_id, br_offloads, 97*3ee6233eSVlad Buslov extack); 9819e9bfa0SVlad Buslov } 9919e9bfa0SVlad Buslov 10019e9bfa0SVlad Buslov static int mlx5_esw_bridge_switchdev_port_event(struct notifier_block *nb, 10119e9bfa0SVlad Buslov unsigned long event, void *ptr) 10219e9bfa0SVlad Buslov { 10319e9bfa0SVlad Buslov int err = 0; 10419e9bfa0SVlad Buslov 10519e9bfa0SVlad Buslov switch (event) { 10619e9bfa0SVlad Buslov case NETDEV_PRECHANGEUPPER: 10719e9bfa0SVlad Buslov break; 10819e9bfa0SVlad Buslov 10919e9bfa0SVlad Buslov case NETDEV_CHANGEUPPER: 11019e9bfa0SVlad Buslov err = mlx5_esw_bridge_port_changeupper(nb, ptr); 11119e9bfa0SVlad Buslov break; 11219e9bfa0SVlad Buslov } 11319e9bfa0SVlad Buslov 11419e9bfa0SVlad Buslov return notifier_from_errno(err); 11519e9bfa0SVlad Buslov } 11619e9bfa0SVlad Buslov 117*3ee6233eSVlad Buslov static int 118*3ee6233eSVlad Buslov mlx5_esw_bridge_port_obj_add(struct net_device *dev, 119*3ee6233eSVlad Buslov struct switchdev_notifier_port_obj_info *port_obj_info, 120*3ee6233eSVlad Buslov struct mlx5_esw_bridge_offloads *br_offloads) 121d75b9e80SVlad Buslov { 122*3ee6233eSVlad Buslov struct netlink_ext_ack *extack = switchdev_notifier_info_to_extack(&port_obj_info->info); 123*3ee6233eSVlad Buslov const struct switchdev_obj *obj = port_obj_info->obj; 124d75b9e80SVlad Buslov const struct switchdev_obj_port_vlan *vlan; 125*3ee6233eSVlad Buslov u16 vport_num, esw_owner_vhca_id; 126*3ee6233eSVlad Buslov int err; 127d75b9e80SVlad Buslov 128*3ee6233eSVlad Buslov err = mlx5_esw_bridge_vport_num_vhca_id_get(dev, br_offloads->esw, &vport_num, 129*3ee6233eSVlad Buslov &esw_owner_vhca_id); 130*3ee6233eSVlad Buslov if (err) 131*3ee6233eSVlad Buslov return 0; 132*3ee6233eSVlad Buslov 133*3ee6233eSVlad Buslov port_obj_info->handled = true; 134d75b9e80SVlad Buslov 135d75b9e80SVlad Buslov switch (obj->id) { 136d75b9e80SVlad Buslov case SWITCHDEV_OBJ_ID_PORT_VLAN: 137d75b9e80SVlad Buslov vlan = SWITCHDEV_OBJ_PORT_VLAN(obj); 138*3ee6233eSVlad Buslov err = mlx5_esw_bridge_port_vlan_add(vport_num, esw_owner_vhca_id, vlan->vid, 139*3ee6233eSVlad Buslov vlan->flags, br_offloads, extack); 140d75b9e80SVlad Buslov break; 141d75b9e80SVlad Buslov default: 142d75b9e80SVlad Buslov return -EOPNOTSUPP; 143d75b9e80SVlad Buslov } 144d75b9e80SVlad Buslov return err; 145d75b9e80SVlad Buslov } 146d75b9e80SVlad Buslov 147*3ee6233eSVlad Buslov static int 148*3ee6233eSVlad Buslov mlx5_esw_bridge_port_obj_del(struct net_device *dev, 149*3ee6233eSVlad Buslov struct switchdev_notifier_port_obj_info *port_obj_info, 150*3ee6233eSVlad Buslov struct mlx5_esw_bridge_offloads *br_offloads) 151d75b9e80SVlad Buslov { 152*3ee6233eSVlad Buslov const struct switchdev_obj *obj = port_obj_info->obj; 153d75b9e80SVlad Buslov const struct switchdev_obj_port_vlan *vlan; 154*3ee6233eSVlad Buslov u16 vport_num, esw_owner_vhca_id; 155*3ee6233eSVlad Buslov int err; 156d75b9e80SVlad Buslov 157*3ee6233eSVlad Buslov err = mlx5_esw_bridge_vport_num_vhca_id_get(dev, br_offloads->esw, &vport_num, 158*3ee6233eSVlad Buslov &esw_owner_vhca_id); 159*3ee6233eSVlad Buslov if (err) 160*3ee6233eSVlad Buslov return 0; 161*3ee6233eSVlad Buslov 162*3ee6233eSVlad Buslov port_obj_info->handled = true; 163d75b9e80SVlad Buslov 164d75b9e80SVlad Buslov switch (obj->id) { 165d75b9e80SVlad Buslov case SWITCHDEV_OBJ_ID_PORT_VLAN: 166d75b9e80SVlad Buslov vlan = SWITCHDEV_OBJ_PORT_VLAN(obj); 167*3ee6233eSVlad Buslov mlx5_esw_bridge_port_vlan_del(vport_num, esw_owner_vhca_id, vlan->vid, br_offloads); 168d75b9e80SVlad Buslov break; 169d75b9e80SVlad Buslov default: 170d75b9e80SVlad Buslov return -EOPNOTSUPP; 171d75b9e80SVlad Buslov } 172d75b9e80SVlad Buslov return 0; 173d75b9e80SVlad Buslov } 174d75b9e80SVlad Buslov 175*3ee6233eSVlad Buslov static int 176*3ee6233eSVlad Buslov mlx5_esw_bridge_port_obj_attr_set(struct net_device *dev, 177*3ee6233eSVlad Buslov struct switchdev_notifier_port_attr_info *port_attr_info, 178*3ee6233eSVlad Buslov struct mlx5_esw_bridge_offloads *br_offloads) 179c636a0f0SVlad Buslov { 180*3ee6233eSVlad Buslov struct netlink_ext_ack *extack = switchdev_notifier_info_to_extack(&port_attr_info->info); 181*3ee6233eSVlad Buslov const struct switchdev_attr *attr = port_attr_info->attr; 182*3ee6233eSVlad Buslov u16 vport_num, esw_owner_vhca_id; 183*3ee6233eSVlad Buslov int err; 184c636a0f0SVlad Buslov 185*3ee6233eSVlad Buslov err = mlx5_esw_bridge_lower_rep_vport_num_vhca_id_get(dev, br_offloads->esw, &vport_num, 186*3ee6233eSVlad Buslov &esw_owner_vhca_id); 187*3ee6233eSVlad Buslov if (err) 188*3ee6233eSVlad Buslov return 0; 189*3ee6233eSVlad Buslov 190*3ee6233eSVlad Buslov port_attr_info->handled = true; 191c636a0f0SVlad Buslov 192c636a0f0SVlad Buslov switch (attr->id) { 193c636a0f0SVlad Buslov case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS: 194c636a0f0SVlad Buslov if (attr->u.brport_flags.mask & ~(BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD)) { 195c636a0f0SVlad Buslov NL_SET_ERR_MSG_MOD(extack, "Flag is not supported"); 196c636a0f0SVlad Buslov err = -EINVAL; 197c636a0f0SVlad Buslov } 198c636a0f0SVlad Buslov break; 199c636a0f0SVlad Buslov case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS: 200c636a0f0SVlad Buslov break; 201c636a0f0SVlad Buslov case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME: 202*3ee6233eSVlad Buslov err = mlx5_esw_bridge_ageing_time_set(vport_num, esw_owner_vhca_id, 203*3ee6233eSVlad Buslov attr->u.ageing_time, br_offloads); 204c636a0f0SVlad Buslov break; 205d75b9e80SVlad Buslov case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING: 206*3ee6233eSVlad Buslov err = mlx5_esw_bridge_vlan_filtering_set(vport_num, esw_owner_vhca_id, 207*3ee6233eSVlad Buslov attr->u.vlan_filtering, br_offloads); 208d75b9e80SVlad Buslov break; 209c636a0f0SVlad Buslov default: 210c636a0f0SVlad Buslov err = -EOPNOTSUPP; 211c636a0f0SVlad Buslov } 212c636a0f0SVlad Buslov 213c636a0f0SVlad Buslov return err; 214c636a0f0SVlad Buslov } 215c636a0f0SVlad Buslov 216*3ee6233eSVlad Buslov static int mlx5_esw_bridge_event_blocking(struct notifier_block *nb, 217c636a0f0SVlad Buslov unsigned long event, void *ptr) 218c636a0f0SVlad Buslov { 219*3ee6233eSVlad Buslov struct mlx5_esw_bridge_offloads *br_offloads = container_of(nb, 220*3ee6233eSVlad Buslov struct mlx5_esw_bridge_offloads, 221*3ee6233eSVlad Buslov nb_blk); 222c636a0f0SVlad Buslov struct net_device *dev = switchdev_notifier_info_to_dev(ptr); 223c636a0f0SVlad Buslov int err; 224c636a0f0SVlad Buslov 225c636a0f0SVlad Buslov switch (event) { 226d75b9e80SVlad Buslov case SWITCHDEV_PORT_OBJ_ADD: 227*3ee6233eSVlad Buslov err = mlx5_esw_bridge_port_obj_add(dev, ptr, br_offloads); 228d75b9e80SVlad Buslov break; 229d75b9e80SVlad Buslov case SWITCHDEV_PORT_OBJ_DEL: 230*3ee6233eSVlad Buslov err = mlx5_esw_bridge_port_obj_del(dev, ptr, br_offloads); 231d75b9e80SVlad Buslov break; 232c636a0f0SVlad Buslov case SWITCHDEV_PORT_ATTR_SET: 233*3ee6233eSVlad Buslov err = mlx5_esw_bridge_port_obj_attr_set(dev, ptr, br_offloads); 234c636a0f0SVlad Buslov break; 235c636a0f0SVlad Buslov default: 236c636a0f0SVlad Buslov err = 0; 237c636a0f0SVlad Buslov } 238c636a0f0SVlad Buslov 239c636a0f0SVlad Buslov return notifier_from_errno(err); 240c636a0f0SVlad Buslov } 241c636a0f0SVlad Buslov 2427cd6a54aSVlad Buslov static void 2437cd6a54aSVlad Buslov mlx5_esw_bridge_cleanup_switchdev_fdb_work(struct mlx5_bridge_switchdev_fdb_work *fdb_work) 2447cd6a54aSVlad Buslov { 2457cd6a54aSVlad Buslov dev_put(fdb_work->dev); 2467cd6a54aSVlad Buslov kfree(fdb_work->fdb_info.addr); 2477cd6a54aSVlad Buslov kfree(fdb_work); 2487cd6a54aSVlad Buslov } 2497cd6a54aSVlad Buslov 2507cd6a54aSVlad Buslov static void mlx5_esw_bridge_switchdev_fdb_event_work(struct work_struct *work) 2517cd6a54aSVlad Buslov { 2527cd6a54aSVlad Buslov struct mlx5_bridge_switchdev_fdb_work *fdb_work = 2537cd6a54aSVlad Buslov container_of(work, struct mlx5_bridge_switchdev_fdb_work, work); 2547cd6a54aSVlad Buslov struct switchdev_notifier_fdb_info *fdb_info = 2557cd6a54aSVlad Buslov &fdb_work->fdb_info; 256*3ee6233eSVlad Buslov struct mlx5_esw_bridge_offloads *br_offloads; 2577cd6a54aSVlad Buslov struct net_device *dev = fdb_work->dev; 258*3ee6233eSVlad Buslov u16 vport_num, esw_owner_vhca_id; 2597cd6a54aSVlad Buslov struct mlx5e_priv *priv; 260*3ee6233eSVlad Buslov int err; 2617cd6a54aSVlad Buslov 2627cd6a54aSVlad Buslov rtnl_lock(); 2637cd6a54aSVlad Buslov 2647cd6a54aSVlad Buslov priv = netdev_priv(dev); 265*3ee6233eSVlad Buslov br_offloads = priv->mdev->priv.eswitch->br_offloads; 266*3ee6233eSVlad Buslov err = mlx5_esw_bridge_vport_num_vhca_id_get(dev, br_offloads->esw, &vport_num, 267*3ee6233eSVlad Buslov &esw_owner_vhca_id); 268*3ee6233eSVlad Buslov if (err) 2697cd6a54aSVlad Buslov goto out; 2707cd6a54aSVlad Buslov 2717cd6a54aSVlad Buslov if (fdb_work->add) 272*3ee6233eSVlad Buslov mlx5_esw_bridge_fdb_create(dev, vport_num, esw_owner_vhca_id, br_offloads, 273*3ee6233eSVlad Buslov fdb_info); 2747cd6a54aSVlad Buslov else 275*3ee6233eSVlad Buslov mlx5_esw_bridge_fdb_remove(dev, vport_num, esw_owner_vhca_id, br_offloads, 276*3ee6233eSVlad Buslov fdb_info); 2777cd6a54aSVlad Buslov 2787cd6a54aSVlad Buslov out: 2797cd6a54aSVlad Buslov rtnl_unlock(); 2807cd6a54aSVlad Buslov mlx5_esw_bridge_cleanup_switchdev_fdb_work(fdb_work); 2817cd6a54aSVlad Buslov } 2827cd6a54aSVlad Buslov 2837cd6a54aSVlad Buslov static struct mlx5_bridge_switchdev_fdb_work * 2847cd6a54aSVlad Buslov mlx5_esw_bridge_init_switchdev_fdb_work(struct net_device *dev, bool add, 2857cd6a54aSVlad Buslov struct switchdev_notifier_fdb_info *fdb_info) 2867cd6a54aSVlad Buslov { 2877cd6a54aSVlad Buslov struct mlx5_bridge_switchdev_fdb_work *work; 2887cd6a54aSVlad Buslov u8 *addr; 2897cd6a54aSVlad Buslov 2907cd6a54aSVlad Buslov work = kzalloc(sizeof(*work), GFP_ATOMIC); 2917cd6a54aSVlad Buslov if (!work) 2927cd6a54aSVlad Buslov return ERR_PTR(-ENOMEM); 2937cd6a54aSVlad Buslov 2947cd6a54aSVlad Buslov INIT_WORK(&work->work, mlx5_esw_bridge_switchdev_fdb_event_work); 2957cd6a54aSVlad Buslov memcpy(&work->fdb_info, fdb_info, sizeof(work->fdb_info)); 2967cd6a54aSVlad Buslov 2977cd6a54aSVlad Buslov addr = kzalloc(ETH_ALEN, GFP_ATOMIC); 2987cd6a54aSVlad Buslov if (!addr) { 2997cd6a54aSVlad Buslov kfree(work); 3007cd6a54aSVlad Buslov return ERR_PTR(-ENOMEM); 3017cd6a54aSVlad Buslov } 3027cd6a54aSVlad Buslov ether_addr_copy(addr, fdb_info->addr); 3037cd6a54aSVlad Buslov work->fdb_info.addr = addr; 3047cd6a54aSVlad Buslov 3057cd6a54aSVlad Buslov dev_hold(dev); 3067cd6a54aSVlad Buslov work->dev = dev; 3077cd6a54aSVlad Buslov work->add = add; 3087cd6a54aSVlad Buslov return work; 3097cd6a54aSVlad Buslov } 3107cd6a54aSVlad Buslov 3117cd6a54aSVlad Buslov static int mlx5_esw_bridge_switchdev_event(struct notifier_block *nb, 3127cd6a54aSVlad Buslov unsigned long event, void *ptr) 3137cd6a54aSVlad Buslov { 3147cd6a54aSVlad Buslov struct mlx5_esw_bridge_offloads *br_offloads = container_of(nb, 3157cd6a54aSVlad Buslov struct mlx5_esw_bridge_offloads, 3167cd6a54aSVlad Buslov nb); 3177cd6a54aSVlad Buslov struct net_device *dev = switchdev_notifier_info_to_dev(ptr); 3187cd6a54aSVlad Buslov struct switchdev_notifier_fdb_info *fdb_info; 3197cd6a54aSVlad Buslov struct mlx5_bridge_switchdev_fdb_work *work; 3207cd6a54aSVlad Buslov struct switchdev_notifier_info *info = ptr; 3217cd6a54aSVlad Buslov struct net_device *upper; 3227cd6a54aSVlad Buslov 323c636a0f0SVlad Buslov if (event == SWITCHDEV_PORT_ATTR_SET) { 324*3ee6233eSVlad Buslov int err = mlx5_esw_bridge_port_obj_attr_set(dev, ptr, br_offloads); 325*3ee6233eSVlad Buslov 326c636a0f0SVlad Buslov return notifier_from_errno(err); 327c636a0f0SVlad Buslov } 328c636a0f0SVlad Buslov 3297cd6a54aSVlad Buslov upper = netdev_master_upper_dev_get_rcu(dev); 3307cd6a54aSVlad Buslov if (!upper) 3317cd6a54aSVlad Buslov return NOTIFY_DONE; 3327cd6a54aSVlad Buslov if (!netif_is_bridge_master(upper)) 3337cd6a54aSVlad Buslov return NOTIFY_DONE; 3347cd6a54aSVlad Buslov 335*3ee6233eSVlad Buslov if (!mlx5e_eswitch_rep(dev)) 336*3ee6233eSVlad Buslov return NOTIFY_DONE; 337*3ee6233eSVlad Buslov if (!mlx5_esw_bridge_dev_same_esw(dev, br_offloads->esw)) 338*3ee6233eSVlad Buslov return NOTIFY_DONE; 339*3ee6233eSVlad Buslov 3407cd6a54aSVlad Buslov switch (event) { 3417cd6a54aSVlad Buslov case SWITCHDEV_FDB_ADD_TO_DEVICE: 3427cd6a54aSVlad Buslov case SWITCHDEV_FDB_DEL_TO_DEVICE: 3437cd6a54aSVlad Buslov fdb_info = container_of(info, 3447cd6a54aSVlad Buslov struct switchdev_notifier_fdb_info, 3457cd6a54aSVlad Buslov info); 3467cd6a54aSVlad Buslov 3477cd6a54aSVlad Buslov work = mlx5_esw_bridge_init_switchdev_fdb_work(dev, 3487cd6a54aSVlad Buslov event == SWITCHDEV_FDB_ADD_TO_DEVICE, 3497cd6a54aSVlad Buslov fdb_info); 3507cd6a54aSVlad Buslov if (IS_ERR(work)) { 3517cd6a54aSVlad Buslov WARN_ONCE(1, "Failed to init switchdev work, err=%ld", 3527cd6a54aSVlad Buslov PTR_ERR(work)); 3537cd6a54aSVlad Buslov return notifier_from_errno(PTR_ERR(work)); 3547cd6a54aSVlad Buslov } 3557cd6a54aSVlad Buslov 3567cd6a54aSVlad Buslov queue_work(br_offloads->wq, &work->work); 3577cd6a54aSVlad Buslov break; 3587cd6a54aSVlad Buslov default: 3597cd6a54aSVlad Buslov break; 3607cd6a54aSVlad Buslov } 3617cd6a54aSVlad Buslov return NOTIFY_DONE; 3627cd6a54aSVlad Buslov } 3637cd6a54aSVlad Buslov 364c636a0f0SVlad Buslov static void mlx5_esw_bridge_update_work(struct work_struct *work) 365c636a0f0SVlad Buslov { 366c636a0f0SVlad Buslov struct mlx5_esw_bridge_offloads *br_offloads = container_of(work, 367c636a0f0SVlad Buslov struct mlx5_esw_bridge_offloads, 368c636a0f0SVlad Buslov update_work.work); 369c636a0f0SVlad Buslov 370c636a0f0SVlad Buslov rtnl_lock(); 371c636a0f0SVlad Buslov mlx5_esw_bridge_update(br_offloads); 372c636a0f0SVlad Buslov rtnl_unlock(); 373c636a0f0SVlad Buslov 374c636a0f0SVlad Buslov queue_delayed_work(br_offloads->wq, &br_offloads->update_work, 375c636a0f0SVlad Buslov msecs_to_jiffies(MLX5_ESW_BRIDGE_UPDATE_INTERVAL)); 376c636a0f0SVlad Buslov } 377c636a0f0SVlad Buslov 37819e9bfa0SVlad Buslov void mlx5e_rep_bridge_init(struct mlx5e_priv *priv) 37919e9bfa0SVlad Buslov { 38019e9bfa0SVlad Buslov struct mlx5_esw_bridge_offloads *br_offloads; 38119e9bfa0SVlad Buslov struct mlx5_core_dev *mdev = priv->mdev; 38219e9bfa0SVlad Buslov struct mlx5_eswitch *esw = 38319e9bfa0SVlad Buslov mdev->priv.eswitch; 38419e9bfa0SVlad Buslov int err; 38519e9bfa0SVlad Buslov 38619e9bfa0SVlad Buslov rtnl_lock(); 38719e9bfa0SVlad Buslov br_offloads = mlx5_esw_bridge_init(esw); 38819e9bfa0SVlad Buslov rtnl_unlock(); 38919e9bfa0SVlad Buslov if (IS_ERR(br_offloads)) { 39019e9bfa0SVlad Buslov esw_warn(mdev, "Failed to init esw bridge (err=%ld)\n", PTR_ERR(br_offloads)); 39119e9bfa0SVlad Buslov return; 39219e9bfa0SVlad Buslov } 39319e9bfa0SVlad Buslov 3947cd6a54aSVlad Buslov br_offloads->wq = alloc_ordered_workqueue("mlx5_bridge_wq", 0); 3957cd6a54aSVlad Buslov if (!br_offloads->wq) { 3967cd6a54aSVlad Buslov esw_warn(mdev, "Failed to allocate bridge offloads workqueue\n"); 3977cd6a54aSVlad Buslov goto err_alloc_wq; 3987cd6a54aSVlad Buslov } 399c636a0f0SVlad Buslov INIT_DELAYED_WORK(&br_offloads->update_work, mlx5_esw_bridge_update_work); 400c636a0f0SVlad Buslov queue_delayed_work(br_offloads->wq, &br_offloads->update_work, 401c636a0f0SVlad Buslov msecs_to_jiffies(MLX5_ESW_BRIDGE_UPDATE_INTERVAL)); 4027cd6a54aSVlad Buslov 4037cd6a54aSVlad Buslov br_offloads->nb.notifier_call = mlx5_esw_bridge_switchdev_event; 4047cd6a54aSVlad Buslov err = register_switchdev_notifier(&br_offloads->nb); 4057cd6a54aSVlad Buslov if (err) { 4067cd6a54aSVlad Buslov esw_warn(mdev, "Failed to register switchdev notifier (err=%d)\n", err); 4077cd6a54aSVlad Buslov goto err_register_swdev; 4087cd6a54aSVlad Buslov } 4097cd6a54aSVlad Buslov 410c636a0f0SVlad Buslov br_offloads->nb_blk.notifier_call = mlx5_esw_bridge_event_blocking; 411c636a0f0SVlad Buslov err = register_switchdev_blocking_notifier(&br_offloads->nb_blk); 412c636a0f0SVlad Buslov if (err) { 413c636a0f0SVlad Buslov esw_warn(mdev, "Failed to register blocking switchdev notifier (err=%d)\n", err); 414c636a0f0SVlad Buslov goto err_register_swdev_blk; 415c636a0f0SVlad Buslov } 416c636a0f0SVlad Buslov 41719e9bfa0SVlad Buslov br_offloads->netdev_nb.notifier_call = mlx5_esw_bridge_switchdev_port_event; 41819e9bfa0SVlad Buslov err = register_netdevice_notifier(&br_offloads->netdev_nb); 41919e9bfa0SVlad Buslov if (err) { 42019e9bfa0SVlad Buslov esw_warn(mdev, "Failed to register bridge offloads netdevice notifier (err=%d)\n", 42119e9bfa0SVlad Buslov err); 4227cd6a54aSVlad Buslov goto err_register_netdev; 42319e9bfa0SVlad Buslov } 4247cd6a54aSVlad Buslov return; 4257cd6a54aSVlad Buslov 4267cd6a54aSVlad Buslov err_register_netdev: 427c636a0f0SVlad Buslov unregister_switchdev_blocking_notifier(&br_offloads->nb_blk); 428c636a0f0SVlad Buslov err_register_swdev_blk: 4297cd6a54aSVlad Buslov unregister_switchdev_notifier(&br_offloads->nb); 4307cd6a54aSVlad Buslov err_register_swdev: 4317cd6a54aSVlad Buslov destroy_workqueue(br_offloads->wq); 4327cd6a54aSVlad Buslov err_alloc_wq: 4337cd6a54aSVlad Buslov mlx5_esw_bridge_cleanup(esw); 43419e9bfa0SVlad Buslov } 43519e9bfa0SVlad Buslov 43619e9bfa0SVlad Buslov void mlx5e_rep_bridge_cleanup(struct mlx5e_priv *priv) 43719e9bfa0SVlad Buslov { 43819e9bfa0SVlad Buslov struct mlx5_esw_bridge_offloads *br_offloads; 43919e9bfa0SVlad Buslov struct mlx5_core_dev *mdev = priv->mdev; 44019e9bfa0SVlad Buslov struct mlx5_eswitch *esw = 44119e9bfa0SVlad Buslov mdev->priv.eswitch; 44219e9bfa0SVlad Buslov 44319e9bfa0SVlad Buslov br_offloads = esw->br_offloads; 44419e9bfa0SVlad Buslov if (!br_offloads) 44519e9bfa0SVlad Buslov return; 44619e9bfa0SVlad Buslov 44719e9bfa0SVlad Buslov unregister_netdevice_notifier(&br_offloads->netdev_nb); 448c636a0f0SVlad Buslov unregister_switchdev_blocking_notifier(&br_offloads->nb_blk); 4497cd6a54aSVlad Buslov unregister_switchdev_notifier(&br_offloads->nb); 450c636a0f0SVlad Buslov cancel_delayed_work(&br_offloads->update_work); 4517cd6a54aSVlad Buslov destroy_workqueue(br_offloads->wq); 45219e9bfa0SVlad Buslov rtnl_lock(); 45319e9bfa0SVlad Buslov mlx5_esw_bridge_cleanup(esw); 45419e9bfa0SVlad Buslov rtnl_unlock(); 45519e9bfa0SVlad Buslov } 456