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