xenbus_comms.c revision 1.1 1 1.1 bouyer /******************************************************************************
2 1.1 bouyer * xenbus_comms.c
3 1.1 bouyer *
4 1.1 bouyer * Low level code to talks to Xen Store: ringbuffer and event channel.
5 1.1 bouyer *
6 1.1 bouyer * Copyright (C) 2005 Rusty Russell, IBM Corporation
7 1.1 bouyer *
8 1.1 bouyer * This file may be distributed separately from the Linux kernel, or
9 1.1 bouyer * incorporated into other software packages, subject to the following license:
10 1.1 bouyer *
11 1.1 bouyer * Permission is hereby granted, free of charge, to any person obtaining a copy
12 1.1 bouyer * of this source file (the "Software"), to deal in the Software without
13 1.1 bouyer * restriction, including without limitation the rights to use, copy, modify,
14 1.1 bouyer * merge, publish, distribute, sublicense, and/or sell copies of the Software,
15 1.1 bouyer * and to permit persons to whom the Software is furnished to do so, subject to
16 1.1 bouyer * the following conditions:
17 1.1 bouyer *
18 1.1 bouyer * The above copyright notice and this permission notice shall be included in
19 1.1 bouyer * all copies or substantial portions of the Software.
20 1.1 bouyer *
21 1.1 bouyer * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 1.1 bouyer * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 1.1 bouyer * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 1.1 bouyer * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 1.1 bouyer * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 1.1 bouyer * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
27 1.1 bouyer * IN THE SOFTWARE.
28 1.1 bouyer */
29 1.1 bouyer
30 1.1 bouyer #include <asm/hypervisor.h>
31 1.1 bouyer #include <asm-xen/evtchn.h>
32 1.1 bouyer #include <linux/wait.h>
33 1.1 bouyer #include <linux/interrupt.h>
34 1.1 bouyer #include <linux/sched.h>
35 1.1 bouyer #include <linux/err.h>
36 1.1 bouyer #include <asm-xen/xenbus.h>
37 1.1 bouyer #include "xenbus_comms.h"
38 1.1 bouyer
39 1.1 bouyer static int xenbus_irq;
40 1.1 bouyer
41 1.1 bouyer extern void xenbus_probe(void *);
42 1.1 bouyer extern int xenstored_ready;
43 1.1 bouyer static DECLARE_WORK(probe_work, xenbus_probe, NULL);
44 1.1 bouyer
45 1.1 bouyer DECLARE_WAIT_QUEUE_HEAD(xb_waitq);
46 1.1 bouyer
47 1.1 bouyer static inline struct xenstore_domain_interface *xenstore_domain_interface(void)
48 1.1 bouyer {
49 1.1 bouyer return mfn_to_virt(xen_start_info->store_mfn);
50 1.1 bouyer }
51 1.1 bouyer
52 1.1 bouyer static irqreturn_t wake_waiting(int irq, void *unused, struct pt_regs *regs)
53 1.1 bouyer {
54 1.1 bouyer if (unlikely(xenstored_ready == 0)) {
55 1.1 bouyer xenstored_ready = 1;
56 1.1 bouyer schedule_work(&probe_work);
57 1.1 bouyer }
58 1.1 bouyer
59 1.1 bouyer wake_up(&xb_waitq);
60 1.1 bouyer return IRQ_HANDLED;
61 1.1 bouyer }
62 1.1 bouyer
63 1.1 bouyer static int check_indexes(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod)
64 1.1 bouyer {
65 1.1 bouyer return ((prod - cons) <= XENSTORE_RING_SIZE);
66 1.1 bouyer }
67 1.1 bouyer
68 1.1 bouyer static void *get_output_chunk(XENSTORE_RING_IDX cons,
69 1.1 bouyer XENSTORE_RING_IDX prod,
70 1.1 bouyer char *buf, uint32_t *len)
71 1.1 bouyer {
72 1.1 bouyer *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod);
73 1.1 bouyer if ((XENSTORE_RING_SIZE - (prod - cons)) < *len)
74 1.1 bouyer *len = XENSTORE_RING_SIZE - (prod - cons);
75 1.1 bouyer return buf + MASK_XENSTORE_IDX(prod);
76 1.1 bouyer }
77 1.1 bouyer
78 1.1 bouyer static const void *get_input_chunk(XENSTORE_RING_IDX cons,
79 1.1 bouyer XENSTORE_RING_IDX prod,
80 1.1 bouyer const char *buf, uint32_t *len)
81 1.1 bouyer {
82 1.1 bouyer *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(cons);
83 1.1 bouyer if ((prod - cons) < *len)
84 1.1 bouyer *len = prod - cons;
85 1.1 bouyer return buf + MASK_XENSTORE_IDX(cons);
86 1.1 bouyer }
87 1.1 bouyer
88 1.1 bouyer int xb_write(const void *data, unsigned len)
89 1.1 bouyer {
90 1.1 bouyer struct xenstore_domain_interface *intf = xenstore_domain_interface();
91 1.1 bouyer XENSTORE_RING_IDX cons, prod;
92 1.1 bouyer
93 1.1 bouyer while (len != 0) {
94 1.1 bouyer void *dst;
95 1.1 bouyer unsigned int avail;
96 1.1 bouyer
97 1.1 bouyer wait_event_interruptible(xb_waitq,
98 1.1 bouyer (intf->req_prod - intf->req_cons) !=
99 1.1 bouyer XENSTORE_RING_SIZE);
100 1.1 bouyer
101 1.1 bouyer /* Read indexes, then verify. */
102 1.1 bouyer cons = intf->req_cons;
103 1.1 bouyer prod = intf->req_prod;
104 1.1 bouyer mb();
105 1.1 bouyer if (!check_indexes(cons, prod))
106 1.1 bouyer return -EIO;
107 1.1 bouyer
108 1.1 bouyer dst = get_output_chunk(cons, prod, intf->req, &avail);
109 1.1 bouyer if (avail == 0)
110 1.1 bouyer continue;
111 1.1 bouyer if (avail > len)
112 1.1 bouyer avail = len;
113 1.1 bouyer
114 1.1 bouyer memcpy(dst, data, avail);
115 1.1 bouyer data += avail;
116 1.1 bouyer len -= avail;
117 1.1 bouyer
118 1.1 bouyer /* Other side must not see new header until data is there. */
119 1.1 bouyer wmb();
120 1.1 bouyer intf->req_prod += avail;
121 1.1 bouyer
122 1.1 bouyer /* This implies mb() before other side sees interrupt. */
123 1.1 bouyer notify_remote_via_evtchn(xen_start_info->store_evtchn);
124 1.1 bouyer }
125 1.1 bouyer
126 1.1 bouyer return 0;
127 1.1 bouyer }
128 1.1 bouyer
129 1.1 bouyer int xb_read(void *data, unsigned len)
130 1.1 bouyer {
131 1.1 bouyer struct xenstore_domain_interface *intf = xenstore_domain_interface();
132 1.1 bouyer XENSTORE_RING_IDX cons, prod;
133 1.1 bouyer
134 1.1 bouyer while (len != 0) {
135 1.1 bouyer unsigned int avail;
136 1.1 bouyer const char *src;
137 1.1 bouyer
138 1.1 bouyer wait_event_interruptible(xb_waitq,
139 1.1 bouyer intf->rsp_cons != intf->rsp_prod);
140 1.1 bouyer
141 1.1 bouyer /* Read indexes, then verify. */
142 1.1 bouyer cons = intf->rsp_cons;
143 1.1 bouyer prod = intf->rsp_prod;
144 1.1 bouyer mb();
145 1.1 bouyer if (!check_indexes(cons, prod))
146 1.1 bouyer return -EIO;
147 1.1 bouyer
148 1.1 bouyer src = get_input_chunk(cons, prod, intf->rsp, &avail);
149 1.1 bouyer if (avail == 0)
150 1.1 bouyer continue;
151 1.1 bouyer if (avail > len)
152 1.1 bouyer avail = len;
153 1.1 bouyer
154 1.1 bouyer /* We must read header before we read data. */
155 1.1 bouyer rmb();
156 1.1 bouyer
157 1.1 bouyer memcpy(data, src, avail);
158 1.1 bouyer data += avail;
159 1.1 bouyer len -= avail;
160 1.1 bouyer
161 1.1 bouyer /* Other side must not see free space until we've copied out */
162 1.1 bouyer mb();
163 1.1 bouyer intf->rsp_cons += avail;
164 1.1 bouyer
165 1.1 bouyer pr_debug("Finished read of %i bytes (%i to go)\n", avail, len);
166 1.1 bouyer
167 1.1 bouyer /* Implies mb(): they will see new header. */
168 1.1 bouyer notify_remote_via_evtchn(xen_start_info->store_evtchn);
169 1.1 bouyer }
170 1.1 bouyer
171 1.1 bouyer return 0;
172 1.1 bouyer }
173 1.1 bouyer
174 1.1 bouyer /* Set up interrupt handler off store event channel. */
175 1.1 bouyer int xb_init_comms(void)
176 1.1 bouyer {
177 1.1 bouyer int err;
178 1.1 bouyer
179 1.1 bouyer if (xenbus_irq)
180 1.1 bouyer unbind_from_irqhandler(xenbus_irq, &xb_waitq);
181 1.1 bouyer
182 1.1 bouyer err = bind_evtchn_to_irqhandler(
183 1.1 bouyer xen_start_info->store_evtchn, wake_waiting,
184 1.1 bouyer 0, "xenbus", &xb_waitq);
185 1.1 bouyer if (err <= 0) {
186 1.1 bouyer printk(KERN_ERR "XENBUS request irq failed %i\n", err);
187 1.1 bouyer return err;
188 1.1 bouyer }
189 1.1 bouyer
190 1.1 bouyer xenbus_irq = err;
191 1.1 bouyer
192 1.1 bouyer return 0;
193 1.1 bouyer }
194 1.1 bouyer
195 1.1 bouyer /*
196 1.1 bouyer * Local variables:
197 1.1 bouyer * c-file-style: "linux"
198 1.1 bouyer * indent-tabs-mode: t
199 1.1 bouyer * c-indent-level: 8
200 1.1 bouyer * c-basic-offset: 8
201 1.1 bouyer * tab-width: 8
202 1.1 bouyer * End:
203 1.1 bouyer */
204