2a031e26101b564ea312be3f10506722610fcae4
[dpdk.git] / drivers / net / mlx5 / mlx5_mp.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2019 6WIND S.A.
3  * Copyright 2019 Mellanox Technologies, Ltd
4  */
5
6 #include <assert.h>
7 #include <stdio.h>
8 #include <time.h>
9
10 #include <rte_eal.h>
11 #include <rte_ethdev_driver.h>
12 #include <rte_string_fns.h>
13
14 #include "mlx5.h"
15 #include "mlx5_rxtx.h"
16 #include "mlx5_utils.h"
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
29 mp_init_msg(struct rte_eth_dev *dev, struct rte_mp_msg *msg,
30             enum mlx5_mp_req_type type)
31 {
32         struct mlx5_mp_param *param = (struct mlx5_mp_param *)msg->param;
33
34         memset(msg, 0, sizeof(*msg));
35         strlcpy(msg->name, MLX5_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
53 mp_primary_handle(const struct rte_mp_msg *mp_msg, const void *peer)
54 {
55         struct rte_mp_msg mp_res;
56         struct mlx5_mp_param *res = (struct mlx5_mp_param *)mp_res.param;
57         const struct mlx5_mp_param *param =
58                 (const struct mlx5_mp_param *)mp_msg->param;
59         struct rte_eth_dev *dev;
60         struct mlx5_priv *priv;
61         struct mlx5_mr_cache entry;
62         uint32_t lkey;
63         int ret;
64
65         assert(rte_eal_process_type() == RTE_PROC_PRIMARY);
66         if (!rte_eth_dev_is_valid_port(param->port_id)) {
67                 rte_errno = ENODEV;
68                 DRV_LOG(ERR, "port %u invalid port ID", param->port_id);
69                 return -rte_errno;
70         }
71         dev = &rte_eth_devices[param->port_id];
72         priv = dev->data->dev_private;
73         switch (param->type) {
74         case MLX5_MP_REQ_CREATE_MR:
75                 mp_init_msg(dev, &mp_res, param->type);
76                 lkey = mlx5_mr_create_primary(dev, &entry, param->args.addr);
77                 if (lkey == UINT32_MAX)
78                         res->result = -rte_errno;
79                 ret = rte_mp_reply(&mp_res, peer);
80                 break;
81         case MLX5_MP_REQ_VERBS_CMD_FD:
82                 mp_init_msg(dev, &mp_res, param->type);
83                 mp_res.num_fds = 1;
84                 mp_res.fds[0] = priv->sh->ctx->cmd_fd;
85                 res->result = 0;
86                 ret = rte_mp_reply(&mp_res, peer);
87                 break;
88         case MLX5_MP_REQ_QUEUE_STATE_MODIFY:
89                 mp_init_msg(dev, &mp_res, param->type);
90                 res->result = mlx5_queue_state_modify_primary
91                                         (dev, &param->args.state_modify);
92                 ret = rte_mp_reply(&mp_res, peer);
93                 break;
94         default:
95                 rte_errno = EINVAL;
96                 DRV_LOG(ERR, "port %u invalid mp request type",
97                         dev->data->port_id);
98                 return -rte_errno;
99         }
100         return ret;
101 }
102
103 /**
104  * IPC message handler of a secondary process.
105  *
106  * @param[in] dev
107  *   Pointer to Ethernet structure.
108  * @param[in] peer
109  *   Pointer to the peer socket path.
110  *
111  * @return
112  *   0 on success, a negative errno value otherwise and rte_errno is set.
113  */
114 static int
115 mp_secondary_handle(const struct rte_mp_msg *mp_msg, const void *peer)
116 {
117         struct rte_mp_msg mp_res;
118         struct mlx5_mp_param *res = (struct mlx5_mp_param *)mp_res.param;
119         const struct mlx5_mp_param *param =
120                 (const struct mlx5_mp_param *)mp_msg->param;
121         struct rte_eth_dev *dev;
122         int ret;
123
124         assert(rte_eal_process_type() == RTE_PROC_SECONDARY);
125         if (!rte_eth_dev_is_valid_port(param->port_id)) {
126                 rte_errno = ENODEV;
127                 DRV_LOG(ERR, "port %u invalid port ID", param->port_id);
128                 return -rte_errno;
129         }
130         dev = &rte_eth_devices[param->port_id];
131         switch (param->type) {
132         case MLX5_MP_REQ_START_RXTX:
133                 DRV_LOG(INFO, "port %u starting datapath", dev->data->port_id);
134                 rte_mb();
135                 dev->rx_pkt_burst = mlx5_select_rx_function(dev);
136                 dev->tx_pkt_burst = mlx5_select_tx_function(dev);
137                 mp_init_msg(dev, &mp_res, param->type);
138                 res->result = 0;
139                 ret = rte_mp_reply(&mp_res, peer);
140                 break;
141         case MLX5_MP_REQ_STOP_RXTX:
142                 DRV_LOG(INFO, "port %u stopping datapath", dev->data->port_id);
143                 dev->rx_pkt_burst = removed_rx_burst;
144                 dev->tx_pkt_burst = removed_tx_burst;
145                 rte_mb();
146                 mp_init_msg(dev, &mp_res, param->type);
147                 res->result = 0;
148                 ret = rte_mp_reply(&mp_res, peer);
149                 break;
150         default:
151                 rte_errno = EINVAL;
152                 DRV_LOG(ERR, "port %u invalid mp request type",
153                         dev->data->port_id);
154                 return -rte_errno;
155         }
156         return ret;
157 }
158
159 /**
160  * Broadcast request of stopping/starting data-path to secondary processes.
161  *
162  * @param[in] dev
163  *   Pointer to Ethernet structure.
164  * @param[in] type
165  *   Request type.
166  */
167 static void
168 mp_req_on_rxtx(struct rte_eth_dev *dev, enum mlx5_mp_req_type type)
169 {
170         struct rte_mp_msg mp_req;
171         struct rte_mp_msg *mp_res;
172         struct rte_mp_reply mp_rep;
173         struct mlx5_mp_param *res;
174         struct timespec ts = {.tv_sec = MLX5_MP_REQ_TIMEOUT_SEC, .tv_nsec = 0};
175         int ret;
176         int i;
177
178         assert(rte_eal_process_type() == RTE_PROC_PRIMARY);
179         if (!mlx5_shared_data->secondary_cnt)
180                 return;
181         if (type != MLX5_MP_REQ_START_RXTX && type != MLX5_MP_REQ_STOP_RXTX) {
182                 DRV_LOG(ERR, "port %u unknown request (req_type %d)",
183                         dev->data->port_id, type);
184                 return;
185         }
186         mp_init_msg(dev, &mp_req, type);
187         ret = rte_mp_request_sync(&mp_req, &mp_rep, &ts);
188         if (ret) {
189                 if (rte_errno != ENOTSUP)
190                         DRV_LOG(ERR, "port %u failed to request stop/start Rx/Tx (%d)",
191                                 dev->data->port_id, type);
192                 goto exit;
193         }
194         if (mp_rep.nb_sent != mp_rep.nb_received) {
195                 DRV_LOG(ERR,
196                         "port %u not all secondaries responded (req_type %d)",
197                         dev->data->port_id, type);
198                 goto exit;
199         }
200         for (i = 0; i < mp_rep.nb_received; i++) {
201                 mp_res = &mp_rep.msgs[i];
202                 res = (struct mlx5_mp_param *)mp_res->param;
203                 if (res->result) {
204                         DRV_LOG(ERR, "port %u request failed on secondary #%d",
205                                 dev->data->port_id, i);
206                         goto exit;
207                 }
208         }
209 exit:
210         free(mp_rep.msgs);
211 }
212
213 /**
214  * Broadcast request of starting data-path to secondary processes. The request
215  * is synchronous.
216  *
217  * @param[in] dev
218  *   Pointer to Ethernet structure.
219  */
220 void
221 mlx5_mp_req_start_rxtx(struct rte_eth_dev *dev)
222 {
223         mp_req_on_rxtx(dev, MLX5_MP_REQ_START_RXTX);
224 }
225
226 /**
227  * Broadcast request of stopping data-path to secondary processes. The request
228  * is synchronous.
229  *
230  * @param[in] dev
231  *   Pointer to Ethernet structure.
232  */
233 void
234 mlx5_mp_req_stop_rxtx(struct rte_eth_dev *dev)
235 {
236         mp_req_on_rxtx(dev, MLX5_MP_REQ_STOP_RXTX);
237 }
238
239 /**
240  * Request Memory Region creation to the primary process.
241  *
242  * @param[in] dev
243  *   Pointer to Ethernet structure.
244  * @param addr
245  *   Target virtual address to register.
246  *
247  * @return
248  *   0 on success, a negative errno value otherwise and rte_errno is set.
249  */
250 int
251 mlx5_mp_req_mr_create(struct rte_eth_dev *dev, uintptr_t addr)
252 {
253         struct rte_mp_msg mp_req;
254         struct rte_mp_msg *mp_res;
255         struct rte_mp_reply mp_rep;
256         struct mlx5_mp_param *req = (struct mlx5_mp_param *)mp_req.param;
257         struct mlx5_mp_param *res;
258         struct timespec ts = {.tv_sec = MLX5_MP_REQ_TIMEOUT_SEC, .tv_nsec = 0};
259         int ret;
260
261         assert(rte_eal_process_type() == RTE_PROC_SECONDARY);
262         mp_init_msg(dev, &mp_req, MLX5_MP_REQ_CREATE_MR);
263         req->args.addr = addr;
264         ret = rte_mp_request_sync(&mp_req, &mp_rep, &ts);
265         if (ret) {
266                 DRV_LOG(ERR, "port %u request to primary process failed",
267                         dev->data->port_id);
268                 return -rte_errno;
269         }
270         assert(mp_rep.nb_received == 1);
271         mp_res = &mp_rep.msgs[0];
272         res = (struct mlx5_mp_param *)mp_res->param;
273         ret = res->result;
274         if (ret)
275                 rte_errno = -ret;
276         free(mp_rep.msgs);
277         return ret;
278 }
279
280 /**
281  * Request Verbs queue state modification to the primary process.
282  *
283  * @param[in] dev
284  *   Pointer to Ethernet structure.
285  * @param sm
286  *   State modify parameters.
287  *
288  * @return
289  *   0 on success, a negative errno value otherwise and rte_errno is set.
290  */
291 int
292 mlx5_mp_req_queue_state_modify(struct rte_eth_dev *dev,
293                                struct mlx5_mp_arg_queue_state_modify *sm)
294 {
295         struct rte_mp_msg mp_req;
296         struct rte_mp_msg *mp_res;
297         struct rte_mp_reply mp_rep;
298         struct mlx5_mp_param *req = (struct mlx5_mp_param *)mp_req.param;
299         struct mlx5_mp_param *res;
300         struct timespec ts = {.tv_sec = MLX5_MP_REQ_TIMEOUT_SEC, .tv_nsec = 0};
301         int ret;
302
303         assert(rte_eal_process_type() == RTE_PROC_SECONDARY);
304         mp_init_msg(dev, &mp_req, MLX5_MP_REQ_QUEUE_STATE_MODIFY);
305         req->args.state_modify = *sm;
306         ret = rte_mp_request_sync(&mp_req, &mp_rep, &ts);
307         if (ret) {
308                 DRV_LOG(ERR, "port %u request to primary process failed",
309                         dev->data->port_id);
310                 return -rte_errno;
311         }
312         assert(mp_rep.nb_received == 1);
313         mp_res = &mp_rep.msgs[0];
314         res = (struct mlx5_mp_param *)mp_res->param;
315         ret = res->result;
316         free(mp_rep.msgs);
317         return ret;
318 }
319
320 /**
321  * Request Verbs command file descriptor for mmap to the primary process.
322  *
323  * @param[in] dev
324  *   Pointer to Ethernet structure.
325  *
326  * @return
327  *   fd on success, a negative errno value otherwise and rte_errno is set.
328  */
329 int
330 mlx5_mp_req_verbs_cmd_fd(struct rte_eth_dev *dev)
331 {
332         struct rte_mp_msg mp_req;
333         struct rte_mp_msg *mp_res;
334         struct rte_mp_reply mp_rep;
335         struct mlx5_mp_param *res;
336         struct timespec ts = {.tv_sec = MLX5_MP_REQ_TIMEOUT_SEC, .tv_nsec = 0};
337         int ret;
338
339         assert(rte_eal_process_type() == RTE_PROC_SECONDARY);
340         mp_init_msg(dev, &mp_req, MLX5_MP_REQ_VERBS_CMD_FD);
341         ret = rte_mp_request_sync(&mp_req, &mp_rep, &ts);
342         if (ret) {
343                 DRV_LOG(ERR, "port %u request to primary process failed",
344                         dev->data->port_id);
345                 return -rte_errno;
346         }
347         assert(mp_rep.nb_received == 1);
348         mp_res = &mp_rep.msgs[0];
349         res = (struct mlx5_mp_param *)mp_res->param;
350         if (res->result) {
351                 rte_errno = -res->result;
352                 DRV_LOG(ERR,
353                         "port %u failed to get command FD from primary process",
354                         dev->data->port_id);
355                 ret = -rte_errno;
356                 goto exit;
357         }
358         assert(mp_res->num_fds == 1);
359         ret = mp_res->fds[0];
360         DRV_LOG(DEBUG, "port %u command FD from primary is %d",
361                 dev->data->port_id, ret);
362 exit:
363         free(mp_rep.msgs);
364         return ret;
365 }
366
367 /**
368  * Initialize by primary process.
369  */
370 int
371 mlx5_mp_init_primary(void)
372 {
373         int ret;
374
375         assert(rte_eal_process_type() == RTE_PROC_PRIMARY);
376
377         /* primary is allowed to not support IPC */
378         ret = rte_mp_action_register(MLX5_MP_NAME, mp_primary_handle);
379         if (ret && rte_errno != ENOTSUP)
380                 return -1;
381         return 0;
382 }
383
384 /**
385  * Un-initialize by primary process.
386  */
387 void
388 mlx5_mp_uninit_primary(void)
389 {
390         assert(rte_eal_process_type() == RTE_PROC_PRIMARY);
391         rte_mp_action_unregister(MLX5_MP_NAME);
392 }
393
394 /**
395  * Initialize by secondary process.
396  */
397 int
398 mlx5_mp_init_secondary(void)
399 {
400         assert(rte_eal_process_type() == RTE_PROC_SECONDARY);
401         return rte_mp_action_register(MLX5_MP_NAME, mp_secondary_handle);
402 }
403
404 /**
405  * Un-initialize by secondary process.
406  */
407 void
408 mlx5_mp_uninit_secondary(void)
409 {
410         assert(rte_eal_process_type() == RTE_PROC_SECONDARY);
411         rte_mp_action_unregister(MLX5_MP_NAME);
412 }