vmbus.c revision 302167
1/*- 2 * Copyright (c) 2009-2012,2016 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: stable/10/sys/dev/hyperv/vmbus/vmbus.c 302167 2016-06-24 02:06:13Z 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 <dev/hyperv/include/hyperv.h> 63#include <dev/hyperv/vmbus/hv_vmbus_priv.h> 64#include <dev/hyperv/vmbus/hyperv_reg.h> 65#include <dev/hyperv/vmbus/hyperv_var.h> 66#include <dev/hyperv/vmbus/vmbus_reg.h> 67#include <dev/hyperv/vmbus/vmbus_var.h> 68 69#include <contrib/dev/acpica/include/acpi.h> 70#include "acpi_if.h" 71 72struct vmbus_softc *vmbus_sc; 73 74extern inthand_t IDTVEC(rsvd), IDTVEC(vmbus_isr); 75 76static void 77vmbus_msg_task(void *xsc, int pending __unused) 78{ 79 struct vmbus_softc *sc = xsc; 80 volatile struct vmbus_message *msg; 81 82 msg = VMBUS_PCPU_GET(sc, message, curcpu) + VMBUS_SINT_MESSAGE; 83 for (;;) { 84 const hv_vmbus_channel_msg_table_entry *entry; 85 hv_vmbus_channel_msg_header *hdr; 86 hv_vmbus_channel_msg_type msg_type; 87 88 if (msg->msg_type == VMBUS_MSGTYPE_NONE) 89 break; /* no message */ 90 91 /* XXX: update messageHandler interface */ 92 hdr = __DEVOLATILE(hv_vmbus_channel_msg_header *, 93 msg->msg_data); 94 msg_type = hdr->message_type; 95 96 if (msg_type >= HV_CHANNEL_MESSAGE_COUNT) { 97 printf("VMBUS: unknown message type = %d\n", msg_type); 98 goto handled; 99 } 100 101 entry = &g_channel_message_table[msg_type]; 102 if (entry->messageHandler) 103 entry->messageHandler(hdr); 104handled: 105 msg->msg_type = VMBUS_MSGTYPE_NONE; 106 /* 107 * Make sure the write to msg_type (i.e. set to 108 * VMBUS_MSGTYPE_NONE) happens before we read the 109 * msg_flags and EOMing. Otherwise, the EOMing will 110 * not deliver any more messages since there is no 111 * empty slot 112 * 113 * NOTE: 114 * mb() is used here, since atomic_thread_fence_seq_cst() 115 * will become compiler fence on UP kernel. 116 */ 117 mb(); 118 if (msg->msg_flags & VMBUS_MSGFLAG_PENDING) { 119 /* 120 * This will cause message queue rescan to possibly 121 * deliver another msg from the hypervisor 122 */ 123 wrmsr(MSR_HV_EOM, 0); 124 } 125 } 126} 127 128static __inline int 129vmbus_handle_intr1(struct vmbus_softc *sc, struct trapframe *frame, int cpu) 130{ 131 volatile struct vmbus_message *msg; 132 struct vmbus_message *msg_base; 133 134 msg_base = VMBUS_PCPU_GET(sc, message, cpu); 135 136 /* 137 * Check event timer. 138 * 139 * TODO: move this to independent IDT vector. 140 */ 141 msg = msg_base + VMBUS_SINT_TIMER; 142 if (msg->msg_type == VMBUS_MSGTYPE_TIMER_EXPIRED) { 143 msg->msg_type = VMBUS_MSGTYPE_NONE; 144 145 vmbus_et_intr(frame); 146 147 /* 148 * Make sure the write to msg_type (i.e. set to 149 * VMBUS_MSGTYPE_NONE) happens before we read the 150 * msg_flags and EOMing. Otherwise, the EOMing will 151 * not deliver any more messages since there is no 152 * empty slot 153 * 154 * NOTE: 155 * mb() is used here, since atomic_thread_fence_seq_cst() 156 * will become compiler fence on UP kernel. 157 */ 158 mb(); 159 if (msg->msg_flags & VMBUS_MSGFLAG_PENDING) { 160 /* 161 * This will cause message queue rescan to possibly 162 * deliver another msg from the hypervisor 163 */ 164 wrmsr(MSR_HV_EOM, 0); 165 } 166 } 167 168 /* 169 * Check events. Hot path for network and storage I/O data; high rate. 170 * 171 * NOTE: 172 * As recommended by the Windows guest fellows, we check events before 173 * checking messages. 174 */ 175 sc->vmbus_event_proc(sc, cpu); 176 177 /* 178 * Check messages. Mainly management stuffs; ultra low rate. 179 */ 180 msg = msg_base + VMBUS_SINT_MESSAGE; 181 if (__predict_false(msg->msg_type != VMBUS_MSGTYPE_NONE)) { 182 taskqueue_enqueue(VMBUS_PCPU_GET(sc, message_tq, cpu), 183 VMBUS_PCPU_PTR(sc, message_task, cpu)); 184 } 185 186 return (FILTER_HANDLED); 187} 188 189void 190vmbus_handle_intr(struct trapframe *trap_frame) 191{ 192 struct vmbus_softc *sc = vmbus_get_softc(); 193 int cpu = curcpu; 194 195 /* 196 * Disable preemption. 197 */ 198 critical_enter(); 199 200 /* 201 * Do a little interrupt counting. 202 */ 203 (*VMBUS_PCPU_GET(sc, intr_cnt, cpu))++; 204 205 vmbus_handle_intr1(sc, trap_frame, cpu); 206 207 /* 208 * Enable preemption. 209 */ 210 critical_exit(); 211} 212 213static void 214vmbus_synic_setup(void *xsc) 215{ 216 struct vmbus_softc *sc = xsc; 217 int cpu = curcpu; 218 uint64_t val, orig; 219 uint32_t sint; 220 221 if (hyperv_features & CPUID_HV_MSR_VP_INDEX) { 222 /* 223 * Save virtual processor id. 224 */ 225 VMBUS_PCPU_GET(sc, vcpuid, cpu) = rdmsr(MSR_HV_VP_INDEX); 226 } else { 227 /* 228 * XXX 229 * Virtual processoor id is only used by a pretty broken 230 * channel selection code from storvsc. It's nothing 231 * critical even if CPUID_HV_MSR_VP_INDEX is not set; keep 232 * moving on. 233 */ 234 VMBUS_PCPU_GET(sc, vcpuid, cpu) = cpu; 235 } 236 237 /* 238 * Setup the SynIC message. 239 */ 240 orig = rdmsr(MSR_HV_SIMP); 241 val = MSR_HV_SIMP_ENABLE | (orig & MSR_HV_SIMP_RSVD_MASK) | 242 ((VMBUS_PCPU_GET(sc, message_dma.hv_paddr, cpu) >> PAGE_SHIFT) << 243 MSR_HV_SIMP_PGSHIFT); 244 wrmsr(MSR_HV_SIMP, val); 245 246 /* 247 * Setup the SynIC event flags. 248 */ 249 orig = rdmsr(MSR_HV_SIEFP); 250 val = MSR_HV_SIEFP_ENABLE | (orig & MSR_HV_SIEFP_RSVD_MASK) | 251 ((VMBUS_PCPU_GET(sc, event_flags_dma.hv_paddr, cpu) 252 >> PAGE_SHIFT) << MSR_HV_SIEFP_PGSHIFT); 253 wrmsr(MSR_HV_SIEFP, val); 254 255 256 /* 257 * Configure and unmask SINT for message and event flags. 258 */ 259 sint = MSR_HV_SINT0 + VMBUS_SINT_MESSAGE; 260 orig = rdmsr(sint); 261 val = sc->vmbus_idtvec | MSR_HV_SINT_AUTOEOI | 262 (orig & MSR_HV_SINT_RSVD_MASK); 263 wrmsr(sint, val); 264 265 /* 266 * Configure and unmask SINT for timer. 267 */ 268 sint = MSR_HV_SINT0 + VMBUS_SINT_TIMER; 269 orig = rdmsr(sint); 270 val = sc->vmbus_idtvec | MSR_HV_SINT_AUTOEOI | 271 (orig & MSR_HV_SINT_RSVD_MASK); 272 wrmsr(sint, val); 273 274 /* 275 * All done; enable SynIC. 276 */ 277 orig = rdmsr(MSR_HV_SCONTROL); 278 val = MSR_HV_SCTRL_ENABLE | (orig & MSR_HV_SCTRL_RSVD_MASK); 279 wrmsr(MSR_HV_SCONTROL, val); 280} 281 282static void 283vmbus_synic_teardown(void *arg) 284{ 285 uint64_t orig; 286 uint32_t sint; 287 288 /* 289 * Disable SynIC. 290 */ 291 orig = rdmsr(MSR_HV_SCONTROL); 292 wrmsr(MSR_HV_SCONTROL, (orig & MSR_HV_SCTRL_RSVD_MASK)); 293 294 /* 295 * Mask message and event flags SINT. 296 */ 297 sint = MSR_HV_SINT0 + VMBUS_SINT_MESSAGE; 298 orig = rdmsr(sint); 299 wrmsr(sint, orig | MSR_HV_SINT_MASKED); 300 301 /* 302 * Mask timer SINT. 303 */ 304 sint = MSR_HV_SINT0 + VMBUS_SINT_TIMER; 305 orig = rdmsr(sint); 306 wrmsr(sint, orig | MSR_HV_SINT_MASKED); 307 308 /* 309 * Teardown SynIC message. 310 */ 311 orig = rdmsr(MSR_HV_SIMP); 312 wrmsr(MSR_HV_SIMP, (orig & MSR_HV_SIMP_RSVD_MASK)); 313 314 /* 315 * Teardown SynIC event flags. 316 */ 317 orig = rdmsr(MSR_HV_SIEFP); 318 wrmsr(MSR_HV_SIEFP, (orig & MSR_HV_SIEFP_RSVD_MASK)); 319} 320 321static int 322vmbus_dma_alloc(struct vmbus_softc *sc) 323{ 324 int cpu; 325 326 CPU_FOREACH(cpu) { 327 void *ptr; 328 329 /* 330 * Per-cpu messages and event flags. 331 */ 332 ptr = hyperv_dmamem_alloc(bus_get_dma_tag(sc->vmbus_dev), 333 PAGE_SIZE, 0, PAGE_SIZE, 334 VMBUS_PCPU_PTR(sc, message_dma, cpu), 335 BUS_DMA_WAITOK | BUS_DMA_ZERO); 336 if (ptr == NULL) 337 return ENOMEM; 338 VMBUS_PCPU_GET(sc, message, cpu) = ptr; 339 340 ptr = hyperv_dmamem_alloc(bus_get_dma_tag(sc->vmbus_dev), 341 PAGE_SIZE, 0, PAGE_SIZE, 342 VMBUS_PCPU_PTR(sc, event_flags_dma, cpu), 343 BUS_DMA_WAITOK | BUS_DMA_ZERO); 344 if (ptr == NULL) 345 return ENOMEM; 346 VMBUS_PCPU_GET(sc, event_flags, cpu) = ptr; 347 } 348 return 0; 349} 350 351static void 352vmbus_dma_free(struct vmbus_softc *sc) 353{ 354 int cpu; 355 356 CPU_FOREACH(cpu) { 357 if (VMBUS_PCPU_GET(sc, message, cpu) != NULL) { 358 hyperv_dmamem_free( 359 VMBUS_PCPU_PTR(sc, message_dma, cpu), 360 VMBUS_PCPU_GET(sc, message, cpu)); 361 VMBUS_PCPU_GET(sc, message, cpu) = NULL; 362 } 363 if (VMBUS_PCPU_GET(sc, event_flags, cpu) != NULL) { 364 hyperv_dmamem_free( 365 VMBUS_PCPU_PTR(sc, event_flags_dma, cpu), 366 VMBUS_PCPU_GET(sc, event_flags, cpu)); 367 VMBUS_PCPU_GET(sc, event_flags, cpu) = NULL; 368 } 369 } 370} 371 372/** 373 * @brief Find a free IDT slot and setup the interrupt handler. 374 */ 375static int 376vmbus_vector_alloc(void) 377{ 378 int vector; 379 uintptr_t func; 380 struct gate_descriptor *ip; 381 382 /* 383 * Search backwards form the highest IDT vector available for use 384 * as vmbus channel callback vector. We install 'hv_vmbus_callback' 385 * handler at that vector and use it to interrupt vcpus. 386 */ 387 vector = APIC_SPURIOUS_INT; 388 while (--vector >= APIC_IPI_INTS) { 389 ip = &idt[vector]; 390 func = ((long)ip->gd_hioffset << 16 | ip->gd_looffset); 391 if (func == (uintptr_t)&IDTVEC(rsvd)) { 392#ifdef __i386__ 393 setidt(vector , IDTVEC(vmbus_isr), SDT_SYS386IGT, 394 SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); 395#else 396 setidt(vector , IDTVEC(vmbus_isr), SDT_SYSIGT, 397 SEL_KPL, 0); 398#endif 399 400 return (vector); 401 } 402 } 403 return (0); 404} 405 406/** 407 * @brief Restore the IDT slot to rsvd. 408 */ 409static void 410vmbus_vector_free(int vector) 411{ 412 uintptr_t func; 413 struct gate_descriptor *ip; 414 415 if (vector == 0) 416 return; 417 418 KASSERT(vector >= APIC_IPI_INTS && vector < APIC_SPURIOUS_INT, 419 ("invalid vector %d", vector)); 420 421 ip = &idt[vector]; 422 func = ((long)ip->gd_hioffset << 16 | ip->gd_looffset); 423 KASSERT(func == (uintptr_t)&IDTVEC(hv_vmbus_callback), 424 ("invalid vector %d", vector)); 425 426 setidt(vector, IDTVEC(rsvd), SDT_SYSIGT, SEL_KPL, 0); 427} 428 429static void 430vmbus_cpuset_setthread_task(void *xmask, int pending __unused) 431{ 432 cpuset_t *mask = xmask; 433 int error; 434 435 error = cpuset_setthread(curthread->td_tid, mask); 436 if (error) { 437 panic("curthread=%ju: can't pin; error=%d", 438 (uintmax_t)curthread->td_tid, error); 439 } 440} 441 442static int 443vmbus_intr_setup(struct vmbus_softc *sc) 444{ 445 int cpu; 446 447 CPU_FOREACH(cpu) { 448 struct task cpuset_task; 449 char buf[MAXCOMLEN + 1]; 450 cpuset_t cpu_mask; 451 452 /* Allocate an interrupt counter for Hyper-V interrupt */ 453 snprintf(buf, sizeof(buf), "cpu%d:hyperv", cpu); 454 intrcnt_add(buf, VMBUS_PCPU_PTR(sc, intr_cnt, cpu)); 455 456 /* 457 * Setup taskqueue to handle events. Task will be per- 458 * channel. 459 */ 460 VMBUS_PCPU_GET(sc, event_tq, cpu) = taskqueue_create_fast( 461 "hyperv event", M_WAITOK, taskqueue_thread_enqueue, 462 VMBUS_PCPU_PTR(sc, event_tq, cpu)); 463 taskqueue_start_threads(VMBUS_PCPU_PTR(sc, event_tq, cpu), 464 1, PI_NET, "hvevent%d", cpu); 465 466 CPU_SETOF(cpu, &cpu_mask); 467 TASK_INIT(&cpuset_task, 0, vmbus_cpuset_setthread_task, 468 &cpu_mask); 469 taskqueue_enqueue(VMBUS_PCPU_GET(sc, event_tq, cpu), 470 &cpuset_task); 471 taskqueue_drain(VMBUS_PCPU_GET(sc, event_tq, cpu), 472 &cpuset_task); 473 474 /* 475 * Setup tasks and taskqueues to handle messages. 476 */ 477 VMBUS_PCPU_GET(sc, message_tq, cpu) = taskqueue_create_fast( 478 "hyperv msg", M_WAITOK, taskqueue_thread_enqueue, 479 VMBUS_PCPU_PTR(sc, message_tq, cpu)); 480 taskqueue_start_threads(VMBUS_PCPU_PTR(sc, message_tq, cpu), 1, 481 PI_NET, "hvmsg%d", cpu); 482 TASK_INIT(VMBUS_PCPU_PTR(sc, message_task, cpu), 0, 483 vmbus_msg_task, sc); 484 485 CPU_SETOF(cpu, &cpu_mask); 486 TASK_INIT(&cpuset_task, 0, vmbus_cpuset_setthread_task, 487 &cpu_mask); 488 taskqueue_enqueue(VMBUS_PCPU_GET(sc, message_tq, cpu), 489 &cpuset_task); 490 taskqueue_drain(VMBUS_PCPU_GET(sc, message_tq, cpu), 491 &cpuset_task); 492 } 493 494 /* 495 * All Hyper-V ISR required resources are setup, now let's find a 496 * free IDT vector for Hyper-V ISR and set it up. 497 */ 498 sc->vmbus_idtvec = vmbus_vector_alloc(); 499 if (sc->vmbus_idtvec == 0) { 500 device_printf(sc->vmbus_dev, "cannot find free IDT vector\n"); 501 return ENXIO; 502 } 503 if(bootverbose) { 504 device_printf(sc->vmbus_dev, "vmbus IDT vector %d\n", 505 sc->vmbus_idtvec); 506 } 507 return 0; 508} 509 510static void 511vmbus_intr_teardown(struct vmbus_softc *sc) 512{ 513 int cpu; 514 515 vmbus_vector_free(sc->vmbus_idtvec); 516 517 CPU_FOREACH(cpu) { 518 if (VMBUS_PCPU_GET(sc, event_tq, cpu) != NULL) { 519 taskqueue_free(VMBUS_PCPU_GET(sc, event_tq, cpu)); 520 VMBUS_PCPU_GET(sc, event_tq, cpu) = NULL; 521 } 522 if (VMBUS_PCPU_GET(sc, message_tq, cpu) != NULL) { 523 taskqueue_drain(VMBUS_PCPU_GET(sc, message_tq, cpu), 524 VMBUS_PCPU_PTR(sc, message_task, cpu)); 525 taskqueue_free(VMBUS_PCPU_GET(sc, message_tq, cpu)); 526 VMBUS_PCPU_GET(sc, message_tq, cpu) = NULL; 527 } 528 } 529} 530 531static int 532vmbus_read_ivar(device_t dev, device_t child, int index, uintptr_t *result) 533{ 534 struct hv_device *child_dev_ctx = device_get_ivars(child); 535 536 switch (index) { 537 case HV_VMBUS_IVAR_TYPE: 538 *result = (uintptr_t)&child_dev_ctx->class_id; 539 return (0); 540 541 case HV_VMBUS_IVAR_INSTANCE: 542 *result = (uintptr_t)&child_dev_ctx->device_id; 543 return (0); 544 545 case HV_VMBUS_IVAR_DEVCTX: 546 *result = (uintptr_t)child_dev_ctx; 547 return (0); 548 549 case HV_VMBUS_IVAR_NODE: 550 *result = (uintptr_t)child_dev_ctx->device; 551 return (0); 552 } 553 return (ENOENT); 554} 555 556static int 557vmbus_write_ivar(device_t dev, device_t child, int index, uintptr_t value) 558{ 559 switch (index) { 560 case HV_VMBUS_IVAR_TYPE: 561 case HV_VMBUS_IVAR_INSTANCE: 562 case HV_VMBUS_IVAR_DEVCTX: 563 case HV_VMBUS_IVAR_NODE: 564 /* read-only */ 565 return (EINVAL); 566 } 567 return (ENOENT); 568} 569 570static int 571vmbus_child_pnpinfo_str(device_t dev, device_t child, char *buf, size_t buflen) 572{ 573 struct hv_device *dev_ctx = device_get_ivars(child); 574 char guidbuf[HYPERV_GUID_STRLEN]; 575 576 if (dev_ctx == NULL) 577 return (0); 578 579 strlcat(buf, "classid=", buflen); 580 hyperv_guid2str(&dev_ctx->class_id, guidbuf, sizeof(guidbuf)); 581 strlcat(buf, guidbuf, buflen); 582 583 strlcat(buf, " deviceid=", buflen); 584 hyperv_guid2str(&dev_ctx->device_id, guidbuf, sizeof(guidbuf)); 585 strlcat(buf, guidbuf, buflen); 586 587 return (0); 588} 589 590struct hv_device * 591hv_vmbus_child_device_create(hv_guid type, hv_guid instance, 592 hv_vmbus_channel *channel) 593{ 594 hv_device *child_dev; 595 596 /* 597 * Allocate the new child device 598 */ 599 child_dev = malloc(sizeof(hv_device), M_DEVBUF, M_WAITOK | M_ZERO); 600 601 child_dev->channel = channel; 602 memcpy(&child_dev->class_id, &type, sizeof(hv_guid)); 603 memcpy(&child_dev->device_id, &instance, sizeof(hv_guid)); 604 605 return (child_dev); 606} 607 608int 609hv_vmbus_child_device_register(struct hv_device *child_dev) 610{ 611 device_t child, parent; 612 613 parent = vmbus_get_device(); 614 if (bootverbose) { 615 char name[HYPERV_GUID_STRLEN]; 616 617 hyperv_guid2str(&child_dev->class_id, name, sizeof(name)); 618 device_printf(parent, "add device, classid: %s\n", name); 619 } 620 621 child = device_add_child(parent, NULL, -1); 622 child_dev->device = child; 623 device_set_ivars(child, child_dev); 624 625 return (0); 626} 627 628int 629hv_vmbus_child_device_unregister(struct hv_device *child_dev) 630{ 631 int ret = 0; 632 /* 633 * XXXKYS: Ensure that this is the opposite of 634 * device_add_child() 635 */ 636 mtx_lock(&Giant); 637 ret = device_delete_child(vmbus_get_device(), child_dev->device); 638 mtx_unlock(&Giant); 639 return(ret); 640} 641 642static int 643vmbus_probe(device_t dev) 644{ 645 char *id[] = { "VMBUS", NULL }; 646 647 if (ACPI_ID_PROBE(device_get_parent(dev), dev, id) == NULL || 648 device_get_unit(dev) != 0 || vm_guest != VM_GUEST_HV || 649 (hyperv_features & CPUID_HV_MSR_SYNIC) == 0) 650 return (ENXIO); 651 652 device_set_desc(dev, "Hyper-V Vmbus"); 653 654 return (BUS_PROBE_DEFAULT); 655} 656 657/** 658 * @brief Main vmbus driver initialization routine. 659 * 660 * Here, we 661 * - initialize the vmbus driver context 662 * - setup various driver entry points 663 * - invoke the vmbus hv main init routine 664 * - get the irq resource 665 * - invoke the vmbus to add the vmbus root device 666 * - setup the vmbus root device 667 * - retrieve the channel offers 668 */ 669static int 670vmbus_bus_init(void) 671{ 672 struct vmbus_softc *sc = vmbus_get_softc(); 673 int ret; 674 675 if (sc->vmbus_flags & VMBUS_FLAG_ATTACHED) 676 return (0); 677 sc->vmbus_flags |= VMBUS_FLAG_ATTACHED; 678 679 /* 680 * Allocate DMA stuffs. 681 */ 682 ret = vmbus_dma_alloc(sc); 683 if (ret != 0) 684 goto cleanup; 685 686 /* 687 * Setup interrupt. 688 */ 689 ret = vmbus_intr_setup(sc); 690 if (ret != 0) 691 goto cleanup; 692 693 /* 694 * Setup SynIC. 695 */ 696 if (bootverbose) 697 device_printf(sc->vmbus_dev, "smp_started = %d\n", smp_started); 698 smp_rendezvous(NULL, vmbus_synic_setup, NULL, sc); 699 sc->vmbus_flags |= VMBUS_FLAG_SYNIC; 700 701 /* 702 * Connect to VMBus in the root partition 703 */ 704 ret = hv_vmbus_connect(); 705 706 if (ret != 0) 707 goto cleanup; 708 709 if (hv_vmbus_protocal_version == HV_VMBUS_VERSION_WS2008 || 710 hv_vmbus_protocal_version == HV_VMBUS_VERSION_WIN7) 711 sc->vmbus_event_proc = vmbus_event_proc_compat; 712 else 713 sc->vmbus_event_proc = vmbus_event_proc; 714 715 hv_vmbus_request_channel_offers(); 716 717 vmbus_scan(); 718 bus_generic_attach(sc->vmbus_dev); 719 device_printf(sc->vmbus_dev, "device scan, probe and attach done\n"); 720 721 return (ret); 722 723cleanup: 724 vmbus_intr_teardown(sc); 725 vmbus_dma_free(sc); 726 727 return (ret); 728} 729 730static void 731vmbus_event_proc_dummy(struct vmbus_softc *sc __unused, int cpu __unused) 732{ 733} 734 735static int 736vmbus_attach(device_t dev) 737{ 738 vmbus_sc = device_get_softc(dev); 739 vmbus_sc->vmbus_dev = dev; 740 741 /* 742 * Event processing logic will be configured: 743 * - After the vmbus protocol version negotiation. 744 * - Before we request channel offers. 745 */ 746 vmbus_sc->vmbus_event_proc = vmbus_event_proc_dummy; 747 748 /* 749 * If the system has already booted and thread 750 * scheduling is possible indicated by the global 751 * cold set to zero, we just call the driver 752 * initialization directly. 753 */ 754 if (!cold) 755 vmbus_bus_init(); 756 757 bus_generic_probe(dev); 758 return (0); 759} 760 761static void 762vmbus_sysinit(void *arg __unused) 763{ 764 if (vm_guest != VM_GUEST_HV || vmbus_get_softc() == NULL) 765 return; 766 767 /* 768 * If the system has already booted and thread 769 * scheduling is possible, as indicated by the 770 * global cold set to zero, we just call the driver 771 * initialization directly. 772 */ 773 if (!cold) 774 vmbus_bus_init(); 775} 776 777static int 778vmbus_detach(device_t dev) 779{ 780 struct vmbus_softc *sc = device_get_softc(dev); 781 782 hv_vmbus_release_unattached_channels(); 783 hv_vmbus_disconnect(); 784 785 if (sc->vmbus_flags & VMBUS_FLAG_SYNIC) { 786 sc->vmbus_flags &= ~VMBUS_FLAG_SYNIC; 787 smp_rendezvous(NULL, vmbus_synic_teardown, NULL, NULL); 788 } 789 790 vmbus_intr_teardown(sc); 791 vmbus_dma_free(sc); 792 793 return (0); 794} 795 796static device_method_t vmbus_methods[] = { 797 /* Device interface */ 798 DEVMETHOD(device_probe, vmbus_probe), 799 DEVMETHOD(device_attach, vmbus_attach), 800 DEVMETHOD(device_detach, vmbus_detach), 801 DEVMETHOD(device_shutdown, bus_generic_shutdown), 802 DEVMETHOD(device_suspend, bus_generic_suspend), 803 DEVMETHOD(device_resume, bus_generic_resume), 804 805 /* Bus interface */ 806 DEVMETHOD(bus_add_child, bus_generic_add_child), 807 DEVMETHOD(bus_print_child, bus_generic_print_child), 808 DEVMETHOD(bus_read_ivar, vmbus_read_ivar), 809 DEVMETHOD(bus_write_ivar, vmbus_write_ivar), 810 DEVMETHOD(bus_child_pnpinfo_str, vmbus_child_pnpinfo_str), 811 812 DEVMETHOD_END 813}; 814 815static driver_t vmbus_driver = { 816 "vmbus", 817 vmbus_methods, 818 sizeof(struct vmbus_softc) 819}; 820 821static devclass_t vmbus_devclass; 822 823DRIVER_MODULE(vmbus, acpi, vmbus_driver, vmbus_devclass, NULL, NULL); 824MODULE_DEPEND(vmbus, acpi, 1, 1, 1); 825MODULE_VERSION(vmbus, 1); 826 827/* 828 * NOTE: 829 * We have to start as the last step of SI_SUB_SMP, i.e. after SMP is 830 * initialized. 831 */ 832SYSINIT(vmbus_initialize, SI_SUB_SMP, SI_ORDER_ANY, vmbus_sysinit, NULL); 833 834