hv_vmbus_drv_freebsd.c revision 296373
1/*- 2 * Copyright (c) 2009-2012 Microsoft Corp. 3 * Copyright (c) 2012 NetApp Inc. 4 * Copyright (c) 2012 Citrix Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice unmodified, this list of conditions, and the following 12 * disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29/* 30 * VM Bus Driver Implementation 31 */ 32#include <sys/cdefs.h> 33__FBSDID("$FreeBSD: releng/10.3/sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c 295789 2016-02-19 02:03:14Z sephe $"); 34 35#include <sys/param.h> 36#include <sys/bus.h> 37#include <sys/kernel.h> 38#include <sys/lock.h> 39#include <sys/malloc.h> 40#include <sys/module.h> 41#include <sys/proc.h> 42#include <sys/sysctl.h> 43#include <sys/syslog.h> 44#include <sys/systm.h> 45#include <sys/rtprio.h> 46#include <sys/interrupt.h> 47#include <sys/sx.h> 48#include <sys/taskqueue.h> 49#include <sys/mutex.h> 50#include <sys/smp.h> 51 52#include <machine/resource.h> 53#include <sys/rman.h> 54 55#include <machine/stdarg.h> 56#include <machine/intr_machdep.h> 57#include <machine/md_var.h> 58#include <machine/segments.h> 59#include <sys/pcpu.h> 60#include <machine/apicvar.h> 61 62#include "hv_vmbus_priv.h" 63 64#include <contrib/dev/acpica/include/acpi.h> 65#include "acpi_if.h" 66 67static device_t vmbus_devp; 68static int vmbus_inited; 69static hv_setup_args setup_args; /* only CPU 0 supported at this time */ 70 71static char *vmbus_ids[] = { "VMBUS", NULL }; 72 73/** 74 * @brief Software interrupt thread routine to handle channel messages from 75 * the hypervisor. 76 */ 77static void 78vmbus_msg_swintr(void *arg) 79{ 80 int cpu; 81 void* page_addr; 82 hv_vmbus_channel_msg_header *hdr; 83 hv_vmbus_channel_msg_table_entry *entry; 84 hv_vmbus_channel_msg_type msg_type; 85 hv_vmbus_message* msg; 86 hv_vmbus_message* copied; 87 static bool warned = false; 88 89 cpu = (int)(long)arg; 90 KASSERT(cpu <= mp_maxid, ("VMBUS: vmbus_msg_swintr: " 91 "cpu out of range!")); 92 93 page_addr = hv_vmbus_g_context.syn_ic_msg_page[cpu]; 94 msg = (hv_vmbus_message*) page_addr + HV_VMBUS_MESSAGE_SINT; 95 96 for (;;) { 97 if (msg->header.message_type == HV_MESSAGE_TYPE_NONE) 98 break; /* no message */ 99 100 hdr = (hv_vmbus_channel_msg_header *)msg->u.payload; 101 msg_type = hdr->message_type; 102 103 if (msg_type >= HV_CHANNEL_MESSAGE_COUNT && !warned) { 104 warned = true; 105 printf("VMBUS: unknown message type = %d\n", msg_type); 106 goto handled; 107 } 108 109 entry = &g_channel_message_table[msg_type]; 110 111 if (entry->handler_no_sleep) 112 entry->messageHandler(hdr); 113 else { 114 115 copied = malloc(sizeof(hv_vmbus_message), 116 M_DEVBUF, M_NOWAIT); 117 KASSERT(copied != NULL, 118 ("Error VMBUS: malloc failed to allocate" 119 " hv_vmbus_message!")); 120 if (copied == NULL) 121 continue; 122 123 memcpy(copied, msg, sizeof(hv_vmbus_message)); 124 hv_queue_work_item(hv_vmbus_g_connection.work_queue, 125 hv_vmbus_on_channel_message, 126 copied); 127 } 128handled: 129 msg->header.message_type = HV_MESSAGE_TYPE_NONE; 130 131 /* 132 * Make sure the write to message_type (ie set to 133 * HV_MESSAGE_TYPE_NONE) happens before we read the 134 * message_pending and EOMing. Otherwise, the EOMing will 135 * not deliver any more messages 136 * since there is no empty slot 137 */ 138 wmb(); 139 140 if (msg->header.message_flags.u.message_pending) { 141 /* 142 * This will cause message queue rescan to possibly 143 * deliver another msg from the hypervisor 144 */ 145 wrmsr(HV_X64_MSR_EOM, 0); 146 } 147 } 148} 149 150/** 151 * @brief Interrupt filter routine for VMBUS. 152 * 153 * The purpose of this routine is to determine the type of VMBUS protocol 154 * message to process - an event or a channel message. 155 */ 156static inline int 157hv_vmbus_isr(struct trapframe *frame) 158{ 159 int cpu; 160 hv_vmbus_message* msg; 161 hv_vmbus_synic_event_flags* event; 162 void* page_addr; 163 164 cpu = PCPU_GET(cpuid); 165 166 /* 167 * The Windows team has advised that we check for events 168 * before checking for messages. This is the way they do it 169 * in Windows when running as a guest in Hyper-V 170 */ 171 172 page_addr = hv_vmbus_g_context.syn_ic_event_page[cpu]; 173 event = (hv_vmbus_synic_event_flags*) 174 page_addr + HV_VMBUS_MESSAGE_SINT; 175 176 if ((hv_vmbus_protocal_version == HV_VMBUS_VERSION_WS2008) || 177 (hv_vmbus_protocal_version == HV_VMBUS_VERSION_WIN7)) { 178 /* Since we are a child, we only need to check bit 0 */ 179 if (synch_test_and_clear_bit(0, &event->flags32[0])) { 180 swi_sched(hv_vmbus_g_context.event_swintr[cpu], 0); 181 } 182 } else { 183 /* 184 * On host with Win8 or above, we can directly look at 185 * the event page. If bit n is set, we have an interrupt 186 * on the channel with id n. 187 * Directly schedule the event software interrupt on 188 * current cpu. 189 */ 190 swi_sched(hv_vmbus_g_context.event_swintr[cpu], 0); 191 } 192 193 /* Check if there are actual msgs to be process */ 194 page_addr = hv_vmbus_g_context.syn_ic_msg_page[cpu]; 195 msg = (hv_vmbus_message*) page_addr + HV_VMBUS_MESSAGE_SINT; 196 197 /* we call eventtimer process the message */ 198 if (msg->header.message_type == HV_MESSAGE_TIMER_EXPIRED) { 199 msg->header.message_type = HV_MESSAGE_TYPE_NONE; 200 201 /* 202 * Make sure the write to message_type (ie set to 203 * HV_MESSAGE_TYPE_NONE) happens before we read the 204 * message_pending and EOMing. Otherwise, the EOMing will 205 * not deliver any more messages 206 * since there is no empty slot 207 */ 208 wmb(); 209 210 if (msg->header.message_flags.u.message_pending) { 211 /* 212 * This will cause message queue rescan to possibly 213 * deliver another msg from the hypervisor 214 */ 215 wrmsr(HV_X64_MSR_EOM, 0); 216 } 217 hv_et_intr(frame); 218 return (FILTER_HANDLED); 219 } 220 221 if (msg->header.message_type != HV_MESSAGE_TYPE_NONE) { 222 swi_sched(hv_vmbus_g_context.msg_swintr[cpu], 0); 223 } 224 225 return (FILTER_HANDLED); 226} 227 228uint32_t hv_vmbus_swintr_event_cpu[MAXCPU]; 229u_long *hv_vmbus_intr_cpu[MAXCPU]; 230 231void 232hv_vector_handler(struct trapframe *trap_frame) 233{ 234 int cpu; 235 236 /* 237 * Disable preemption. 238 */ 239 critical_enter(); 240 241 /* 242 * Do a little interrupt counting. 243 */ 244 cpu = PCPU_GET(cpuid); 245 (*hv_vmbus_intr_cpu[cpu])++; 246 247 hv_vmbus_isr(trap_frame); 248 249 /* 250 * Enable preemption. 251 */ 252 critical_exit(); 253} 254 255static int 256vmbus_read_ivar( 257 device_t dev, 258 device_t child, 259 int index, 260 uintptr_t* result) 261{ 262 struct hv_device *child_dev_ctx = device_get_ivars(child); 263 264 switch (index) { 265 266 case HV_VMBUS_IVAR_TYPE: 267 *result = (uintptr_t) &child_dev_ctx->class_id; 268 return (0); 269 case HV_VMBUS_IVAR_INSTANCE: 270 *result = (uintptr_t) &child_dev_ctx->device_id; 271 return (0); 272 case HV_VMBUS_IVAR_DEVCTX: 273 *result = (uintptr_t) child_dev_ctx; 274 return (0); 275 case HV_VMBUS_IVAR_NODE: 276 *result = (uintptr_t) child_dev_ctx->device; 277 return (0); 278 } 279 return (ENOENT); 280} 281 282static int 283vmbus_write_ivar( 284 device_t dev, 285 device_t child, 286 int index, 287 uintptr_t value) 288{ 289 switch (index) { 290 291 case HV_VMBUS_IVAR_TYPE: 292 case HV_VMBUS_IVAR_INSTANCE: 293 case HV_VMBUS_IVAR_DEVCTX: 294 case HV_VMBUS_IVAR_NODE: 295 /* read-only */ 296 return (EINVAL); 297 } 298 return (ENOENT); 299} 300 301struct hv_device* 302hv_vmbus_child_device_create( 303 hv_guid type, 304 hv_guid instance, 305 hv_vmbus_channel* channel) 306{ 307 hv_device* child_dev; 308 309 /* 310 * Allocate the new child device 311 */ 312 child_dev = malloc(sizeof(hv_device), M_DEVBUF, 313 M_NOWAIT | M_ZERO); 314 KASSERT(child_dev != NULL, 315 ("Error VMBUS: malloc failed to allocate hv_device!")); 316 317 if (child_dev == NULL) 318 return (NULL); 319 320 child_dev->channel = channel; 321 memcpy(&child_dev->class_id, &type, sizeof(hv_guid)); 322 memcpy(&child_dev->device_id, &instance, sizeof(hv_guid)); 323 324 return (child_dev); 325} 326 327static void 328print_dev_guid(struct hv_device *dev) 329{ 330 int i; 331 unsigned char guid_name[100]; 332 for (i = 0; i < 32; i += 2) 333 sprintf(&guid_name[i], "%02x", dev->class_id.data[i / 2]); 334 if(bootverbose) 335 printf("VMBUS: Class ID: %s\n", guid_name); 336} 337 338int 339hv_vmbus_child_device_register(struct hv_device *child_dev) 340{ 341 device_t child; 342 int ret = 0; 343 344 print_dev_guid(child_dev); 345 346 347 child = device_add_child(vmbus_devp, NULL, -1); 348 child_dev->device = child; 349 device_set_ivars(child, child_dev); 350 351 mtx_lock(&Giant); 352 ret = device_probe_and_attach(child); 353 mtx_unlock(&Giant); 354 355 return (0); 356} 357 358int 359hv_vmbus_child_device_unregister(struct hv_device *child_dev) 360{ 361 int ret = 0; 362 /* 363 * XXXKYS: Ensure that this is the opposite of 364 * device_add_child() 365 */ 366 mtx_lock(&Giant); 367 ret = device_delete_child(vmbus_devp, child_dev->device); 368 mtx_unlock(&Giant); 369 return(ret); 370} 371 372static int 373vmbus_probe(device_t dev) { 374 if (ACPI_ID_PROBE(device_get_parent(dev), dev, vmbus_ids) == NULL || 375 device_get_unit(dev) != 0) 376 return (ENXIO); 377 378 device_set_desc(dev, "Vmbus Devices"); 379 380 return (BUS_PROBE_DEFAULT); 381} 382 383#ifdef HYPERV 384extern inthand_t IDTVEC(rsvd), IDTVEC(hv_vmbus_callback); 385 386/** 387 * @brief Find a free IDT slot and setup the interrupt handler. 388 */ 389static int 390vmbus_vector_alloc(void) 391{ 392 int vector; 393 uintptr_t func; 394 struct gate_descriptor *ip; 395 396 /* 397 * Search backwards form the highest IDT vector available for use 398 * as vmbus channel callback vector. We install 'hv_vmbus_callback' 399 * handler at that vector and use it to interrupt vcpus. 400 */ 401 vector = APIC_SPURIOUS_INT; 402 while (--vector >= APIC_IPI_INTS) { 403 ip = &idt[vector]; 404 func = ((long)ip->gd_hioffset << 16 | ip->gd_looffset); 405 if (func == (uintptr_t)&IDTVEC(rsvd)) { 406#ifdef __i386__ 407 setidt(vector , IDTVEC(hv_vmbus_callback), SDT_SYS386IGT, 408 SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); 409#else 410 setidt(vector , IDTVEC(hv_vmbus_callback), SDT_SYSIGT, 411 SEL_KPL, 0); 412#endif 413 414 return (vector); 415 } 416 } 417 return (0); 418} 419 420/** 421 * @brief Restore the IDT slot to rsvd. 422 */ 423static void 424vmbus_vector_free(int vector) 425{ 426 uintptr_t func; 427 struct gate_descriptor *ip; 428 429 if (vector == 0) 430 return; 431 432 KASSERT(vector >= APIC_IPI_INTS && vector < APIC_SPURIOUS_INT, 433 ("invalid vector %d", vector)); 434 435 ip = &idt[vector]; 436 func = ((long)ip->gd_hioffset << 16 | ip->gd_looffset); 437 KASSERT(func == (uintptr_t)&IDTVEC(hv_vmbus_callback), 438 ("invalid vector %d", vector)); 439 440 setidt(vector, IDTVEC(rsvd), SDT_SYSIGT, SEL_KPL, 0); 441} 442 443#else /* HYPERV */ 444 445static int 446vmbus_vector_alloc(void) 447{ 448 return(0); 449} 450 451static void 452vmbus_vector_free(int vector) 453{ 454} 455 456#endif /* HYPERV */ 457 458/** 459 * @brief Main vmbus driver initialization routine. 460 * 461 * Here, we 462 * - initialize the vmbus driver context 463 * - setup various driver entry points 464 * - invoke the vmbus hv main init routine 465 * - get the irq resource 466 * - invoke the vmbus to add the vmbus root device 467 * - setup the vmbus root device 468 * - retrieve the channel offers 469 */ 470static int 471vmbus_bus_init(void) 472{ 473 int i, j, n, ret; 474 char buf[MAXCOMLEN + 1]; 475 476 if (vmbus_inited) 477 return (0); 478 479 vmbus_inited = 1; 480 481 ret = hv_vmbus_init(); 482 483 if (ret) { 484 if(bootverbose) 485 printf("Error VMBUS: Hypervisor Initialization Failed!\n"); 486 return (ret); 487 } 488 489 /* 490 * Find a free IDT slot for vmbus callback. 491 */ 492 hv_vmbus_g_context.hv_cb_vector = vmbus_vector_alloc(); 493 494 if (hv_vmbus_g_context.hv_cb_vector == 0) { 495 if(bootverbose) 496 printf("Error VMBUS: Cannot find free IDT slot for " 497 "vmbus callback!\n"); 498 goto cleanup; 499 } 500 501 if(bootverbose) 502 printf("VMBUS: vmbus callback vector %d\n", 503 hv_vmbus_g_context.hv_cb_vector); 504 505 /* 506 * Notify the hypervisor of our vector. 507 */ 508 setup_args.vector = hv_vmbus_g_context.hv_cb_vector; 509 510 CPU_FOREACH(j) { 511 hv_vmbus_swintr_event_cpu[j] = 0; 512 hv_vmbus_g_context.hv_event_intr_event[j] = NULL; 513 hv_vmbus_g_context.hv_msg_intr_event[j] = NULL; 514 hv_vmbus_g_context.event_swintr[j] = NULL; 515 hv_vmbus_g_context.msg_swintr[j] = NULL; 516 517 snprintf(buf, sizeof(buf), "cpu%d:hyperv", j); 518 intrcnt_add(buf, &hv_vmbus_intr_cpu[j]); 519 520 for (i = 0; i < 2; i++) 521 setup_args.page_buffers[2 * j + i] = NULL; 522 } 523 524 /* 525 * Per cpu setup. 526 */ 527 CPU_FOREACH(j) { 528 /* 529 * Setup software interrupt thread and handler for msg handling. 530 */ 531 ret = swi_add(&hv_vmbus_g_context.hv_msg_intr_event[j], 532 "hv_msg", vmbus_msg_swintr, (void *)(long)j, SWI_CLOCK, 0, 533 &hv_vmbus_g_context.msg_swintr[j]); 534 if (ret) { 535 if(bootverbose) 536 printf("VMBUS: failed to setup msg swi for " 537 "cpu %d\n", j); 538 goto cleanup1; 539 } 540 541 /* 542 * Bind the swi thread to the cpu. 543 */ 544 ret = intr_event_bind(hv_vmbus_g_context.hv_msg_intr_event[j], 545 j); 546 if (ret) { 547 if(bootverbose) 548 printf("VMBUS: failed to bind msg swi thread " 549 "to cpu %d\n", j); 550 goto cleanup1; 551 } 552 553 /* 554 * Setup software interrupt thread and handler for 555 * event handling. 556 */ 557 ret = swi_add(&hv_vmbus_g_context.hv_event_intr_event[j], 558 "hv_event", hv_vmbus_on_events, (void *)(long)j, 559 SWI_CLOCK, 0, &hv_vmbus_g_context.event_swintr[j]); 560 if (ret) { 561 if(bootverbose) 562 printf("VMBUS: failed to setup event swi for " 563 "cpu %d\n", j); 564 goto cleanup1; 565 } 566 567 /* 568 * Prepare the per cpu msg and event pages to be called on each cpu. 569 */ 570 for(i = 0; i < 2; i++) { 571 setup_args.page_buffers[2 * j + i] = 572 malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT | M_ZERO); 573 if (setup_args.page_buffers[2 * j + i] == NULL) { 574 KASSERT(setup_args.page_buffers[2 * j + i] != NULL, 575 ("Error VMBUS: malloc failed!")); 576 goto cleanup1; 577 } 578 } 579 } 580 581 if (bootverbose) 582 printf("VMBUS: Calling smp_rendezvous, smp_started = %d\n", 583 smp_started); 584 585 smp_rendezvous(NULL, hv_vmbus_synic_init, NULL, &setup_args); 586 587 /* 588 * Connect to VMBus in the root partition 589 */ 590 ret = hv_vmbus_connect(); 591 592 if (ret != 0) 593 goto cleanup1; 594 595 hv_vmbus_request_channel_offers(); 596 return (ret); 597 598 cleanup1: 599 /* 600 * Free pages alloc'ed 601 */ 602 for (n = 0; n < 2 * MAXCPU; n++) 603 if (setup_args.page_buffers[n] != NULL) 604 free(setup_args.page_buffers[n], M_DEVBUF); 605 606 /* 607 * remove swi and vmbus callback vector; 608 */ 609 CPU_FOREACH(j) { 610 if (hv_vmbus_g_context.msg_swintr[j] != NULL) 611 swi_remove(hv_vmbus_g_context.msg_swintr[j]); 612 if (hv_vmbus_g_context.event_swintr[j] != NULL) 613 swi_remove(hv_vmbus_g_context.event_swintr[j]); 614 hv_vmbus_g_context.hv_msg_intr_event[j] = NULL; 615 hv_vmbus_g_context.hv_event_intr_event[j] = NULL; 616 } 617 618 vmbus_vector_free(hv_vmbus_g_context.hv_cb_vector); 619 620 cleanup: 621 hv_vmbus_cleanup(); 622 623 return (ret); 624} 625 626static int 627vmbus_attach(device_t dev) 628{ 629 if(bootverbose) 630 device_printf(dev, "VMBUS: attach dev: %p\n", dev); 631 vmbus_devp = dev; 632 633 /* 634 * If the system has already booted and thread 635 * scheduling is possible indicated by the global 636 * cold set to zero, we just call the driver 637 * initialization directly. 638 */ 639 if (!cold) 640 vmbus_bus_init(); 641 642 return (0); 643} 644 645static void 646vmbus_init(void) 647{ 648 if (vm_guest != VM_GUEST_HV) 649 return; 650 651 /* 652 * If the system has already booted and thread 653 * scheduling is possible, as indicated by the 654 * global cold set to zero, we just call the driver 655 * initialization directly. 656 */ 657 if (!cold) 658 vmbus_bus_init(); 659} 660 661static void 662vmbus_bus_exit(void) 663{ 664 int i; 665 666 hv_vmbus_release_unattached_channels(); 667 hv_vmbus_disconnect(); 668 669 smp_rendezvous(NULL, hv_vmbus_synic_cleanup, NULL, NULL); 670 671 for(i = 0; i < 2 * MAXCPU; i++) { 672 if (setup_args.page_buffers[i] != 0) 673 free(setup_args.page_buffers[i], M_DEVBUF); 674 } 675 676 hv_vmbus_cleanup(); 677 678 /* remove swi */ 679 CPU_FOREACH(i) { 680 if (hv_vmbus_g_context.msg_swintr[i] != NULL) 681 swi_remove(hv_vmbus_g_context.msg_swintr[i]); 682 if (hv_vmbus_g_context.event_swintr[i] != NULL) 683 swi_remove(hv_vmbus_g_context.event_swintr[i]); 684 hv_vmbus_g_context.hv_msg_intr_event[i] = NULL; 685 hv_vmbus_g_context.hv_event_intr_event[i] = NULL; 686 } 687 688 vmbus_vector_free(hv_vmbus_g_context.hv_cb_vector); 689 690 return; 691} 692 693static void 694vmbus_exit(void) 695{ 696 vmbus_bus_exit(); 697} 698 699static int 700vmbus_detach(device_t dev) 701{ 702 vmbus_exit(); 703 return (0); 704} 705 706static void 707vmbus_mod_load(void) 708{ 709 if(bootverbose) 710 printf("VMBUS: load\n"); 711} 712 713static void 714vmbus_mod_unload(void) 715{ 716 if(bootverbose) 717 printf("VMBUS: unload\n"); 718} 719 720static int 721vmbus_modevent(module_t mod, int what, void *arg) 722{ 723 switch (what) { 724 725 case MOD_LOAD: 726 vmbus_mod_load(); 727 break; 728 case MOD_UNLOAD: 729 vmbus_mod_unload(); 730 break; 731 } 732 733 return (0); 734} 735 736static device_method_t vmbus_methods[] = { 737 /** Device interface */ 738 DEVMETHOD(device_probe, vmbus_probe), 739 DEVMETHOD(device_attach, vmbus_attach), 740 DEVMETHOD(device_detach, vmbus_detach), 741 DEVMETHOD(device_shutdown, bus_generic_shutdown), 742 DEVMETHOD(device_suspend, bus_generic_suspend), 743 DEVMETHOD(device_resume, bus_generic_resume), 744 745 /** Bus interface */ 746 DEVMETHOD(bus_add_child, bus_generic_add_child), 747 DEVMETHOD(bus_print_child, bus_generic_print_child), 748 DEVMETHOD(bus_read_ivar, vmbus_read_ivar), 749 DEVMETHOD(bus_write_ivar, vmbus_write_ivar), 750 751 { 0, 0 } }; 752 753static char driver_name[] = "vmbus"; 754static driver_t vmbus_driver = { driver_name, vmbus_methods,0, }; 755 756 757devclass_t vmbus_devclass; 758 759DRIVER_MODULE(vmbus, acpi, vmbus_driver, vmbus_devclass, vmbus_modevent, 0); 760MODULE_DEPEND(vmbus, acpi, 1, 1, 1); 761MODULE_VERSION(vmbus, 1); 762 763/* We want to be started after SMP is initialized */ 764SYSINIT(vmb_init, SI_SUB_SMP + 1, SI_ORDER_FIRST, vmbus_init, NULL); 765 766