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 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <sys/types.h> 28 #include <sys/xpv_support.h> 29 #include <sys/hypervisor.h> 30 #include <sys/machsystm.h> 31 #include <sys/mutex.h> 32 #include <sys/cmn_err.h> 33 #include <sys/dditypes.h> 34 #include <sys/atomic.h> 35 #include <sys/sysmacros.h> 36 #include <sys/cpu.h> 37 #include <sys/psw.h> 38 #include <sys/psm.h> 39 #include <sys/sdt.h> 40 41 extern dev_info_t *xpv_dip; 42 static ddi_intr_handle_t *evtchn_ihp = NULL; 43 static ddi_softint_handle_t evtchn_to_handle[NR_EVENT_CHANNELS]; 44 kmutex_t ec_lock; 45 46 static int evtchn_callback_irq = -1; 47 48 static volatile ulong_t *pending_events; 49 static volatile ulong_t *masked_events; 50 51 /* log2(NBBY * sizeof (ulong)) */ 52 #ifdef __amd64 53 #define EVTCHN_SHIFT 6 54 #else /* __i386 */ 55 #define EVTCHN_SHIFT 5 56 #endif 57 58 /* Atomically get and clear a ulong from memory. */ 59 #define GET_AND_CLEAR(src, targ) { \ 60 membar_enter(); \ 61 do { \ 62 targ = *src; \ 63 } while (atomic_cas_ulong(src, targ, 0) != targ); \ 64 } 65 66 /* Get the first and last bits set in a bitmap */ 67 #define GET_BOUNDS(bitmap, low, high) { \ 68 int _i; \ 69 low = high = -1; \ 70 for (_i = 0; _i <= sizeof (ulong_t); _i++) \ 71 if (bitmap & (1UL << _i)) { \ 72 if (low == -1) \ 73 low = _i; \ 74 high = _i; \ 75 } \ 76 } 77 78 void 79 ec_bind_evtchn_to_handler(int evtchn, pri_t pri, ec_handler_fcn_t handler, 80 void *arg1) 81 { 82 ddi_softint_handle_t hdl; 83 84 if (evtchn < 0 || evtchn > NR_EVENT_CHANNELS) { 85 cmn_err(CE_WARN, "Binding invalid event channel: %d", evtchn); 86 return; 87 } 88 89 (void) ddi_intr_add_softint(xpv_dip, &hdl, pri, handler, (caddr_t)arg1); 90 mutex_enter(&ec_lock); 91 ASSERT(evtchn_to_handle[evtchn] == NULL); 92 evtchn_to_handle[evtchn] = hdl; 93 mutex_exit(&ec_lock); 94 95 /* Let the hypervisor know we're prepared to handle this event */ 96 hypervisor_unmask_event(evtchn); 97 } 98 99 void 100 ec_unbind_evtchn(int evtchn) 101 { 102 evtchn_close_t close; 103 ddi_softint_handle_t hdl; 104 105 if (evtchn < 0 || evtchn > NR_EVENT_CHANNELS) { 106 cmn_err(CE_WARN, "Unbinding invalid event channel: %d", evtchn); 107 return; 108 } 109 110 /* 111 * Let the hypervisor know we're no longer prepared to handle this 112 * event 113 */ 114 hypervisor_mask_event(evtchn); 115 116 /* Cleanup the event handler metadata */ 117 mutex_enter(&ec_lock); 118 hdl = evtchn_to_handle[evtchn]; 119 evtchn_to_handle[evtchn] = NULL; 120 mutex_exit(&ec_lock); 121 122 close.port = evtchn; 123 (void) HYPERVISOR_event_channel_op(EVTCHNOP_close, &close); 124 (void) ddi_intr_remove_softint(hdl); 125 } 126 127 void 128 ec_notify_via_evtchn(unsigned int port) 129 { 130 evtchn_send_t send; 131 132 if ((int)port == -1) 133 return; 134 send.port = port; 135 (void) HYPERVISOR_event_channel_op(EVTCHNOP_send, &send); 136 } 137 138 void 139 hypervisor_unmask_event(unsigned int ev) 140 { 141 int index = ev >> EVTCHN_SHIFT; 142 ulong_t bit = 1UL << (ev & ((1UL << EVTCHN_SHIFT) - 1)); 143 volatile ulong_t *maskp; 144 evtchn_unmask_t unmask; 145 146 /* 147 * index,bit contain the event number as an index into the 148 * masked-events bitmask. Set it to 0. 149 */ 150 maskp = &masked_events[index]; 151 atomic_and_ulong(maskp, ~bit); 152 153 /* Let the hypervisor know the event has been unmasked */ 154 unmask.port = ev; 155 if (HYPERVISOR_event_channel_op(EVTCHNOP_unmask, &unmask) != 0) 156 panic("xen_evtchn_unmask() failed"); 157 } 158 159 /* Set a bit in an evtchan mask word */ 160 void 161 hypervisor_mask_event(uint_t ev) 162 { 163 int index = ev >> EVTCHN_SHIFT; 164 ulong_t bit = 1UL << (ev & ((1UL << EVTCHN_SHIFT) - 1)); 165 volatile ulong_t *maskp; 166 167 maskp = &masked_events[index]; 168 atomic_or_ulong(maskp, bit); 169 } 170 171 void 172 hypervisor_clear_event(uint_t ev) 173 { 174 int index = ev >> EVTCHN_SHIFT; 175 ulong_t bit = 1UL << (ev & ((1UL << EVTCHN_SHIFT) - 1)); 176 volatile ulong_t *maskp; 177 178 maskp = &pending_events[index]; 179 atomic_and_ulong(maskp, ~bit); 180 } 181 182 int 183 xen_alloc_unbound_evtchn(int domid, int *evtchnp) 184 { 185 evtchn_alloc_unbound_t alloc; 186 int err; 187 188 alloc.dom = DOMID_SELF; 189 alloc.remote_dom = (domid_t)domid; 190 191 if ((err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, 192 &alloc)) == 0) { 193 *evtchnp = alloc.port; 194 /* ensure evtchn is masked till we're ready to use it */ 195 (void) hypervisor_mask_event(*evtchnp); 196 } else { 197 err = xen_xlate_errcode(err); 198 } 199 200 return (err); 201 } 202 203 int 204 xen_bind_interdomain(int domid, int remote_port, int *port) 205 { 206 evtchn_bind_interdomain_t bind; 207 int err; 208 209 bind.remote_dom = (domid_t)domid; 210 bind.remote_port = remote_port; 211 if ((err = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain, 212 &bind)) == 0) 213 *port = bind.local_port; 214 else 215 err = xen_xlate_errcode(err); 216 return (err); 217 } 218 219 /*ARGSUSED*/ 220 uint_t 221 evtchn_callback_fcn(caddr_t arg0, caddr_t arg1) 222 { 223 ulong_t pending_word; 224 int i, j, port; 225 volatile struct vcpu_info *vci; 226 uint_t rv = DDI_INTR_UNCLAIMED; 227 ddi_softint_handle_t hdl; 228 int low, high; 229 ulong_t sels; 230 231 /* 232 * Xen hard-codes all notifications to VCPU0, so we bind 233 * ourselves via xpv.conf. Note that this also assumes that all 234 * evtchns are bound to VCPU0, which is true by default. 235 */ 236 ASSERT(CPU->cpu_id == 0); 237 238 vci = &HYPERVISOR_shared_info->vcpu_info[0]; 239 240 again: 241 DTRACE_PROBE2(evtchn__scan__start, int, vci->evtchn_upcall_pending, 242 ulong_t, vci->evtchn_pending_sel); 243 244 atomic_and_8(&vci->evtchn_upcall_pending, 0); 245 246 /* 247 * Find the upper and lower bounds in which we need to search for 248 * pending events. 249 */ 250 GET_AND_CLEAR(&vci->evtchn_pending_sel, sels); 251 252 /* sels == 1 is by far the most common case. Make it fast */ 253 if (sels == 1) 254 low = high = 0; 255 else if (sels == 0) 256 return (rv); 257 else 258 GET_BOUNDS(sels, low, high); 259 260 /* Scan the port list, looking for words with bits set */ 261 for (i = low; i <= high; i++) { 262 ulong_t tmp; 263 264 GET_AND_CLEAR(&pending_events[i], tmp); 265 pending_word = tmp & ~(masked_events[i]); 266 267 /* Scan the bits in the word, looking for pending events */ 268 while (pending_word != 0) { 269 j = lowbit(pending_word) - 1; 270 port = (i << EVTCHN_SHIFT) + j; 271 pending_word = pending_word & ~(1 << j); 272 273 /* 274 * If there is a handler registered for this event, 275 * schedule a softint of the appropriate priority 276 * to execute it. 277 */ 278 if ((hdl = evtchn_to_handle[port]) != NULL) { 279 (void) ddi_intr_trigger_softint(hdl, NULL); 280 rv = DDI_INTR_CLAIMED; 281 } 282 } 283 } 284 DTRACE_PROBE2(evtchn__scan__end, int, vci->evtchn_upcall_pending, 285 ulong_t, vci->evtchn_pending_sel); 286 287 if ((volatile uint8_t)vci->evtchn_upcall_pending || 288 ((volatile ulong_t)vci->evtchn_pending_sel)) 289 goto again; 290 291 return (rv); 292 } 293 294 static int 295 set_hvm_callback(int irq) 296 { 297 struct xen_hvm_param xhp; 298 299 xhp.domid = DOMID_SELF; 300 xhp.index = HVM_PARAM_CALLBACK_IRQ; 301 xhp.value = irq; 302 return (HYPERVISOR_hvm_op(HVMOP_set_param, &xhp)); 303 } 304 305 void 306 ec_fini() 307 { 308 int i; 309 310 for (i = 0; i < NR_EVENT_CHANNELS; i++) 311 ec_unbind_evtchn(i); 312 313 evtchn_callback_irq = -1; 314 if (evtchn_ihp != NULL) { 315 (void) ddi_intr_disable(*evtchn_ihp); 316 (void) ddi_intr_remove_handler(*evtchn_ihp); 317 (void) ddi_intr_free(*evtchn_ihp); 318 kmem_free(evtchn_ihp, sizeof (ddi_intr_handle_t)); 319 evtchn_ihp = NULL; 320 } 321 } 322 323 int 324 ec_init(dev_info_t *dip) 325 { 326 int i; 327 int rv, actual; 328 ddi_intr_handle_t *ihp; 329 330 /* 331 * Translate the variable-sized pending and masked event bitmasks 332 * into constant-sized arrays of uint32_t's. 333 */ 334 pending_events = &HYPERVISOR_shared_info->evtchn_pending[0]; 335 masked_events = &HYPERVISOR_shared_info->evtchn_mask[0]; 336 337 /* 338 * Clear our event handler structures and prevent the hypervisor 339 * from triggering any events. 340 */ 341 mutex_init(&ec_lock, NULL, MUTEX_SPIN, (void *)ipltospl(SPL7)); 342 for (i = 0; i < NR_EVENT_CHANNELS; i++) { 343 evtchn_to_handle[i] = NULL; 344 (void) hypervisor_mask_event(i); 345 } 346 347 /* 348 * Allocate and initialize an interrupt handler to process the 349 * hypervisor's "hey you have events pending!" interrupt. 350 */ 351 ihp = kmem_zalloc(sizeof (ddi_intr_handle_t), KM_SLEEP); 352 rv = ddi_intr_alloc(dip, ihp, DDI_INTR_TYPE_FIXED, 0, 1, &actual, 353 DDI_INTR_ALLOC_NORMAL); 354 if (rv < 0 || actual != 1) { 355 cmn_err(CE_WARN, "Could not allocate evtchn interrupt: %d", 356 rv); 357 return (-1); 358 } 359 360 rv = ddi_intr_add_handler(*ihp, evtchn_callback_fcn, NULL, NULL); 361 if (rv < 0) { 362 (void) ddi_intr_free(*ihp); 363 cmn_err(CE_WARN, "Could not attach evtchn handler"); 364 return (-1); 365 } 366 evtchn_ihp = ihp; 367 368 if (ddi_intr_enable(*ihp) != DDI_SUCCESS) { 369 cmn_err(CE_WARN, "Could not enable evtchn interrupts\n"); 370 return (-1); 371 } 372 373 /* Tell the hypervisor which interrupt we're waiting on. */ 374 evtchn_callback_irq = ((ddi_intr_handle_impl_t *)*ihp)->ih_vector; 375 376 if (set_hvm_callback(evtchn_callback_irq) != 0) { 377 cmn_err(CE_WARN, "Couldn't register evtchn callback"); 378 return (-1); 379 } 380 return (0); 381 } 382 383 void 384 ec_resume(void) 385 { 386 int i; 387 388 /* New event-channel space is not 'live' yet. */ 389 for (i = 0; i < NR_EVENT_CHANNELS; i++) 390 (void) hypervisor_mask_event(i); 391 if (set_hvm_callback(evtchn_callback_irq) != 0) 392 cmn_err(CE_WARN, "Couldn't register evtchn callback"); 393 394 } 395