xref: /dpdk/drivers/net/hns3/hns3_mp.c (revision 96c33cfb)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2018-2021 HiSilicon Limited.
3  */
4 
5 #include <rte_eal.h>
6 #include <ethdev_driver.h>
7 #include <rte_string_fns.h>
8 #include <rte_io.h>
9 
10 #include "hns3_ethdev.h"
11 #include "hns3_logs.h"
12 #include "hns3_rxtx.h"
13 #include "hns3_mp.h"
14 
15 /* local data for primary or secondary process. */
16 static struct hns3_process_local_data process_data;
17 
18 /*
19  * Initialize IPC message.
20  *
21  * @param[in] dev
22  *   Pointer to Ethernet structure.
23  * @param[out] msg
24  *   Pointer to message to fill in.
25  * @param[in] type
26  *   Message type.
27  */
28 static inline void
mp_init_msg(struct rte_eth_dev * dev,struct rte_mp_msg * msg,enum hns3_mp_req_type type)29 mp_init_msg(struct rte_eth_dev *dev, struct rte_mp_msg *msg,
30 	    enum hns3_mp_req_type type)
31 {
32 	struct hns3_mp_param *param = (struct hns3_mp_param *)msg->param;
33 
34 	memset(msg, 0, sizeof(*msg));
35 	strlcpy(msg->name, HNS3_MP_NAME, sizeof(msg->name));
36 	msg->len_param = sizeof(*param);
37 	param->type = type;
38 	param->port_id = dev->data->port_id;
39 }
40 
41 /*
42  * IPC message handler of primary process.
43  *
44  * @param[in] dev
45  *   Pointer to Ethernet structure.
46  * @param[in] peer
47  *   Pointer to the peer socket path.
48  *
49  * @return
50  *   0 on success, a negative errno value otherwise and rte_errno is set.
51  */
52 static int
mp_primary_handle(const struct rte_mp_msg * mp_msg __rte_unused,const void * peer __rte_unused)53 mp_primary_handle(const struct rte_mp_msg *mp_msg __rte_unused,
54 		  const void *peer __rte_unused)
55 {
56 	return 0;
57 }
58 
59 /*
60  * IPC message handler of a secondary process.
61  *
62  * @param[in] dev
63  *   Pointer to Ethernet structure.
64  * @param[in] peer
65  *   Pointer to the peer socket path.
66  *
67  * @return
68  *   0 on success, a negative errno value otherwise and rte_errno is set.
69  */
70 static int
mp_secondary_handle(const struct rte_mp_msg * mp_msg,const void * peer)71 mp_secondary_handle(const struct rte_mp_msg *mp_msg, const void *peer)
72 {
73 	struct rte_mp_msg mp_res;
74 	struct hns3_mp_param *res = (struct hns3_mp_param *)mp_res.param;
75 	const struct hns3_mp_param *param =
76 		(const struct hns3_mp_param *)mp_msg->param;
77 	struct rte_eth_dev *dev;
78 	int ret;
79 
80 	if (!rte_eth_dev_is_valid_port(param->port_id)) {
81 		rte_errno = ENODEV;
82 		PMD_INIT_LOG(ERR, "port %d invalid port ID", param->port_id);
83 		return -rte_errno;
84 	}
85 	dev = &rte_eth_devices[param->port_id];
86 	switch (param->type) {
87 	case HNS3_MP_REQ_START_RXTX:
88 		PMD_INIT_LOG(INFO, "port %u starting datapath",
89 			     dev->data->port_id);
90 		hns3_set_rxtx_function(dev);
91 		break;
92 	case HNS3_MP_REQ_STOP_RXTX:
93 		PMD_INIT_LOG(INFO, "port %u stopping datapath",
94 			     dev->data->port_id);
95 		hns3_set_rxtx_function(dev);
96 		break;
97 	case HNS3_MP_REQ_START_TX:
98 		PMD_INIT_LOG(INFO, "port %u starting Tx datapath",
99 			     dev->data->port_id);
100 		hns3_start_tx_datapath(dev);
101 		break;
102 	case HNS3_MP_REQ_STOP_TX:
103 		PMD_INIT_LOG(INFO, "port %u stopping Tx datapath",
104 			     dev->data->port_id);
105 		hns3_stop_tx_datapath(dev);
106 		break;
107 	default:
108 		rte_errno = EINVAL;
109 		PMD_INIT_LOG(ERR, "port %u invalid mp request type",
110 			     dev->data->port_id);
111 		return -rte_errno;
112 	}
113 
114 	rte_mb();
115 	mp_init_msg(dev, &mp_res, param->type);
116 	res->result = 0;
117 	ret = rte_mp_reply(&mp_res, peer);
118 
119 	return ret;
120 }
121 
122 static bool
mp_req_type_is_valid(enum hns3_mp_req_type type)123 mp_req_type_is_valid(enum hns3_mp_req_type type)
124 {
125 	return type == HNS3_MP_REQ_START_RXTX ||
126 		type == HNS3_MP_REQ_STOP_RXTX ||
127 		type == HNS3_MP_REQ_START_TX ||
128 		type == HNS3_MP_REQ_STOP_TX;
129 }
130 
131 /*
132  * Broadcast request of stopping/starting data-path to secondary processes.
133  *
134  * @param[in] dev
135  *   Pointer to Ethernet structure.
136  * @param[in] type
137  *   Request type.
138  */
139 static void
mp_req_on_rxtx(struct rte_eth_dev * dev,enum hns3_mp_req_type type)140 mp_req_on_rxtx(struct rte_eth_dev *dev, enum hns3_mp_req_type type)
141 {
142 	struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
143 	struct rte_mp_msg mp_req;
144 	struct rte_mp_msg *mp_res;
145 	struct rte_mp_reply mp_rep;
146 	struct hns3_mp_param *res;
147 	struct timespec ts;
148 	int ret;
149 	int i;
150 
151 	if (rte_eal_process_type() == RTE_PROC_SECONDARY ||
152 		__atomic_load_n(&hw->secondary_cnt, __ATOMIC_RELAXED) == 0)
153 		return;
154 
155 	if (!mp_req_type_is_valid(type)) {
156 		hns3_err(hw, "port %u unknown request (req_type %d)",
157 			 dev->data->port_id, type);
158 		return;
159 	}
160 	mp_init_msg(dev, &mp_req, type);
161 	ts.tv_sec = HNS3_MP_REQ_TIMEOUT_SEC;
162 	ts.tv_nsec = 0;
163 	ret = rte_mp_request_sync(&mp_req, &mp_rep, &ts);
164 	if (ret) {
165 		hns3_err(hw, "port %u failed to request stop/start Rx/Tx (%d)",
166 			 dev->data->port_id, type);
167 		goto exit;
168 	}
169 	if (mp_rep.nb_sent != mp_rep.nb_received) {
170 		PMD_INIT_LOG(ERR,
171 			"port %u not all secondaries responded (req_type %d)",
172 			dev->data->port_id, type);
173 		goto exit;
174 	}
175 	for (i = 0; i < mp_rep.nb_received; i++) {
176 		mp_res = &mp_rep.msgs[i];
177 		res = (struct hns3_mp_param *)mp_res->param;
178 		if (res->result) {
179 			hns3_err(hw, "port %u request failed on secondary #%d",
180 				 dev->data->port_id, i);
181 			goto exit;
182 		}
183 	}
184 exit:
185 	free(mp_rep.msgs);
186 }
187 
188 /*
189  * Broadcast request of starting data-path to secondary processes. The request
190  * is synchronous.
191  *
192  * @param[in] dev
193  *   Pointer to Ethernet structure.
194  */
hns3_mp_req_start_rxtx(struct rte_eth_dev * dev)195 void hns3_mp_req_start_rxtx(struct rte_eth_dev *dev)
196 {
197 	mp_req_on_rxtx(dev, HNS3_MP_REQ_START_RXTX);
198 }
199 
200 /*
201  * Broadcast request of stopping data-path to secondary processes. The request
202  * is synchronous.
203  *
204  * @param[in] dev
205  *   Pointer to Ethernet structure.
206  */
hns3_mp_req_stop_rxtx(struct rte_eth_dev * dev)207 void hns3_mp_req_stop_rxtx(struct rte_eth_dev *dev)
208 {
209 	mp_req_on_rxtx(dev, HNS3_MP_REQ_STOP_RXTX);
210 }
211 
212 void
hns3_mp_req_stop_tx(struct rte_eth_dev * dev)213 hns3_mp_req_stop_tx(struct rte_eth_dev *dev)
214 {
215 	mp_req_on_rxtx(dev, HNS3_MP_REQ_STOP_TX);
216 }
217 
218 void
hns3_mp_req_start_tx(struct rte_eth_dev * dev)219 hns3_mp_req_start_tx(struct rte_eth_dev *dev)
220 {
221 	mp_req_on_rxtx(dev, HNS3_MP_REQ_START_TX);
222 }
223 
224 /*
225  * Initialize by primary process.
226  */
227 static int
hns3_mp_init_primary(void)228 hns3_mp_init_primary(void)
229 {
230 	int ret;
231 
232 	if (process_data.init_done)
233 		return 0;
234 
235 	/* primary is allowed to not support IPC */
236 	ret = rte_mp_action_register(HNS3_MP_NAME, mp_primary_handle);
237 	if (ret && rte_errno != ENOTSUP)
238 		return ret;
239 
240 	process_data.init_done = true;
241 
242 	return 0;
243 }
244 
245 /*
246  * Initialize by secondary process.
247  */
248 static int
hns3_mp_init_secondary(void)249 hns3_mp_init_secondary(void)
250 {
251 	int ret;
252 
253 	if (process_data.init_done)
254 		return 0;
255 
256 	ret = rte_mp_action_register(HNS3_MP_NAME, mp_secondary_handle);
257 	if (ret && rte_errno != ENOTSUP)
258 		return ret;
259 
260 	process_data.init_done = true;
261 
262 	return 0;
263 }
264 
265 int
hns3_mp_init(struct rte_eth_dev * dev)266 hns3_mp_init(struct rte_eth_dev *dev)
267 {
268 	struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
269 	int ret;
270 
271 	if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
272 		ret = hns3_mp_init_secondary();
273 		if (ret) {
274 			PMD_INIT_LOG(ERR, "Failed to init for secondary process, ret = %d",
275 				     ret);
276 			return ret;
277 		}
278 		__atomic_fetch_add(&hw->secondary_cnt, 1, __ATOMIC_RELAXED);
279 	} else {
280 		ret = hns3_mp_init_primary();
281 		if (ret) {
282 			PMD_INIT_LOG(ERR, "Failed to init for primary process, ret = %d",
283 				     ret);
284 			return ret;
285 		}
286 	}
287 
288 	process_data.eth_dev_cnt++;
289 
290 	return 0;
291 }
292 
hns3_mp_uninit(struct rte_eth_dev * dev)293 void hns3_mp_uninit(struct rte_eth_dev *dev)
294 {
295 	struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(dev->data->dev_private);
296 
297 	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
298 		__atomic_fetch_sub(&hw->secondary_cnt, 1, __ATOMIC_RELAXED);
299 
300 	process_data.eth_dev_cnt--;
301 	if (process_data.eth_dev_cnt == 0) {
302 		rte_mp_action_unregister(HNS3_MP_NAME);
303 		process_data.init_done = false;
304 	}
305 }
306