Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2010-2014 Intel Corporation
3 : : */
4 : :
5 : : #include <glob.h>
6 : : #include <stdio.h>
7 : : #include <unistd.h>
8 : : #include <limits.h>
9 : : #include <fcntl.h>
10 : : #include <string.h>
11 : : #include <errno.h>
12 : : #include <poll.h>
13 : :
14 : :
15 : : #include <eal_export.h>
16 : : #include <rte_log.h>
17 : : #include <rte_power_guest_channel.h>
18 : :
19 : : #include "guest_channel.h"
20 : :
21 [ - + ]: 252 : RTE_LOG_REGISTER_SUFFIX(guest_channel_logtype, guest_channel, INFO);
22 : : #define RTE_LOGTYPE_GUEST_CHANNEL guest_channel_logtype
23 : : #define GUEST_CHANNEL_LOG(level, ...) \
24 : : RTE_LOG_LINE(level, GUEST_CHANNEL, "" __VA_ARGS__)
25 : :
26 : : /* Timeout for incoming message in milliseconds. */
27 : : #define TIMEOUT 10
28 : :
29 : : static int global_fds[RTE_MAX_LCORE] = { [0 ... RTE_MAX_LCORE-1] = -1 };
30 : :
31 : : int
32 : 0 : guest_channel_host_check_exists(const char *path)
33 : : {
34 : : char glob_path[PATH_MAX];
35 : : glob_t g;
36 : : int ret;
37 : :
38 : : /* we cannot know in advance which cores have VM channels, so glob */
39 : : snprintf(glob_path, PATH_MAX, "%s.*", path);
40 : :
41 : 0 : ret = glob(glob_path, GLOB_NOSORT, NULL, &g);
42 [ # # ]: 0 : if (ret != 0) {
43 : : /* couldn't read anything */
44 : : ret = 0;
45 : 0 : goto out;
46 : : }
47 : :
48 : : /* do we have at least one match? */
49 : 0 : ret = g.gl_pathc > 0;
50 : :
51 : 0 : out:
52 : 0 : globfree(&g);
53 : 0 : return ret;
54 : : }
55 : :
56 : : int
57 : 2 : guest_channel_host_connect(const char *path, unsigned int lcore_id)
58 : : {
59 : : int flags, ret;
60 : : struct rte_power_channel_packet pkt;
61 : : char fd_path[PATH_MAX];
62 : : int fd = -1;
63 : :
64 [ - + ]: 2 : if (lcore_id >= RTE_MAX_LCORE) {
65 : 0 : GUEST_CHANNEL_LOG(ERR, "Channel(%u) is out of range 0...%d",
66 : : lcore_id, RTE_MAX_LCORE-1);
67 : 0 : return -1;
68 : : }
69 : : /* check if path is already open */
70 [ - + ]: 2 : if (global_fds[lcore_id] != -1) {
71 : 0 : GUEST_CHANNEL_LOG(ERR, "Channel(%u) is already open with fd %d",
72 : : lcore_id, global_fds[lcore_id]);
73 : 0 : return -1;
74 : : }
75 : :
76 : : snprintf(fd_path, PATH_MAX, "%s.%u", path, lcore_id);
77 : 2 : GUEST_CHANNEL_LOG(INFO, "Opening channel '%s' for lcore %u",
78 : : fd_path, lcore_id);
79 : : fd = open(fd_path, O_RDWR);
80 [ + - ]: 2 : if (fd < 0) {
81 : 2 : GUEST_CHANNEL_LOG(ERR, "Unable to connect to '%s' with error "
82 : : "%s", fd_path, strerror(errno));
83 : 2 : return -1;
84 : : }
85 : :
86 : 0 : flags = fcntl(fd, F_GETFL, 0);
87 [ # # ]: 0 : if (flags < 0) {
88 : 0 : GUEST_CHANNEL_LOG(ERR, "Failed on fcntl get flags for file %s",
89 : : fd_path);
90 : 0 : goto error;
91 : : }
92 : :
93 : 0 : flags |= O_NONBLOCK;
94 [ # # ]: 0 : if (fcntl(fd, F_SETFL, flags) < 0) {
95 : 0 : GUEST_CHANNEL_LOG(ERR, "Failed on setting non-blocking mode for "
96 : : "file %s", fd_path);
97 : 0 : goto error;
98 : : }
99 : : /* QEMU needs a delay after connection */
100 : 0 : sleep(1);
101 : :
102 : : /* Send a test packet, this command is ignored by the host, but a successful
103 : : * send indicates that the host endpoint is monitoring.
104 : : */
105 : 0 : pkt.command = RTE_POWER_CPU_POWER_CONNECT;
106 : 0 : global_fds[lcore_id] = fd;
107 : 0 : ret = guest_channel_send_msg(&pkt, lcore_id);
108 [ # # ]: 0 : if (ret != 0) {
109 [ # # ]: 0 : GUEST_CHANNEL_LOG(ERR,
110 : : "Error on channel '%s' communications test: %s",
111 : : fd_path, ret > 0 ? strerror(ret) :
112 : : "channel not connected");
113 : 0 : goto error;
114 : : }
115 : 0 : GUEST_CHANNEL_LOG(INFO, "Channel '%s' is now connected", fd_path);
116 : 0 : return 0;
117 : 0 : error:
118 : 0 : close(fd);
119 : 0 : global_fds[lcore_id] = -1;
120 : 0 : return -1;
121 : : }
122 : :
123 : : int
124 : 0 : guest_channel_send_msg(struct rte_power_channel_packet *pkt,
125 : : unsigned int lcore_id)
126 : : {
127 : : int ret, buffer_len = sizeof(*pkt);
128 : : void *buffer = pkt;
129 : :
130 [ # # ]: 0 : if (lcore_id >= RTE_MAX_LCORE) {
131 : 0 : GUEST_CHANNEL_LOG(ERR, "Channel(%u) is out of range 0...%d",
132 : : lcore_id, RTE_MAX_LCORE-1);
133 : 0 : return -1;
134 : : }
135 : :
136 [ # # ]: 0 : if (global_fds[lcore_id] < 0) {
137 : 0 : GUEST_CHANNEL_LOG(ERR, "Channel is not connected");
138 : 0 : return -1;
139 : : }
140 [ # # ]: 0 : while (buffer_len > 0) {
141 : 0 : ret = write(global_fds[lcore_id], buffer, buffer_len);
142 [ # # ]: 0 : if (ret == buffer_len)
143 : : return 0;
144 [ # # ]: 0 : if (ret == -1) {
145 [ # # ]: 0 : if (errno == EINTR)
146 : 0 : continue;
147 : 0 : return errno;
148 : : }
149 : 0 : buffer = (char *)buffer + ret;
150 : 0 : buffer_len -= ret;
151 : : }
152 : : return 0;
153 : : }
154 : :
155 : : RTE_EXPORT_SYMBOL(rte_power_guest_channel_send_msg)
156 : 0 : int rte_power_guest_channel_send_msg(struct rte_power_channel_packet *pkt,
157 : : unsigned int lcore_id)
158 : : {
159 : 0 : return guest_channel_send_msg(pkt, lcore_id);
160 : : }
161 : :
162 : 0 : int power_guest_channel_read_msg(void *pkt,
163 : : size_t pkt_len,
164 : : unsigned int lcore_id)
165 : : {
166 : : int ret;
167 : : struct pollfd fds;
168 : :
169 [ # # ]: 0 : if (pkt_len == 0 || pkt == NULL)
170 : : return -1;
171 : :
172 [ # # ]: 0 : if (lcore_id >= RTE_MAX_LCORE) {
173 : 0 : GUEST_CHANNEL_LOG(ERR, "Channel(%u) is out of range 0...%d",
174 : : lcore_id, RTE_MAX_LCORE-1);
175 : 0 : return -1;
176 : : }
177 : :
178 [ # # ]: 0 : if (global_fds[lcore_id] < 0) {
179 : 0 : GUEST_CHANNEL_LOG(ERR, "Channel is not connected");
180 : 0 : return -1;
181 : : }
182 : :
183 : 0 : fds.fd = global_fds[lcore_id];
184 : 0 : fds.events = POLLIN;
185 : :
186 : : ret = poll(&fds, 1, TIMEOUT);
187 [ # # ]: 0 : if (ret == 0) {
188 : 0 : GUEST_CHANNEL_LOG(DEBUG, "Timeout occurred during poll function.");
189 : 0 : return -1;
190 [ # # ]: 0 : } else if (ret < 0) {
191 : 0 : GUEST_CHANNEL_LOG(ERR, "Error occurred during poll function: %s",
192 : : strerror(errno));
193 : 0 : return -1;
194 : : }
195 : :
196 [ # # ]: 0 : while (pkt_len > 0) {
197 [ # # ]: 0 : ret = read(global_fds[lcore_id],
198 : : pkt, pkt_len);
199 : :
200 [ # # ]: 0 : if (ret < 0) {
201 [ # # ]: 0 : if (errno == EINTR)
202 : 0 : continue;
203 : : return -1;
204 : : }
205 : :
206 [ # # ]: 0 : if (ret == 0) {
207 : 0 : GUEST_CHANNEL_LOG(ERR, "Expected more data, but connection has been closed.");
208 : 0 : return -1;
209 : : }
210 : 0 : pkt = (char *)pkt + ret;
211 : 0 : pkt_len -= ret;
212 : : }
213 : :
214 : : return 0;
215 : : }
216 : :
217 : : RTE_EXPORT_SYMBOL(rte_power_guest_channel_receive_msg)
218 : 0 : int rte_power_guest_channel_receive_msg(void *pkt,
219 : : size_t pkt_len,
220 : : unsigned int lcore_id)
221 : : {
222 : 0 : return power_guest_channel_read_msg(pkt, pkt_len, lcore_id);
223 : : }
224 : :
225 : : void
226 : 0 : guest_channel_host_disconnect(unsigned int lcore_id)
227 : : {
228 [ # # ]: 0 : if (lcore_id >= RTE_MAX_LCORE) {
229 : 0 : GUEST_CHANNEL_LOG(ERR, "Channel(%u) is out of range 0...%d",
230 : : lcore_id, RTE_MAX_LCORE-1);
231 : 0 : return;
232 : : }
233 [ # # ]: 0 : if (global_fds[lcore_id] < 0)
234 : : return;
235 : 0 : close(global_fds[lcore_id]);
236 : 0 : global_fds[lcore_id] = -1;
237 : : }
|