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