xref: /dpdk/drivers/net/mlx4/mlx4_mp.c (revision 68a03efeed657e6e05f281479b33b51102797e15)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2019 6WIND S.A.
3  * Copyright 2019 Mellanox Technologies, Ltd
4  */
5 
6 #include <stdio.h>
7 #include <time.h>
8 
9 #include <rte_eal.h>
10 #include <ethdev_driver.h>
11 #include <rte_string_fns.h>
12 
13 #include "mlx4.h"
14 #include "mlx4_rxtx.h"
15 #include "mlx4_utils.h"
16 
17 /**
18  * Initialize IPC message.
19  *
20  * @param[in] dev
21  *   Pointer to Ethernet structure.
22  * @param[out] msg
23  *   Pointer to message to fill in.
24  * @param[in] type
25  *   Message type.
26  */
27 static inline void
28 mp_init_msg(struct rte_eth_dev *dev, struct rte_mp_msg *msg,
29 	    enum mlx4_mp_req_type type)
30 {
31 	struct mlx4_mp_param *param = (struct mlx4_mp_param *)msg->param;
32 
33 	memset(msg, 0, sizeof(*msg));
34 	strlcpy(msg->name, MLX4_MP_NAME, sizeof(msg->name));
35 	msg->len_param = sizeof(*param);
36 	param->type = type;
37 	param->port_id = dev->data->port_id;
38 }
39 
40 /**
41  * IPC message handler of primary process.
42  *
43  * @param[in] dev
44  *   Pointer to Ethernet structure.
45  * @param[in] peer
46  *   Pointer to the peer socket path.
47  *
48  * @return
49  *   0 on success, negative errno value otherwise and rte_errno is set.
50  */
51 static int
52 mp_primary_handle(const struct rte_mp_msg *mp_msg, const void *peer)
53 {
54 	struct rte_mp_msg mp_res;
55 	struct mlx4_mp_param *res = (struct mlx4_mp_param *)mp_res.param;
56 	const struct mlx4_mp_param *param =
57 		(const struct mlx4_mp_param *)mp_msg->param;
58 	struct rte_eth_dev *dev;
59 	struct mlx4_priv *priv;
60 	struct mlx4_mr_cache entry;
61 	uint32_t lkey;
62 	int ret;
63 
64 	MLX4_ASSERT(rte_eal_process_type() == RTE_PROC_PRIMARY);
65 	if (!rte_eth_dev_is_valid_port(param->port_id)) {
66 		rte_errno = ENODEV;
67 		ERROR("port %u invalid port ID", param->port_id);
68 		return -rte_errno;
69 	}
70 	dev = &rte_eth_devices[param->port_id];
71 	priv = dev->data->dev_private;
72 	switch (param->type) {
73 	case MLX4_MP_REQ_CREATE_MR:
74 		mp_init_msg(dev, &mp_res, param->type);
75 		lkey = mlx4_mr_create_primary(dev, &entry, param->args.addr);
76 		if (lkey == UINT32_MAX)
77 			res->result = -rte_errno;
78 		ret = rte_mp_reply(&mp_res, peer);
79 		break;
80 	case MLX4_MP_REQ_VERBS_CMD_FD:
81 		mp_init_msg(dev, &mp_res, param->type);
82 		mp_res.num_fds = 1;
83 		mp_res.fds[0] = priv->ctx->cmd_fd;
84 		res->result = 0;
85 		ret = rte_mp_reply(&mp_res, peer);
86 		break;
87 	default:
88 		rte_errno = EINVAL;
89 		ERROR("port %u invalid mp request type", dev->data->port_id);
90 		return -rte_errno;
91 	}
92 	return ret;
93 }
94 
95 /**
96  * IPC message handler of a secondary process.
97  *
98  * @param[in] dev
99  *   Pointer to Ethernet structure.
100  * @param[in] peer
101  *   Pointer to the peer socket path.
102  *
103  * @return
104  *   0 on success, a negative errno value otherwise and rte_errno is set.
105  */
106 static int
107 mp_secondary_handle(const struct rte_mp_msg *mp_msg, const void *peer)
108 {
109 	struct rte_mp_msg mp_res;
110 	struct mlx4_mp_param *res = (struct mlx4_mp_param *)mp_res.param;
111 	const struct mlx4_mp_param *param =
112 		(const struct mlx4_mp_param *)mp_msg->param;
113 	struct rte_eth_dev *dev;
114 #ifdef HAVE_IBV_MLX4_UAR_MMAP_OFFSET
115 	struct mlx4_proc_priv *ppriv;
116 #endif
117 	int ret;
118 
119 	MLX4_ASSERT(rte_eal_process_type() == RTE_PROC_SECONDARY);
120 	if (!rte_eth_dev_is_valid_port(param->port_id)) {
121 		rte_errno = ENODEV;
122 		ERROR("port %u invalid port ID", param->port_id);
123 		return -rte_errno;
124 	}
125 	dev = &rte_eth_devices[param->port_id];
126 	switch (param->type) {
127 	case MLX4_MP_REQ_START_RXTX:
128 		INFO("port %u starting datapath", dev->data->port_id);
129 		rte_mb();
130 		dev->tx_pkt_burst = mlx4_tx_burst;
131 		dev->rx_pkt_burst = mlx4_rx_burst;
132 #ifdef HAVE_IBV_MLX4_UAR_MMAP_OFFSET
133 		ppriv = (struct mlx4_proc_priv *)dev->process_private;
134 		if (ppriv->uar_table_sz != dev->data->nb_tx_queues) {
135 			mlx4_tx_uar_uninit_secondary(dev);
136 			mlx4_proc_priv_uninit(dev);
137 			ret = mlx4_proc_priv_init(dev);
138 			if (ret)
139 				return -rte_errno;
140 			ret = mlx4_tx_uar_init_secondary(dev, mp_msg->fds[0]);
141 			if (ret) {
142 				mlx4_proc_priv_uninit(dev);
143 				return -rte_errno;
144 			}
145 		}
146 #endif
147 		mp_init_msg(dev, &mp_res, param->type);
148 		res->result = 0;
149 		ret = rte_mp_reply(&mp_res, peer);
150 		break;
151 	case MLX4_MP_REQ_STOP_RXTX:
152 		INFO("port %u stopping datapath", dev->data->port_id);
153 		dev->tx_pkt_burst = mlx4_tx_burst_removed;
154 		dev->rx_pkt_burst = mlx4_rx_burst_removed;
155 		rte_mb();
156 		mp_init_msg(dev, &mp_res, param->type);
157 		res->result = 0;
158 		ret = rte_mp_reply(&mp_res, peer);
159 		break;
160 	default:
161 		rte_errno = EINVAL;
162 		ERROR("port %u invalid mp request type", dev->data->port_id);
163 		return -rte_errno;
164 	}
165 	return ret;
166 }
167 
168 /**
169  * Broadcast request of stopping/starting data-path to secondary processes.
170  *
171  * @param[in] dev
172  *   Pointer to Ethernet structure.
173  * @param[in] type
174  *   Request type.
175  */
176 static void
177 mp_req_on_rxtx(struct rte_eth_dev *dev, enum mlx4_mp_req_type type)
178 {
179 	struct rte_mp_msg mp_req;
180 	struct rte_mp_msg *mp_res;
181 	struct rte_mp_reply mp_rep;
182 	struct mlx4_mp_param *res __rte_unused;
183 	struct timespec ts = {.tv_sec = MLX4_MP_REQ_TIMEOUT_SEC, .tv_nsec = 0};
184 	struct mlx4_priv *priv;
185 	int ret;
186 	int i;
187 
188 	MLX4_ASSERT(rte_eal_process_type() == RTE_PROC_PRIMARY);
189 	if (!mlx4_shared_data->secondary_cnt)
190 		return;
191 	if (type != MLX4_MP_REQ_START_RXTX && type != MLX4_MP_REQ_STOP_RXTX) {
192 		ERROR("port %u unknown request (req_type %d)",
193 		      dev->data->port_id, type);
194 		return;
195 	}
196 	mp_init_msg(dev, &mp_req, type);
197 	if (type == MLX4_MP_REQ_START_RXTX) {
198 		priv = dev->data->dev_private;
199 		mp_req.num_fds = 1;
200 		mp_req.fds[0] = priv->ctx->cmd_fd;
201 	}
202 	ret = rte_mp_request_sync(&mp_req, &mp_rep, &ts);
203 	if (ret) {
204 		if (rte_errno != ENOTSUP)
205 			ERROR("port %u failed to request stop/start Rx/Tx (%d)",
206 					dev->data->port_id, type);
207 		goto exit;
208 	}
209 	if (mp_rep.nb_sent != mp_rep.nb_received) {
210 		ERROR("port %u not all secondaries responded (req_type %d)",
211 		      dev->data->port_id, type);
212 		goto exit;
213 	}
214 	for (i = 0; i < mp_rep.nb_received; i++) {
215 		mp_res = &mp_rep.msgs[i];
216 		res = (struct mlx4_mp_param *)mp_res->param;
217 		if (res->result) {
218 			ERROR("port %u request failed on secondary #%d",
219 			      dev->data->port_id, i);
220 			goto exit;
221 		}
222 	}
223 exit:
224 	free(mp_rep.msgs);
225 }
226 
227 /**
228  * Broadcast request of starting data-path to secondary processes. The request
229  * is synchronous.
230  *
231  * @param[in] dev
232  *   Pointer to Ethernet structure.
233  */
234 void
235 mlx4_mp_req_start_rxtx(struct rte_eth_dev *dev)
236 {
237 	mp_req_on_rxtx(dev, MLX4_MP_REQ_START_RXTX);
238 }
239 
240 /**
241  * Broadcast request of stopping data-path to secondary processes. The request
242  * is synchronous.
243  *
244  * @param[in] dev
245  *   Pointer to Ethernet structure.
246  */
247 void
248 mlx4_mp_req_stop_rxtx(struct rte_eth_dev *dev)
249 {
250 	mp_req_on_rxtx(dev, MLX4_MP_REQ_STOP_RXTX);
251 }
252 
253 /**
254  * Request Memory Region creation to the primary process.
255  *
256  * @param[in] dev
257  *   Pointer to Ethernet structure.
258  * @param addr
259  *   Target virtual address to register.
260  *
261  * @return
262  *   0 on success, a negative errno value otherwise and rte_errno is set.
263  */
264 int
265 mlx4_mp_req_mr_create(struct rte_eth_dev *dev, uintptr_t addr)
266 {
267 	struct rte_mp_msg mp_req;
268 	struct rte_mp_msg *mp_res;
269 	struct rte_mp_reply mp_rep;
270 	struct mlx4_mp_param *req = (struct mlx4_mp_param *)mp_req.param;
271 	struct mlx4_mp_param *res;
272 	struct timespec ts = {.tv_sec = MLX4_MP_REQ_TIMEOUT_SEC, .tv_nsec = 0};
273 	int ret;
274 
275 	MLX4_ASSERT(rte_eal_process_type() == RTE_PROC_SECONDARY);
276 	mp_init_msg(dev, &mp_req, MLX4_MP_REQ_CREATE_MR);
277 	req->args.addr = addr;
278 	ret = rte_mp_request_sync(&mp_req, &mp_rep, &ts);
279 	if (ret) {
280 		ERROR("port %u request to primary process failed",
281 		      dev->data->port_id);
282 		return -rte_errno;
283 	}
284 	MLX4_ASSERT(mp_rep.nb_received == 1);
285 	mp_res = &mp_rep.msgs[0];
286 	res = (struct mlx4_mp_param *)mp_res->param;
287 	ret = res->result;
288 	if (ret)
289 		rte_errno = -ret;
290 	free(mp_rep.msgs);
291 	return ret;
292 }
293 
294 /**
295  * IPC message handler of primary process.
296  *
297  * @param[in] dev
298  *   Pointer to Ethernet structure.
299  *
300  * @return
301  *   fd on success, a negative errno value otherwise and rte_errno is set.
302  */
303 int
304 mlx4_mp_req_verbs_cmd_fd(struct rte_eth_dev *dev)
305 {
306 	struct rte_mp_msg mp_req;
307 	struct rte_mp_msg *mp_res;
308 	struct rte_mp_reply mp_rep;
309 	struct mlx4_mp_param *res;
310 	struct timespec ts = {.tv_sec = MLX4_MP_REQ_TIMEOUT_SEC, .tv_nsec = 0};
311 	int ret;
312 
313 	MLX4_ASSERT(rte_eal_process_type() == RTE_PROC_SECONDARY);
314 	mp_init_msg(dev, &mp_req, MLX4_MP_REQ_VERBS_CMD_FD);
315 	ret = rte_mp_request_sync(&mp_req, &mp_rep, &ts);
316 	if (ret) {
317 		ERROR("port %u request to primary process failed",
318 		      dev->data->port_id);
319 		return -rte_errno;
320 	}
321 	MLX4_ASSERT(mp_rep.nb_received == 1);
322 	mp_res = &mp_rep.msgs[0];
323 	res = (struct mlx4_mp_param *)mp_res->param;
324 	if (res->result) {
325 		rte_errno = -res->result;
326 		ERROR("port %u failed to get command FD from primary process",
327 		      dev->data->port_id);
328 		ret = -rte_errno;
329 		goto exit;
330 	}
331 	MLX4_ASSERT(mp_res->num_fds == 1);
332 	ret = mp_res->fds[0];
333 	DEBUG("port %u command FD from primary is %d",
334 	      dev->data->port_id, ret);
335 exit:
336 	free(mp_rep.msgs);
337 	return ret;
338 }
339 
340 /**
341  * Initialize by primary process.
342  */
343 int
344 mlx4_mp_init_primary(void)
345 {
346 	int ret;
347 
348 	MLX4_ASSERT(rte_eal_process_type() == RTE_PROC_PRIMARY);
349 
350 	/* primary is allowed to not support IPC */
351 	ret = rte_mp_action_register(MLX4_MP_NAME, mp_primary_handle);
352 	if (ret && rte_errno != ENOTSUP)
353 		return -1;
354 	return 0;
355 }
356 
357 /**
358  * Un-initialize by primary process.
359  */
360 void
361 mlx4_mp_uninit_primary(void)
362 {
363 	MLX4_ASSERT(rte_eal_process_type() == RTE_PROC_PRIMARY);
364 	rte_mp_action_unregister(MLX4_MP_NAME);
365 }
366 
367 /**
368  * Initialize by secondary process.
369  */
370 int
371 mlx4_mp_init_secondary(void)
372 {
373 	MLX4_ASSERT(rte_eal_process_type() == RTE_PROC_SECONDARY);
374 	return rte_mp_action_register(MLX4_MP_NAME, mp_secondary_handle);
375 }
376 
377 /**
378  * Un-initialize by secondary process.
379  */
380 void
381 mlx4_mp_uninit_secondary(void)
382 {
383 	MLX4_ASSERT(rte_eal_process_type() == RTE_PROC_SECONDARY);
384 	rte_mp_action_unregister(MLX4_MP_NAME);
385 }
386