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