xref: /openbmc/linux/net/bridge/br_mrp_switchdev.c (revision 2634682f)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 
3 #include <net/switchdev.h>
4 
5 #include "br_private_mrp.h"
6 
7 int br_mrp_switchdev_add(struct net_bridge *br, struct br_mrp *mrp)
8 {
9 	struct switchdev_obj_mrp mrp_obj = {
10 		.obj.orig_dev = br->dev,
11 		.obj.id = SWITCHDEV_OBJ_ID_MRP,
12 		.p_port = rtnl_dereference(mrp->p_port)->dev,
13 		.s_port = rtnl_dereference(mrp->s_port)->dev,
14 		.ring_id = mrp->ring_id,
15 		.prio = mrp->prio,
16 	};
17 	int err;
18 
19 	err = switchdev_port_obj_add(br->dev, &mrp_obj.obj, NULL);
20 
21 	if (err && err != -EOPNOTSUPP)
22 		return err;
23 
24 	return 0;
25 }
26 
27 int br_mrp_switchdev_del(struct net_bridge *br, struct br_mrp *mrp)
28 {
29 	struct switchdev_obj_mrp mrp_obj = {
30 		.obj.orig_dev = br->dev,
31 		.obj.id = SWITCHDEV_OBJ_ID_MRP,
32 		.p_port = NULL,
33 		.s_port = NULL,
34 		.ring_id = mrp->ring_id,
35 	};
36 	int err;
37 
38 	err = switchdev_port_obj_del(br->dev, &mrp_obj.obj);
39 
40 	if (err && err != -EOPNOTSUPP)
41 		return err;
42 
43 	return 0;
44 }
45 
46 int br_mrp_switchdev_set_ring_role(struct net_bridge *br,
47 				   struct br_mrp *mrp,
48 				   enum br_mrp_ring_role_type role)
49 {
50 	struct switchdev_obj_ring_role_mrp mrp_role = {
51 		.obj.orig_dev = br->dev,
52 		.obj.id = SWITCHDEV_OBJ_ID_RING_ROLE_MRP,
53 		.ring_role = role,
54 		.ring_id = mrp->ring_id,
55 	};
56 	int err;
57 
58 	if (role == BR_MRP_RING_ROLE_DISABLED)
59 		err = switchdev_port_obj_del(br->dev, &mrp_role.obj);
60 	else
61 		err = switchdev_port_obj_add(br->dev, &mrp_role.obj, NULL);
62 
63 	return err;
64 }
65 
66 int br_mrp_switchdev_send_ring_test(struct net_bridge *br,
67 				    struct br_mrp *mrp, u32 interval,
68 				    u8 max_miss, u32 period,
69 				    bool monitor)
70 {
71 	struct switchdev_obj_ring_test_mrp test = {
72 		.obj.orig_dev = br->dev,
73 		.obj.id = SWITCHDEV_OBJ_ID_RING_TEST_MRP,
74 		.interval = interval,
75 		.max_miss = max_miss,
76 		.ring_id = mrp->ring_id,
77 		.period = period,
78 		.monitor = monitor,
79 	};
80 	int err;
81 
82 	if (interval == 0)
83 		err = switchdev_port_obj_del(br->dev, &test.obj);
84 	else
85 		err = switchdev_port_obj_add(br->dev, &test.obj, NULL);
86 
87 	return err;
88 }
89 
90 int br_mrp_switchdev_set_ring_state(struct net_bridge *br,
91 				    struct br_mrp *mrp,
92 				    enum br_mrp_ring_state_type state)
93 {
94 	struct switchdev_obj_ring_state_mrp mrp_state = {
95 		.obj.orig_dev = br->dev,
96 		.obj.id = SWITCHDEV_OBJ_ID_RING_STATE_MRP,
97 		.ring_state = state,
98 		.ring_id = mrp->ring_id,
99 	};
100 	int err;
101 
102 	err = switchdev_port_obj_add(br->dev, &mrp_state.obj, NULL);
103 
104 	if (err && err != -EOPNOTSUPP)
105 		return err;
106 
107 	return 0;
108 }
109 
110 int br_mrp_switchdev_set_in_role(struct net_bridge *br, struct br_mrp *mrp,
111 				 u16 in_id, u32 ring_id,
112 				 enum br_mrp_in_role_type role)
113 {
114 	struct switchdev_obj_in_role_mrp mrp_role = {
115 		.obj.orig_dev = br->dev,
116 		.obj.id = SWITCHDEV_OBJ_ID_IN_ROLE_MRP,
117 		.in_role = role,
118 		.in_id = mrp->in_id,
119 		.ring_id = mrp->ring_id,
120 		.i_port = rtnl_dereference(mrp->i_port)->dev,
121 	};
122 	int err;
123 
124 	if (role == BR_MRP_IN_ROLE_DISABLED)
125 		err = switchdev_port_obj_del(br->dev, &mrp_role.obj);
126 	else
127 		err = switchdev_port_obj_add(br->dev, &mrp_role.obj, NULL);
128 
129 	return err;
130 }
131 
132 int br_mrp_switchdev_set_in_state(struct net_bridge *br, struct br_mrp *mrp,
133 				  enum br_mrp_in_state_type state)
134 {
135 	struct switchdev_obj_in_state_mrp mrp_state = {
136 		.obj.orig_dev = br->dev,
137 		.obj.id = SWITCHDEV_OBJ_ID_IN_STATE_MRP,
138 		.in_state = state,
139 		.in_id = mrp->in_id,
140 	};
141 	int err;
142 
143 	err = switchdev_port_obj_add(br->dev, &mrp_state.obj, NULL);
144 
145 	if (err && err != -EOPNOTSUPP)
146 		return err;
147 
148 	return 0;
149 }
150 
151 int br_mrp_switchdev_send_in_test(struct net_bridge *br, struct br_mrp *mrp,
152 				  u32 interval, u8 max_miss, u32 period)
153 {
154 	struct switchdev_obj_in_test_mrp test = {
155 		.obj.orig_dev = br->dev,
156 		.obj.id = SWITCHDEV_OBJ_ID_IN_TEST_MRP,
157 		.interval = interval,
158 		.max_miss = max_miss,
159 		.in_id = mrp->in_id,
160 		.period = period,
161 	};
162 	int err;
163 
164 	if (interval == 0)
165 		err = switchdev_port_obj_del(br->dev, &test.obj);
166 	else
167 		err = switchdev_port_obj_add(br->dev, &test.obj, NULL);
168 
169 	return err;
170 }
171 
172 int br_mrp_port_switchdev_set_state(struct net_bridge_port *p,
173 				    enum br_mrp_port_state_type state)
174 {
175 	struct switchdev_attr attr = {
176 		.orig_dev = p->dev,
177 		.id = SWITCHDEV_ATTR_ID_MRP_PORT_STATE,
178 		.u.mrp_port_state = state,
179 	};
180 	int err;
181 
182 	err = switchdev_port_attr_set(p->dev, &attr);
183 	if (err && err != -EOPNOTSUPP)
184 		br_warn(p->br, "error setting offload MRP state on port %u(%s)\n",
185 			(unsigned int)p->port_no, p->dev->name);
186 
187 	return err;
188 }
189 
190 int br_mrp_port_switchdev_set_role(struct net_bridge_port *p,
191 				   enum br_mrp_port_role_type role)
192 {
193 	struct switchdev_attr attr = {
194 		.orig_dev = p->dev,
195 		.id = SWITCHDEV_ATTR_ID_MRP_PORT_ROLE,
196 		.u.mrp_port_role = role,
197 	};
198 	int err;
199 
200 	err = switchdev_port_attr_set(p->dev, &attr);
201 	if (err && err != -EOPNOTSUPP)
202 		return err;
203 
204 	return 0;
205 }
206