ipc: handle unsupported IPC in action register
[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                 DRV_LOG(ERR, "port %u failed to request stop/start Rx/Tx (%d)",
184                         dev->data->port_id, type);
185                 goto exit;
186         }
187         if (mp_rep.nb_sent != mp_rep.nb_received) {
188                 DRV_LOG(ERR,
189                         "port %u not all secondaries responded (req_type %d)",
190                         dev->data->port_id, type);
191                 goto exit;
192         }
193         for (i = 0; i < mp_rep.nb_received; i++) {
194                 mp_res = &mp_rep.msgs[i];
195                 res = (struct mlx5_mp_param *)mp_res->param;
196                 if (res->result) {
197                         DRV_LOG(ERR, "port %u request failed on secondary #%d",
198                                 dev->data->port_id, i);
199                         goto exit;
200                 }
201         }
202 exit:
203         free(mp_rep.msgs);
204 }
205
206 /**
207  * Broadcast request of starting data-path to secondary processes. The request
208  * is synchronous.
209  *
210  * @param[in] dev
211  *   Pointer to Ethernet structure.
212  */
213 void
214 mlx5_mp_req_start_rxtx(struct rte_eth_dev *dev)
215 {
216         mp_req_on_rxtx(dev, MLX5_MP_REQ_START_RXTX);
217 }
218
219 /**
220  * Broadcast request of stopping data-path to secondary processes. The request
221  * is synchronous.
222  *
223  * @param[in] dev
224  *   Pointer to Ethernet structure.
225  */
226 void
227 mlx5_mp_req_stop_rxtx(struct rte_eth_dev *dev)
228 {
229         mp_req_on_rxtx(dev, MLX5_MP_REQ_STOP_RXTX);
230 }
231
232 /**
233  * Request Memory Region creation to the primary process.
234  *
235  * @param[in] dev
236  *   Pointer to Ethernet structure.
237  * @param addr
238  *   Target virtual address to register.
239  *
240  * @return
241  *   0 on success, a negative errno value otherwise and rte_errno is set.
242  */
243 int
244 mlx5_mp_req_mr_create(struct rte_eth_dev *dev, uintptr_t addr)
245 {
246         struct rte_mp_msg mp_req;
247         struct rte_mp_msg *mp_res;
248         struct rte_mp_reply mp_rep;
249         struct mlx5_mp_param *req = (struct mlx5_mp_param *)mp_req.param;
250         struct mlx5_mp_param *res;
251         struct timespec ts = {.tv_sec = MLX5_MP_REQ_TIMEOUT_SEC, .tv_nsec = 0};
252         int ret;
253
254         assert(rte_eal_process_type() == RTE_PROC_SECONDARY);
255         mp_init_msg(dev, &mp_req, MLX5_MP_REQ_CREATE_MR);
256         req->args.addr = addr;
257         ret = rte_mp_request_sync(&mp_req, &mp_rep, &ts);
258         if (ret) {
259                 DRV_LOG(ERR, "port %u request to primary process failed",
260                         dev->data->port_id);
261                 return -rte_errno;
262         }
263         assert(mp_rep.nb_received == 1);
264         mp_res = &mp_rep.msgs[0];
265         res = (struct mlx5_mp_param *)mp_res->param;
266         ret = res->result;
267         if (ret)
268                 rte_errno = -ret;
269         free(mp_rep.msgs);
270         return ret;
271 }
272
273 /**
274  * Request Verbs command file descriptor for mmap to the primary process.
275  *
276  * @param[in] dev
277  *   Pointer to Ethernet structure.
278  *
279  * @return
280  *   fd on success, a negative errno value otherwise and rte_errno is set.
281  */
282 int
283 mlx5_mp_req_verbs_cmd_fd(struct rte_eth_dev *dev)
284 {
285         struct rte_mp_msg mp_req;
286         struct rte_mp_msg *mp_res;
287         struct rte_mp_reply mp_rep;
288         struct mlx5_mp_param *res;
289         struct timespec ts = {.tv_sec = MLX5_MP_REQ_TIMEOUT_SEC, .tv_nsec = 0};
290         int ret;
291
292         assert(rte_eal_process_type() == RTE_PROC_SECONDARY);
293         mp_init_msg(dev, &mp_req, MLX5_MP_REQ_VERBS_CMD_FD);
294         ret = rte_mp_request_sync(&mp_req, &mp_rep, &ts);
295         if (ret) {
296                 DRV_LOG(ERR, "port %u request to primary process failed",
297                         dev->data->port_id);
298                 return -rte_errno;
299         }
300         assert(mp_rep.nb_received == 1);
301         mp_res = &mp_rep.msgs[0];
302         res = (struct mlx5_mp_param *)mp_res->param;
303         if (res->result) {
304                 rte_errno = -res->result;
305                 DRV_LOG(ERR,
306                         "port %u failed to get command FD from primary process",
307                         dev->data->port_id);
308                 ret = -rte_errno;
309                 goto exit;
310         }
311         assert(mp_res->num_fds == 1);
312         ret = mp_res->fds[0];
313         DRV_LOG(DEBUG, "port %u command FD from primary is %d",
314                 dev->data->port_id, ret);
315 exit:
316         free(mp_rep.msgs);
317         return ret;
318 }
319
320 /**
321  * Initialize by primary process.
322  */
323 int
324 mlx5_mp_init_primary(void)
325 {
326         int ret;
327
328         assert(rte_eal_process_type() == RTE_PROC_PRIMARY);
329
330         /* primary is allowed to not support IPC */
331         ret = rte_mp_action_register(MLX5_MP_NAME, mp_primary_handle);
332         if (ret && rte_errno != ENOTSUP)
333                 return -1;
334         return 0;
335 }
336
337 /**
338  * Un-initialize by primary process.
339  */
340 void
341 mlx5_mp_uninit_primary(void)
342 {
343         assert(rte_eal_process_type() == RTE_PROC_PRIMARY);
344         rte_mp_action_unregister(MLX5_MP_NAME);
345 }
346
347 /**
348  * Initialize by secondary process.
349  */
350 int
351 mlx5_mp_init_secondary(void)
352 {
353         assert(rte_eal_process_type() == RTE_PROC_SECONDARY);
354         return rte_mp_action_register(MLX5_MP_NAME, mp_secondary_handle);
355 }
356
357 /**
358  * Un-initialize by secondary process.
359  */
360 void
361 mlx5_mp_uninit_secondary(void)
362 {
363         assert(rte_eal_process_type() == RTE_PROC_SECONDARY);
364         rte_mp_action_unregister(MLX5_MP_NAME);
365 }