1d30ea906Sjfb8856606 /* SPDX-License-Identifier: BSD-3-Clause
2d30ea906Sjfb8856606  * Copyright(c) 2018 Intel Corporation
3d30ea906Sjfb8856606  */
4d30ea906Sjfb8856606 #include <string.h>
5d30ea906Sjfb8856606 
6d30ea906Sjfb8856606 #include <rte_eal.h>
7*4418919fSjohnjiang #include <rte_errno.h>
8d30ea906Sjfb8856606 #include <rte_alarm.h>
9d30ea906Sjfb8856606 #include <rte_string_fns.h>
10d30ea906Sjfb8856606 #include <rte_devargs.h>
11d30ea906Sjfb8856606 
12d30ea906Sjfb8856606 #include "hotplug_mp.h"
13d30ea906Sjfb8856606 #include "eal_private.h"
14d30ea906Sjfb8856606 
15d30ea906Sjfb8856606 #define MP_TIMEOUT_S 5 /**< 5 seconds timeouts */
16d30ea906Sjfb8856606 
17d30ea906Sjfb8856606 struct mp_reply_bundle {
18d30ea906Sjfb8856606 	struct rte_mp_msg msg;
19d30ea906Sjfb8856606 	void *peer;
20d30ea906Sjfb8856606 };
21d30ea906Sjfb8856606 
cmp_dev_name(const struct rte_device * dev,const void * _name)22d30ea906Sjfb8856606 static int cmp_dev_name(const struct rte_device *dev, const void *_name)
23d30ea906Sjfb8856606 {
24d30ea906Sjfb8856606 	const char *name = _name;
25d30ea906Sjfb8856606 
26d30ea906Sjfb8856606 	return strcmp(dev->name, name);
27d30ea906Sjfb8856606 }
28d30ea906Sjfb8856606 
29d30ea906Sjfb8856606 /**
30d30ea906Sjfb8856606  * Secondary to primary request.
31d30ea906Sjfb8856606  * start from function eal_dev_hotplug_request_to_primary.
32d30ea906Sjfb8856606  *
33d30ea906Sjfb8856606  * device attach on secondary:
34d30ea906Sjfb8856606  * a) secondary send sync request to the primary.
35d30ea906Sjfb8856606  * b) primary receive the request and attach the new device if
36d30ea906Sjfb8856606  *    failed goto i).
37d30ea906Sjfb8856606  * c) primary forward attach sync request to all secondary.
38d30ea906Sjfb8856606  * d) secondary receive the request and attach the device and send a reply.
39d30ea906Sjfb8856606  * e) primary check the reply if all success goes to j).
40d30ea906Sjfb8856606  * f) primary send attach rollback sync request to all secondary.
41d30ea906Sjfb8856606  * g) secondary receive the request and detach the device and send a reply.
42d30ea906Sjfb8856606  * h) primary receive the reply and detach device as rollback action.
43d30ea906Sjfb8856606  * i) send attach fail to secondary as a reply of step a), goto k).
44d30ea906Sjfb8856606  * j) send attach success to secondary as a reply of step a).
45d30ea906Sjfb8856606  * k) secondary receive reply and return.
46d30ea906Sjfb8856606  *
47d30ea906Sjfb8856606  * device detach on secondary:
48d30ea906Sjfb8856606  * a) secondary send sync request to the primary.
49d30ea906Sjfb8856606  * b) primary send detach sync request to all secondary.
50d30ea906Sjfb8856606  * c) secondary detach the device and send a reply.
51d30ea906Sjfb8856606  * d) primary check the reply if all success goes to g).
52d30ea906Sjfb8856606  * e) primary send detach rollback sync request to all secondary.
53d30ea906Sjfb8856606  * f) secondary receive the request and attach back device. goto h).
54d30ea906Sjfb8856606  * g) primary detach the device if success goto i), else goto e).
55d30ea906Sjfb8856606  * h) primary send detach fail to secondary as a reply of step a), goto j).
56d30ea906Sjfb8856606  * i) primary send detach success to secondary as a reply of step a).
57d30ea906Sjfb8856606  * j) secondary receive reply and return.
58d30ea906Sjfb8856606  */
59d30ea906Sjfb8856606 
60d30ea906Sjfb8856606 static int
send_response_to_secondary(const struct eal_dev_mp_req * req,int result,const void * peer)61d30ea906Sjfb8856606 send_response_to_secondary(const struct eal_dev_mp_req *req,
62d30ea906Sjfb8856606 			int result,
63d30ea906Sjfb8856606 			const void *peer)
64d30ea906Sjfb8856606 {
65d30ea906Sjfb8856606 	struct rte_mp_msg mp_resp;
66d30ea906Sjfb8856606 	struct eal_dev_mp_req *resp =
67d30ea906Sjfb8856606 		(struct eal_dev_mp_req *)mp_resp.param;
68d30ea906Sjfb8856606 	int ret;
69d30ea906Sjfb8856606 
70d30ea906Sjfb8856606 	memset(&mp_resp, 0, sizeof(mp_resp));
71d30ea906Sjfb8856606 	mp_resp.len_param = sizeof(*resp);
72d30ea906Sjfb8856606 	strlcpy(mp_resp.name, EAL_DEV_MP_ACTION_REQUEST, sizeof(mp_resp.name));
73d30ea906Sjfb8856606 	memcpy(resp, req, sizeof(*req));
74d30ea906Sjfb8856606 	resp->result = result;
75d30ea906Sjfb8856606 
76d30ea906Sjfb8856606 	ret = rte_mp_reply(&mp_resp, peer);
77d30ea906Sjfb8856606 	if (ret != 0)
78d30ea906Sjfb8856606 		RTE_LOG(ERR, EAL, "failed to send response to secondary\n");
79d30ea906Sjfb8856606 
80d30ea906Sjfb8856606 	return ret;
81d30ea906Sjfb8856606 }
82d30ea906Sjfb8856606 
83d30ea906Sjfb8856606 static void
__handle_secondary_request(void * param)84d30ea906Sjfb8856606 __handle_secondary_request(void *param)
85d30ea906Sjfb8856606 {
86d30ea906Sjfb8856606 	struct mp_reply_bundle *bundle = param;
87d30ea906Sjfb8856606 		const struct rte_mp_msg *msg = &bundle->msg;
88d30ea906Sjfb8856606 	const struct eal_dev_mp_req *req =
89d30ea906Sjfb8856606 		(const struct eal_dev_mp_req *)msg->param;
90d30ea906Sjfb8856606 	struct eal_dev_mp_req tmp_req;
91d30ea906Sjfb8856606 	struct rte_devargs da;
92d30ea906Sjfb8856606 	struct rte_device *dev;
93d30ea906Sjfb8856606 	struct rte_bus *bus;
94d30ea906Sjfb8856606 	int ret = 0;
95d30ea906Sjfb8856606 
96d30ea906Sjfb8856606 	tmp_req = *req;
97d30ea906Sjfb8856606 
98d30ea906Sjfb8856606 	if (req->t == EAL_DEV_REQ_TYPE_ATTACH) {
99d30ea906Sjfb8856606 		ret = local_dev_probe(req->devargs, &dev);
100d30ea906Sjfb8856606 		if (ret != 0) {
101d30ea906Sjfb8856606 			RTE_LOG(ERR, EAL, "Failed to hotplug add device on primary\n");
102d30ea906Sjfb8856606 			if (ret != -EEXIST)
103d30ea906Sjfb8856606 				goto finish;
104d30ea906Sjfb8856606 		}
105d30ea906Sjfb8856606 		ret = eal_dev_hotplug_request_to_secondary(&tmp_req);
106d30ea906Sjfb8856606 		if (ret != 0) {
107d30ea906Sjfb8856606 			RTE_LOG(ERR, EAL, "Failed to send hotplug request to secondary\n");
108d30ea906Sjfb8856606 			ret = -ENOMSG;
109d30ea906Sjfb8856606 			goto rollback;
110d30ea906Sjfb8856606 		}
111d30ea906Sjfb8856606 		if (tmp_req.result != 0) {
112d30ea906Sjfb8856606 			ret = tmp_req.result;
113d30ea906Sjfb8856606 			RTE_LOG(ERR, EAL, "Failed to hotplug add device on secondary\n");
114d30ea906Sjfb8856606 			if (ret != -EEXIST)
115d30ea906Sjfb8856606 				goto rollback;
116d30ea906Sjfb8856606 		}
117d30ea906Sjfb8856606 	} else if (req->t == EAL_DEV_REQ_TYPE_DETACH) {
118d30ea906Sjfb8856606 		ret = rte_devargs_parse(&da, req->devargs);
119d30ea906Sjfb8856606 		if (ret != 0)
120d30ea906Sjfb8856606 			goto finish;
121d30ea906Sjfb8856606 		free(da.args); /* we don't need those */
122d30ea906Sjfb8856606 		da.args = NULL;
123d30ea906Sjfb8856606 
124d30ea906Sjfb8856606 		ret = eal_dev_hotplug_request_to_secondary(&tmp_req);
125d30ea906Sjfb8856606 		if (ret != 0) {
126d30ea906Sjfb8856606 			RTE_LOG(ERR, EAL, "Failed to send hotplug request to secondary\n");
127d30ea906Sjfb8856606 			ret = -ENOMSG;
128d30ea906Sjfb8856606 			goto rollback;
129d30ea906Sjfb8856606 		}
130d30ea906Sjfb8856606 
131d30ea906Sjfb8856606 		bus = rte_bus_find_by_name(da.bus->name);
132d30ea906Sjfb8856606 		if (bus == NULL) {
133d30ea906Sjfb8856606 			RTE_LOG(ERR, EAL, "Cannot find bus (%s)\n", da.bus->name);
134d30ea906Sjfb8856606 			ret = -ENOENT;
135d30ea906Sjfb8856606 			goto finish;
136d30ea906Sjfb8856606 		}
137d30ea906Sjfb8856606 
138d30ea906Sjfb8856606 		dev = bus->find_device(NULL, cmp_dev_name, da.name);
139d30ea906Sjfb8856606 		if (dev == NULL) {
140d30ea906Sjfb8856606 			RTE_LOG(ERR, EAL, "Cannot find plugged device (%s)\n", da.name);
141d30ea906Sjfb8856606 			ret = -ENOENT;
142d30ea906Sjfb8856606 			goto finish;
143d30ea906Sjfb8856606 		}
144d30ea906Sjfb8856606 
145d30ea906Sjfb8856606 		if (tmp_req.result != 0) {
146d30ea906Sjfb8856606 			RTE_LOG(ERR, EAL, "Failed to hotplug remove device on secondary\n");
147d30ea906Sjfb8856606 			ret = tmp_req.result;
148d30ea906Sjfb8856606 			if (ret != -ENOENT)
149d30ea906Sjfb8856606 				goto rollback;
150d30ea906Sjfb8856606 		}
151d30ea906Sjfb8856606 
152d30ea906Sjfb8856606 		ret = local_dev_remove(dev);
153d30ea906Sjfb8856606 		if (ret != 0) {
154d30ea906Sjfb8856606 			RTE_LOG(ERR, EAL, "Failed to hotplug remove device on primary\n");
155d30ea906Sjfb8856606 			if (ret != -ENOENT)
156d30ea906Sjfb8856606 				goto rollback;
157d30ea906Sjfb8856606 		}
158d30ea906Sjfb8856606 	} else {
159d30ea906Sjfb8856606 		RTE_LOG(ERR, EAL, "unsupported secondary to primary request\n");
160d30ea906Sjfb8856606 		ret = -ENOTSUP;
161d30ea906Sjfb8856606 	}
162d30ea906Sjfb8856606 	goto finish;
163d30ea906Sjfb8856606 
164d30ea906Sjfb8856606 rollback:
165d30ea906Sjfb8856606 	if (req->t == EAL_DEV_REQ_TYPE_ATTACH) {
166d30ea906Sjfb8856606 		tmp_req.t = EAL_DEV_REQ_TYPE_ATTACH_ROLLBACK;
167d30ea906Sjfb8856606 		eal_dev_hotplug_request_to_secondary(&tmp_req);
168d30ea906Sjfb8856606 		local_dev_remove(dev);
169d30ea906Sjfb8856606 	} else {
170d30ea906Sjfb8856606 		tmp_req.t = EAL_DEV_REQ_TYPE_DETACH_ROLLBACK;
171d30ea906Sjfb8856606 		eal_dev_hotplug_request_to_secondary(&tmp_req);
172d30ea906Sjfb8856606 	}
173d30ea906Sjfb8856606 
174d30ea906Sjfb8856606 finish:
175d30ea906Sjfb8856606 	ret = send_response_to_secondary(&tmp_req, ret, bundle->peer);
176d30ea906Sjfb8856606 	if (ret)
177d30ea906Sjfb8856606 		RTE_LOG(ERR, EAL, "failed to send response to secondary\n");
178d30ea906Sjfb8856606 
179d30ea906Sjfb8856606 	free(bundle->peer);
180d30ea906Sjfb8856606 	free(bundle);
181d30ea906Sjfb8856606 }
182d30ea906Sjfb8856606 
183d30ea906Sjfb8856606 static int
handle_secondary_request(const struct rte_mp_msg * msg,const void * peer)184d30ea906Sjfb8856606 handle_secondary_request(const struct rte_mp_msg *msg, const void *peer)
185d30ea906Sjfb8856606 {
186d30ea906Sjfb8856606 	struct mp_reply_bundle *bundle;
187d30ea906Sjfb8856606 	const struct eal_dev_mp_req *req =
188d30ea906Sjfb8856606 		(const struct eal_dev_mp_req *)msg->param;
189d30ea906Sjfb8856606 	int ret = 0;
190d30ea906Sjfb8856606 
191d30ea906Sjfb8856606 	bundle = malloc(sizeof(*bundle));
192d30ea906Sjfb8856606 	if (bundle == NULL) {
193d30ea906Sjfb8856606 		RTE_LOG(ERR, EAL, "not enough memory\n");
194d30ea906Sjfb8856606 		return send_response_to_secondary(req, -ENOMEM, peer);
195d30ea906Sjfb8856606 	}
196d30ea906Sjfb8856606 
197d30ea906Sjfb8856606 	bundle->msg = *msg;
198d30ea906Sjfb8856606 	/**
199d30ea906Sjfb8856606 	 * We need to send reply on interrupt thread, but peer can't be
200d30ea906Sjfb8856606 	 * parsed directly, so this is a temporal hack, need to be fixed
201d30ea906Sjfb8856606 	 * when it is ready.
202d30ea906Sjfb8856606 	 */
203d30ea906Sjfb8856606 	bundle->peer = strdup(peer);
204*4418919fSjohnjiang 	if (bundle->peer == NULL) {
205*4418919fSjohnjiang 		free(bundle);
206*4418919fSjohnjiang 		RTE_LOG(ERR, EAL, "not enough memory\n");
207*4418919fSjohnjiang 		return send_response_to_secondary(req, -ENOMEM, peer);
208*4418919fSjohnjiang 	}
209d30ea906Sjfb8856606 
210d30ea906Sjfb8856606 	/**
211d30ea906Sjfb8856606 	 * We are at IPC callback thread, sync IPC is not allowed due to
212d30ea906Sjfb8856606 	 * dead lock, so we delegate the task to interrupt thread.
213d30ea906Sjfb8856606 	 */
214d30ea906Sjfb8856606 	ret = rte_eal_alarm_set(1, __handle_secondary_request, bundle);
215d30ea906Sjfb8856606 	if (ret != 0) {
216d30ea906Sjfb8856606 		RTE_LOG(ERR, EAL, "failed to add mp task\n");
2171646932aSjfb8856606 		free(bundle->peer);
2181646932aSjfb8856606 		free(bundle);
219d30ea906Sjfb8856606 		return send_response_to_secondary(req, ret, peer);
220d30ea906Sjfb8856606 	}
221d30ea906Sjfb8856606 	return 0;
222d30ea906Sjfb8856606 }
223d30ea906Sjfb8856606 
__handle_primary_request(void * param)224d30ea906Sjfb8856606 static void __handle_primary_request(void *param)
225d30ea906Sjfb8856606 {
226d30ea906Sjfb8856606 	struct mp_reply_bundle *bundle = param;
227d30ea906Sjfb8856606 	struct rte_mp_msg *msg = &bundle->msg;
228d30ea906Sjfb8856606 	const struct eal_dev_mp_req *req =
229d30ea906Sjfb8856606 		(const struct eal_dev_mp_req *)msg->param;
230d30ea906Sjfb8856606 	struct rte_mp_msg mp_resp;
231d30ea906Sjfb8856606 	struct eal_dev_mp_req *resp =
232d30ea906Sjfb8856606 		(struct eal_dev_mp_req *)mp_resp.param;
233d30ea906Sjfb8856606 	struct rte_devargs *da;
234d30ea906Sjfb8856606 	struct rte_device *dev;
235d30ea906Sjfb8856606 	struct rte_bus *bus;
236d30ea906Sjfb8856606 	int ret = 0;
237d30ea906Sjfb8856606 
238d30ea906Sjfb8856606 	memset(&mp_resp, 0, sizeof(mp_resp));
239d30ea906Sjfb8856606 
240d30ea906Sjfb8856606 	switch (req->t) {
241d30ea906Sjfb8856606 	case EAL_DEV_REQ_TYPE_ATTACH:
242d30ea906Sjfb8856606 	case EAL_DEV_REQ_TYPE_DETACH_ROLLBACK:
243d30ea906Sjfb8856606 		ret = local_dev_probe(req->devargs, &dev);
244d30ea906Sjfb8856606 		break;
245d30ea906Sjfb8856606 	case EAL_DEV_REQ_TYPE_DETACH:
246d30ea906Sjfb8856606 	case EAL_DEV_REQ_TYPE_ATTACH_ROLLBACK:
247d30ea906Sjfb8856606 		da = calloc(1, sizeof(*da));
248d30ea906Sjfb8856606 		if (da == NULL) {
249d30ea906Sjfb8856606 			ret = -ENOMEM;
250d30ea906Sjfb8856606 			break;
251d30ea906Sjfb8856606 		}
252d30ea906Sjfb8856606 
253d30ea906Sjfb8856606 		ret = rte_devargs_parse(da, req->devargs);
254d30ea906Sjfb8856606 		if (ret != 0)
255d30ea906Sjfb8856606 			goto quit;
256d30ea906Sjfb8856606 
257d30ea906Sjfb8856606 		bus = rte_bus_find_by_name(da->bus->name);
258d30ea906Sjfb8856606 		if (bus == NULL) {
259d30ea906Sjfb8856606 			RTE_LOG(ERR, EAL, "Cannot find bus (%s)\n", da->bus->name);
260d30ea906Sjfb8856606 			ret = -ENOENT;
261d30ea906Sjfb8856606 			goto quit;
262d30ea906Sjfb8856606 		}
263d30ea906Sjfb8856606 
264d30ea906Sjfb8856606 		dev = bus->find_device(NULL, cmp_dev_name, da->name);
265d30ea906Sjfb8856606 		if (dev == NULL) {
266d30ea906Sjfb8856606 			RTE_LOG(ERR, EAL, "Cannot find plugged device (%s)\n", da->name);
267d30ea906Sjfb8856606 			ret = -ENOENT;
268d30ea906Sjfb8856606 			goto quit;
269d30ea906Sjfb8856606 		}
270d30ea906Sjfb8856606 
271d30ea906Sjfb8856606 		if (!rte_dev_is_probed(dev)) {
272d30ea906Sjfb8856606 			if (req->t == EAL_DEV_REQ_TYPE_ATTACH_ROLLBACK) {
273d30ea906Sjfb8856606 				/**
274d30ea906Sjfb8856606 				 * Don't fail the rollback just because there's
275d30ea906Sjfb8856606 				 * nothing to do.
276d30ea906Sjfb8856606 				 */
277d30ea906Sjfb8856606 				ret = 0;
278d30ea906Sjfb8856606 			} else
279d30ea906Sjfb8856606 				ret = -ENODEV;
280d30ea906Sjfb8856606 
281d30ea906Sjfb8856606 			goto quit;
282d30ea906Sjfb8856606 		}
283d30ea906Sjfb8856606 
284d30ea906Sjfb8856606 		ret = local_dev_remove(dev);
285d30ea906Sjfb8856606 quit:
286d30ea906Sjfb8856606 		free(da->args);
287d30ea906Sjfb8856606 		free(da);
288d30ea906Sjfb8856606 		break;
289d30ea906Sjfb8856606 	default:
290d30ea906Sjfb8856606 		ret = -EINVAL;
291d30ea906Sjfb8856606 	}
292d30ea906Sjfb8856606 
293d30ea906Sjfb8856606 	strlcpy(mp_resp.name, EAL_DEV_MP_ACTION_REQUEST, sizeof(mp_resp.name));
294d30ea906Sjfb8856606 	mp_resp.len_param = sizeof(*req);
295d30ea906Sjfb8856606 	memcpy(resp, req, sizeof(*resp));
296d30ea906Sjfb8856606 	resp->result = ret;
297d30ea906Sjfb8856606 	if (rte_mp_reply(&mp_resp, bundle->peer) < 0)
298d30ea906Sjfb8856606 		RTE_LOG(ERR, EAL, "failed to send reply to primary request\n");
299d30ea906Sjfb8856606 
300d30ea906Sjfb8856606 	free(bundle->peer);
301d30ea906Sjfb8856606 	free(bundle);
302d30ea906Sjfb8856606 }
303d30ea906Sjfb8856606 
304d30ea906Sjfb8856606 static int
handle_primary_request(const struct rte_mp_msg * msg,const void * peer)305d30ea906Sjfb8856606 handle_primary_request(const struct rte_mp_msg *msg, const void *peer)
306d30ea906Sjfb8856606 {
307d30ea906Sjfb8856606 	struct rte_mp_msg mp_resp;
308d30ea906Sjfb8856606 	const struct eal_dev_mp_req *req =
309d30ea906Sjfb8856606 		(const struct eal_dev_mp_req *)msg->param;
310d30ea906Sjfb8856606 	struct eal_dev_mp_req *resp =
311d30ea906Sjfb8856606 		(struct eal_dev_mp_req *)mp_resp.param;
312d30ea906Sjfb8856606 	struct mp_reply_bundle *bundle;
313d30ea906Sjfb8856606 	int ret = 0;
314d30ea906Sjfb8856606 
315d30ea906Sjfb8856606 	memset(&mp_resp, 0, sizeof(mp_resp));
316d30ea906Sjfb8856606 	strlcpy(mp_resp.name, EAL_DEV_MP_ACTION_REQUEST, sizeof(mp_resp.name));
317d30ea906Sjfb8856606 	mp_resp.len_param = sizeof(*req);
318d30ea906Sjfb8856606 	memcpy(resp, req, sizeof(*resp));
319d30ea906Sjfb8856606 
320d30ea906Sjfb8856606 	bundle = calloc(1, sizeof(*bundle));
321d30ea906Sjfb8856606 	if (bundle == NULL) {
322*4418919fSjohnjiang 		RTE_LOG(ERR, EAL, "not enough memory\n");
323d30ea906Sjfb8856606 		resp->result = -ENOMEM;
324d30ea906Sjfb8856606 		ret = rte_mp_reply(&mp_resp, peer);
325d30ea906Sjfb8856606 		if (ret)
326d30ea906Sjfb8856606 			RTE_LOG(ERR, EAL, "failed to send reply to primary request\n");
327d30ea906Sjfb8856606 		return ret;
328d30ea906Sjfb8856606 	}
329d30ea906Sjfb8856606 
330d30ea906Sjfb8856606 	bundle->msg = *msg;
331d30ea906Sjfb8856606 	/**
332d30ea906Sjfb8856606 	 * We need to send reply on interrupt thread, but peer can't be
333d30ea906Sjfb8856606 	 * parsed directly, so this is a temporal hack, need to be fixed
334d30ea906Sjfb8856606 	 * when it is ready.
335d30ea906Sjfb8856606 	 */
336d30ea906Sjfb8856606 	bundle->peer = (void *)strdup(peer);
337*4418919fSjohnjiang 	if (bundle->peer == NULL) {
338*4418919fSjohnjiang 		RTE_LOG(ERR, EAL, "not enough memory\n");
339*4418919fSjohnjiang 		free(bundle);
340*4418919fSjohnjiang 		resp->result = -ENOMEM;
341*4418919fSjohnjiang 		ret = rte_mp_reply(&mp_resp, peer);
342*4418919fSjohnjiang 		if (ret)
343*4418919fSjohnjiang 			RTE_LOG(ERR, EAL, "failed to send reply to primary request\n");
344*4418919fSjohnjiang 		return ret;
345*4418919fSjohnjiang 	}
346d30ea906Sjfb8856606 
347d30ea906Sjfb8856606 	/**
348d30ea906Sjfb8856606 	 * We are at IPC callback thread, sync IPC is not allowed due to
349d30ea906Sjfb8856606 	 * dead lock, so we delegate the task to interrupt thread.
350d30ea906Sjfb8856606 	 */
351d30ea906Sjfb8856606 	ret = rte_eal_alarm_set(1, __handle_primary_request, bundle);
352d30ea906Sjfb8856606 	if (ret != 0) {
3531646932aSjfb8856606 		free(bundle->peer);
3541646932aSjfb8856606 		free(bundle);
355d30ea906Sjfb8856606 		resp->result = ret;
356d30ea906Sjfb8856606 		ret = rte_mp_reply(&mp_resp, peer);
357d30ea906Sjfb8856606 		if  (ret != 0) {
358d30ea906Sjfb8856606 			RTE_LOG(ERR, EAL, "failed to send reply to primary request\n");
359d30ea906Sjfb8856606 			return ret;
360d30ea906Sjfb8856606 		}
361d30ea906Sjfb8856606 	}
362d30ea906Sjfb8856606 	return 0;
363d30ea906Sjfb8856606 }
364d30ea906Sjfb8856606 
eal_dev_hotplug_request_to_primary(struct eal_dev_mp_req * req)365d30ea906Sjfb8856606 int eal_dev_hotplug_request_to_primary(struct eal_dev_mp_req *req)
366d30ea906Sjfb8856606 {
367d30ea906Sjfb8856606 	struct rte_mp_msg mp_req;
368d30ea906Sjfb8856606 	struct rte_mp_reply mp_reply;
369d30ea906Sjfb8856606 	struct timespec ts = {.tv_sec = MP_TIMEOUT_S, .tv_nsec = 0};
370d30ea906Sjfb8856606 	struct eal_dev_mp_req *resp;
371d30ea906Sjfb8856606 	int ret;
372d30ea906Sjfb8856606 
373d30ea906Sjfb8856606 	memset(&mp_req, 0, sizeof(mp_req));
374d30ea906Sjfb8856606 	memcpy(mp_req.param, req, sizeof(*req));
375d30ea906Sjfb8856606 	mp_req.len_param = sizeof(*req);
376d30ea906Sjfb8856606 	strlcpy(mp_req.name, EAL_DEV_MP_ACTION_REQUEST, sizeof(mp_req.name));
377d30ea906Sjfb8856606 
378d30ea906Sjfb8856606 	ret = rte_mp_request_sync(&mp_req, &mp_reply, &ts);
379d30ea906Sjfb8856606 	if (ret || mp_reply.nb_received != 1) {
3801646932aSjfb8856606 		RTE_LOG(ERR, EAL, "Cannot send request to primary\n");
381d30ea906Sjfb8856606 		if (!ret)
382d30ea906Sjfb8856606 			return -1;
383d30ea906Sjfb8856606 		return ret;
384d30ea906Sjfb8856606 	}
385d30ea906Sjfb8856606 
386d30ea906Sjfb8856606 	resp = (struct eal_dev_mp_req *)mp_reply.msgs[0].param;
387d30ea906Sjfb8856606 	req->result = resp->result;
388d30ea906Sjfb8856606 
389d30ea906Sjfb8856606 	free(mp_reply.msgs);
390d30ea906Sjfb8856606 	return ret;
391d30ea906Sjfb8856606 }
392d30ea906Sjfb8856606 
eal_dev_hotplug_request_to_secondary(struct eal_dev_mp_req * req)393d30ea906Sjfb8856606 int eal_dev_hotplug_request_to_secondary(struct eal_dev_mp_req *req)
394d30ea906Sjfb8856606 {
395d30ea906Sjfb8856606 	struct rte_mp_msg mp_req;
396d30ea906Sjfb8856606 	struct rte_mp_reply mp_reply;
397d30ea906Sjfb8856606 	struct timespec ts = {.tv_sec = MP_TIMEOUT_S, .tv_nsec = 0};
398d30ea906Sjfb8856606 	int ret;
399d30ea906Sjfb8856606 	int i;
400d30ea906Sjfb8856606 
401d30ea906Sjfb8856606 	memset(&mp_req, 0, sizeof(mp_req));
402d30ea906Sjfb8856606 	memcpy(mp_req.param, req, sizeof(*req));
403d30ea906Sjfb8856606 	mp_req.len_param = sizeof(*req);
404d30ea906Sjfb8856606 	strlcpy(mp_req.name, EAL_DEV_MP_ACTION_REQUEST, sizeof(mp_req.name));
405d30ea906Sjfb8856606 
406d30ea906Sjfb8856606 	ret = rte_mp_request_sync(&mp_req, &mp_reply, &ts);
407d30ea906Sjfb8856606 	if (ret != 0) {
408*4418919fSjohnjiang 		/* if IPC is not supported, behave as if the call succeeded */
409*4418919fSjohnjiang 		if (rte_errno != ENOTSUP)
410d30ea906Sjfb8856606 			RTE_LOG(ERR, EAL, "rte_mp_request_sync failed\n");
411*4418919fSjohnjiang 		else
412*4418919fSjohnjiang 			ret = 0;
413d30ea906Sjfb8856606 		return ret;
414d30ea906Sjfb8856606 	}
415d30ea906Sjfb8856606 
416d30ea906Sjfb8856606 	if (mp_reply.nb_sent != mp_reply.nb_received) {
417d30ea906Sjfb8856606 		RTE_LOG(ERR, EAL, "not all secondary reply\n");
418d30ea906Sjfb8856606 		free(mp_reply.msgs);
419d30ea906Sjfb8856606 		return -1;
420d30ea906Sjfb8856606 	}
421d30ea906Sjfb8856606 
422d30ea906Sjfb8856606 	req->result = 0;
423d30ea906Sjfb8856606 	for (i = 0; i < mp_reply.nb_received; i++) {
424d30ea906Sjfb8856606 		struct eal_dev_mp_req *resp =
425d30ea906Sjfb8856606 			(struct eal_dev_mp_req *)mp_reply.msgs[i].param;
426d30ea906Sjfb8856606 		if (resp->result != 0) {
427d30ea906Sjfb8856606 			if (req->t == EAL_DEV_REQ_TYPE_ATTACH &&
428d30ea906Sjfb8856606 				resp->result == -EEXIST)
429d30ea906Sjfb8856606 				continue;
430d30ea906Sjfb8856606 			if (req->t == EAL_DEV_REQ_TYPE_DETACH &&
431d30ea906Sjfb8856606 				resp->result == -ENOENT)
432d30ea906Sjfb8856606 				continue;
433d30ea906Sjfb8856606 			req->result = resp->result;
434d30ea906Sjfb8856606 		}
435d30ea906Sjfb8856606 	}
436d30ea906Sjfb8856606 
437d30ea906Sjfb8856606 	free(mp_reply.msgs);
438d30ea906Sjfb8856606 	return 0;
439d30ea906Sjfb8856606 }
440d30ea906Sjfb8856606 
eal_mp_dev_hotplug_init(void)4414b05018fSfengbojiang int eal_mp_dev_hotplug_init(void)
442d30ea906Sjfb8856606 {
443d30ea906Sjfb8856606 	int ret;
444d30ea906Sjfb8856606 
445d30ea906Sjfb8856606 	if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
446d30ea906Sjfb8856606 		ret = rte_mp_action_register(EAL_DEV_MP_ACTION_REQUEST,
447d30ea906Sjfb8856606 					handle_secondary_request);
448*4418919fSjohnjiang 		/* primary is allowed to not support IPC */
449*4418919fSjohnjiang 		if (ret != 0 && rte_errno != ENOTSUP) {
450d30ea906Sjfb8856606 			RTE_LOG(ERR, EAL, "Couldn't register '%s' action\n",
451d30ea906Sjfb8856606 				EAL_DEV_MP_ACTION_REQUEST);
452d30ea906Sjfb8856606 			return ret;
453d30ea906Sjfb8856606 		}
454d30ea906Sjfb8856606 	} else {
455d30ea906Sjfb8856606 		ret = rte_mp_action_register(EAL_DEV_MP_ACTION_REQUEST,
456d30ea906Sjfb8856606 					handle_primary_request);
457d30ea906Sjfb8856606 		if (ret != 0) {
458d30ea906Sjfb8856606 			RTE_LOG(ERR, EAL, "Couldn't register '%s' action\n",
459d30ea906Sjfb8856606 				EAL_DEV_MP_ACTION_REQUEST);
460d30ea906Sjfb8856606 			return ret;
461d30ea906Sjfb8856606 		}
462d30ea906Sjfb8856606 	}
463d30ea906Sjfb8856606 
464d30ea906Sjfb8856606 	return 0;
465d30ea906Sjfb8856606 }
466