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