net/ice/base: fix null pointer dereferences for parser
[dpdk.git] / drivers / net / mlx4 / mlx4_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 <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                 dev->tx_pkt_burst = mlx4_tx_burst;
130                 dev->rx_pkt_burst = mlx4_rx_burst;
131 #ifdef HAVE_IBV_MLX4_UAR_MMAP_OFFSET
132                 ppriv = (struct mlx4_proc_priv *)dev->process_private;
133                 if (ppriv->uar_table_sz != dev->data->nb_tx_queues) {
134                         mlx4_tx_uar_uninit_secondary(dev);
135                         mlx4_proc_priv_uninit(dev);
136                         ret = mlx4_proc_priv_init(dev);
137                         if (ret)
138                                 return -rte_errno;
139                         ret = mlx4_tx_uar_init_secondary(dev, mp_msg->fds[0]);
140                         if (ret) {
141                                 mlx4_proc_priv_uninit(dev);
142                                 return -rte_errno;
143                         }
144                 }
145 #endif
146                 rte_mb();
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 }