direct-io.hg

view linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_comms.c @ 7356:af38c6b205f6

Keir moved barriers,
Competence questions are raised:
Correctness withers.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
author kaf24@firebug.cl.cam.ac.uk
date Wed Oct 12 17:00:29 2005 +0100 (2005-10-12)
parents 74d56b7ff46c
children 2796f432858e
line source
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 */
30 #include <asm/hypervisor.h>
31 #include <asm-xen/evtchn.h>
32 #include <linux/wait.h>
33 #include <linux/interrupt.h>
34 #include <linux/sched.h>
35 #include <linux/err.h>
36 #include "xenbus_comms.h"
38 #define RINGBUF_DATASIZE ((PAGE_SIZE / 2) - sizeof(struct ringbuf_head))
39 struct ringbuf_head
40 {
41 u32 write; /* Next place to write to */
42 u32 read; /* Next place to read from */
43 u8 flags;
44 char buf[0];
45 } __attribute__((packed));
47 static int xenbus_irq;
49 DECLARE_WAIT_QUEUE_HEAD(xb_waitq);
51 static inline struct ringbuf_head *outbuf(void)
52 {
53 return mfn_to_virt(xen_start_info->store_mfn);
54 }
56 static inline struct ringbuf_head *inbuf(void)
57 {
58 return mfn_to_virt(xen_start_info->store_mfn) + PAGE_SIZE/2;
59 }
61 static irqreturn_t wake_waiting(int irq, void *unused, struct pt_regs *regs)
62 {
63 wake_up(&xb_waitq);
64 return IRQ_HANDLED;
65 }
67 static int check_buffer(const struct ringbuf_head *h)
68 {
69 return (h->write < RINGBUF_DATASIZE && h->read < RINGBUF_DATASIZE);
70 }
72 /* We can't fill last byte: would look like empty buffer. */
73 static void *get_output_chunk(const struct ringbuf_head *h,
74 void *buf, u32 *len)
75 {
76 u32 read_mark;
78 if (h->read == 0)
79 read_mark = RINGBUF_DATASIZE - 1;
80 else
81 read_mark = h->read - 1;
83 /* Here to the end of buffer, unless they haven't read some out. */
84 *len = RINGBUF_DATASIZE - h->write;
85 if (read_mark >= h->write)
86 *len = read_mark - h->write;
87 return buf + h->write;
88 }
90 static const void *get_input_chunk(const struct ringbuf_head *h,
91 const void *buf, u32 *len)
92 {
93 /* Here to the end of buffer, unless they haven't written some. */
94 *len = RINGBUF_DATASIZE - h->read;
95 if (h->write >= h->read)
96 *len = h->write - h->read;
97 return buf + h->read;
98 }
100 static void update_output_chunk(struct ringbuf_head *h, u32 len)
101 {
102 h->write += len;
103 if (h->write == RINGBUF_DATASIZE)
104 h->write = 0;
105 }
107 static void update_input_chunk(struct ringbuf_head *h, u32 len)
108 {
109 h->read += len;
110 if (h->read == RINGBUF_DATASIZE)
111 h->read = 0;
112 }
114 static int output_avail(struct ringbuf_head *out)
115 {
116 unsigned int avail;
118 get_output_chunk(out, out->buf, &avail);
119 return avail != 0;
120 }
122 int xb_write(const void *data, unsigned len)
123 {
124 struct ringbuf_head h;
125 struct ringbuf_head *out = outbuf();
127 do {
128 void *dst;
129 unsigned int avail;
131 wait_event_interruptible(xb_waitq, output_avail(out));
133 /* Make local copy of header to check for sanity. */
134 h = *out;
135 if (!check_buffer(&h))
136 return -EIO;
138 dst = get_output_chunk(&h, out->buf, &avail);
139 if (avail == 0)
140 continue;
141 if (avail > len)
142 avail = len;
144 /* Make sure we read header before we write data
145 * (implied by data-dependency, but let's play safe). */
146 mb();
148 memcpy(dst, data, avail);
149 data += avail;
150 len -= avail;
152 /* Other side must not see new header until data is there. */
153 wmb();
154 update_output_chunk(out, avail);
156 /* This implies mb() before other side sees interrupt. */
157 notify_remote_via_evtchn(xen_start_info->store_evtchn);
158 } while (len != 0);
160 return 0;
161 }
163 int xs_input_avail(void)
164 {
165 unsigned int avail;
166 struct ringbuf_head *in = inbuf();
168 get_input_chunk(in, in->buf, &avail);
169 return avail != 0;
170 }
172 int xb_read(void *data, unsigned len)
173 {
174 struct ringbuf_head h;
175 struct ringbuf_head *in = inbuf();
176 int was_full;
178 while (len != 0) {
179 unsigned int avail;
180 const char *src;
182 wait_event_interruptible(xb_waitq, xs_input_avail());
184 h = *in;
185 if (!check_buffer(&h))
186 return -EIO;
188 src = get_input_chunk(&h, in->buf, &avail);
189 if (avail == 0)
190 continue;
191 if (avail > len)
192 avail = len;
193 was_full = !output_avail(&h);
195 /* We must read header before we read data. */
196 rmb();
198 memcpy(data, src, avail);
199 data += avail;
200 len -= avail;
202 /* Other side must not see free space until we've copied out */
203 mb();
205 update_input_chunk(in, avail);
206 pr_debug("Finished read of %i bytes (%i to go)\n", avail, len);
207 /* If it was full, tell them we've taken some. */
208 if (was_full)
209 /* Implies mb(): they will see new header. */
210 notify_remote_via_evtchn(xen_start_info->store_evtchn);
211 }
213 return 0;
214 }
216 /* Set up interrupt handler off store event channel. */
217 int xb_init_comms(void)
218 {
219 int err;
221 if (xenbus_irq)
222 unbind_evtchn_from_irqhandler(xenbus_irq, &xb_waitq);
223 xenbus_irq = 0;
225 if (!xen_start_info->store_evtchn)
226 return 0;
228 err = bind_evtchn_to_irqhandler(
229 xen_start_info->store_evtchn, wake_waiting,
230 0, "xenbus", &xb_waitq);
231 if (err <= 0) {
232 printk(KERN_ERR "XENBUS request irq failed %i\n", err);
233 return err;
234 }
236 xenbus_irq = err;
238 /* FIXME zero out page -- domain builder should probably do this*/
239 memset(mfn_to_virt(xen_start_info->store_mfn), 0, PAGE_SIZE);
241 return 0;
242 }
244 /*
245 * Local variables:
246 * c-file-style: "linux"
247 * indent-tabs-mode: t
248 * c-indent-level: 8
249 * c-basic-offset: 8
250 * tab-width: 8
251 * End:
252 */