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