1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright 2019 6WIND S.A.
3 * Copyright 2019 Mellanox Technologies, Ltd
10 #include <rte_ethdev_driver.h>
11 #include <rte_string_fns.h>
14 #include "mlx5_rxtx.h"
15 #include "mlx5_utils.h"
18 * Initialize IPC message.
21 * Pointer to Ethernet structure.
23 * Pointer to message to fill in.
28 mp_init_msg(struct rte_eth_dev *dev, struct rte_mp_msg *msg,
29 enum mlx5_mp_req_type type)
31 struct mlx5_mp_param *param = (struct mlx5_mp_param *)msg->param;
33 memset(msg, 0, sizeof(*msg));
34 strlcpy(msg->name, MLX5_MP_NAME, sizeof(msg->name));
35 msg->len_param = sizeof(*param);
37 param->port_id = dev->data->port_id;
41 * IPC message handler of primary process.
44 * Pointer to Ethernet structure.
46 * Pointer to the peer socket path.
49 * 0 on success, a negative errno value otherwise and rte_errno is set.
52 mp_primary_handle(const struct rte_mp_msg *mp_msg, const void *peer)
54 struct rte_mp_msg mp_res;
55 struct mlx5_mp_param *res = (struct mlx5_mp_param *)mp_res.param;
56 const struct mlx5_mp_param *param =
57 (const struct mlx5_mp_param *)mp_msg->param;
58 struct rte_eth_dev *dev;
59 struct mlx5_priv *priv;
60 struct mlx5_mr_cache entry;
64 MLX5_ASSERT(rte_eal_process_type() == RTE_PROC_PRIMARY);
65 if (!rte_eth_dev_is_valid_port(param->port_id)) {
67 DRV_LOG(ERR, "port %u invalid port ID", param->port_id);
70 dev = &rte_eth_devices[param->port_id];
71 priv = dev->data->dev_private;
72 switch (param->type) {
73 case MLX5_MP_REQ_CREATE_MR:
74 mp_init_msg(dev, &mp_res, param->type);
75 lkey = mlx5_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);
80 case MLX5_MP_REQ_VERBS_CMD_FD:
81 mp_init_msg(dev, &mp_res, param->type);
83 mp_res.fds[0] = priv->sh->ctx->cmd_fd;
85 ret = rte_mp_reply(&mp_res, peer);
87 case MLX5_MP_REQ_QUEUE_STATE_MODIFY:
88 mp_init_msg(dev, &mp_res, param->type);
89 res->result = mlx5_queue_state_modify_primary
90 (dev, ¶m->args.state_modify);
91 ret = rte_mp_reply(&mp_res, peer);
95 DRV_LOG(ERR, "port %u invalid mp request type",
103 * IPC message handler of a secondary process.
106 * Pointer to Ethernet structure.
108 * Pointer to the peer socket path.
111 * 0 on success, a negative errno value otherwise and rte_errno is set.
114 mp_secondary_handle(const struct rte_mp_msg *mp_msg, const void *peer)
116 struct rte_mp_msg mp_res;
117 struct mlx5_mp_param *res = (struct mlx5_mp_param *)mp_res.param;
118 const struct mlx5_mp_param *param =
119 (const struct mlx5_mp_param *)mp_msg->param;
120 struct rte_eth_dev *dev;
123 MLX5_ASSERT(rte_eal_process_type() == RTE_PROC_SECONDARY);
124 if (!rte_eth_dev_is_valid_port(param->port_id)) {
126 DRV_LOG(ERR, "port %u invalid port ID", param->port_id);
129 dev = &rte_eth_devices[param->port_id];
130 switch (param->type) {
131 case MLX5_MP_REQ_START_RXTX:
132 DRV_LOG(INFO, "port %u starting datapath", dev->data->port_id);
134 dev->rx_pkt_burst = mlx5_select_rx_function(dev);
135 dev->tx_pkt_burst = mlx5_select_tx_function(dev);
136 mp_init_msg(dev, &mp_res, param->type);
138 ret = rte_mp_reply(&mp_res, peer);
140 case MLX5_MP_REQ_STOP_RXTX:
141 DRV_LOG(INFO, "port %u stopping datapath", dev->data->port_id);
142 dev->rx_pkt_burst = removed_rx_burst;
143 dev->tx_pkt_burst = removed_tx_burst;
145 mp_init_msg(dev, &mp_res, param->type);
147 ret = rte_mp_reply(&mp_res, peer);
151 DRV_LOG(ERR, "port %u invalid mp request type",
159 * Broadcast request of stopping/starting data-path to secondary processes.
162 * Pointer to Ethernet structure.
167 mp_req_on_rxtx(struct rte_eth_dev *dev, enum mlx5_mp_req_type type)
169 struct rte_mp_msg mp_req;
170 struct rte_mp_msg *mp_res;
171 struct rte_mp_reply mp_rep;
172 struct mlx5_mp_param *res;
173 struct timespec ts = {.tv_sec = MLX5_MP_REQ_TIMEOUT_SEC, .tv_nsec = 0};
177 MLX5_ASSERT(rte_eal_process_type() == RTE_PROC_PRIMARY);
178 if (!mlx5_shared_data->secondary_cnt)
180 if (type != MLX5_MP_REQ_START_RXTX && type != MLX5_MP_REQ_STOP_RXTX) {
181 DRV_LOG(ERR, "port %u unknown request (req_type %d)",
182 dev->data->port_id, type);
185 mp_init_msg(dev, &mp_req, type);
186 ret = rte_mp_request_sync(&mp_req, &mp_rep, &ts);
188 if (rte_errno != ENOTSUP)
189 DRV_LOG(ERR, "port %u failed to request stop/start Rx/Tx (%d)",
190 dev->data->port_id, type);
193 if (mp_rep.nb_sent != mp_rep.nb_received) {
195 "port %u not all secondaries responded (req_type %d)",
196 dev->data->port_id, type);
199 for (i = 0; i < mp_rep.nb_received; i++) {
200 mp_res = &mp_rep.msgs[i];
201 res = (struct mlx5_mp_param *)mp_res->param;
203 DRV_LOG(ERR, "port %u request failed on secondary #%d",
204 dev->data->port_id, i);
213 * Broadcast request of starting data-path to secondary processes. The request
217 * Pointer to Ethernet structure.
220 mlx5_mp_req_start_rxtx(struct rte_eth_dev *dev)
222 mp_req_on_rxtx(dev, MLX5_MP_REQ_START_RXTX);
226 * Broadcast request of stopping data-path to secondary processes. The request
230 * Pointer to Ethernet structure.
233 mlx5_mp_req_stop_rxtx(struct rte_eth_dev *dev)
235 mp_req_on_rxtx(dev, MLX5_MP_REQ_STOP_RXTX);
239 * Request Memory Region creation to the primary process.
242 * Pointer to Ethernet structure.
244 * Target virtual address to register.
247 * 0 on success, a negative errno value otherwise and rte_errno is set.
250 mlx5_mp_req_mr_create(struct rte_eth_dev *dev, uintptr_t addr)
252 struct rte_mp_msg mp_req;
253 struct rte_mp_msg *mp_res;
254 struct rte_mp_reply mp_rep;
255 struct mlx5_mp_param *req = (struct mlx5_mp_param *)mp_req.param;
256 struct mlx5_mp_param *res;
257 struct timespec ts = {.tv_sec = MLX5_MP_REQ_TIMEOUT_SEC, .tv_nsec = 0};
260 MLX5_ASSERT(rte_eal_process_type() == RTE_PROC_SECONDARY);
261 mp_init_msg(dev, &mp_req, MLX5_MP_REQ_CREATE_MR);
262 req->args.addr = addr;
263 ret = rte_mp_request_sync(&mp_req, &mp_rep, &ts);
265 DRV_LOG(ERR, "port %u request to primary process failed",
269 MLX5_ASSERT(mp_rep.nb_received == 1);
270 mp_res = &mp_rep.msgs[0];
271 res = (struct mlx5_mp_param *)mp_res->param;
280 * Request Verbs queue state modification to the primary process.
283 * Pointer to Ethernet structure.
285 * State modify parameters.
288 * 0 on success, a negative errno value otherwise and rte_errno is set.
291 mlx5_mp_req_queue_state_modify(struct rte_eth_dev *dev,
292 struct mlx5_mp_arg_queue_state_modify *sm)
294 struct rte_mp_msg mp_req;
295 struct rte_mp_msg *mp_res;
296 struct rte_mp_reply mp_rep;
297 struct mlx5_mp_param *req = (struct mlx5_mp_param *)mp_req.param;
298 struct mlx5_mp_param *res;
299 struct timespec ts = {.tv_sec = MLX5_MP_REQ_TIMEOUT_SEC, .tv_nsec = 0};
302 MLX5_ASSERT(rte_eal_process_type() == RTE_PROC_SECONDARY);
303 mp_init_msg(dev, &mp_req, MLX5_MP_REQ_QUEUE_STATE_MODIFY);
304 req->args.state_modify = *sm;
305 ret = rte_mp_request_sync(&mp_req, &mp_rep, &ts);
307 DRV_LOG(ERR, "port %u request to primary process failed",
311 MLX5_ASSERT(mp_rep.nb_received == 1);
312 mp_res = &mp_rep.msgs[0];
313 res = (struct mlx5_mp_param *)mp_res->param;
320 * Request Verbs command file descriptor for mmap to the primary process.
323 * Pointer to Ethernet structure.
326 * fd on success, a negative errno value otherwise and rte_errno is set.
329 mlx5_mp_req_verbs_cmd_fd(struct rte_eth_dev *dev)
331 struct rte_mp_msg mp_req;
332 struct rte_mp_msg *mp_res;
333 struct rte_mp_reply mp_rep;
334 struct mlx5_mp_param *res;
335 struct timespec ts = {.tv_sec = MLX5_MP_REQ_TIMEOUT_SEC, .tv_nsec = 0};
338 MLX5_ASSERT(rte_eal_process_type() == RTE_PROC_SECONDARY);
339 mp_init_msg(dev, &mp_req, MLX5_MP_REQ_VERBS_CMD_FD);
340 ret = rte_mp_request_sync(&mp_req, &mp_rep, &ts);
342 DRV_LOG(ERR, "port %u request to primary process failed",
346 MLX5_ASSERT(mp_rep.nb_received == 1);
347 mp_res = &mp_rep.msgs[0];
348 res = (struct mlx5_mp_param *)mp_res->param;
350 rte_errno = -res->result;
352 "port %u failed to get command FD from primary process",
357 MLX5_ASSERT(mp_res->num_fds == 1);
358 ret = mp_res->fds[0];
359 DRV_LOG(DEBUG, "port %u command FD from primary is %d",
360 dev->data->port_id, ret);
367 * Initialize by primary process.
370 mlx5_mp_init_primary(void)
374 MLX5_ASSERT(rte_eal_process_type() == RTE_PROC_PRIMARY);
376 /* primary is allowed to not support IPC */
377 ret = rte_mp_action_register(MLX5_MP_NAME, mp_primary_handle);
378 if (ret && rte_errno != ENOTSUP)
384 * Un-initialize by primary process.
387 mlx5_mp_uninit_primary(void)
389 MLX5_ASSERT(rte_eal_process_type() == RTE_PROC_PRIMARY);
390 rte_mp_action_unregister(MLX5_MP_NAME);
394 * Initialize by secondary process.
397 mlx5_mp_init_secondary(void)
399 MLX5_ASSERT(rte_eal_process_type() == RTE_PROC_SECONDARY);
400 return rte_mp_action_register(MLX5_MP_NAME, mp_secondary_handle);
404 * Un-initialize by secondary process.
407 mlx5_mp_uninit_secondary(void)
409 MLX5_ASSERT(rte_eal_process_type() == RTE_PROC_SECONDARY);
410 rte_mp_action_unregister(MLX5_MP_NAME);