xenbus_comms.c revision 1.5 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