1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * 29 * xenbus_comms.c 30 * 31 * Low level code to talks to Xen Store: ringbuffer and event channel. 32 * 33 * Copyright (C) 2005 Rusty Russell, IBM Corporation 34 * 35 * This file may be distributed separately from the Linux kernel, or 36 * incorporated into other software packages, subject to the following license: 37 * 38 * Permission is hereby granted, free of charge, to any person obtaining a copy 39 * of this source file (the "Software"), to deal in the Software without 40 * restriction, including without limitation the rights to use, copy, modify, 41 * merge, publish, distribute, sublicense, and/or sell copies of the Software, 42 * and to permit persons to whom the Software is furnished to do so, subject to 43 * the following conditions: 44 * 45 * The above copyright notice and this permission notice shall be included in 46 * all copies or substantial portions of the Software. 47 * 48 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 49 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 50 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 51 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 52 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 53 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 54 * IN THE SOFTWARE. 55 */ 56 57 #pragma ident "%Z%%M% %I% %E% SMI" 58 59 #include <sys/types.h> 60 #include <vm/hat.h> 61 #include <vm/as.h> 62 #include <sys/bootinfo.h> 63 #include <sys/bootconf.h> 64 #include <vm/kboot_mmu.h> 65 #include <vm/seg_kmem.h> 66 #include <sys/hypervisor.h> 67 #include <sys/evtchn_impl.h> 68 #include <sys/condvar.h> 69 #include <sys/mutex.h> 70 #include <sys/atomic.h> 71 #include <sys/mman.h> 72 #include <sys/errno.h> 73 #include <sys/cmn_err.h> 74 #include <sys/avintr.h> 75 #include <xen/sys/xenbus_comms.h> 76 #include <xen/public/io/xs_wire.h> 77 78 static int xenbus_irq; 79 static ddi_umem_cookie_t xb_cookie; /* cookie for xenbus comm page */ 80 extern caddr_t xb_addr; /* va of xenbus comm page */ 81 82 static kcondvar_t xb_wait_cv; 83 static kmutex_t xb_wait_lock; 84 85 #define xs_domain_interface(ra) ((struct xenstore_domain_interface *)(ra)) 86 87 /*ARGSUSED*/ 88 static uint_t 89 xenbus_intr(void *unused) 90 { 91 mutex_enter(&xb_wait_lock); 92 cv_broadcast(&xb_wait_cv); 93 mutex_exit(&xb_wait_lock); 94 return (DDI_INTR_CLAIMED); 95 } 96 97 static int 98 check_indexes(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod) 99 { 100 return ((prod - cons) <= XENSTORE_RING_SIZE); 101 } 102 103 static void * 104 get_output_chunk(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod, 105 char *buf, uint32_t *len) 106 { 107 *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod); 108 if ((XENSTORE_RING_SIZE - (prod - cons)) < *len) 109 *len = XENSTORE_RING_SIZE - (prod - cons); 110 return ((void *)(buf + MASK_XENSTORE_IDX(prod))); 111 } 112 113 static const void * 114 get_input_chunk(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod, 115 const char *buf, uint32_t *len) 116 { 117 *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(cons); 118 if ((prod - cons) < *len) 119 *len = prod - cons; 120 return ((void *)(buf + MASK_XENSTORE_IDX(cons))); 121 } 122 123 124 int 125 xb_write(const void *data, unsigned len) 126 { 127 volatile struct xenstore_domain_interface *intf = 128 xs_domain_interface(xb_addr); 129 XENSTORE_RING_IDX cons, prod; 130 extern int do_polled_io; 131 132 while (len != 0) { 133 void *dst; 134 unsigned int avail; 135 136 mutex_enter(&xb_wait_lock); 137 while ((intf->req_prod - intf->req_cons) == 138 XENSTORE_RING_SIZE) { 139 if (interrupts_unleashed && !do_polled_io) { 140 if (cv_wait_sig(&xb_wait_cv, 141 &xb_wait_lock) == 0) { 142 mutex_exit(&xb_wait_lock); 143 return (EINTR); 144 } 145 } else { /* polled mode needed for early probes */ 146 (void) HYPERVISOR_yield(); 147 } 148 } 149 mutex_exit(&xb_wait_lock); 150 /* Read indexes, then verify. */ 151 cons = intf->req_cons; 152 prod = intf->req_prod; 153 membar_enter(); 154 if (!check_indexes(cons, prod)) 155 return (EIO); 156 157 dst = get_output_chunk(cons, prod, (char *)intf->req, &avail); 158 if (avail == 0) 159 continue; 160 if (avail > len) 161 avail = len; 162 163 (void) memcpy(dst, data, avail); 164 data = (void *)((uintptr_t)data + avail); 165 len -= avail; 166 167 /* Other side must not see new header until data is there. */ 168 membar_producer(); 169 intf->req_prod += avail; 170 171 /* This implies mb() before other side sees interrupt. */ 172 ec_notify_via_evtchn(xen_info->store_evtchn); 173 } 174 175 return (0); 176 } 177 178 int 179 xb_read(void *data, unsigned len) 180 { 181 volatile struct xenstore_domain_interface *intf = 182 xs_domain_interface(xb_addr); 183 XENSTORE_RING_IDX cons, prod; 184 extern int do_polled_io; 185 186 while (len != 0) { 187 unsigned int avail; 188 const char *src; 189 190 mutex_enter(&xb_wait_lock); 191 while (intf->rsp_cons == intf->rsp_prod) { 192 if (interrupts_unleashed && !do_polled_io) { 193 if (cv_wait_sig(&xb_wait_cv, 194 &xb_wait_lock) == 0) { 195 mutex_exit(&xb_wait_lock); 196 return (EINTR); 197 } 198 } else { /* polled mode needed for early probes */ 199 (void) HYPERVISOR_yield(); 200 } 201 } 202 mutex_exit(&xb_wait_lock); 203 /* Read indexes, then verify. */ 204 cons = intf->rsp_cons; 205 prod = intf->rsp_prod; 206 membar_enter(); 207 if (!check_indexes(cons, prod)) 208 return (EIO); 209 210 src = get_input_chunk(cons, prod, (char *)intf->rsp, &avail); 211 if (avail == 0) 212 continue; 213 if (avail > len) 214 avail = len; 215 216 /* We must read header before we read data. */ 217 membar_consumer(); 218 219 (void) memcpy(data, src, avail); 220 data = (void *)((uintptr_t)data + avail); 221 len -= avail; 222 223 /* Other side must not see free space until we've copied out */ 224 membar_enter(); 225 intf->rsp_cons += avail; 226 227 /* Implies mb(): they will see new header. */ 228 ec_notify_via_evtchn(xen_info->store_evtchn); 229 } 230 231 return (0); 232 } 233 234 void 235 xb_suspend(void) 236 { 237 rem_avintr(NULL, IPL_XENBUS, (avfunc)xenbus_intr, xenbus_irq); 238 } 239 240 void 241 xb_setup_intr(void) 242 { 243 xenbus_irq = ec_bind_evtchn_to_irq(xen_info->store_evtchn); 244 if (!add_avintr(NULL, IPL_XENBUS, (avfunc)xenbus_intr, "xenbus", 245 xenbus_irq, NULL, NULL, NULL, NULL)) 246 cmn_err(CE_WARN, "XENBUS add intr failed\n"); 247 } 248 249 /* 250 * Set up our xenstore page and event channel. Domain 0 needs to allocate a 251 * page and event channel; other domains use what we are told. 252 */ 253 void 254 xb_init(void) 255 { 256 int err; 257 258 if (DOMAIN_IS_INITDOMAIN(xen_info)) { 259 260 if (xb_addr != NULL) 261 return; 262 263 xb_addr = ddi_umem_alloc(PAGESIZE, DDI_UMEM_SLEEP, 264 &xb_cookie); 265 xen_info->store_mfn = pfn_to_mfn(hat_getpfnum(kas.a_hat, 266 xb_addr)); 267 268 err = xen_alloc_unbound_evtchn(0, 269 (int *)&xen_info->store_evtchn); 270 ASSERT(err == 0); 271 } else { 272 /* 273 * This is harmless on first boot, but needed for resume and 274 * migrate. We use kbm_map_ma() as a shortcut instead of 275 * directly using HYPERVISOR_update_va_mapping(). 276 */ 277 ASSERT(xb_addr != NULL); 278 kbm_map_ma(mfn_to_ma(xen_info->store_mfn), 279 (uintptr_t)xb_addr, 0); 280 } 281 282 ASSERT(xen_info->store_evtchn); 283 } 284 285 void * 286 xb_xenstore_cookie(void) 287 { 288 ASSERT(DOMAIN_IS_INITDOMAIN(xen_info)); 289 return (xb_cookie); 290 } 291