xref: /netbsd-src/sys/arch/xen/xenbus/xenbus_comms.c (revision 8b0f9554ff8762542c4defc4f70e1eb76fb508fa)
1 /* $NetBSD: xenbus_comms.c,v 1.5 2007/11/22 16:17:11 bouyer Exp $ */
2 /******************************************************************************
3  * xenbus_comms.c
4  *
5  * Low level code to talks to Xen Store: ringbuffer and event channel.
6  *
7  * Copyright (C) 2005 Rusty Russell, IBM Corporation
8  *
9  * This file may be distributed separately from the Linux kernel, or
10  * incorporated into other software packages, subject to the following license:
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining a copy
13  * of this source file (the "Software"), to deal in the Software without
14  * restriction, including without limitation the rights to use, copy, modify,
15  * merge, publish, distribute, sublicense, and/or sell copies of the Software,
16  * and to permit persons to whom the Software is furnished to do so, subject to
17  * the following conditions:
18  *
19  * The above copyright notice and this permission notice shall be included in
20  * all copies or substantial portions of the Software.
21  *
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
28  * IN THE SOFTWARE.
29  */
30 
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: xenbus_comms.c,v 1.5 2007/11/22 16:17:11 bouyer Exp $");
33 
34 #include <sys/types.h>
35 #include <sys/null.h>
36 #include <sys/errno.h>
37 #include <sys/malloc.h>
38 #include <sys/param.h>
39 #include <sys/proc.h>
40 #include <sys/systm.h>
41 
42 #include <xen/hypervisor.h>
43 #include <xen/evtchn.h>
44 #include <xen/xenbus.h>
45 #include "xenbus_comms.h"
46 
47 #undef XENDEBUG
48 #ifdef XENDEBUG
49 #define XENPRINTF(x) printf x
50 #else
51 #define XENPRINTF(x)
52 #endif
53 
54 struct xenstore_domain_interface *xenstore_interface;
55 
56 static int xenbus_irq = 0;
57 
58 extern int xenstored_ready;
59 // static DECLARE_WORK(probe_work, xenbus_probe, NULL);
60 
61 static int wake_waiting(void *);
62 static int check_indexes(XENSTORE_RING_IDX, XENSTORE_RING_IDX);
63 static void *get_output_chunk(XENSTORE_RING_IDX, XENSTORE_RING_IDX,
64     char *, uint32_t *);
65 static const void *get_input_chunk(XENSTORE_RING_IDX, XENSTORE_RING_IDX,
66     const char *, uint32_t *);
67 
68 
69 static inline struct xenstore_domain_interface *
70 xenstore_domain_interface(void)
71 {
72 	return xenstore_interface;
73 }
74 
75 static int
76 wake_waiting(void *arg)
77 {
78 	if (__predict_false(xenstored_ready == 0 &&
79 	    xen_start_info.flags & SIF_INITDOMAIN)) {
80 		xenstored_ready = 1;
81 		wakeup(&xenstored_ready);
82 	}
83 
84 	wakeup(&xenstore_interface);
85 	return 1;
86 }
87 
88 static int
89 check_indexes(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod)
90 {
91 	return ((prod - cons) <= XENSTORE_RING_SIZE);
92 }
93 
94 static void *
95 get_output_chunk(XENSTORE_RING_IDX cons,
96 			      XENSTORE_RING_IDX prod,
97 			      char *buf, uint32_t *len)
98 {
99 	*len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod);
100 	if ((XENSTORE_RING_SIZE - (prod - cons)) < *len)
101 		*len = XENSTORE_RING_SIZE - (prod - cons);
102 	return buf + MASK_XENSTORE_IDX(prod);
103 }
104 
105 static const void *
106 get_input_chunk(XENSTORE_RING_IDX cons,
107 				   XENSTORE_RING_IDX prod,
108 				   const char *buf, uint32_t *len)
109 {
110 	*len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(cons);
111 	if ((prod - cons) < *len)
112 		*len = prod - cons;
113 	return buf + MASK_XENSTORE_IDX(cons);
114 }
115 
116 int
117 xb_write(const void *data, unsigned len)
118 {
119 	struct xenstore_domain_interface *intf = xenstore_domain_interface();
120 	XENSTORE_RING_IDX cons, prod;
121 
122 	int s = spltty();
123 
124 	while (len != 0) {
125 		void *dst;
126 		unsigned int avail;
127 
128 		while ((intf->req_prod - intf->req_cons) == XENSTORE_RING_SIZE) {
129 			XENPRINTF(("xb_write tsleep\n"));
130 			tsleep(&xenstore_interface, PRIBIO, "wrst", 0);
131 			XENPRINTF(("xb_write tsleep done\n"));
132 		}
133 
134 		/* Read indexes, then verify. */
135 		cons = intf->req_cons;
136 		prod = intf->req_prod;
137 		x86_lfence();
138 		if (!check_indexes(cons, prod)) {
139 			splx(s);
140 			return EIO;
141 		}
142 
143 		dst = get_output_chunk(cons, prod, intf->req, &avail);
144 		if (avail == 0)
145 			continue;
146 		if (avail > len)
147 			avail = len;
148 
149 		memcpy(dst, data, avail);
150 		data = (const char *)data + avail;
151 		len -= avail;
152 
153 		/* Other side must not see new header until data is there. */
154 		x86_lfence();
155 		intf->req_prod += avail;
156 		x86_lfence();
157 
158 		hypervisor_notify_via_evtchn(xen_start_info.store_evtchn);
159 	}
160 
161 	splx(s);
162 	return 0;
163 }
164 
165 int
166 xb_read(void *data, unsigned len)
167 {
168 	struct xenstore_domain_interface *intf = xenstore_domain_interface();
169 	XENSTORE_RING_IDX cons, prod;
170 
171 	int s = spltty();
172 
173 	while (len != 0) {
174 		unsigned int avail;
175 		const char *src;
176 
177 		while (intf->rsp_cons == intf->rsp_prod)
178 			tsleep(&xenstore_interface, PRIBIO, "rdst", 0);
179 
180 		/* Read indexes, then verify. */
181 		cons = intf->rsp_cons;
182 		prod = intf->rsp_prod;
183 		x86_lfence();
184 		if (!check_indexes(cons, prod)) {
185 			XENPRINTF(("xb_read EIO\n"));
186 			splx(s);
187 			return EIO;
188 		}
189 
190 		src = get_input_chunk(cons, prod, intf->rsp, &avail);
191 		if (avail == 0)
192 			continue;
193 		if (avail > len)
194 			avail = len;
195 
196 		/* We must read header before we read data. */
197 		x86_lfence();
198 
199 		memcpy(data, src, avail);
200 		data = (char *)data + avail;
201 		len -= avail;
202 
203 		/* Other side must not see free space until we've copied out */
204 		x86_lfence();
205 		intf->rsp_cons += avail;
206 		x86_lfence();
207 
208 		XENPRINTF(("Finished read of %i bytes (%i to go)\n",
209 		    avail, len));
210 
211 		hypervisor_notify_via_evtchn(xen_start_info.store_evtchn);
212 	}
213 
214 	splx(s);
215 	return 0;
216 }
217 
218 /* Set up interrupt handler off store event channel. */
219 int
220 xb_init_comms(struct device *dev)
221 {
222 	int err;
223 
224 	if (xenbus_irq)
225 		event_remove_handler(xenbus_irq, wake_waiting, NULL);
226 
227 	err = event_set_handler(xen_start_info.store_evtchn, wake_waiting,
228 	    NULL, IPL_TTY, "xenbus");
229 	if (err) {
230 		printf("XENBUS request irq failed %i\n", err);
231 		return err;
232 	}
233 	xenbus_irq = xen_start_info.store_evtchn;
234 	printf("%s: using event channel %d\n", dev->dv_xname, xenbus_irq);
235 	hypervisor_enable_event(xenbus_irq);
236 	return 0;
237 }
238 
239 /*
240  * Local variables:
241  *  c-file-style: "linux"
242  *  indent-tabs-mode: t
243  *  c-indent-level: 8
244  *  c-basic-offset: 8
245  *  tab-width: 8
246  * End:
247  */
248