hv_connection.c revision 294553
1250199Sgrehan/*- 2250199Sgrehan * Copyright (c) 2009-2012 Microsoft Corp. 3250199Sgrehan * Copyright (c) 2012 NetApp Inc. 4250199Sgrehan * Copyright (c) 2012 Citrix Inc. 5250199Sgrehan * All rights reserved. 6250199Sgrehan * 7250199Sgrehan * Redistribution and use in source and binary forms, with or without 8250199Sgrehan * modification, are permitted provided that the following conditions 9250199Sgrehan * are met: 10250199Sgrehan * 1. Redistributions of source code must retain the above copyright 11250199Sgrehan * notice unmodified, this list of conditions, and the following 12250199Sgrehan * disclaimer. 13250199Sgrehan * 2. Redistributions in binary form must reproduce the above copyright 14250199Sgrehan * notice, this list of conditions and the following disclaimer in the 15250199Sgrehan * documentation and/or other materials provided with the distribution. 16250199Sgrehan * 17250199Sgrehan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18250199Sgrehan * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19250199Sgrehan * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20250199Sgrehan * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21250199Sgrehan * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22250199Sgrehan * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23250199Sgrehan * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24250199Sgrehan * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25250199Sgrehan * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26250199Sgrehan * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27250199Sgrehan */ 28250199Sgrehan 29250199Sgrehan#include <sys/param.h> 30296028Ssephe#include <sys/malloc.h> 31250199Sgrehan#include <sys/systm.h> 32250199Sgrehan#include <sys/lock.h> 33250199Sgrehan#include <sys/mutex.h> 34250199Sgrehan#include <machine/bus.h> 35250199Sgrehan#include <vm/vm.h> 36250199Sgrehan#include <vm/vm_param.h> 37250199Sgrehan#include <vm/pmap.h> 38250199Sgrehan 39250199Sgrehan#include "hv_vmbus_priv.h" 40250199Sgrehan 41250199Sgrehan/* 42250199Sgrehan * Globals 43250199Sgrehan */ 44250199Sgrehanhv_vmbus_connection hv_vmbus_g_connection = 45250199Sgrehan { .connect_state = HV_DISCONNECTED, 46250199Sgrehan .next_gpadl_handle = 0xE1E10, }; 47250199Sgrehan 48250199Sgrehanuint32_t hv_vmbus_protocal_version = HV_VMBUS_VERSION_WS2008; 49282212Swhu 50282212Swhustatic uint32_t 51282212Swhuhv_vmbus_get_next_version(uint32_t current_ver) 52282212Swhu{ 53282212Swhu switch (current_ver) { 54282212Swhu case (HV_VMBUS_VERSION_WIN7): 55282212Swhu return(HV_VMBUS_VERSION_WS2008); 56282212Swhu 57282212Swhu case (HV_VMBUS_VERSION_WIN8): 58282212Swhu return(HV_VMBUS_VERSION_WIN7); 59282212Swhu 60282212Swhu case (HV_VMBUS_VERSION_WIN8_1): 61282212Swhu return(HV_VMBUS_VERSION_WIN8); 62282212Swhu 63282212Swhu case (HV_VMBUS_VERSION_WS2008): 64282212Swhu default: 65282212Swhu return(HV_VMBUS_VERSION_INVALID); 66282212Swhu } 67282212Swhu} 68282212Swhu 69282212Swhu/** 70250199Sgrehan * Negotiate the highest supported hypervisor version. 71282212Swhu */ 72282212Swhustatic int 73282212Swhuhv_vmbus_negotiate_version(hv_vmbus_channel_msg_info *msg_info, 74282212Swhu uint32_t version) 75282212Swhu{ 76282212Swhu int ret = 0; 77282212Swhu hv_vmbus_channel_initiate_contact *msg; 78282212Swhu 79282212Swhu sema_init(&msg_info->wait_sema, 0, "Msg Info Sema"); 80282212Swhu msg = (hv_vmbus_channel_initiate_contact*) msg_info->msg; 81282212Swhu 82282212Swhu msg->header.message_type = HV_CHANNEL_MESSAGE_INITIATED_CONTACT; 83282212Swhu msg->vmbus_version_requested = version; 84282212Swhu 85282212Swhu msg->interrupt_page = hv_get_phys_addr( 86282212Swhu hv_vmbus_g_connection.interrupt_page); 87282212Swhu 88282212Swhu msg->monitor_page_1 = hv_get_phys_addr( 89282212Swhu hv_vmbus_g_connection.monitor_pages); 90295309Ssephe 91282212Swhu msg->monitor_page_2 = 92295308Ssephe hv_get_phys_addr( 93295309Ssephe ((uint8_t *) hv_vmbus_g_connection.monitor_pages 94282212Swhu + PAGE_SIZE)); 95282212Swhu 96282212Swhu /** 97282212Swhu * Add to list before we send the request since we may receive the 98282212Swhu * response before returning from this routine 99282212Swhu */ 100282212Swhu mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock); 101282212Swhu 102282212Swhu TAILQ_INSERT_TAIL( 103282212Swhu &hv_vmbus_g_connection.channel_msg_anchor, 104282212Swhu msg_info, 105282212Swhu msg_list_entry); 106282212Swhu 107282212Swhu mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock); 108282212Swhu 109282212Swhu ret = hv_vmbus_post_message( 110282212Swhu msg, 111282212Swhu sizeof(hv_vmbus_channel_initiate_contact)); 112282212Swhu 113282212Swhu if (ret != 0) { 114282212Swhu mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock); 115282212Swhu TAILQ_REMOVE( 116282212Swhu &hv_vmbus_g_connection.channel_msg_anchor, 117282212Swhu msg_info, 118282212Swhu msg_list_entry); 119282212Swhu mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock); 120282212Swhu return (ret); 121282212Swhu } 122282212Swhu 123282212Swhu /** 124282212Swhu * Wait for the connection response 125296028Ssephe */ 126282212Swhu ret = sema_timedwait(&msg_info->wait_sema, 500); /* KYS 5 seconds */ 127282212Swhu 128282212Swhu mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock); 129282212Swhu TAILQ_REMOVE( 130282212Swhu &hv_vmbus_g_connection.channel_msg_anchor, 131282212Swhu msg_info, 132282212Swhu msg_list_entry); 133282212Swhu mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock); 134282212Swhu 135282212Swhu /** 136282212Swhu * Check if successful 137282212Swhu */ 138282212Swhu if (msg_info->response.version_response.version_supported) { 139282212Swhu hv_vmbus_g_connection.connect_state = HV_CONNECTED; 140282212Swhu } else { 141282212Swhu ret = ECONNREFUSED; 142282212Swhu } 143282212Swhu 144282212Swhu return (ret); 145282212Swhu} 146282212Swhu 147250199Sgrehan/** 148250199Sgrehan * Send a connect request on the partition service connection 149250199Sgrehan */ 150250199Sgrehanint 151250199Sgrehanhv_vmbus_connect(void) { 152282212Swhu int ret = 0; 153250199Sgrehan uint32_t version; 154250199Sgrehan hv_vmbus_channel_msg_info* msg_info = NULL; 155250199Sgrehan 156250199Sgrehan /** 157250199Sgrehan * Make sure we are not connecting or connected 158250199Sgrehan */ 159250199Sgrehan if (hv_vmbus_g_connection.connect_state != HV_DISCONNECTED) { 160250199Sgrehan return (-1); 161250199Sgrehan } 162250199Sgrehan 163250199Sgrehan /** 164250199Sgrehan * Initialize the vmbus connection 165250199Sgrehan */ 166250199Sgrehan hv_vmbus_g_connection.connect_state = HV_CONNECTING; 167250199Sgrehan hv_vmbus_g_connection.work_queue = hv_work_queue_create("vmbusQ"); 168250199Sgrehan sema_init(&hv_vmbus_g_connection.control_sema, 1, "control_sema"); 169250199Sgrehan 170250199Sgrehan TAILQ_INIT(&hv_vmbus_g_connection.channel_msg_anchor); 171250199Sgrehan mtx_init(&hv_vmbus_g_connection.channel_msg_lock, "vmbus channel msg", 172250199Sgrehan NULL, MTX_SPIN); 173282212Swhu 174250199Sgrehan TAILQ_INIT(&hv_vmbus_g_connection.channel_anchor); 175250199Sgrehan mtx_init(&hv_vmbus_g_connection.channel_lock, "vmbus channel", 176250199Sgrehan NULL, MTX_DEF); 177250199Sgrehan 178250199Sgrehan /** 179295309Ssephe * Setup the vmbus event connection for channel interrupt abstraction 180250199Sgrehan * stuff 181295309Ssephe */ 182250199Sgrehan hv_vmbus_g_connection.interrupt_page = contigmalloc( 183250199Sgrehan PAGE_SIZE, M_DEVBUF, 184250199Sgrehan M_NOWAIT | M_ZERO, 0UL, 185250199Sgrehan BUS_SPACE_MAXADDR, 186250199Sgrehan PAGE_SIZE, 0); 187250199Sgrehan KASSERT(hv_vmbus_g_connection.interrupt_page != NULL, 188250199Sgrehan ("Error VMBUS: malloc failed to allocate Channel" 189250199Sgrehan " Request Event message!")); 190250199Sgrehan if (hv_vmbus_g_connection.interrupt_page == NULL) { 191250199Sgrehan ret = ENOMEM; 192250199Sgrehan goto cleanup; 193250199Sgrehan } 194295309Ssephe 195295309Ssephe hv_vmbus_g_connection.recv_interrupt_page = 196250199Sgrehan hv_vmbus_g_connection.interrupt_page; 197295309Ssephe 198295309Ssephe hv_vmbus_g_connection.send_interrupt_page = 199250199Sgrehan ((uint8_t *) hv_vmbus_g_connection.interrupt_page + 200295309Ssephe (PAGE_SIZE >> 1)); 201295309Ssephe 202250199Sgrehan /** 203250199Sgrehan * Set up the monitor notification facility. The 1st page for 204250199Sgrehan * parent->child and the 2nd page for child->parent 205250199Sgrehan */ 206295308Ssephe hv_vmbus_g_connection.monitor_pages = contigmalloc( 207250199Sgrehan 2 * PAGE_SIZE, 208294553Ssephe M_DEVBUF, 209294553Ssephe M_NOWAIT | M_ZERO, 210294553Ssephe 0UL, 211282212Swhu BUS_SPACE_MAXADDR, 212282212Swhu PAGE_SIZE, 213250199Sgrehan 0); 214282212Swhu KASSERT(hv_vmbus_g_connection.monitor_pages != NULL, 215250199Sgrehan ("Error VMBUS: malloc failed to allocate Monitor Pages!")); 216282212Swhu if (hv_vmbus_g_connection.monitor_pages == NULL) { 217282212Swhu ret = ENOMEM; 218282212Swhu goto cleanup; 219282212Swhu } 220282212Swhu 221282212Swhu msg_info = (hv_vmbus_channel_msg_info*) 222282212Swhu malloc(sizeof(hv_vmbus_channel_msg_info) + 223282212Swhu sizeof(hv_vmbus_channel_initiate_contact), 224250199Sgrehan M_DEVBUF, M_NOWAIT | M_ZERO); 225282212Swhu KASSERT(msg_info != NULL, 226282212Swhu ("Error VMBUS: malloc failed for Initiate Contact message!")); 227250199Sgrehan if (msg_info == NULL) { 228282212Swhu ret = ENOMEM; 229282212Swhu goto cleanup; 230250199Sgrehan } 231282212Swhu 232282212Swhu hv_vmbus_g_connection.channels = malloc(sizeof(hv_vmbus_channel*) * 233293870Ssephe HV_CHANNEL_MAX_COUNT, 234282212Swhu M_DEVBUF, M_WAITOK | M_ZERO); 235250199Sgrehan /* 236250199Sgrehan * Find the highest vmbus version number we can support. 237250199Sgrehan */ 238250199Sgrehan version = HV_VMBUS_VERSION_CURRENT; 239250199Sgrehan 240250199Sgrehan do { 241250199Sgrehan ret = hv_vmbus_negotiate_version(msg_info, version); 242250199Sgrehan if (ret == EWOULDBLOCK) { 243250199Sgrehan /* 244250199Sgrehan * We timed out. 245250199Sgrehan */ 246250199Sgrehan goto cleanup; 247250199Sgrehan } 248250199Sgrehan 249250199Sgrehan if (hv_vmbus_g_connection.connect_state == HV_CONNECTED) 250250199Sgrehan break; 251250199Sgrehan 252295964Ssephe version = hv_vmbus_get_next_version(version); 253250199Sgrehan } while (version != HV_VMBUS_VERSION_INVALID); 254250199Sgrehan 255250199Sgrehan hv_vmbus_protocal_version = version; 256295309Ssephe if (bootverbose) 257295309Ssephe printf("VMBUS: Protocol Version: %d.%d\n", 258250199Sgrehan version >> 16, version & 0xFFFF); 259250199Sgrehan 260250199Sgrehan sema_destroy(&msg_info->wait_sema); 261250199Sgrehan free(msg_info, M_DEVBUF); 262250199Sgrehan 263250199Sgrehan return (0); 264294553Ssephe 265250199Sgrehan /* 266250199Sgrehan * Cleanup after failure! 267250199Sgrehan */ 268250199Sgrehan cleanup: 269250199Sgrehan 270250199Sgrehan hv_vmbus_g_connection.connect_state = HV_DISCONNECTED; 271250199Sgrehan 272250199Sgrehan hv_work_queue_close(hv_vmbus_g_connection.work_queue); 273250199Sgrehan sema_destroy(&hv_vmbus_g_connection.control_sema); 274295308Ssephe mtx_destroy(&hv_vmbus_g_connection.channel_lock); 275250199Sgrehan mtx_destroy(&hv_vmbus_g_connection.channel_msg_lock); 276295308Ssephe 277250199Sgrehan if (hv_vmbus_g_connection.interrupt_page != NULL) { 278295308Ssephe contigfree( 279250199Sgrehan hv_vmbus_g_connection.interrupt_page, 280295964Ssephe PAGE_SIZE, 281250199Sgrehan M_DEVBUF); 282250199Sgrehan hv_vmbus_g_connection.interrupt_page = NULL; 283250199Sgrehan } 284294553Ssephe 285250199Sgrehan if (hv_vmbus_g_connection.monitor_pages != NULL) { 286250199Sgrehan contigfree( 287250199Sgrehan hv_vmbus_g_connection.monitor_pages, 288250199Sgrehan 2 * PAGE_SIZE, 289250199Sgrehan M_DEVBUF); 290250199Sgrehan hv_vmbus_g_connection.monitor_pages = NULL; 291250199Sgrehan } 292250199Sgrehan 293250199Sgrehan if (msg_info) { 294294886Ssephe sema_destroy(&msg_info->wait_sema); 295250199Sgrehan free(msg_info, M_DEVBUF); 296282212Swhu } 297250199Sgrehan 298282212Swhu free(hv_vmbus_g_connection.channels, M_DEVBUF); 299282212Swhu return (ret); 300250199Sgrehan} 301282212Swhu 302282212Swhu/** 303250199Sgrehan * Send a disconnect request on the partition service connection 304250199Sgrehan */ 305282212Swhuint 306282212Swhuhv_vmbus_disconnect(void) { 307250199Sgrehan int ret = 0; 308282212Swhu hv_vmbus_channel_unload* msg; 309282212Swhu 310282212Swhu msg = malloc(sizeof(hv_vmbus_channel_unload), 311282212Swhu M_DEVBUF, M_NOWAIT | M_ZERO); 312282212Swhu KASSERT(msg != NULL, 313282212Swhu ("Error VMBUS: malloc failed to allocate Channel Unload Msg!")); 314282212Swhu if (msg == NULL) 315282212Swhu return (ENOMEM); 316282212Swhu 317282212Swhu msg->message_type = HV_CHANNEL_MESSAGE_UNLOAD; 318282212Swhu 319282212Swhu ret = hv_vmbus_post_message(msg, sizeof(hv_vmbus_channel_unload)); 320282212Swhu 321282212Swhu 322282212Swhu contigfree(hv_vmbus_g_connection.interrupt_page, PAGE_SIZE, M_DEVBUF); 323282212Swhu 324282212Swhu mtx_destroy(&hv_vmbus_g_connection.channel_msg_lock); 325282212Swhu 326282212Swhu hv_work_queue_close(hv_vmbus_g_connection.work_queue); 327282212Swhu sema_destroy(&hv_vmbus_g_connection.control_sema); 328282212Swhu 329250199Sgrehan free(hv_vmbus_g_connection.channels, M_DEVBUF); 330250199Sgrehan hv_vmbus_g_connection.connect_state = HV_DISCONNECTED; 331250199Sgrehan 332250199Sgrehan free(msg, M_DEVBUF); 333250199Sgrehan 334250199Sgrehan return (ret); 335294553Ssephe} 336250199Sgrehan 337250199Sgrehan/** 338250199Sgrehan * Process a channel event notification 339250199Sgrehan */ 340250199Sgrehanstatic void 341250199SgrehanVmbusProcessChannelEvent(uint32_t relid) 342250199Sgrehan{ 343250199Sgrehan void* arg; 344250199Sgrehan uint32_t bytes_to_read; 345250199Sgrehan hv_vmbus_channel* channel; 346294886Ssephe boolean_t is_batched_reading; 347294886Ssephe 348294886Ssephe /** 349294886Ssephe * Find the channel based on this relid and invokes 350250199Sgrehan * the channel callback to process the event 351294886Ssephe */ 352294886Ssephe 353296272Sjhb channel = hv_vmbus_g_connection.channels[relid]; 354250199Sgrehan 355250199Sgrehan if (channel == NULL) { 356250199Sgrehan return; 357250199Sgrehan } 358250199Sgrehan /** 359250199Sgrehan * To deal with the race condition where we might 360250199Sgrehan * receive a packet while the relevant driver is 361250199Sgrehan * being unloaded, dispatch the callback while 362250199Sgrehan * holding the channel lock. The unloading driver 363250199Sgrehan * will acquire the same channel lock to set the 364250199Sgrehan * callback to NULL. This closes the window. 365250199Sgrehan */ 366250199Sgrehan 367297219Ssephe /* 368297219Ssephe * Disable the lock due to newly added WITNESS check in r277723. 369250199Sgrehan * Will seek other way to avoid race condition. 370297219Ssephe * -- whu 371297219Ssephe */ 372297219Ssephe // mtx_lock(&channel->inbound_lock); 373250199Sgrehan if (channel->on_channel_callback != NULL) { 374297219Ssephe arg = channel->channel_callback_context; 375297219Ssephe is_batched_reading = channel->batched_reading; 376250199Sgrehan /* 377297219Ssephe * Optimize host to guest signaling by ensuring: 378297219Ssephe * 1. While reading the channel, we disable interrupts from 379297219Ssephe * host. 380250199Sgrehan * 2. Ensure that we process all posted messages from the host 381297219Ssephe * before returning from this callback. 382297219Ssephe * 3. Once we return, enable signaling from the host. Once this 383297219Ssephe * state is set we check to see if additional packets are 384297219Ssephe * available to read. In this case we repeat the process. 385297219Ssephe */ 386297219Ssephe do { 387297219Ssephe if (is_batched_reading) 388297219Ssephe hv_ring_buffer_read_begin(&channel->inbound); 389297219Ssephe 390250199Sgrehan channel->on_channel_callback(arg); 391250199Sgrehan 392297219Ssephe if (is_batched_reading) 393297219Ssephe bytes_to_read = 394250199Sgrehan hv_ring_buffer_read_end(&channel->inbound); 395297219Ssephe else 396250199Sgrehan bytes_to_read = 0; 397250199Sgrehan } while (is_batched_reading && (bytes_to_read != 0)); 398250199Sgrehan } 399250199Sgrehan // mtx_unlock(&channel->inbound_lock); 400250199Sgrehan} 401250199Sgrehan 402282212Swhu/** 403250199Sgrehan * Handler for events 404282212Swhu */ 405250199Sgrehanvoid 406250199Sgrehanhv_vmbus_on_events(void *arg) 407250199Sgrehan{ 408250199Sgrehan int bit; 409250199Sgrehan int cpu; 410250199Sgrehan int dword; 411282212Swhu void *page_addr; 412250199Sgrehan uint32_t* recv_interrupt_page = NULL; 413250199Sgrehan int rel_id; 414250199Sgrehan int maxdword; 415 hv_vmbus_synic_event_flags *event; 416 /* int maxdword = PAGE_SIZE >> 3; */ 417 418 cpu = (int)(long)arg; 419 KASSERT(cpu <= mp_maxid, ("VMBUS: hv_vmbus_on_events: " 420 "cpu out of range!")); 421 422 if ((hv_vmbus_protocal_version == HV_VMBUS_VERSION_WS2008) || 423 (hv_vmbus_protocal_version == HV_VMBUS_VERSION_WIN7)) { 424 maxdword = HV_MAX_NUM_CHANNELS_SUPPORTED >> 5; 425 /* 426 * receive size is 1/2 page and divide that by 4 bytes 427 */ 428 recv_interrupt_page = 429 hv_vmbus_g_connection.recv_interrupt_page; 430 } else { 431 /* 432 * On Host with Win8 or above, the event page can be 433 * checked directly to get the id of the channel 434 * that has the pending interrupt. 435 */ 436 maxdword = HV_EVENT_FLAGS_DWORD_COUNT; 437 page_addr = hv_vmbus_g_context.syn_ic_event_page[cpu]; 438 event = (hv_vmbus_synic_event_flags *) 439 page_addr + HV_VMBUS_MESSAGE_SINT; 440 recv_interrupt_page = event->flags32; 441 } 442 443 /* 444 * Check events 445 */ 446 if (recv_interrupt_page != NULL) { 447 for (dword = 0; dword < maxdword; dword++) { 448 if (recv_interrupt_page[dword]) { 449 for (bit = 0; bit < HV_CHANNEL_DWORD_LEN; bit++) { 450 if (synch_test_and_clear_bit(bit, 451 (uint32_t *) &recv_interrupt_page[dword])) { 452 rel_id = (dword << 5) + bit; 453 if (rel_id == 0) { 454 /* 455 * Special case - 456 * vmbus channel protocol msg. 457 */ 458 continue; 459 } else { 460 VmbusProcessChannelEvent(rel_id); 461 462 } 463 } 464 } 465 } 466 } 467 } 468 469 return; 470} 471 472/** 473 * Send a msg on the vmbus's message connection 474 */ 475int hv_vmbus_post_message(void *buffer, size_t bufferLen) { 476 int ret = 0; 477 hv_vmbus_connection_id connId; 478 unsigned retries = 0; 479 480 /* NetScaler delays from previous code were consolidated here */ 481 static int delayAmount[] = {100, 100, 100, 500, 500, 5000, 5000, 5000}; 482 483 /* for(each entry in delayAmount) try to post message, 484 * delay a little bit before retrying 485 */ 486 for (retries = 0; 487 retries < sizeof(delayAmount)/sizeof(delayAmount[0]); retries++) { 488 connId.as_uint32_t = 0; 489 connId.u.id = HV_VMBUS_MESSAGE_CONNECTION_ID; 490 ret = hv_vmbus_post_msg_via_msg_ipc(connId, 1, buffer, bufferLen); 491 if (ret != HV_STATUS_INSUFFICIENT_BUFFERS) 492 break; 493 /* TODO: KYS We should use a blocking wait call */ 494 DELAY(delayAmount[retries]); 495 } 496 497 KASSERT(ret == 0, ("Error VMBUS: Message Post Failed\n")); 498 499 return (ret); 500} 501 502/** 503 * Send an event notification to the parent 504 */ 505int 506hv_vmbus_set_event(hv_vmbus_channel *channel) { 507 int ret = 0; 508 uint32_t child_rel_id = channel->offer_msg.child_rel_id; 509 510 /* Each uint32_t represents 32 channels */ 511 512 synch_set_bit(child_rel_id & 31, 513 (((uint32_t *)hv_vmbus_g_connection.send_interrupt_page 514 + (child_rel_id >> 5)))); 515 ret = hv_vmbus_signal_event(channel->signal_event_param); 516 517 return (ret); 518} 519