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