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 [ - + ]: 303 : 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 : 1 : 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 : : /* check if path is already open */
65 [ - + ]: 1 : if (global_fds[lcore_id] != -1) {
66 : 0 : GUEST_CHANNEL_LOG(ERR, "Channel(%u) is already open with fd %d",
67 : : lcore_id, global_fds[lcore_id]);
68 : 0 : return -1;
69 : : }
70 : :
71 : : snprintf(fd_path, PATH_MAX, "%s.%u", path, lcore_id);
72 : 1 : GUEST_CHANNEL_LOG(INFO, "Opening channel '%s' for lcore %u",
73 : : fd_path, lcore_id);
74 : : fd = open(fd_path, O_RDWR);
75 [ + - ]: 1 : if (fd < 0) {
76 : 1 : GUEST_CHANNEL_LOG(ERR, "Unable to connect to '%s' with error "
77 : : "%s", fd_path, strerror(errno));
78 : 1 : return -1;
79 : : }
80 : :
81 : 0 : flags = fcntl(fd, F_GETFL, 0);
82 [ # # ]: 0 : if (flags < 0) {
83 : 0 : GUEST_CHANNEL_LOG(ERR, "Failed on fcntl get flags for file %s",
84 : : fd_path);
85 : 0 : goto error;
86 : : }
87 : :
88 : 0 : flags |= O_NONBLOCK;
89 [ # # ]: 0 : if (fcntl(fd, F_SETFL, flags) < 0) {
90 : 0 : GUEST_CHANNEL_LOG(ERR, "Failed on setting non-blocking mode for "
91 : : "file %s", fd_path);
92 : 0 : goto error;
93 : : }
94 : : /* QEMU needs a delay after connection */
95 : 0 : sleep(1);
96 : :
97 : : /* Send a test packet, this command is ignored by the host, but a successful
98 : : * send indicates that the host endpoint is monitoring.
99 : : */
100 : 0 : pkt.command = RTE_POWER_CPU_POWER_CONNECT;
101 : 0 : global_fds[lcore_id] = fd;
102 : 0 : ret = guest_channel_send_msg(&pkt, lcore_id);
103 [ # # ]: 0 : if (ret != 0) {
104 [ # # ]: 0 : GUEST_CHANNEL_LOG(ERR,
105 : : "Error on channel '%s' communications test: %s",
106 : : fd_path, ret > 0 ? strerror(ret) :
107 : : "channel not connected");
108 : 0 : goto error;
109 : : }
110 : 0 : GUEST_CHANNEL_LOG(INFO, "Channel '%s' is now connected", fd_path);
111 : 0 : return 0;
112 : 0 : error:
113 : 0 : close(fd);
114 : 0 : global_fds[lcore_id] = -1;
115 : 0 : return -1;
116 : : }
117 : :
118 : : int
119 : 0 : guest_channel_send_msg(struct rte_power_channel_packet *pkt,
120 : : unsigned int lcore_id)
121 : : {
122 : : int ret, buffer_len = sizeof(*pkt);
123 : : void *buffer = pkt;
124 : :
125 [ # # ]: 0 : if (global_fds[lcore_id] < 0) {
126 : 0 : GUEST_CHANNEL_LOG(ERR, "Channel is not connected");
127 : 0 : return -1;
128 : : }
129 [ # # ]: 0 : while (buffer_len > 0) {
130 : 0 : ret = write(global_fds[lcore_id], buffer, buffer_len);
131 [ # # ]: 0 : if (ret == buffer_len)
132 : : return 0;
133 [ # # ]: 0 : if (ret == -1) {
134 [ # # ]: 0 : if (errno == EINTR)
135 : 0 : continue;
136 : 0 : return errno;
137 : : }
138 : 0 : buffer = (char *)buffer + ret;
139 : 0 : buffer_len -= ret;
140 : : }
141 : : return 0;
142 : : }
143 : :
144 : : RTE_EXPORT_SYMBOL(rte_power_guest_channel_send_msg)
145 : 0 : int rte_power_guest_channel_send_msg(struct rte_power_channel_packet *pkt,
146 : : unsigned int lcore_id)
147 : : {
148 : 0 : return guest_channel_send_msg(pkt, lcore_id);
149 : : }
150 : :
151 : 0 : int power_guest_channel_read_msg(void *pkt,
152 : : size_t pkt_len,
153 : : unsigned int lcore_id)
154 : : {
155 : : int ret;
156 : : struct pollfd fds;
157 : :
158 [ # # ]: 0 : if (pkt_len == 0 || pkt == NULL)
159 : : return -1;
160 : :
161 [ # # ]: 0 : if (global_fds[lcore_id] < 0) {
162 : 0 : GUEST_CHANNEL_LOG(ERR, "Channel is not connected");
163 : 0 : return -1;
164 : : }
165 : :
166 : 0 : fds.fd = global_fds[lcore_id];
167 : 0 : fds.events = POLLIN;
168 : :
169 : : ret = poll(&fds, 1, TIMEOUT);
170 [ # # ]: 0 : if (ret == 0) {
171 : 0 : GUEST_CHANNEL_LOG(DEBUG, "Timeout occurred during poll function.");
172 : 0 : return -1;
173 [ # # ]: 0 : } else if (ret < 0) {
174 : 0 : GUEST_CHANNEL_LOG(ERR, "Error occurred during poll function: %s",
175 : : strerror(errno));
176 : 0 : return -1;
177 : : }
178 : :
179 [ # # ]: 0 : while (pkt_len > 0) {
180 [ # # ]: 0 : ret = read(global_fds[lcore_id],
181 : : pkt, pkt_len);
182 : :
183 [ # # ]: 0 : if (ret < 0) {
184 [ # # ]: 0 : if (errno == EINTR)
185 : 0 : continue;
186 : : return -1;
187 : : }
188 : :
189 [ # # ]: 0 : if (ret == 0) {
190 : 0 : GUEST_CHANNEL_LOG(ERR, "Expected more data, but connection has been closed.");
191 : 0 : return -1;
192 : : }
193 : 0 : pkt = (char *)pkt + ret;
194 : 0 : pkt_len -= ret;
195 : : }
196 : :
197 : : return 0;
198 : : }
199 : :
200 : : RTE_EXPORT_SYMBOL(rte_power_guest_channel_receive_msg)
201 : 0 : int rte_power_guest_channel_receive_msg(void *pkt,
202 : : size_t pkt_len,
203 : : unsigned int lcore_id)
204 : : {
205 : 0 : return power_guest_channel_read_msg(pkt, pkt_len, lcore_id);
206 : : }
207 : :
208 : : void
209 : 0 : guest_channel_host_disconnect(unsigned int lcore_id)
210 : : {
211 [ # # ]: 0 : if (global_fds[lcore_id] < 0)
212 : : return;
213 : 0 : close(global_fds[lcore_id]);
214 : 0 : global_fds[lcore_id] = -1;
215 : : }
|