1 /* $NetBSD: xenbus_comms.c,v 1.12 2009/01/16 20:16:47 jym 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.12 2009/01/16 20:16:47 jym Exp $"); 33 34 #include <sys/types.h> 35 #include <sys/null.h> 36 #include <sys/errno.h> 37 #include <sys/param.h> 38 #include <sys/proc.h> 39 #include <sys/systm.h> 40 41 #include <xen/xen.h> /* for xendomain_is_dom0() */ 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 && xendomain_is_dom0())) { 79 xenstored_ready = 1; 80 wakeup(&xenstored_ready); 81 } 82 83 wakeup(&xenstore_interface); 84 return 1; 85 } 86 87 static int 88 check_indexes(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod) 89 { 90 return ((prod - cons) <= XENSTORE_RING_SIZE); 91 } 92 93 static void * 94 get_output_chunk(XENSTORE_RING_IDX cons, 95 XENSTORE_RING_IDX prod, 96 char *buf, uint32_t *len) 97 { 98 *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod); 99 if ((XENSTORE_RING_SIZE - (prod - cons)) < *len) 100 *len = XENSTORE_RING_SIZE - (prod - cons); 101 return buf + MASK_XENSTORE_IDX(prod); 102 } 103 104 static const void * 105 get_input_chunk(XENSTORE_RING_IDX cons, 106 XENSTORE_RING_IDX prod, 107 const char *buf, uint32_t *len) 108 { 109 *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(cons); 110 if ((prod - cons) < *len) 111 *len = prod - cons; 112 return buf + MASK_XENSTORE_IDX(cons); 113 } 114 115 int 116 xb_write(const void *data, unsigned len) 117 { 118 struct xenstore_domain_interface *intf = xenstore_domain_interface(); 119 XENSTORE_RING_IDX cons, prod; 120 121 int s = spltty(); 122 123 while (len != 0) { 124 void *dst; 125 unsigned int avail; 126 127 while ((intf->req_prod - intf->req_cons) == XENSTORE_RING_SIZE) { 128 XENPRINTF(("xb_write tsleep\n")); 129 tsleep(&xenstore_interface, PRIBIO, "wrst", 0); 130 XENPRINTF(("xb_write tsleep done\n")); 131 } 132 133 /* Read indexes, then verify. */ 134 cons = intf->req_cons; 135 prod = intf->req_prod; 136 xen_rmb(); 137 if (!check_indexes(cons, prod)) { 138 splx(s); 139 return EIO; 140 } 141 142 dst = get_output_chunk(cons, prod, intf->req, &avail); 143 if (avail == 0) 144 continue; 145 if (avail > len) 146 avail = len; 147 148 memcpy(dst, data, avail); 149 data = (const char *)data + avail; 150 len -= avail; 151 152 /* Other side must not see new header until data is there. */ 153 xen_rmb(); 154 intf->req_prod += avail; 155 xen_rmb(); 156 157 hypervisor_notify_via_evtchn(xen_start_info.store_evtchn); 158 } 159 160 splx(s); 161 return 0; 162 } 163 164 int 165 xb_read(void *data, unsigned len) 166 { 167 struct xenstore_domain_interface *intf = xenstore_domain_interface(); 168 XENSTORE_RING_IDX cons, prod; 169 170 int s = spltty(); 171 172 while (len != 0) { 173 unsigned int avail; 174 const char *src; 175 176 while (intf->rsp_cons == intf->rsp_prod) 177 tsleep(&xenstore_interface, PRIBIO, "rdst", 0); 178 179 /* Read indexes, then verify. */ 180 cons = intf->rsp_cons; 181 prod = intf->rsp_prod; 182 xen_rmb(); 183 if (!check_indexes(cons, prod)) { 184 XENPRINTF(("xb_read EIO\n")); 185 splx(s); 186 return EIO; 187 } 188 189 src = get_input_chunk(cons, prod, intf->rsp, &avail); 190 if (avail == 0) 191 continue; 192 if (avail > len) 193 avail = len; 194 195 /* We must read header before we read data. */ 196 xen_rmb(); 197 198 memcpy(data, src, avail); 199 data = (char *)data + avail; 200 len -= avail; 201 202 /* Other side must not see free space until we've copied out */ 203 xen_rmb(); 204 intf->rsp_cons += avail; 205 xen_rmb(); 206 207 XENPRINTF(("Finished read of %i bytes (%i to go)\n", 208 avail, len)); 209 210 hypervisor_notify_via_evtchn(xen_start_info.store_evtchn); 211 } 212 213 splx(s); 214 return 0; 215 } 216 217 /* Set up interrupt handler of store event channel. */ 218 int 219 xb_init_comms(device_t dev) 220 { 221 int err; 222 223 if (xenbus_irq) 224 event_remove_handler(xenbus_irq, wake_waiting, NULL); 225 226 err = event_set_handler(xen_start_info.store_evtchn, wake_waiting, 227 NULL, IPL_TTY, "xenbus"); 228 if (err) { 229 aprint_error_dev(dev, "request irq failed %i\n", err); 230 return err; 231 } 232 xenbus_irq = xen_start_info.store_evtchn; 233 aprint_verbose_dev(dev, "using event channel %d\n", xenbus_irq); 234 hypervisor_enable_event(xenbus_irq); 235 return 0; 236 } 237 238 /* 239 * Local variables: 240 * c-file-style: "linux" 241 * indent-tabs-mode: t 242 * c-indent-level: 8 243 * c-basic-offset: 8 244 * tab-width: 8 245 * End: 246 */ 247