]>
Commit | Line | Data |
---|---|---|
9f95a23c TL |
1 | /* SPDX-License-Identifier: BSD-3-Clause |
2 | * Copyright 2019 6WIND S.A. | |
3 | * Copyright 2019 Mellanox Technologies, Ltd | |
4 | */ | |
5 | ||
9f95a23c TL |
6 | #include <stdio.h> |
7 | #include <time.h> | |
8 | ||
9 | #include <rte_eal.h> | |
10 | #include <rte_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 | ||
f67539c2 | 64 | MLX4_ASSERT(rte_eal_process_type() == RTE_PROC_PRIMARY); |
9f95a23c TL |
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 | int ret; | |
115 | ||
f67539c2 | 116 | MLX4_ASSERT(rte_eal_process_type() == RTE_PROC_SECONDARY); |
9f95a23c TL |
117 | if (!rte_eth_dev_is_valid_port(param->port_id)) { |
118 | rte_errno = ENODEV; | |
119 | ERROR("port %u invalid port ID", param->port_id); | |
120 | return -rte_errno; | |
121 | } | |
122 | dev = &rte_eth_devices[param->port_id]; | |
123 | switch (param->type) { | |
124 | case MLX4_MP_REQ_START_RXTX: | |
125 | INFO("port %u starting datapath", dev->data->port_id); | |
126 | rte_mb(); | |
127 | dev->tx_pkt_burst = mlx4_tx_burst; | |
128 | dev->rx_pkt_burst = mlx4_rx_burst; | |
129 | mp_init_msg(dev, &mp_res, param->type); | |
130 | res->result = 0; | |
131 | ret = rte_mp_reply(&mp_res, peer); | |
132 | break; | |
133 | case MLX4_MP_REQ_STOP_RXTX: | |
134 | INFO("port %u stopping datapath", dev->data->port_id); | |
135 | dev->tx_pkt_burst = mlx4_tx_burst_removed; | |
136 | dev->rx_pkt_burst = mlx4_rx_burst_removed; | |
137 | rte_mb(); | |
138 | mp_init_msg(dev, &mp_res, param->type); | |
139 | res->result = 0; | |
140 | ret = rte_mp_reply(&mp_res, peer); | |
141 | break; | |
142 | default: | |
143 | rte_errno = EINVAL; | |
144 | ERROR("port %u invalid mp request type", dev->data->port_id); | |
145 | return -rte_errno; | |
146 | } | |
147 | return ret; | |
148 | } | |
149 | ||
150 | /** | |
151 | * Broadcast request of stopping/starting data-path to secondary processes. | |
152 | * | |
153 | * @param[in] dev | |
154 | * Pointer to Ethernet structure. | |
155 | * @param[in] type | |
156 | * Request type. | |
157 | */ | |
158 | static void | |
159 | mp_req_on_rxtx(struct rte_eth_dev *dev, enum mlx4_mp_req_type type) | |
160 | { | |
161 | struct rte_mp_msg mp_req; | |
162 | struct rte_mp_msg *mp_res; | |
163 | struct rte_mp_reply mp_rep; | |
164 | struct mlx4_mp_param *res __rte_unused; | |
165 | struct timespec ts = {.tv_sec = MLX4_MP_REQ_TIMEOUT_SEC, .tv_nsec = 0}; | |
166 | int ret; | |
167 | int i; | |
168 | ||
f67539c2 | 169 | MLX4_ASSERT(rte_eal_process_type() == RTE_PROC_PRIMARY); |
9f95a23c TL |
170 | if (!mlx4_shared_data->secondary_cnt) |
171 | return; | |
172 | if (type != MLX4_MP_REQ_START_RXTX && type != MLX4_MP_REQ_STOP_RXTX) { | |
173 | ERROR("port %u unknown request (req_type %d)", | |
174 | dev->data->port_id, type); | |
175 | return; | |
176 | } | |
177 | mp_init_msg(dev, &mp_req, type); | |
178 | ret = rte_mp_request_sync(&mp_req, &mp_rep, &ts); | |
179 | if (ret) { | |
f67539c2 TL |
180 | if (rte_errno != ENOTSUP) |
181 | ERROR("port %u failed to request stop/start Rx/Tx (%d)", | |
182 | dev->data->port_id, type); | |
9f95a23c TL |
183 | goto exit; |
184 | } | |
185 | if (mp_rep.nb_sent != mp_rep.nb_received) { | |
186 | ERROR("port %u not all secondaries responded (req_type %d)", | |
187 | dev->data->port_id, type); | |
188 | goto exit; | |
189 | } | |
190 | for (i = 0; i < mp_rep.nb_received; i++) { | |
191 | mp_res = &mp_rep.msgs[i]; | |
192 | res = (struct mlx4_mp_param *)mp_res->param; | |
193 | if (res->result) { | |
194 | ERROR("port %u request failed on secondary #%d", | |
195 | dev->data->port_id, i); | |
196 | goto exit; | |
197 | } | |
198 | } | |
199 | exit: | |
200 | free(mp_rep.msgs); | |
201 | } | |
202 | ||
203 | /** | |
204 | * Broadcast request of starting data-path to secondary processes. The request | |
205 | * is synchronous. | |
206 | * | |
207 | * @param[in] dev | |
208 | * Pointer to Ethernet structure. | |
209 | */ | |
210 | void | |
211 | mlx4_mp_req_start_rxtx(struct rte_eth_dev *dev) | |
212 | { | |
213 | mp_req_on_rxtx(dev, MLX4_MP_REQ_START_RXTX); | |
214 | } | |
215 | ||
216 | /** | |
217 | * Broadcast request of stopping data-path to secondary processes. The request | |
218 | * is synchronous. | |
219 | * | |
220 | * @param[in] dev | |
221 | * Pointer to Ethernet structure. | |
222 | */ | |
223 | void | |
224 | mlx4_mp_req_stop_rxtx(struct rte_eth_dev *dev) | |
225 | { | |
226 | mp_req_on_rxtx(dev, MLX4_MP_REQ_STOP_RXTX); | |
227 | } | |
228 | ||
229 | /** | |
230 | * Request Memory Region creation to the primary process. | |
231 | * | |
232 | * @param[in] dev | |
233 | * Pointer to Ethernet structure. | |
234 | * @param addr | |
235 | * Target virtual address to register. | |
236 | * | |
237 | * @return | |
238 | * 0 on success, a negative errno value otherwise and rte_errno is set. | |
239 | */ | |
240 | int | |
241 | mlx4_mp_req_mr_create(struct rte_eth_dev *dev, uintptr_t addr) | |
242 | { | |
243 | struct rte_mp_msg mp_req; | |
244 | struct rte_mp_msg *mp_res; | |
245 | struct rte_mp_reply mp_rep; | |
246 | struct mlx4_mp_param *req = (struct mlx4_mp_param *)mp_req.param; | |
247 | struct mlx4_mp_param *res; | |
248 | struct timespec ts = {.tv_sec = MLX4_MP_REQ_TIMEOUT_SEC, .tv_nsec = 0}; | |
249 | int ret; | |
250 | ||
f67539c2 | 251 | MLX4_ASSERT(rte_eal_process_type() == RTE_PROC_SECONDARY); |
9f95a23c TL |
252 | mp_init_msg(dev, &mp_req, MLX4_MP_REQ_CREATE_MR); |
253 | req->args.addr = addr; | |
254 | ret = rte_mp_request_sync(&mp_req, &mp_rep, &ts); | |
255 | if (ret) { | |
256 | ERROR("port %u request to primary process failed", | |
257 | dev->data->port_id); | |
258 | return -rte_errno; | |
259 | } | |
f67539c2 | 260 | MLX4_ASSERT(mp_rep.nb_received == 1); |
9f95a23c TL |
261 | mp_res = &mp_rep.msgs[0]; |
262 | res = (struct mlx4_mp_param *)mp_res->param; | |
263 | ret = res->result; | |
264 | if (ret) | |
265 | rte_errno = -ret; | |
266 | free(mp_rep.msgs); | |
267 | return ret; | |
268 | } | |
269 | ||
270 | /** | |
271 | * IPC message handler of primary process. | |
272 | * | |
273 | * @param[in] dev | |
274 | * Pointer to Ethernet structure. | |
275 | * | |
276 | * @return | |
277 | * fd on success, a negative errno value otherwise and rte_errno is set. | |
278 | */ | |
279 | int | |
280 | mlx4_mp_req_verbs_cmd_fd(struct rte_eth_dev *dev) | |
281 | { | |
282 | struct rte_mp_msg mp_req; | |
283 | struct rte_mp_msg *mp_res; | |
284 | struct rte_mp_reply mp_rep; | |
285 | struct mlx4_mp_param *res; | |
286 | struct timespec ts = {.tv_sec = MLX4_MP_REQ_TIMEOUT_SEC, .tv_nsec = 0}; | |
287 | int ret; | |
288 | ||
f67539c2 | 289 | MLX4_ASSERT(rte_eal_process_type() == RTE_PROC_SECONDARY); |
9f95a23c TL |
290 | mp_init_msg(dev, &mp_req, MLX4_MP_REQ_VERBS_CMD_FD); |
291 | ret = rte_mp_request_sync(&mp_req, &mp_rep, &ts); | |
292 | if (ret) { | |
293 | ERROR("port %u request to primary process failed", | |
294 | dev->data->port_id); | |
295 | return -rte_errno; | |
296 | } | |
f67539c2 | 297 | MLX4_ASSERT(mp_rep.nb_received == 1); |
9f95a23c TL |
298 | mp_res = &mp_rep.msgs[0]; |
299 | res = (struct mlx4_mp_param *)mp_res->param; | |
300 | if (res->result) { | |
301 | rte_errno = -res->result; | |
302 | ERROR("port %u failed to get command FD from primary process", | |
303 | dev->data->port_id); | |
304 | ret = -rte_errno; | |
305 | goto exit; | |
306 | } | |
f67539c2 | 307 | MLX4_ASSERT(mp_res->num_fds == 1); |
9f95a23c TL |
308 | ret = mp_res->fds[0]; |
309 | DEBUG("port %u command FD from primary is %d", | |
310 | dev->data->port_id, ret); | |
311 | exit: | |
312 | free(mp_rep.msgs); | |
313 | return ret; | |
314 | } | |
315 | ||
316 | /** | |
317 | * Initialize by primary process. | |
318 | */ | |
f67539c2 | 319 | int |
9f95a23c TL |
320 | mlx4_mp_init_primary(void) |
321 | { | |
f67539c2 TL |
322 | int ret; |
323 | ||
324 | MLX4_ASSERT(rte_eal_process_type() == RTE_PROC_PRIMARY); | |
325 | ||
326 | /* primary is allowed to not support IPC */ | |
327 | ret = rte_mp_action_register(MLX4_MP_NAME, mp_primary_handle); | |
328 | if (ret && rte_errno != ENOTSUP) | |
329 | return -1; | |
330 | return 0; | |
9f95a23c TL |
331 | } |
332 | ||
333 | /** | |
334 | * Un-initialize by primary process. | |
335 | */ | |
336 | void | |
337 | mlx4_mp_uninit_primary(void) | |
338 | { | |
f67539c2 | 339 | MLX4_ASSERT(rte_eal_process_type() == RTE_PROC_PRIMARY); |
9f95a23c TL |
340 | rte_mp_action_unregister(MLX4_MP_NAME); |
341 | } | |
342 | ||
343 | /** | |
344 | * Initialize by secondary process. | |
345 | */ | |
f67539c2 | 346 | int |
9f95a23c TL |
347 | mlx4_mp_init_secondary(void) |
348 | { | |
f67539c2 TL |
349 | MLX4_ASSERT(rte_eal_process_type() == RTE_PROC_SECONDARY); |
350 | return rte_mp_action_register(MLX4_MP_NAME, mp_secondary_handle); | |
9f95a23c TL |
351 | } |
352 | ||
353 | /** | |
354 | * Un-initialize by secondary process. | |
355 | */ | |
356 | void | |
357 | mlx4_mp_uninit_secondary(void) | |
358 | { | |
f67539c2 | 359 | MLX4_ASSERT(rte_eal_process_type() == RTE_PROC_SECONDARY); |
9f95a23c TL |
360 | rte_mp_action_unregister(MLX4_MP_NAME); |
361 | } |