xref: /dpdk/drivers/net/mlx5/linux/mlx5_mp_os.c (revision 8b8036a66e3d59ffa58afb8d96fa2c73262155a7)
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 <mlx5_common_mp.h>
14 #include <mlx5_common_mr.h>
15 #include <mlx5_malloc.h>
16 
17 #include "mlx5.h"
18 #include "mlx5_rxtx.h"
19 #include "mlx5_rx.h"
20 #include "mlx5_tx.h"
21 #include "mlx5_utils.h"
22 
23 /**
24  * Handle a port-agnostic message.
25  *
26  * @return
27  *   0 on success, 1 when message is not port-agnostic, (-1) on error.
28  */
29 static int
30 mlx5_mp_os_handle_port_agnostic(const struct rte_mp_msg *mp_msg,
31 				const void *peer)
32 {
33 	struct rte_mp_msg mp_res;
34 	struct mlx5_mp_param *res = (struct mlx5_mp_param *)mp_res.param;
35 	const struct mlx5_mp_param *param =
36 		(const struct mlx5_mp_param *)mp_msg->param;
37 	const struct mlx5_mp_arg_mr_manage *mng = &param->args.mr_manage;
38 	struct mr_cache_entry entry;
39 	uint32_t lkey;
40 
41 	switch (param->type) {
42 	case MLX5_MP_REQ_CREATE_MR:
43 		mp_init_port_agnostic_msg(&mp_res, param->type);
44 		lkey = mlx5_mr_create(mng->cdev, &mng->cdev->mr_scache, &entry,
45 				      mng->addr);
46 		if (lkey == UINT32_MAX)
47 			res->result = -rte_errno;
48 		return rte_mp_reply(&mp_res, peer);
49 	case MLX5_MP_REQ_MEMPOOL_REGISTER:
50 		mp_init_port_agnostic_msg(&mp_res, param->type);
51 		res->result = mlx5_mr_mempool_register(mng->cdev, mng->mempool);
52 		return rte_mp_reply(&mp_res, peer);
53 	case MLX5_MP_REQ_MEMPOOL_UNREGISTER:
54 		mp_init_port_agnostic_msg(&mp_res, param->type);
55 		res->result = mlx5_mr_mempool_unregister(mng->cdev,
56 							 mng->mempool);
57 		return rte_mp_reply(&mp_res, peer);
58 	default:
59 		return 1;
60 	}
61 	return -1;
62 }
63 
64 int
65 mlx5_mp_os_primary_handle(const struct rte_mp_msg *mp_msg, const void *peer)
66 {
67 	struct rte_mp_msg mp_res;
68 	struct mlx5_mp_param *res = (struct mlx5_mp_param *)mp_res.param;
69 	const struct mlx5_mp_param *param =
70 		(const struct mlx5_mp_param *)mp_msg->param;
71 	struct rte_eth_dev *dev;
72 	struct mlx5_priv *priv;
73 	struct mlx5_common_device *cdev;
74 	int ret;
75 
76 	MLX5_ASSERT(rte_eal_process_type() == RTE_PROC_PRIMARY);
77 	/* Port-agnostic messages. */
78 	ret = mlx5_mp_os_handle_port_agnostic(mp_msg, peer);
79 	if (ret <= 0)
80 		return ret;
81 	/* Port-specific messages. */
82 	if (!rte_eth_dev_is_valid_port(param->port_id)) {
83 		rte_errno = ENODEV;
84 		DRV_LOG(ERR, "port %u invalid port ID", param->port_id);
85 		return -rte_errno;
86 	}
87 	dev = &rte_eth_devices[param->port_id];
88 	priv = dev->data->dev_private;
89 	cdev = priv->sh->cdev;
90 	switch (param->type) {
91 	case MLX5_MP_REQ_VERBS_CMD_FD:
92 		mp_init_msg(&priv->mp_id, &mp_res, param->type);
93 		mp_res.num_fds = 1;
94 		mp_res.fds[0] = ((struct ibv_context *)cdev->ctx)->cmd_fd;
95 		res->result = 0;
96 		ret = rte_mp_reply(&mp_res, peer);
97 		break;
98 	case MLX5_MP_REQ_QUEUE_STATE_MODIFY:
99 		mp_init_msg(&priv->mp_id, &mp_res, param->type);
100 		res->result = mlx5_queue_state_modify_primary
101 					(dev, &param->args.state_modify);
102 		ret = rte_mp_reply(&mp_res, peer);
103 		break;
104 	case MLX5_MP_REQ_QUEUE_RX_STOP:
105 		mp_init_msg(&priv->mp_id, &mp_res, param->type);
106 		res->result = mlx5_rx_queue_stop_primary
107 					(dev, param->args.queue_id.queue_id);
108 		ret = rte_mp_reply(&mp_res, peer);
109 		break;
110 	case MLX5_MP_REQ_QUEUE_RX_START:
111 		mp_init_msg(&priv->mp_id, &mp_res, param->type);
112 		res->result = mlx5_rx_queue_start_primary
113 					(dev, param->args.queue_id.queue_id);
114 		ret = rte_mp_reply(&mp_res, peer);
115 		break;
116 	case MLX5_MP_REQ_QUEUE_TX_STOP:
117 		mp_init_msg(&priv->mp_id, &mp_res, param->type);
118 		res->result = mlx5_tx_queue_stop_primary
119 					(dev, param->args.queue_id.queue_id);
120 		ret = rte_mp_reply(&mp_res, peer);
121 		break;
122 	case MLX5_MP_REQ_QUEUE_TX_START:
123 		mp_init_msg(&priv->mp_id, &mp_res, param->type);
124 		res->result = mlx5_tx_queue_start_primary
125 					(dev, param->args.queue_id.queue_id);
126 		ret = rte_mp_reply(&mp_res, peer);
127 		break;
128 	default:
129 		rte_errno = EINVAL;
130 		DRV_LOG(ERR, "port %u invalid mp request type",
131 			dev->data->port_id);
132 		return -rte_errno;
133 	}
134 	return ret;
135 }
136 
137 /**
138  * IPC message handler of a secondary process.
139  *
140  * @param[in] dev
141  *   Pointer to Ethernet structure.
142  * @param[in] peer
143  *   Pointer to the peer socket path.
144  *
145  * @return
146  *   0 on success, a negative errno value otherwise and rte_errno is set.
147  */
148 int
149 mlx5_mp_os_secondary_handle(const struct rte_mp_msg *mp_msg, const void *peer)
150 {
151 struct rte_mp_msg mp_res;
152 	struct mlx5_mp_param *res = (struct mlx5_mp_param *)mp_res.param;
153 	const struct mlx5_mp_param *param =
154 		(const struct mlx5_mp_param *)mp_msg->param;
155 	struct rte_eth_dev *dev;
156 	struct mlx5_proc_priv *ppriv;
157 	struct mlx5_priv *priv;
158 	int ret;
159 
160 	MLX5_ASSERT(rte_eal_process_type() == RTE_PROC_SECONDARY);
161 	if (!rte_eth_dev_is_valid_port(param->port_id)) {
162 		rte_errno = ENODEV;
163 		DRV_LOG(ERR, "port %u invalid port ID", param->port_id);
164 		return -rte_errno;
165 	}
166 	dev = &rte_eth_devices[param->port_id];
167 	priv = dev->data->dev_private;
168 	switch (param->type) {
169 	case MLX5_MP_REQ_START_RXTX:
170 		DRV_LOG(INFO, "port %u starting datapath", dev->data->port_id);
171 		dev->rx_pkt_burst = mlx5_select_rx_function(dev);
172 		dev->tx_pkt_burst = mlx5_select_tx_function(dev);
173 		ppriv = (struct mlx5_proc_priv *)dev->process_private;
174 		/* If Tx queue number changes, re-initialize UAR. */
175 		if (ppriv->uar_table_sz != priv->txqs_n) {
176 			mlx5_tx_uar_uninit_secondary(dev);
177 			mlx5_proc_priv_uninit(dev);
178 			ret = mlx5_proc_priv_init(dev);
179 			if (ret)
180 				return -rte_errno;
181 			ret = mlx5_tx_uar_init_secondary(dev, mp_msg->fds[0]);
182 			if (ret) {
183 				mlx5_proc_priv_uninit(dev);
184 				return -rte_errno;
185 			}
186 		}
187 		rte_mb();
188 		mp_init_msg(&priv->mp_id, &mp_res, param->type);
189 		res->result = 0;
190 		ret = rte_mp_reply(&mp_res, peer);
191 		break;
192 	case MLX5_MP_REQ_STOP_RXTX:
193 		DRV_LOG(INFO, "port %u stopping datapath", dev->data->port_id);
194 		dev->rx_pkt_burst = removed_rx_burst;
195 		dev->tx_pkt_burst = removed_tx_burst;
196 		rte_mb();
197 		mp_init_msg(&priv->mp_id, &mp_res, param->type);
198 		res->result = 0;
199 		ret = rte_mp_reply(&mp_res, peer);
200 		break;
201 	default:
202 		rte_errno = EINVAL;
203 		DRV_LOG(ERR, "port %u invalid mp request type",
204 			dev->data->port_id);
205 		return -rte_errno;
206 	}
207 	return ret;
208 }
209 
210 /**
211  * Broadcast request of stopping/starting data-path to secondary processes.
212  *
213  * @param[in] dev
214  *   Pointer to Ethernet structure.
215  * @param[in] type
216  *   Request type.
217  */
218 static void
219 mp_req_on_rxtx(struct rte_eth_dev *dev, enum mlx5_mp_req_type type)
220 {
221 	struct rte_mp_msg mp_req;
222 	struct rte_mp_msg *mp_res;
223 	struct rte_mp_reply mp_rep;
224 	struct mlx5_mp_param *res;
225 	struct timespec ts = {.tv_sec = MLX5_MP_REQ_TIMEOUT_SEC, .tv_nsec = 0};
226 	struct mlx5_priv *priv = dev->data->dev_private;
227 	int ret;
228 	int i;
229 
230 	MLX5_ASSERT(rte_eal_process_type() == RTE_PROC_PRIMARY);
231 	if (!mlx5_shared_data->secondary_cnt)
232 		return;
233 	if (type != MLX5_MP_REQ_START_RXTX && type != MLX5_MP_REQ_STOP_RXTX) {
234 		DRV_LOG(ERR, "port %u unknown request (req_type %d)",
235 			dev->data->port_id, type);
236 		return;
237 	}
238 	mp_init_msg(&priv->mp_id, &mp_req, type);
239 	if (type == MLX5_MP_REQ_START_RXTX) {
240 		mp_req.num_fds = 1;
241 		mp_req.fds[0] =
242 			((struct ibv_context *)priv->sh->cdev->ctx)->cmd_fd;
243 	}
244 	ret = rte_mp_request_sync(&mp_req, &mp_rep, &ts);
245 	if (ret) {
246 		if (rte_errno != ENOTSUP)
247 			DRV_LOG(ERR, "port %u failed to request stop/start Rx/Tx (%d)",
248 				dev->data->port_id, type);
249 		goto exit;
250 	}
251 	if (mp_rep.nb_sent != mp_rep.nb_received) {
252 		DRV_LOG(ERR,
253 			"port %u not all secondaries responded (req_type %d)",
254 			dev->data->port_id, type);
255 		goto exit;
256 	}
257 	for (i = 0; i < mp_rep.nb_received; i++) {
258 		mp_res = &mp_rep.msgs[i];
259 		res = (struct mlx5_mp_param *)mp_res->param;
260 		if (res->result) {
261 			DRV_LOG(ERR, "port %u request failed on secondary #%d",
262 				dev->data->port_id, i);
263 			goto exit;
264 		}
265 	}
266 exit:
267 	mlx5_free(mp_rep.msgs);
268 }
269 
270 /**
271  * Broadcast request of starting data-path to secondary processes. The request
272  * is synchronous.
273  *
274  * @param[in] dev
275  *   Pointer to Ethernet structure.
276  */
277 void
278 mlx5_mp_os_req_start_rxtx(struct rte_eth_dev *dev)
279 {
280 	mp_req_on_rxtx(dev, MLX5_MP_REQ_START_RXTX);
281 }
282 
283 /**
284  * Broadcast request of stopping data-path to secondary processes. The request
285  * is synchronous.
286  *
287  * @param[in] dev
288  *   Pointer to Ethernet structure.
289  */
290 void
291 mlx5_mp_os_req_stop_rxtx(struct rte_eth_dev *dev)
292 {
293 	mp_req_on_rxtx(dev, MLX5_MP_REQ_STOP_RXTX);
294 }
295 
296 /**
297  * Request Verbs Rx/Tx queue stop or start to the primary process.
298  *
299  * @param[in] dev
300  *   Pointer to Ethernet structure.
301  * @param queue_id
302  *   Queue ID to control.
303  * @param req_type
304  *   request type
305  *     MLX5_MP_REQ_QUEUE_RX_START - start Rx queue
306  *     MLX5_MP_REQ_QUEUE_TX_START - stop Tx queue
307  *     MLX5_MP_REQ_QUEUE_RX_STOP - stop Rx queue
308  *     MLX5_MP_REQ_QUEUE_TX_STOP - stop Tx queue
309  * @return
310  *   0 on success, a negative errno value otherwise and
311  *     rte_errno is set.
312  */
313 int
314 mlx5_mp_os_req_queue_control(struct rte_eth_dev *dev, uint16_t queue_id,
315 			  enum mlx5_mp_req_type req_type)
316 {
317 	struct rte_mp_msg mp_req;
318 	struct rte_mp_msg *mp_res;
319 	struct rte_mp_reply mp_rep;
320 	struct mlx5_mp_param *req = (struct mlx5_mp_param *)mp_req.param;
321 	struct mlx5_mp_param *res;
322 	struct timespec ts = {.tv_sec = MLX5_MP_REQ_TIMEOUT_SEC, .tv_nsec = 0};
323 	struct mlx5_priv *priv;
324 	int ret;
325 
326 	MLX5_ASSERT(rte_eal_process_type() == RTE_PROC_SECONDARY);
327 	priv = dev->data->dev_private;
328 	mp_init_msg(&priv->mp_id, &mp_req, req_type);
329 	req->args.queue_id.queue_id = queue_id;
330 	ret = rte_mp_request_sync(&mp_req, &mp_rep, &ts);
331 	if (ret) {
332 		DRV_LOG(ERR, "port %u request to primary process failed",
333 			dev->data->port_id);
334 		return -rte_errno;
335 	}
336 	MLX5_ASSERT(mp_rep.nb_received == 1);
337 	mp_res = &mp_rep.msgs[0];
338 	res = (struct mlx5_mp_param *)mp_res->param;
339 	ret = res->result;
340 	free(mp_rep.msgs);
341 	return ret;
342 }
343