]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/xen/xenbus/xenbus_comms.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / sys / xen / xenbus / xenbus_comms.c
1 /******************************************************************************
2  * xenbus_comms.c
3  *
4  * Low level code to talks to Xen Store: ringbuffer and event channel.
5  *
6  * Copyright (C) 2005 Rusty Russell, IBM Corporation
7  * 
8  * This file may be distributed separately from the Linux kernel, or
9  * incorporated into other software packages, subject to the following license:
10  * 
11  * Permission is hereby granted, free of charge, to any person obtaining a copy
12  * of this source file (the "Software"), to deal in the Software without
13  * restriction, including without limitation the rights to use, copy, modify,
14  * merge, publish, distribute, sublicense, and/or sell copies of the Software,
15  * and to permit persons to whom the Software is furnished to do so, subject to
16  * the following conditions:
17  * 
18  * The above copyright notice and this permission notice shall be included in
19  * all copies or substantial portions of the Software.
20  * 
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
27  * IN THE SOFTWARE.
28  */
29
30
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
34 #include <sys/param.h>
35 #include <sys/bus.h>
36 #include <sys/kernel.h>
37 #include <sys/lock.h>
38 #include <sys/mutex.h>
39 #include <sys/sx.h>
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/syslog.h>
43
44 #include <machine/xen/xen-os.h>
45 #include <xen/hypervisor.h>
46
47 #include <xen/xen_intr.h>
48 #include <xen/evtchn.h>
49 #include <xen/interface/io/xs_wire.h>
50 #include <xen/xenbus/xenbus_comms.h>
51
52 static unsigned int xenstore_irq;
53
54 static inline struct xenstore_domain_interface *
55 xenstore_domain_interface(void)
56 {
57
58         return (struct xenstore_domain_interface *)xen_store;
59 }
60
61 static void
62 xb_intr(void * arg __attribute__((unused)))
63 {
64
65         wakeup(xen_store);
66 }
67
68 static int
69 xb_check_indexes(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod)
70 {
71
72         return ((prod - cons) <= XENSTORE_RING_SIZE);
73 }
74
75 static void *
76 xb_get_output_chunk(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod,
77     char *buf, uint32_t *len)
78 {
79
80         *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod);
81         if ((XENSTORE_RING_SIZE - (prod - cons)) < *len)
82                 *len = XENSTORE_RING_SIZE - (prod - cons);
83         return (buf + MASK_XENSTORE_IDX(prod));
84 }
85
86 static const void *
87 xb_get_input_chunk(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod,
88     const char *buf, uint32_t *len)
89 {
90
91         *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(cons);
92         if ((prod - cons) < *len)
93                 *len = prod - cons;
94         return (buf + MASK_XENSTORE_IDX(cons));
95 }
96
97 int
98 xb_write(const void *tdata, unsigned len, struct lock_object *lock)
99 {
100         struct xenstore_domain_interface *intf = xenstore_domain_interface();
101         XENSTORE_RING_IDX cons, prod;
102         const char *data = (const char *)tdata;
103         int error;
104
105         while (len != 0) {
106                 void *dst;
107                 unsigned int avail;
108
109                 while ((intf->req_prod - intf->req_cons)
110                     == XENSTORE_RING_SIZE) {
111                         error = _sleep(intf,
112                             lock,
113                             PCATCH, "xbwrite", hz/10);
114                         if (error && error != EWOULDBLOCK)
115                                 return (error);
116                 }
117
118                 /* Read indexes, then verify. */
119                 cons = intf->req_cons;
120                 prod = intf->req_prod;
121                 mb();
122                 if (!xb_check_indexes(cons, prod)) {
123                         intf->req_cons = intf->req_prod = 0;
124                         return (EIO);
125                 }
126
127                 dst = xb_get_output_chunk(cons, prod, intf->req, &avail);
128                 if (avail == 0)
129                         continue;
130                 if (avail > len)
131                         avail = len;
132                 mb();
133                                 
134                 memcpy(dst, data, avail);
135                 data += avail;
136                 len -= avail;
137
138                 /* Other side must not see new header until data is there. */
139                 wmb();
140                 intf->req_prod += avail;
141
142                 /* This implies mb() before other side sees interrupt. */
143                 notify_remote_via_evtchn(xen_store_evtchn);
144         }
145
146         return (0);
147 }
148
149 int
150 xb_read(void *tdata, unsigned len, struct lock_object *lock)
151 {
152         struct xenstore_domain_interface *intf = xenstore_domain_interface();
153         XENSTORE_RING_IDX cons, prod;
154         char *data = (char *)tdata;
155         int error;
156
157         while (len != 0) {
158                 unsigned int avail;
159                 const char *src;
160
161                 while (intf->rsp_cons == intf->rsp_prod) {
162                         error = _sleep(intf, lock,
163                             PCATCH, "xbread", hz/10);
164                         if (error && error != EWOULDBLOCK)
165                                 return (error);
166                 }
167                         
168                 /* Read indexes, then verify. */
169                 cons = intf->rsp_cons;
170                 prod = intf->rsp_prod;
171                 if (!xb_check_indexes(cons, prod)) {
172                         intf->rsp_cons = intf->rsp_prod = 0;
173                         return (EIO);
174                 }
175                                 
176                 src = xb_get_input_chunk(cons, prod, intf->rsp, &avail);
177                 if (avail == 0)
178                         continue;
179                 if (avail > len)
180                         avail = len;
181
182                 /* We must read header before we read data. */
183                 rmb();
184
185                 memcpy(data, src, avail);
186                 data += avail;
187                 len -= avail;
188
189                 /* Other side must not see free space until we've copied out */
190                 mb();
191                 intf->rsp_cons += avail;
192
193                 /* Implies mb(): they will see new header. */
194                 notify_remote_via_evtchn(xen_store_evtchn);
195         }
196
197         return (0);
198 }
199
200 /* Set up interrupt handler off store event channel. */
201 int
202 xb_init_comms(void)
203 {
204         struct xenstore_domain_interface *intf = xenstore_domain_interface();
205         int error;
206
207         if (intf->rsp_prod != intf->rsp_cons) {
208                 log(LOG_WARNING, "XENBUS response ring is not quiescent "
209                     "(%08x:%08x): fixing up\n",
210                     intf->rsp_cons, intf->rsp_prod);
211                 intf->rsp_cons = intf->rsp_prod;
212         }
213
214         if (xenstore_irq)
215                 unbind_from_irqhandler(xenstore_irq);
216
217         error = bind_caller_port_to_irqhandler(
218                 xen_store_evtchn, "xenbus",
219                     xb_intr, NULL, INTR_TYPE_NET, &xenstore_irq);
220         if (error) {
221                 log(LOG_WARNING, "XENBUS request irq failed %i\n", error);
222                 return (error);
223         }
224
225         return (0);
226 }