net/mlx4: support secondary process
[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 <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 "mlx4.h"
15 #include "mlx4_rxtx.h"
16 #include "mlx4_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 mlx4_mp_req_type type)
31 {
32         struct mlx4_mp_param *param = (struct mlx4_mp_param *)msg->param;
33
34         memset(msg, 0, sizeof(*msg));
35         strlcpy(msg->name, MLX4_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, 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 mlx4_mp_param *res = (struct mlx4_mp_param *)mp_res.param;
57         const struct mlx4_mp_param *param =
58                 (const struct mlx4_mp_param *)mp_msg->param;
59         struct rte_eth_dev *dev;
60         struct mlx4_priv *priv;
61         int ret;
62
63         assert(rte_eal_process_type() == RTE_PROC_PRIMARY);
64         if (!rte_eth_dev_is_valid_port(param->port_id)) {
65                 rte_errno = ENODEV;
66                 ERROR("port %u invalid port ID", param->port_id);
67                 return -rte_errno;
68         }
69         dev = &rte_eth_devices[param->port_id];
70         priv = dev->data->dev_private;
71         switch (param->type) {
72         case MLX4_MP_REQ_VERBS_CMD_FD:
73                 mp_init_msg(dev, &mp_res, param->type);
74                 mp_res.num_fds = 1;
75                 mp_res.fds[0] = priv->ctx->cmd_fd;
76                 res->result = 0;
77                 ret = rte_mp_reply(&mp_res, peer);
78                 break;
79         default:
80                 rte_errno = EINVAL;
81                 ERROR("port %u invalid mp request type", dev->data->port_id);
82                 return -rte_errno;
83         }
84         return ret;
85 }
86
87 /**
88  * IPC message handler of a secondary process.
89  *
90  * @param[in] dev
91  *   Pointer to Ethernet structure.
92  * @param[in] peer
93  *   Pointer to the peer socket path.
94  *
95  * @return
96  *   0 on success, a negative errno value otherwise and rte_errno is set.
97  */
98 static int
99 mp_secondary_handle(const struct rte_mp_msg *mp_msg, const void *peer)
100 {
101         struct rte_mp_msg mp_res;
102         struct mlx4_mp_param *res = (struct mlx4_mp_param *)mp_res.param;
103         const struct mlx4_mp_param *param =
104                 (const struct mlx4_mp_param *)mp_msg->param;
105         struct rte_eth_dev *dev;
106         int ret;
107
108         assert(rte_eal_process_type() == RTE_PROC_SECONDARY);
109         if (!rte_eth_dev_is_valid_port(param->port_id)) {
110                 rte_errno = ENODEV;
111                 ERROR("port %u invalid port ID", param->port_id);
112                 return -rte_errno;
113         }
114         dev = &rte_eth_devices[param->port_id];
115         switch (param->type) {
116         case MLX4_MP_REQ_START_RXTX:
117                 INFO("port %u starting datapath", dev->data->port_id);
118                 rte_mb();
119                 dev->tx_pkt_burst = mlx4_tx_burst;
120                 dev->rx_pkt_burst = mlx4_rx_burst;
121                 mp_init_msg(dev, &mp_res, param->type);
122                 res->result = 0;
123                 ret = rte_mp_reply(&mp_res, peer);
124                 break;
125         case MLX4_MP_REQ_STOP_RXTX:
126                 INFO("port %u stopping datapath", dev->data->port_id);
127                 dev->tx_pkt_burst = mlx4_tx_burst_removed;
128                 dev->rx_pkt_burst = mlx4_rx_burst_removed;
129                 rte_mb();
130                 mp_init_msg(dev, &mp_res, param->type);
131                 res->result = 0;
132                 ret = rte_mp_reply(&mp_res, peer);
133                 break;
134         default:
135                 rte_errno = EINVAL;
136                 ERROR("port %u invalid mp request type", dev->data->port_id);
137                 return -rte_errno;
138         }
139         return ret;
140 }
141
142 /**
143  * Broadcast request of stopping/starting data-path to secondary processes.
144  *
145  * @param[in] dev
146  *   Pointer to Ethernet structure.
147  * @param[in] type
148  *   Request type.
149  */
150 static void
151 mp_req_on_rxtx(struct rte_eth_dev *dev, enum mlx4_mp_req_type type)
152 {
153         struct rte_mp_msg mp_req;
154         struct rte_mp_msg *mp_res;
155         struct rte_mp_reply mp_rep;
156         struct mlx4_mp_param *res __rte_unused;
157         struct timespec ts = {.tv_sec = MLX4_MP_REQ_TIMEOUT_SEC, .tv_nsec = 0};
158         int ret;
159         int i;
160
161         assert(rte_eal_process_type() == RTE_PROC_PRIMARY);
162         if (!mlx4_shared_data->secondary_cnt)
163                 return;
164         if (type != MLX4_MP_REQ_START_RXTX && type != MLX4_MP_REQ_STOP_RXTX) {
165                 ERROR("port %u unknown request (req_type %d)",
166                       dev->data->port_id, type);
167                 return;
168         }
169         mp_init_msg(dev, &mp_req, type);
170         ret = rte_mp_request_sync(&mp_req, &mp_rep, &ts);
171         if (ret) {
172                 ERROR("port %u failed to request stop/start Rx/Tx (%d)",
173                       dev->data->port_id, type);
174                 goto exit;
175         }
176         if (mp_rep.nb_sent != mp_rep.nb_received) {
177                 ERROR("port %u not all secondaries responded (req_type %d)",
178                       dev->data->port_id, type);
179                 goto exit;
180         }
181         for (i = 0; i < mp_rep.nb_received; i++) {
182                 mp_res = &mp_rep.msgs[i];
183                 res = (struct mlx4_mp_param *)mp_res->param;
184                 if (res->result) {
185                         ERROR("port %u request failed on secondary #%d",
186                               dev->data->port_id, i);
187                         goto exit;
188                 }
189         }
190 exit:
191         free(mp_rep.msgs);
192 }
193
194 /**
195  * Broadcast request of starting data-path to secondary processes. The request
196  * is synchronous.
197  *
198  * @param[in] dev
199  *   Pointer to Ethernet structure.
200  */
201 void
202 mlx4_mp_req_start_rxtx(struct rte_eth_dev *dev)
203 {
204         mp_req_on_rxtx(dev, MLX4_MP_REQ_START_RXTX);
205 }
206
207 /**
208  * Broadcast request of stopping data-path to secondary processes. The request
209  * is synchronous.
210  *
211  * @param[in] dev
212  *   Pointer to Ethernet structure.
213  */
214 void
215 mlx4_mp_req_stop_rxtx(struct rte_eth_dev *dev)
216 {
217         mp_req_on_rxtx(dev, MLX4_MP_REQ_STOP_RXTX);
218 }
219
220 /**
221  * IPC message handler of primary process.
222  *
223  * @param[in] dev
224  *   Pointer to Ethernet structure.
225  *
226  * @return
227  *   fd on success, a negative errno value otherwise and rte_errno is set.
228  */
229 int
230 mlx4_mp_req_verbs_cmd_fd(struct rte_eth_dev *dev)
231 {
232         struct rte_mp_msg mp_req;
233         struct rte_mp_msg *mp_res;
234         struct rte_mp_reply mp_rep;
235         struct mlx4_mp_param *res;
236         struct timespec ts = {.tv_sec = MLX4_MP_REQ_TIMEOUT_SEC, .tv_nsec = 0};
237         int ret;
238
239         assert(rte_eal_process_type() == RTE_PROC_SECONDARY);
240         mp_init_msg(dev, &mp_req, MLX4_MP_REQ_VERBS_CMD_FD);
241         ret = rte_mp_request_sync(&mp_req, &mp_rep, &ts);
242         if (ret) {
243                 ERROR("port %u request to primary process failed",
244                       dev->data->port_id);
245                 return -rte_errno;
246         }
247         assert(mp_rep.nb_received == 1);
248         mp_res = &mp_rep.msgs[0];
249         res = (struct mlx4_mp_param *)mp_res->param;
250         if (res->result) {
251                 rte_errno = -res->result;
252                 ERROR("port %u failed to get command FD from primary process",
253                       dev->data->port_id);
254                 ret = -rte_errno;
255                 goto exit;
256         }
257         assert(mp_res->num_fds == 1);
258         ret = mp_res->fds[0];
259         DEBUG("port %u command FD from primary is %d",
260               dev->data->port_id, ret);
261 exit:
262         free(mp_rep.msgs);
263         return ret;
264 }
265
266 /**
267  * Initialize by primary process.
268  */
269 void
270 mlx4_mp_init_primary(void)
271 {
272         assert(rte_eal_process_type() == RTE_PROC_PRIMARY);
273         rte_mp_action_register(MLX4_MP_NAME, mp_primary_handle);
274 }
275
276 /**
277  * Un-initialize by primary process.
278  */
279 void
280 mlx4_mp_uninit_primary(void)
281 {
282         assert(rte_eal_process_type() == RTE_PROC_PRIMARY);
283         rte_mp_action_unregister(MLX4_MP_NAME);
284 }
285
286 /**
287  * Initialize by secondary process.
288  */
289 void
290 mlx4_mp_init_secondary(void)
291 {
292         assert(rte_eal_process_type() == RTE_PROC_SECONDARY);
293         rte_mp_action_register(MLX4_MP_NAME, mp_secondary_handle);
294 }
295
296 /**
297  * Un-initialize by secondary process.
298  */
299 void
300 mlx4_mp_uninit_secondary(void)
301 {
302         assert(rte_eal_process_type() == RTE_PROC_SECONDARY);
303         rte_mp_action_unregister(MLX4_MP_NAME);
304 }