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