Commit | Line | Data |
---|---|---|
4bac07c9 JF |
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 program is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU General Public License version 2 | |
10 | * as published by the Free Software Foundation; or, when distributed | |
11 | * separately from the Linux kernel or incorporated into other | |
12 | * software packages, subject to the following license: | |
13 | * | |
14 | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
15 | * of this source file (the "Software"), to deal in the Software without | |
16 | * restriction, including without limitation the rights to use, copy, modify, | |
17 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, | |
18 | * and to permit persons to whom the Software is furnished to do so, subject to | |
19 | * the following conditions: | |
20 | * | |
21 | * The above copyright notice and this permission notice shall be included in | |
22 | * all copies or substantial portions of the Software. | |
23 | * | |
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
25 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
26 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
27 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
28 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
29 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | |
30 | * IN THE SOFTWARE. | |
31 | */ | |
32 | ||
33 | #include <linux/wait.h> | |
34 | #include <linux/interrupt.h> | |
35 | #include <linux/sched.h> | |
36 | #include <linux/err.h> | |
37 | #include <xen/xenbus.h> | |
38 | #include <asm/xen/hypervisor.h> | |
39 | #include <xen/events.h> | |
40 | #include <xen/page.h> | |
41 | #include "xenbus_comms.h" | |
42 | ||
43 | static int xenbus_irq; | |
44 | ||
45 | static DECLARE_WORK(probe_work, xenbus_probe); | |
46 | ||
47 | static DECLARE_WAIT_QUEUE_HEAD(xb_waitq); | |
48 | ||
49 | static irqreturn_t wake_waiting(int irq, void *unused) | |
50 | { | |
51 | if (unlikely(xenstored_ready == 0)) { | |
52 | xenstored_ready = 1; | |
53 | schedule_work(&probe_work); | |
54 | } | |
55 | ||
56 | wake_up(&xb_waitq); | |
57 | return IRQ_HANDLED; | |
58 | } | |
59 | ||
60 | static int check_indexes(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod) | |
61 | { | |
62 | return ((prod - cons) <= XENSTORE_RING_SIZE); | |
63 | } | |
64 | ||
65 | static void *get_output_chunk(XENSTORE_RING_IDX cons, | |
66 | XENSTORE_RING_IDX prod, | |
67 | char *buf, uint32_t *len) | |
68 | { | |
69 | *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod); | |
70 | if ((XENSTORE_RING_SIZE - (prod - cons)) < *len) | |
71 | *len = XENSTORE_RING_SIZE - (prod - cons); | |
72 | return buf + MASK_XENSTORE_IDX(prod); | |
73 | } | |
74 | ||
75 | static const void *get_input_chunk(XENSTORE_RING_IDX cons, | |
76 | XENSTORE_RING_IDX prod, | |
77 | const char *buf, uint32_t *len) | |
78 | { | |
79 | *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(cons); | |
80 | if ((prod - cons) < *len) | |
81 | *len = prod - cons; | |
82 | return buf + MASK_XENSTORE_IDX(cons); | |
83 | } | |
84 | ||
85 | /** | |
86 | * xb_write - low level write | |
87 | * @data: buffer to send | |
88 | * @len: length of buffer | |
89 | * | |
90 | * Returns 0 on success, error otherwise. | |
91 | */ | |
92 | int xb_write(const void *data, unsigned len) | |
93 | { | |
94 | struct xenstore_domain_interface *intf = xen_store_interface; | |
95 | XENSTORE_RING_IDX cons, prod; | |
96 | int rc; | |
97 | ||
98 | while (len != 0) { | |
99 | void *dst; | |
100 | unsigned int avail; | |
101 | ||
102 | rc = wait_event_interruptible( | |
103 | xb_waitq, | |
104 | (intf->req_prod - intf->req_cons) != | |
105 | XENSTORE_RING_SIZE); | |
106 | if (rc < 0) | |
107 | return rc; | |
108 | ||
109 | /* Read indexes, then verify. */ | |
110 | cons = intf->req_cons; | |
111 | prod = intf->req_prod; | |
112 | if (!check_indexes(cons, prod)) { | |
113 | intf->req_cons = intf->req_prod = 0; | |
114 | return -EIO; | |
115 | } | |
116 | ||
117 | dst = get_output_chunk(cons, prod, intf->req, &avail); | |
118 | if (avail == 0) | |
119 | continue; | |
120 | if (avail > len) | |
121 | avail = len; | |
122 | ||
123 | /* Must write data /after/ reading the consumer index. */ | |
124 | mb(); | |
125 | ||
126 | memcpy(dst, data, avail); | |
127 | data += avail; | |
128 | len -= avail; | |
129 | ||
130 | /* Other side must not see new producer until data is there. */ | |
131 | wmb(); | |
132 | intf->req_prod += avail; | |
133 | ||
134 | /* Implies mb(): other side will see the updated producer. */ | |
135 | notify_remote_via_evtchn(xen_store_evtchn); | |
136 | } | |
137 | ||
138 | return 0; | |
139 | } | |
140 | ||
141 | int xb_data_to_read(void) | |
142 | { | |
143 | struct xenstore_domain_interface *intf = xen_store_interface; | |
144 | return (intf->rsp_cons != intf->rsp_prod); | |
145 | } | |
146 | ||
147 | int xb_wait_for_data_to_read(void) | |
148 | { | |
149 | return wait_event_interruptible(xb_waitq, xb_data_to_read()); | |
150 | } | |
151 | ||
152 | int xb_read(void *data, unsigned len) | |
153 | { | |
154 | struct xenstore_domain_interface *intf = xen_store_interface; | |
155 | XENSTORE_RING_IDX cons, prod; | |
156 | int rc; | |
157 | ||
158 | while (len != 0) { | |
159 | unsigned int avail; | |
160 | const char *src; | |
161 | ||
162 | rc = xb_wait_for_data_to_read(); | |
163 | if (rc < 0) | |
164 | return rc; | |
165 | ||
166 | /* Read indexes, then verify. */ | |
167 | cons = intf->rsp_cons; | |
168 | prod = intf->rsp_prod; | |
169 | if (!check_indexes(cons, prod)) { | |
170 | intf->rsp_cons = intf->rsp_prod = 0; | |
171 | return -EIO; | |
172 | } | |
173 | ||
174 | src = get_input_chunk(cons, prod, intf->rsp, &avail); | |
175 | if (avail == 0) | |
176 | continue; | |
177 | if (avail > len) | |
178 | avail = len; | |
179 | ||
180 | /* Must read data /after/ reading the producer index. */ | |
181 | rmb(); | |
182 | ||
183 | memcpy(data, src, avail); | |
184 | data += avail; | |
185 | len -= avail; | |
186 | ||
187 | /* Other side must not see free space until we've copied out */ | |
188 | mb(); | |
189 | intf->rsp_cons += avail; | |
190 | ||
191 | pr_debug("Finished read of %i bytes (%i to go)\n", avail, len); | |
192 | ||
193 | /* Implies mb(): other side will see the updated consumer. */ | |
194 | notify_remote_via_evtchn(xen_store_evtchn); | |
195 | } | |
196 | ||
197 | return 0; | |
198 | } | |
199 | ||
200 | /** | |
201 | * xb_init_comms - Set up interrupt handler off store event channel. | |
202 | */ | |
203 | int xb_init_comms(void) | |
204 | { | |
205 | struct xenstore_domain_interface *intf = xen_store_interface; | |
4bac07c9 JF |
206 | |
207 | if (intf->req_prod != intf->req_cons) | |
208 | printk(KERN_ERR "XENBUS request ring is not quiescent " | |
209 | "(%08x:%08x)!\n", intf->req_cons, intf->req_prod); | |
210 | ||
211 | if (intf->rsp_prod != intf->rsp_cons) { | |
212 | printk(KERN_WARNING "XENBUS response ring is not quiescent " | |
213 | "(%08x:%08x): fixing up\n", | |
214 | intf->rsp_cons, intf->rsp_prod); | |
215 | intf->rsp_cons = intf->rsp_prod; | |
216 | } | |
217 | ||
7d88d32a JF |
218 | if (xenbus_irq) { |
219 | /* Already have an irq; assume we're resuming */ | |
220 | rebind_evtchn_irq(xen_store_evtchn, xenbus_irq); | |
221 | } else { | |
222 | int err; | |
223 | err = bind_evtchn_to_irqhandler(xen_store_evtchn, wake_waiting, | |
224 | 0, "xenbus", &xb_waitq); | |
225 | if (err <= 0) { | |
226 | printk(KERN_ERR "XENBUS request irq failed %i\n", err); | |
227 | return err; | |
228 | } | |
4bac07c9 | 229 | |
7d88d32a | 230 | xenbus_irq = err; |
4bac07c9 JF |
231 | } |
232 | ||
4bac07c9 JF |
233 | return 0; |
234 | } |