1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2018 Intel Corporation
8 #include <rte_string_fns.h>
9 #include <rte_devargs.h>
11 #include "hotplug_mp.h"
12 #include "eal_private.h"
14 #define MP_TIMEOUT_S 5 /**< 5 seconds timeouts */
16 static int cmp_dev_name(const struct rte_device *dev, const void *_name)
18 const char *name = _name;
20 return strcmp(dev->name, name);
23 struct mp_reply_bundle {
24 struct rte_mp_msg msg;
29 handle_secondary_request(const struct rte_mp_msg *msg, const void *peer)
36 static void __handle_primary_request(void *param)
38 struct mp_reply_bundle *bundle = param;
39 struct rte_mp_msg *msg = &bundle->msg;
40 const struct eal_dev_mp_req *req =
41 (const struct eal_dev_mp_req *)msg->param;
42 struct rte_mp_msg mp_resp;
43 struct eal_dev_mp_req *resp =
44 (struct eal_dev_mp_req *)mp_resp.param;
45 struct rte_devargs *da;
46 struct rte_device *dev;
50 memset(&mp_resp, 0, sizeof(mp_resp));
53 case EAL_DEV_REQ_TYPE_ATTACH:
54 case EAL_DEV_REQ_TYPE_DETACH_ROLLBACK:
55 ret = local_dev_probe(req->devargs, &dev);
57 case EAL_DEV_REQ_TYPE_DETACH:
58 case EAL_DEV_REQ_TYPE_ATTACH_ROLLBACK:
59 da = calloc(1, sizeof(*da));
65 ret = rte_devargs_parse(da, req->devargs);
69 bus = rte_bus_find_by_name(da->bus->name);
71 RTE_LOG(ERR, EAL, "Cannot find bus (%s)\n", da->bus->name);
76 dev = bus->find_device(NULL, cmp_dev_name, da->name);
78 RTE_LOG(ERR, EAL, "Cannot find plugged device (%s)\n", da->name);
83 ret = local_dev_remove(dev);
90 strlcpy(mp_resp.name, EAL_DEV_MP_ACTION_REQUEST, sizeof(mp_resp.name));
91 mp_resp.len_param = sizeof(*req);
92 memcpy(resp, req, sizeof(*resp));
94 if (rte_mp_reply(&mp_resp, bundle->peer) < 0)
95 RTE_LOG(ERR, EAL, "failed to send reply to primary request\n");
102 handle_primary_request(const struct rte_mp_msg *msg, const void *peer)
104 struct rte_mp_msg mp_resp;
105 const struct eal_dev_mp_req *req =
106 (const struct eal_dev_mp_req *)msg->param;
107 struct eal_dev_mp_req *resp =
108 (struct eal_dev_mp_req *)mp_resp.param;
109 struct mp_reply_bundle *bundle;
112 memset(&mp_resp, 0, sizeof(mp_resp));
113 strlcpy(mp_resp.name, EAL_DEV_MP_ACTION_REQUEST, sizeof(mp_resp.name));
114 mp_resp.len_param = sizeof(*req);
115 memcpy(resp, req, sizeof(*resp));
117 bundle = calloc(1, sizeof(*bundle));
118 if (bundle == NULL) {
119 resp->result = -ENOMEM;
120 ret = rte_mp_reply(&mp_resp, peer);
122 RTE_LOG(ERR, EAL, "failed to send reply to primary request\n");
128 * We need to send reply on interrupt thread, but peer can't be
129 * parsed directly, so this is a temporal hack, need to be fixed
132 bundle->peer = (void *)strdup(peer);
135 * We are at IPC callback thread, sync IPC is not allowed due to
136 * dead lock, so we delegate the task to interrupt thread.
138 ret = rte_eal_alarm_set(1, __handle_primary_request, bundle);
141 ret = rte_mp_reply(&mp_resp, peer);
143 RTE_LOG(ERR, EAL, "failed to send reply to primary request\n");
150 int eal_dev_hotplug_request_to_primary(struct eal_dev_mp_req *req)
156 int eal_dev_hotplug_request_to_secondary(struct eal_dev_mp_req *req)
158 struct rte_mp_msg mp_req;
159 struct rte_mp_reply mp_reply;
160 struct timespec ts = {.tv_sec = MP_TIMEOUT_S, .tv_nsec = 0};
164 memset(&mp_req, 0, sizeof(mp_req));
165 memcpy(mp_req.param, req, sizeof(*req));
166 mp_req.len_param = sizeof(*req);
167 strlcpy(mp_req.name, EAL_DEV_MP_ACTION_REQUEST, sizeof(mp_req.name));
169 ret = rte_mp_request_sync(&mp_req, &mp_reply, &ts);
171 RTE_LOG(ERR, EAL, "rte_mp_request_sync failed\n");
175 if (mp_reply.nb_sent != mp_reply.nb_received) {
176 RTE_LOG(ERR, EAL, "not all secondary reply\n");
181 for (i = 0; i < mp_reply.nb_received; i++) {
182 struct eal_dev_mp_req *resp =
183 (struct eal_dev_mp_req *)mp_reply.msgs[i].param;
184 if (resp->result != 0) {
185 req->result = resp->result;
186 if (req->t == EAL_DEV_REQ_TYPE_ATTACH &&
187 req->result != -EEXIST)
189 if (req->t == EAL_DEV_REQ_TYPE_DETACH &&
190 req->result != -ENOENT)
198 int rte_mp_dev_hotplug_init(void)
202 if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
203 ret = rte_mp_action_register(EAL_DEV_MP_ACTION_REQUEST,
204 handle_secondary_request);
206 RTE_LOG(ERR, EAL, "Couldn't register '%s' action\n",
207 EAL_DEV_MP_ACTION_REQUEST);
211 ret = rte_mp_action_register(EAL_DEV_MP_ACTION_REQUEST,
212 handle_primary_request);
214 RTE_LOG(ERR, EAL, "Couldn't register '%s' action\n",
215 EAL_DEV_MP_ACTION_REQUEST);