xref: /dpdk/drivers/net/mana/mp.c (revision 7649794dcfe9fff3e33f98a93dff65bd11ec3c42)
1517ed6e2SLong Li /* SPDX-License-Identifier: BSD-3-Clause
2517ed6e2SLong Li  * Copyright 2022 Microsoft Corporation
3517ed6e2SLong Li  */
4517ed6e2SLong Li 
5517ed6e2SLong Li #include <rte_malloc.h>
6517ed6e2SLong Li #include <ethdev_driver.h>
7517ed6e2SLong Li #include <rte_log.h>
8*7649794dSLong Li #include <stdlib.h>
9517ed6e2SLong Li 
10517ed6e2SLong Li #include <infiniband/verbs.h>
11517ed6e2SLong Li 
12517ed6e2SLong Li #include "mana.h"
13517ed6e2SLong Li 
14517ed6e2SLong Li extern struct mana_shared_data *mana_shared_data;
15517ed6e2SLong Li 
160f5db3c6SLong Li /*
170f5db3c6SLong Li  * Process MR request from secondary process.
180f5db3c6SLong Li  */
190f5db3c6SLong Li static int
200f5db3c6SLong Li mana_mp_mr_create(struct mana_priv *priv, uintptr_t addr, uint32_t len)
210f5db3c6SLong Li {
220f5db3c6SLong Li 	struct ibv_mr *ibv_mr;
230f5db3c6SLong Li 	int ret;
240f5db3c6SLong Li 	struct mana_mr_cache *mr;
250f5db3c6SLong Li 
260f5db3c6SLong Li 	ibv_mr = ibv_reg_mr(priv->ib_pd, (void *)addr, len,
270f5db3c6SLong Li 			    IBV_ACCESS_LOCAL_WRITE);
280f5db3c6SLong Li 
290f5db3c6SLong Li 	if (!ibv_mr)
300f5db3c6SLong Li 		return -errno;
310f5db3c6SLong Li 
32e2d3a3c0SLong Li 	DP_LOG(DEBUG, "MR (2nd) lkey %u addr %p len %zu",
330f5db3c6SLong Li 	       ibv_mr->lkey, ibv_mr->addr, ibv_mr->length);
340f5db3c6SLong Li 
350f5db3c6SLong Li 	mr = rte_calloc("MANA MR", 1, sizeof(*mr), 0);
360f5db3c6SLong Li 	if (!mr) {
370f5db3c6SLong Li 		DRV_LOG(ERR, "(2nd) Failed to allocate MR");
380f5db3c6SLong Li 		ret = -ENOMEM;
390f5db3c6SLong Li 		goto fail_alloc;
400f5db3c6SLong Li 	}
410f5db3c6SLong Li 	mr->lkey = ibv_mr->lkey;
420f5db3c6SLong Li 	mr->addr = (uintptr_t)ibv_mr->addr;
430f5db3c6SLong Li 	mr->len = ibv_mr->length;
440f5db3c6SLong Li 	mr->verb_obj = ibv_mr;
450f5db3c6SLong Li 
460f5db3c6SLong Li 	rte_spinlock_lock(&priv->mr_btree_lock);
470f5db3c6SLong Li 	ret = mana_mr_btree_insert(&priv->mr_btree, mr);
480f5db3c6SLong Li 	rte_spinlock_unlock(&priv->mr_btree_lock);
490f5db3c6SLong Li 	if (ret) {
500f5db3c6SLong Li 		DRV_LOG(ERR, "(2nd) Failed to add to global MR btree");
510f5db3c6SLong Li 		goto fail_btree;
520f5db3c6SLong Li 	}
530f5db3c6SLong Li 
540f5db3c6SLong Li 	return 0;
550f5db3c6SLong Li 
560f5db3c6SLong Li fail_btree:
570f5db3c6SLong Li 	rte_free(mr);
580f5db3c6SLong Li 
590f5db3c6SLong Li fail_alloc:
600f5db3c6SLong Li 	ibv_dereg_mr(ibv_mr);
610f5db3c6SLong Li 
620f5db3c6SLong Li 	return ret;
630f5db3c6SLong Li }
640f5db3c6SLong Li 
65517ed6e2SLong Li static void
66517ed6e2SLong Li mp_init_msg(struct rte_mp_msg *msg, enum mana_mp_req_type type, int port_id)
67517ed6e2SLong Li {
68517ed6e2SLong Li 	struct mana_mp_param *param;
69517ed6e2SLong Li 
70517ed6e2SLong Li 	strlcpy(msg->name, MANA_MP_NAME, sizeof(msg->name));
71517ed6e2SLong Li 	msg->len_param = sizeof(*param);
72517ed6e2SLong Li 
73517ed6e2SLong Li 	param = (struct mana_mp_param *)msg->param;
74517ed6e2SLong Li 	param->type = type;
75517ed6e2SLong Li 	param->port_id = port_id;
76517ed6e2SLong Li }
77517ed6e2SLong Li 
78517ed6e2SLong Li static int
79517ed6e2SLong Li mana_mp_primary_handle(const struct rte_mp_msg *mp_msg, const void *peer)
80517ed6e2SLong Li {
81517ed6e2SLong Li 	struct rte_eth_dev *dev;
82517ed6e2SLong Li 	const struct mana_mp_param *param =
83517ed6e2SLong Li 		(const struct mana_mp_param *)mp_msg->param;
84517ed6e2SLong Li 	struct rte_mp_msg mp_res = { 0 };
85517ed6e2SLong Li 	struct mana_mp_param *res = (struct mana_mp_param *)mp_res.param;
86517ed6e2SLong Li 	int ret;
87517ed6e2SLong Li 	struct mana_priv *priv;
88517ed6e2SLong Li 
89517ed6e2SLong Li 	if (!rte_eth_dev_is_valid_port(param->port_id)) {
90517ed6e2SLong Li 		DRV_LOG(ERR, "MP handle port ID %u invalid", param->port_id);
91517ed6e2SLong Li 		return -ENODEV;
92517ed6e2SLong Li 	}
93517ed6e2SLong Li 
94517ed6e2SLong Li 	dev = &rte_eth_devices[param->port_id];
95517ed6e2SLong Li 	priv = dev->data->dev_private;
96517ed6e2SLong Li 
97517ed6e2SLong Li 	mp_init_msg(&mp_res, param->type, param->port_id);
98517ed6e2SLong Li 
99517ed6e2SLong Li 	switch (param->type) {
1000f5db3c6SLong Li 	case MANA_MP_REQ_CREATE_MR:
1010f5db3c6SLong Li 		ret = mana_mp_mr_create(priv, param->addr, param->len);
1020f5db3c6SLong Li 		res->result = ret;
1030f5db3c6SLong Li 		ret = rte_mp_reply(&mp_res, peer);
1040f5db3c6SLong Li 		break;
1050f5db3c6SLong Li 
106517ed6e2SLong Li 	case MANA_MP_REQ_VERBS_CMD_FD:
107517ed6e2SLong Li 		mp_res.num_fds = 1;
108517ed6e2SLong Li 		mp_res.fds[0] = priv->ib_ctx->cmd_fd;
109517ed6e2SLong Li 		res->result = 0;
110517ed6e2SLong Li 		ret = rte_mp_reply(&mp_res, peer);
111517ed6e2SLong Li 		break;
112517ed6e2SLong Li 
113517ed6e2SLong Li 	default:
114517ed6e2SLong Li 		DRV_LOG(ERR, "Port %u unknown primary MP type %u",
115517ed6e2SLong Li 			param->port_id, param->type);
116517ed6e2SLong Li 		ret = -EINVAL;
117517ed6e2SLong Li 	}
118517ed6e2SLong Li 
119517ed6e2SLong Li 	return ret;
120517ed6e2SLong Li }
121517ed6e2SLong Li 
122517ed6e2SLong Li static int
123517ed6e2SLong Li mana_mp_secondary_handle(const struct rte_mp_msg *mp_msg, const void *peer)
124517ed6e2SLong Li {
125517ed6e2SLong Li 	struct rte_mp_msg mp_res = { 0 };
126517ed6e2SLong Li 	struct mana_mp_param *res = (struct mana_mp_param *)mp_res.param;
127517ed6e2SLong Li 	const struct mana_mp_param *param =
128517ed6e2SLong Li 		(const struct mana_mp_param *)mp_msg->param;
129517ed6e2SLong Li 	struct rte_eth_dev *dev;
130517ed6e2SLong Li 	int ret;
131517ed6e2SLong Li 
132517ed6e2SLong Li 	if (!rte_eth_dev_is_valid_port(param->port_id)) {
133517ed6e2SLong Li 		DRV_LOG(ERR, "MP handle port ID %u invalid", param->port_id);
134517ed6e2SLong Li 		return -ENODEV;
135517ed6e2SLong Li 	}
136517ed6e2SLong Li 
137517ed6e2SLong Li 	dev = &rte_eth_devices[param->port_id];
138517ed6e2SLong Li 
139517ed6e2SLong Li 	mp_init_msg(&mp_res, param->type, param->port_id);
140517ed6e2SLong Li 
141517ed6e2SLong Li 	switch (param->type) {
142517ed6e2SLong Li 	case MANA_MP_REQ_START_RXTX:
143517ed6e2SLong Li 		DRV_LOG(INFO, "Port %u starting datapath", dev->data->port_id);
144517ed6e2SLong Li 
1457f322844SLong Li 		dev->tx_pkt_burst = mana_tx_burst;
146eb9994ddSLong Li 		dev->rx_pkt_burst = mana_rx_burst;
147eb9994ddSLong Li 
148517ed6e2SLong Li 		rte_mb();
149517ed6e2SLong Li 
150517ed6e2SLong Li 		res->result = 0;
151517ed6e2SLong Li 		ret = rte_mp_reply(&mp_res, peer);
152517ed6e2SLong Li 		break;
153517ed6e2SLong Li 
154517ed6e2SLong Li 	case MANA_MP_REQ_STOP_RXTX:
155517ed6e2SLong Li 		DRV_LOG(INFO, "Port %u stopping datapath", dev->data->port_id);
156517ed6e2SLong Li 
157517ed6e2SLong Li 		dev->tx_pkt_burst = mana_tx_burst_removed;
158517ed6e2SLong Li 		dev->rx_pkt_burst = mana_rx_burst_removed;
159517ed6e2SLong Li 
160517ed6e2SLong Li 		rte_mb();
161517ed6e2SLong Li 
162517ed6e2SLong Li 		res->result = 0;
163517ed6e2SLong Li 		ret = rte_mp_reply(&mp_res, peer);
164517ed6e2SLong Li 		break;
165517ed6e2SLong Li 
166517ed6e2SLong Li 	default:
167517ed6e2SLong Li 		DRV_LOG(ERR, "Port %u unknown secondary MP type %u",
168517ed6e2SLong Li 			param->port_id, param->type);
169517ed6e2SLong Li 		ret = -EINVAL;
170517ed6e2SLong Li 	}
171517ed6e2SLong Li 
172517ed6e2SLong Li 	return ret;
173517ed6e2SLong Li }
174517ed6e2SLong Li 
175517ed6e2SLong Li int
176517ed6e2SLong Li mana_mp_init_primary(void)
177517ed6e2SLong Li {
178517ed6e2SLong Li 	int ret;
179517ed6e2SLong Li 
180517ed6e2SLong Li 	ret = rte_mp_action_register(MANA_MP_NAME, mana_mp_primary_handle);
181517ed6e2SLong Li 	if (ret && rte_errno != ENOTSUP) {
182517ed6e2SLong Li 		DRV_LOG(ERR, "Failed to register primary handler %d %d",
183517ed6e2SLong Li 			ret, rte_errno);
184517ed6e2SLong Li 		return -1;
185517ed6e2SLong Li 	}
186517ed6e2SLong Li 
187517ed6e2SLong Li 	return 0;
188517ed6e2SLong Li }
189517ed6e2SLong Li 
190517ed6e2SLong Li void
191517ed6e2SLong Li mana_mp_uninit_primary(void)
192517ed6e2SLong Li {
193517ed6e2SLong Li 	rte_mp_action_unregister(MANA_MP_NAME);
194517ed6e2SLong Li }
195517ed6e2SLong Li 
196517ed6e2SLong Li int
197517ed6e2SLong Li mana_mp_init_secondary(void)
198517ed6e2SLong Li {
199517ed6e2SLong Li 	return rte_mp_action_register(MANA_MP_NAME, mana_mp_secondary_handle);
200517ed6e2SLong Li }
201517ed6e2SLong Li 
202517ed6e2SLong Li void
203517ed6e2SLong Li mana_mp_uninit_secondary(void)
204517ed6e2SLong Li {
205517ed6e2SLong Li 	rte_mp_action_unregister(MANA_MP_NAME);
206517ed6e2SLong Li }
207517ed6e2SLong Li 
208517ed6e2SLong Li int
209517ed6e2SLong Li mana_mp_req_verbs_cmd_fd(struct rte_eth_dev *dev)
210517ed6e2SLong Li {
211517ed6e2SLong Li 	struct rte_mp_msg mp_req = { 0 };
212517ed6e2SLong Li 	struct rte_mp_msg *mp_res;
213517ed6e2SLong Li 	struct rte_mp_reply mp_rep;
214517ed6e2SLong Li 	struct mana_mp_param *res;
215517ed6e2SLong Li 	struct timespec ts = {.tv_sec = MANA_MP_REQ_TIMEOUT_SEC, .tv_nsec = 0};
216517ed6e2SLong Li 	int ret;
217517ed6e2SLong Li 
218517ed6e2SLong Li 	mp_init_msg(&mp_req, MANA_MP_REQ_VERBS_CMD_FD, dev->data->port_id);
219517ed6e2SLong Li 
220517ed6e2SLong Li 	ret = rte_mp_request_sync(&mp_req, &mp_rep, &ts);
221517ed6e2SLong Li 	if (ret) {
222517ed6e2SLong Li 		DRV_LOG(ERR, "port %u request to primary process failed",
223517ed6e2SLong Li 			dev->data->port_id);
224517ed6e2SLong Li 		return ret;
225517ed6e2SLong Li 	}
226517ed6e2SLong Li 
227517ed6e2SLong Li 	if (mp_rep.nb_received != 1) {
228517ed6e2SLong Li 		DRV_LOG(ERR, "primary replied %u messages", mp_rep.nb_received);
229517ed6e2SLong Li 		ret = -EPROTO;
230517ed6e2SLong Li 		goto exit;
231517ed6e2SLong Li 	}
232517ed6e2SLong Li 
233517ed6e2SLong Li 	mp_res = &mp_rep.msgs[0];
234517ed6e2SLong Li 	res = (struct mana_mp_param *)mp_res->param;
235517ed6e2SLong Li 	if (res->result) {
236517ed6e2SLong Li 		DRV_LOG(ERR, "failed to get CMD FD, port %u",
237517ed6e2SLong Li 			dev->data->port_id);
238517ed6e2SLong Li 		ret = res->result;
239517ed6e2SLong Li 		goto exit;
240517ed6e2SLong Li 	}
241517ed6e2SLong Li 
242517ed6e2SLong Li 	if (mp_res->num_fds != 1) {
243517ed6e2SLong Li 		DRV_LOG(ERR, "got FDs %d unexpected", mp_res->num_fds);
244517ed6e2SLong Li 		ret = -EPROTO;
245517ed6e2SLong Li 		goto exit;
246517ed6e2SLong Li 	}
247517ed6e2SLong Li 
248517ed6e2SLong Li 	ret = mp_res->fds[0];
249517ed6e2SLong Li 	DRV_LOG(ERR, "port %u command FD from primary is %d",
250517ed6e2SLong Li 		dev->data->port_id, ret);
251517ed6e2SLong Li exit:
252517ed6e2SLong Li 	free(mp_rep.msgs);
253517ed6e2SLong Li 	return ret;
254517ed6e2SLong Li }
255517ed6e2SLong Li 
2560f5db3c6SLong Li /*
2570f5db3c6SLong Li  * Request the primary process to register a MR.
2580f5db3c6SLong Li  */
2590f5db3c6SLong Li int
2600f5db3c6SLong Li mana_mp_req_mr_create(struct mana_priv *priv, uintptr_t addr, uint32_t len)
2610f5db3c6SLong Li {
2620f5db3c6SLong Li 	struct rte_mp_msg mp_req = {0};
2630f5db3c6SLong Li 	struct rte_mp_msg *mp_res;
2640f5db3c6SLong Li 	struct rte_mp_reply mp_rep;
2650f5db3c6SLong Li 	struct mana_mp_param *req = (struct mana_mp_param *)mp_req.param;
2660f5db3c6SLong Li 	struct mana_mp_param *res;
2670f5db3c6SLong Li 	struct timespec ts = {.tv_sec = MANA_MP_REQ_TIMEOUT_SEC, .tv_nsec = 0};
2680f5db3c6SLong Li 	int ret;
2690f5db3c6SLong Li 
2700f5db3c6SLong Li 	mp_init_msg(&mp_req, MANA_MP_REQ_CREATE_MR, priv->port_id);
2710f5db3c6SLong Li 	req->addr = addr;
2720f5db3c6SLong Li 	req->len = len;
2730f5db3c6SLong Li 
2740f5db3c6SLong Li 	ret = rte_mp_request_sync(&mp_req, &mp_rep, &ts);
2750f5db3c6SLong Li 	if (ret) {
2760f5db3c6SLong Li 		DRV_LOG(ERR, "Port %u request to primary failed",
2770f5db3c6SLong Li 			req->port_id);
2780f5db3c6SLong Li 		return ret;
2790f5db3c6SLong Li 	}
2800f5db3c6SLong Li 
2810f5db3c6SLong Li 	if (mp_rep.nb_received != 1)
2820f5db3c6SLong Li 		return -EPROTO;
2830f5db3c6SLong Li 
2840f5db3c6SLong Li 	mp_res = &mp_rep.msgs[0];
2850f5db3c6SLong Li 	res = (struct mana_mp_param *)mp_res->param;
2860f5db3c6SLong Li 	ret = res->result;
2870f5db3c6SLong Li 
2880f5db3c6SLong Li 	free(mp_rep.msgs);
2890f5db3c6SLong Li 
2900f5db3c6SLong Li 	return ret;
2910f5db3c6SLong Li }
2920f5db3c6SLong Li 
293517ed6e2SLong Li void
294517ed6e2SLong Li mana_mp_req_on_rxtx(struct rte_eth_dev *dev, enum mana_mp_req_type type)
295517ed6e2SLong Li {
296517ed6e2SLong Li 	struct rte_mp_msg mp_req = { 0 };
297517ed6e2SLong Li 	struct rte_mp_msg *mp_res;
298517ed6e2SLong Li 	struct rte_mp_reply mp_rep;
299517ed6e2SLong Li 	struct mana_mp_param *res;
300517ed6e2SLong Li 	struct timespec ts = {.tv_sec = MANA_MP_REQ_TIMEOUT_SEC, .tv_nsec = 0};
301517ed6e2SLong Li 	int i, ret;
302517ed6e2SLong Li 
303517ed6e2SLong Li 	if (type != MANA_MP_REQ_START_RXTX && type != MANA_MP_REQ_STOP_RXTX) {
304517ed6e2SLong Li 		DRV_LOG(ERR, "port %u unknown request (req_type %d)",
305517ed6e2SLong Li 			dev->data->port_id, type);
306517ed6e2SLong Li 		return;
307517ed6e2SLong Li 	}
308517ed6e2SLong Li 
309517ed6e2SLong Li 	if (!mana_shared_data->secondary_cnt)
310517ed6e2SLong Li 		return;
311517ed6e2SLong Li 
312517ed6e2SLong Li 	mp_init_msg(&mp_req, type, dev->data->port_id);
313517ed6e2SLong Li 
314517ed6e2SLong Li 	ret = rte_mp_request_sync(&mp_req, &mp_rep, &ts);
315517ed6e2SLong Li 	if (ret) {
316517ed6e2SLong Li 		if (rte_errno != ENOTSUP)
317517ed6e2SLong Li 			DRV_LOG(ERR, "port %u failed to request Rx/Tx (%d)",
318517ed6e2SLong Li 				dev->data->port_id, type);
319517ed6e2SLong Li 		goto exit;
320517ed6e2SLong Li 	}
321517ed6e2SLong Li 	if (mp_rep.nb_sent != mp_rep.nb_received) {
322517ed6e2SLong Li 		DRV_LOG(ERR, "port %u not all secondaries responded (%d)",
323517ed6e2SLong Li 			dev->data->port_id, type);
324517ed6e2SLong Li 		goto exit;
325517ed6e2SLong Li 	}
326517ed6e2SLong Li 	for (i = 0; i < mp_rep.nb_received; i++) {
327517ed6e2SLong Li 		mp_res = &mp_rep.msgs[i];
328517ed6e2SLong Li 		res = (struct mana_mp_param *)mp_res->param;
329517ed6e2SLong Li 		if (res->result) {
330517ed6e2SLong Li 			DRV_LOG(ERR, "port %u request failed on secondary %d",
331517ed6e2SLong Li 				dev->data->port_id, i);
332517ed6e2SLong Li 			goto exit;
333517ed6e2SLong Li 		}
334517ed6e2SLong Li 	}
335517ed6e2SLong Li exit:
336517ed6e2SLong Li 	free(mp_rep.msgs);
337517ed6e2SLong Li }
338