37f26cc71cae6c1ccda5ebf841771ba24d915af0
[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         default:
89                 rte_errno = EINVAL;
90                 DRV_LOG(ERR, "port %u invalid mp request type",
91                         dev->data->port_id);
92                 return -rte_errno;
93         }
94         return ret;
95 }
96
97 /**
98  * IPC message handler of a secondary process.
99  *
100  * @param[in] dev
101  *   Pointer to Ethernet structure.
102  * @param[in] peer
103  *   Pointer to the peer socket path.
104  *
105  * @return
106  *   0 on success, a negative errno value otherwise and rte_errno is set.
107  */
108 static int
109 mp_secondary_handle(const struct rte_mp_msg *mp_msg, const void *peer)
110 {
111         struct rte_mp_msg mp_res;
112         struct mlx5_mp_param *res = (struct mlx5_mp_param *)mp_res.param;
113         const struct mlx5_mp_param *param =
114                 (const struct mlx5_mp_param *)mp_msg->param;
115         struct rte_eth_dev *dev;
116         int ret;
117
118         assert(rte_eal_process_type() == RTE_PROC_SECONDARY);
119         if (!rte_eth_dev_is_valid_port(param->port_id)) {
120                 rte_errno = ENODEV;
121                 DRV_LOG(ERR, "port %u invalid port ID", param->port_id);
122                 return -rte_errno;
123         }
124         dev = &rte_eth_devices[param->port_id];
125         switch (param->type) {
126         case MLX5_MP_REQ_START_RXTX:
127                 DRV_LOG(INFO, "port %u starting datapath", dev->data->port_id);
128                 rte_mb();
129                 dev->rx_pkt_burst = mlx5_select_rx_function(dev);
130                 dev->tx_pkt_burst = mlx5_select_tx_function(dev);
131                 mp_init_msg(dev, &mp_res, param->type);
132                 res->result = 0;
133                 ret = rte_mp_reply(&mp_res, peer);
134                 break;
135         case MLX5_MP_REQ_STOP_RXTX:
136                 DRV_LOG(INFO, "port %u stopping datapath", dev->data->port_id);
137                 dev->rx_pkt_burst = removed_rx_burst;
138                 dev->tx_pkt_burst = removed_tx_burst;
139                 rte_mb();
140                 mp_init_msg(dev, &mp_res, param->type);
141                 res->result = 0;
142                 ret = rte_mp_reply(&mp_res, peer);
143                 break;
144         default:
145                 rte_errno = EINVAL;
146                 DRV_LOG(ERR, "port %u invalid mp request type",
147                         dev->data->port_id);
148                 return -rte_errno;
149         }
150         return ret;
151 }
152
153 /**
154  * Broadcast request of stopping/starting data-path to secondary processes.
155  *
156  * @param[in] dev
157  *   Pointer to Ethernet structure.
158  * @param[in] type
159  *   Request type.
160  */
161 static void
162 mp_req_on_rxtx(struct rte_eth_dev *dev, enum mlx5_mp_req_type type)
163 {
164         struct rte_mp_msg mp_req;
165         struct rte_mp_msg *mp_res;
166         struct rte_mp_reply mp_rep;
167         struct mlx5_mp_param *res;
168         struct timespec ts = {.tv_sec = MLX5_MP_REQ_TIMEOUT_SEC, .tv_nsec = 0};
169         int ret;
170         int i;
171
172         assert(rte_eal_process_type() == RTE_PROC_PRIMARY);
173         if (!mlx5_shared_data->secondary_cnt)
174                 return;
175         if (type != MLX5_MP_REQ_START_RXTX && type != MLX5_MP_REQ_STOP_RXTX) {
176                 DRV_LOG(ERR, "port %u unknown request (req_type %d)",
177                         dev->data->port_id, type);
178                 return;
179         }
180         mp_init_msg(dev, &mp_req, type);
181         ret = rte_mp_request_sync(&mp_req, &mp_rep, &ts);
182         if (ret) {
183                 if (rte_errno != ENOTSUP)
184                         DRV_LOG(ERR, "port %u failed to request stop/start Rx/Tx (%d)",
185                                 dev->data->port_id, type);
186                 goto exit;
187         }
188         if (mp_rep.nb_sent != mp_rep.nb_received) {
189                 DRV_LOG(ERR,
190                         "port %u not all secondaries responded (req_type %d)",
191                         dev->data->port_id, type);
192                 goto exit;
193         }
194         for (i = 0; i < mp_rep.nb_received; i++) {
195                 mp_res = &mp_rep.msgs[i];
196                 res = (struct mlx5_mp_param *)mp_res->param;
197                 if (res->result) {
198                         DRV_LOG(ERR, "port %u request failed on secondary #%d",
199                                 dev->data->port_id, i);
200                         goto exit;
201                 }
202         }
203 exit:
204         free(mp_rep.msgs);
205 }
206
207 /**
208  * Broadcast request of starting data-path to secondary processes. The request
209  * is synchronous.
210  *
211  * @param[in] dev
212  *   Pointer to Ethernet structure.
213  */
214 void
215 mlx5_mp_req_start_rxtx(struct rte_eth_dev *dev)
216 {
217         mp_req_on_rxtx(dev, MLX5_MP_REQ_START_RXTX);
218 }
219
220 /**
221  * Broadcast request of stopping data-path to secondary processes. The request
222  * is synchronous.
223  *
224  * @param[in] dev
225  *   Pointer to Ethernet structure.
226  */
227 void
228 mlx5_mp_req_stop_rxtx(struct rte_eth_dev *dev)
229 {
230         mp_req_on_rxtx(dev, MLX5_MP_REQ_STOP_RXTX);
231 }
232
233 /**
234  * Request Memory Region creation to the primary process.
235  *
236  * @param[in] dev
237  *   Pointer to Ethernet structure.
238  * @param addr
239  *   Target virtual address to register.
240  *
241  * @return
242  *   0 on success, a negative errno value otherwise and rte_errno is set.
243  */
244 int
245 mlx5_mp_req_mr_create(struct rte_eth_dev *dev, uintptr_t addr)
246 {
247         struct rte_mp_msg mp_req;
248         struct rte_mp_msg *mp_res;
249         struct rte_mp_reply mp_rep;
250         struct mlx5_mp_param *req = (struct mlx5_mp_param *)mp_req.param;
251         struct mlx5_mp_param *res;
252         struct timespec ts = {.tv_sec = MLX5_MP_REQ_TIMEOUT_SEC, .tv_nsec = 0};
253         int ret;
254
255         assert(rte_eal_process_type() == RTE_PROC_SECONDARY);
256         mp_init_msg(dev, &mp_req, MLX5_MP_REQ_CREATE_MR);
257         req->args.addr = addr;
258         ret = rte_mp_request_sync(&mp_req, &mp_rep, &ts);
259         if (ret) {
260                 DRV_LOG(ERR, "port %u request to primary process failed",
261                         dev->data->port_id);
262                 return -rte_errno;
263         }
264         assert(mp_rep.nb_received == 1);
265         mp_res = &mp_rep.msgs[0];
266         res = (struct mlx5_mp_param *)mp_res->param;
267         ret = res->result;
268         if (ret)
269                 rte_errno = -ret;
270         free(mp_rep.msgs);
271         return ret;
272 }
273
274 /**
275  * Request Verbs command file descriptor for mmap to the primary process.
276  *
277  * @param[in] dev
278  *   Pointer to Ethernet structure.
279  *
280  * @return
281  *   fd on success, a negative errno value otherwise and rte_errno is set.
282  */
283 int
284 mlx5_mp_req_verbs_cmd_fd(struct rte_eth_dev *dev)
285 {
286         struct rte_mp_msg mp_req;
287         struct rte_mp_msg *mp_res;
288         struct rte_mp_reply mp_rep;
289         struct mlx5_mp_param *res;
290         struct timespec ts = {.tv_sec = MLX5_MP_REQ_TIMEOUT_SEC, .tv_nsec = 0};
291         int ret;
292
293         assert(rte_eal_process_type() == RTE_PROC_SECONDARY);
294         mp_init_msg(dev, &mp_req, MLX5_MP_REQ_VERBS_CMD_FD);
295         ret = rte_mp_request_sync(&mp_req, &mp_rep, &ts);
296         if (ret) {
297                 DRV_LOG(ERR, "port %u request to primary process failed",
298                         dev->data->port_id);
299                 return -rte_errno;
300         }
301         assert(mp_rep.nb_received == 1);
302         mp_res = &mp_rep.msgs[0];
303         res = (struct mlx5_mp_param *)mp_res->param;
304         if (res->result) {
305                 rte_errno = -res->result;
306                 DRV_LOG(ERR,
307                         "port %u failed to get command FD from primary process",
308                         dev->data->port_id);
309                 ret = -rte_errno;
310                 goto exit;
311         }
312         assert(mp_res->num_fds == 1);
313         ret = mp_res->fds[0];
314         DRV_LOG(DEBUG, "port %u command FD from primary is %d",
315                 dev->data->port_id, ret);
316 exit:
317         free(mp_rep.msgs);
318         return ret;
319 }
320
321 /**
322  * Initialize by primary process.
323  */
324 int
325 mlx5_mp_init_primary(void)
326 {
327         int ret;
328
329         assert(rte_eal_process_type() == RTE_PROC_PRIMARY);
330
331         /* primary is allowed to not support IPC */
332         ret = rte_mp_action_register(MLX5_MP_NAME, mp_primary_handle);
333         if (ret && rte_errno != ENOTSUP)
334                 return -1;
335         return 0;
336 }
337
338 /**
339  * Un-initialize by primary process.
340  */
341 void
342 mlx5_mp_uninit_primary(void)
343 {
344         assert(rte_eal_process_type() == RTE_PROC_PRIMARY);
345         rte_mp_action_unregister(MLX5_MP_NAME);
346 }
347
348 /**
349  * Initialize by secondary process.
350  */
351 int
352 mlx5_mp_init_secondary(void)
353 {
354         assert(rte_eal_process_type() == RTE_PROC_SECONDARY);
355         return rte_mp_action_register(MLX5_MP_NAME, mp_secondary_handle);
356 }
357
358 /**
359  * Un-initialize by secondary process.
360  */
361 void
362 mlx5_mp_uninit_secondary(void)
363 {
364         assert(rte_eal_process_type() == RTE_PROC_SECONDARY);
365         rte_mp_action_unregister(MLX5_MP_NAME);
366 }