1// SPDX-License-Identifier: GPL-2.0-or-later
2
3#include <net/switchdev.h>
4
5#include "br_private_mrp.h"
6
7int 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
27int 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
46int 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
66int 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
90int 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
110int 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
132int 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
151int 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
172int br_mrp_port_switchdev_set_state(struct net_bridge_port *p, u32 state)
173{
174	struct switchdev_attr attr = {
175		.orig_dev = p->dev,
176		.id = SWITCHDEV_ATTR_ID_PORT_STP_STATE,
177		.u.stp_state = state,
178	};
179	int err;
180
181	err = switchdev_port_attr_set(p->dev, &attr);
182	if (err && err != -EOPNOTSUPP)
183		br_warn(p->br, "error setting offload MRP state on port %u(%s)\n",
184			(unsigned int)p->port_no, p->dev->name);
185
186	return err;
187}
188
189int br_mrp_port_switchdev_set_role(struct net_bridge_port *p,
190				   enum br_mrp_port_role_type role)
191{
192	struct switchdev_attr attr = {
193		.orig_dev = p->dev,
194		.id = SWITCHDEV_ATTR_ID_MRP_PORT_ROLE,
195		.u.mrp_port_role = role,
196	};
197	int err;
198
199	err = switchdev_port_attr_set(p->dev, &attr);
200	if (err && err != -EOPNOTSUPP)
201		return err;
202
203	return 0;
204}
205