vmbus.c revision 300653
175295Sdes/*- 275295Sdes * Copyright (c) 2009-2012,2016 Microsoft Corp. 375295Sdes * Copyright (c) 2012 NetApp Inc. 475295Sdes * Copyright (c) 2012 Citrix Inc. 575295Sdes * All rights reserved. 675295Sdes * 775295Sdes * Redistribution and use in source and binary forms, with or without 875295Sdes * modification, are permitted provided that the following conditions 975295Sdes * are met: 1075295Sdes * 1. Redistributions of source code must retain the above copyright 1175295Sdes * notice unmodified, this list of conditions, and the following 1275295Sdes * disclaimer. 1375295Sdes * 2. Redistributions in binary form must reproduce the above copyright 1475295Sdes * notice, this list of conditions and the following disclaimer in the 1575295Sdes * documentation and/or other materials provided with the distribution. 1675295Sdes * 1775295Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1875295Sdes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1975295Sdes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2075295Sdes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2175295Sdes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2275295Sdes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2375295Sdes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2475295Sdes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2575295Sdes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2675295Sdes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2775295Sdes */ 2875295Sdes 2975295Sdes/* 3075295Sdes * VM Bus Driver Implementation 3175295Sdes */ 3275295Sdes#include <sys/cdefs.h> 3375295Sdes__FBSDID("$FreeBSD: head/sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c 300653 2016-05-25 05:45:43Z sephe $"); 3478073Sdes 3575295Sdes#include <sys/param.h> 3677965Sdes#include <sys/bus.h> 3784246Sdes#include <sys/kernel.h> 3875295Sdes#include <sys/lock.h> 3975295Sdes#include <sys/malloc.h> 4075295Sdes#include <sys/module.h> 4175295Sdes#include <sys/proc.h> 4275295Sdes#include <sys/sysctl.h> 4375295Sdes#include <sys/syslog.h> 4477998Sdes#include <sys/systm.h> 4575295Sdes#include <sys/rtprio.h> 4675295Sdes#include <sys/interrupt.h> 4789071Smsmith#include <sys/sx.h> 4884246Sdes#include <sys/taskqueue.h> 4975295Sdes#include <sys/mutex.h> 5075295Sdes#include <sys/smp.h> 5175295Sdes 5275295Sdes#include <machine/resource.h> 5384246Sdes#include <sys/rman.h> 5484246Sdes 5584246Sdes#include <machine/stdarg.h> 5684246Sdes#include <machine/intr_machdep.h> 5784246Sdes#include <machine/md_var.h> 5884246Sdes#include <machine/segments.h> 5984246Sdes#include <sys/pcpu.h> 6084246Sdes#include <x86/apicvar.h> 6184246Sdes 6284246Sdes#include <dev/hyperv/include/hyperv.h> 6375295Sdes#include <dev/hyperv/vmbus/hv_vmbus_priv.h> 6484246Sdes#include <dev/hyperv/vmbus/vmbus_var.h> 6584246Sdes 6675295Sdes#include <contrib/dev/acpica/include/acpi.h> 6775295Sdes#include "acpi_if.h" 6875295Sdes 6984246Sdesstruct vmbus_softc *vmbus_sc; 7084246Sdes 7175295Sdesstatic char *vmbus_ids[] = { "VMBUS", NULL }; 7275295Sdes 7375295Sdesextern inthand_t IDTVEC(hv_vmbus_callback); 7475295Sdes 7575295Sdesstatic void 7675295Sdesvmbus_msg_task(void *xsc, int pending __unused) 7775295Sdes{ 7875295Sdes struct vmbus_softc *sc = xsc; 7975295Sdes hv_vmbus_message *msg; 8075295Sdes 8193818Sjhb msg = VMBUS_PCPU_GET(sc, message, curcpu) + HV_VMBUS_MESSAGE_SINT; 8293818Sjhb for (;;) { 8384246Sdes const hv_vmbus_channel_msg_table_entry *entry; 8484246Sdes hv_vmbus_channel_msg_header *hdr; 8575295Sdes hv_vmbus_channel_msg_type msg_type; 8675295Sdes 8775295Sdes if (msg->header.message_type == HV_MESSAGE_TYPE_NONE) 8875295Sdes break; /* no message */ 8975295Sdes 9075295Sdes hdr = (hv_vmbus_channel_msg_header *)msg->u.payload; 9175295Sdes msg_type = hdr->message_type; 9275295Sdes 9384246Sdes if (msg_type >= HV_CHANNEL_MESSAGE_COUNT) { 9484386Sdes printf("VMBUS: unknown message type = %d\n", msg_type); 9584386Sdes goto handled; 9684386Sdes } 9775295Sdes 9875295Sdes entry = &g_channel_message_table[msg_type]; 9975295Sdes if (entry->messageHandler) 10075295Sdes entry->messageHandler(hdr); 10175295Sdeshandled: 10275295Sdes msg->header.message_type = HV_MESSAGE_TYPE_NONE; 10375295Sdes /* 10477998Sdes * Make sure the write to message_type (ie set to 10577998Sdes * HV_MESSAGE_TYPE_NONE) happens before we read the 10675295Sdes * message_pending and EOMing. Otherwise, the EOMing will 10777998Sdes * not deliver any more messages 10875295Sdes * since there is no empty slot 10988234Sdillon * 11088234Sdillon * NOTE: 11197940Sdes * mb() is used here, since atomic_thread_fence_seq_cst() 11288234Sdillon * will become compiler fence on UP kernel. 11388234Sdillon */ 11475295Sdes mb(); 11584246Sdes if (msg->header.message_flags.u.message_pending) { 116109969Stjr /* 117109969Stjr * This will cause message queue rescan to possibly 11884246Sdes * deliver another msg from the hypervisor 11975295Sdes */ 12084246Sdes wrmsr(HV_X64_MSR_EOM, 0); 12175295Sdes } 12288234Sdillon } 12388234Sdillon} 12499566Sjeff 12599566Sjeff/** 12675295Sdes * @brief Interrupt filter routine for VMBUS. 12775295Sdes * 12877998Sdes * The purpose of this routine is to determine the type of VMBUS protocol 12977998Sdes * message to process - an event or a channel message. 13077998Sdes */ 13177998Sdesstatic inline int 13277998Sdeshv_vmbus_isr(struct vmbus_softc *sc, struct trapframe *frame, int cpu) 13375295Sdes{ 13475295Sdes hv_vmbus_message *msg, *msg_base; 13575295Sdes 136111119Simp /* 13784246Sdes * The Windows team has advised that we check for events 13884246Sdes * before checking for messages. This is the way they do it 139103314Snjl * in Windows when running as a guest in Hyper-V 140105165Sphk */ 141105165Sphk sc->vmbus_event_proc(sc, cpu); 14275295Sdes 143105165Sphk /* Check if there are actual msgs to be process */ 14477998Sdes msg_base = VMBUS_PCPU_GET(sc, message, cpu); 14577998Sdes msg = msg_base + HV_VMBUS_TIMER_SINT; 14677998Sdes 14775295Sdes /* we call eventtimer process the message */ 14875295Sdes if (msg->header.message_type == HV_MESSAGE_TIMER_EXPIRED) { 149101308Sjeff msg->header.message_type = HV_MESSAGE_TYPE_NONE; 15075295Sdes 15175295Sdes /* call intrrupt handler of event timer */ 15275295Sdes hv_et_intr(frame); 15384246Sdes 15475295Sdes /* 15575295Sdes * Make sure the write to message_type (ie set to 15675295Sdes * HV_MESSAGE_TYPE_NONE) happens before we read the 15777998Sdes * message_pending and EOMing. Otherwise, the EOMing will 15875295Sdes * not deliver any more messages 15975295Sdes * since there is no empty slot 16075295Sdes * 16175295Sdes * NOTE: 16275295Sdes * mb() is used here, since atomic_thread_fence_seq_cst() 16375295Sdes * will become compiler fence on UP kernel. 16475295Sdes */ 16575295Sdes mb(); 16677998Sdes 16777998Sdes if (msg->header.message_flags.u.message_pending) { 16875295Sdes /* 16975295Sdes * This will cause message queue rescan to possibly 17075295Sdes * deliver another msg from the hypervisor 171103314Snjl */ 172103314Snjl wrmsr(HV_X64_MSR_EOM, 0); 173103314Snjl } 174103314Snjl } 175103314Snjl 176103314Snjl msg = msg_base + HV_VMBUS_MESSAGE_SINT; 17784246Sdes if (msg->header.message_type != HV_MESSAGE_TYPE_NONE) { 17877998Sdes taskqueue_enqueue(VMBUS_PCPU_GET(sc, message_tq, cpu), 17984246Sdes VMBUS_PCPU_PTR(sc, message_task, cpu)); 18084246Sdes } 18184246Sdes 18284246Sdes return (FILTER_HANDLED); 18384246Sdes} 18475295Sdes 185105077Smckusickvoid 18699566Sjeffhv_vector_handler(struct trapframe *trap_frame) 18775295Sdes{ 18875295Sdes struct vmbus_softc *sc = vmbus_get_softc(); 18975295Sdes int cpu = curcpu; 19075295Sdes 19175295Sdes /* 19275295Sdes * Disable preemption. 19375295Sdes */ 19475295Sdes critical_enter(); 19575295Sdes 19677998Sdes /* 19788234Sdillon * Do a little interrupt counting. 19888234Sdillon */ 19997940Sdes (*VMBUS_PCPU_GET(sc, intr_cnt, cpu))++; 20075295Sdes 20184246Sdes hv_vmbus_isr(sc, trap_frame, cpu); 20284246Sdes 20384246Sdes /* 20484246Sdes * Enable preemption. 20584246Sdes */ 20684246Sdes critical_exit(); 20777998Sdes} 20884246Sdes 20977998Sdesstatic void 21084246Sdesvmbus_synic_setup(void *xsc) 21184246Sdes{ 21277998Sdes struct vmbus_softc *sc = xsc; 21375295Sdes int cpu; 21475295Sdes hv_vmbus_synic_simp simp; 21575295Sdes hv_vmbus_synic_siefp siefp; 21684246Sdes hv_vmbus_synic_scontrol sctrl; 21784246Sdes hv_vmbus_synic_sint shared_sint; 21884246Sdes 21984246Sdes cpu = PCPU_GET(cpuid); 22084246Sdes 22184246Sdes /* 22284246Sdes * Setup the Synic's message page 22384246Sdes */ 22484246Sdes simp.as_uint64_t = rdmsr(HV_X64_MSR_SIMP); 22584246Sdes simp.u.simp_enabled = 1; 22684246Sdes simp.u.base_simp_gpa = 22784246Sdes VMBUS_PCPU_GET(sc, message_dma.hv_paddr, cpu) >> PAGE_SHIFT; 22884246Sdes 22984246Sdes wrmsr(HV_X64_MSR_SIMP, simp.as_uint64_t); 23084246Sdes 23184246Sdes /* 23284246Sdes * Setup the Synic's event page 23384246Sdes */ 23484246Sdes siefp.as_uint64_t = rdmsr(HV_X64_MSR_SIEFP); 23584246Sdes siefp.u.siefp_enabled = 1; 23684246Sdes siefp.u.base_siefp_gpa = 23784246Sdes VMBUS_PCPU_GET(sc, event_flag_dma.hv_paddr, cpu) >> PAGE_SHIFT; 23888868Stanimura 23988868Stanimura wrmsr(HV_X64_MSR_SIEFP, siefp.as_uint64_t); 24084246Sdes 24184246Sdes /*HV_SHARED_SINT_IDT_VECTOR + 0x20; */ 24284246Sdes shared_sint.as_uint64_t = 0; 24384386Sdes shared_sint.u.vector = sc->vmbus_idtvec; 24484386Sdes shared_sint.u.masked = FALSE; 24584386Sdes shared_sint.u.auto_eoi = TRUE; 24684386Sdes 24784386Sdes wrmsr(HV_X64_MSR_SINT0 + HV_VMBUS_MESSAGE_SINT, 24884386Sdes shared_sint.as_uint64_t); 24984386Sdes 25084386Sdes wrmsr(HV_X64_MSR_SINT0 + HV_VMBUS_TIMER_SINT, 25197940Sdes shared_sint.as_uint64_t); 25284386Sdes 25384386Sdes /* Enable the global synic bit */ 25484386Sdes sctrl.as_uint64_t = rdmsr(HV_X64_MSR_SCONTROL); 25584386Sdes sctrl.u.enable = 1; 25684386Sdes 25784386Sdes wrmsr(HV_X64_MSR_SCONTROL, sctrl.as_uint64_t); 25884386Sdes 25984386Sdes /* 26084386Sdes * Set up the cpuid mapping from Hyper-V to FreeBSD. 26184386Sdes * The array is indexed using FreeBSD cpuid. 26284386Sdes */ 26384386Sdes VMBUS_PCPU_GET(sc, vcpuid, cpu) = rdmsr(HV_X64_MSR_VP_INDEX); 26488868Stanimura} 26588868Stanimura 26684386Sdesstatic void 26784386Sdesvmbus_synic_teardown(void *arg) 26884386Sdes{ 26984386Sdes hv_vmbus_synic_sint shared_sint; 27084386Sdes hv_vmbus_synic_simp simp; 27184386Sdes hv_vmbus_synic_siefp siefp; 27284386Sdes 27384386Sdes shared_sint.as_uint64_t = rdmsr( 27484386Sdes HV_X64_MSR_SINT0 + HV_VMBUS_MESSAGE_SINT); 27584386Sdes 27684386Sdes shared_sint.u.masked = 1; 27784386Sdes 27884386Sdes /* 27984386Sdes * Disable the interrupt 0 280 */ 281 wrmsr( 282 HV_X64_MSR_SINT0 + HV_VMBUS_MESSAGE_SINT, 283 shared_sint.as_uint64_t); 284 285 shared_sint.as_uint64_t = rdmsr( 286 HV_X64_MSR_SINT0 + HV_VMBUS_TIMER_SINT); 287 288 shared_sint.u.masked = 1; 289 290 /* 291 * Disable the interrupt 1 292 */ 293 wrmsr( 294 HV_X64_MSR_SINT0 + HV_VMBUS_TIMER_SINT, 295 shared_sint.as_uint64_t); 296 simp.as_uint64_t = rdmsr(HV_X64_MSR_SIMP); 297 simp.u.simp_enabled = 0; 298 simp.u.base_simp_gpa = 0; 299 300 wrmsr(HV_X64_MSR_SIMP, simp.as_uint64_t); 301 302 siefp.as_uint64_t = rdmsr(HV_X64_MSR_SIEFP); 303 siefp.u.siefp_enabled = 0; 304 siefp.u.base_siefp_gpa = 0; 305 306 wrmsr(HV_X64_MSR_SIEFP, siefp.as_uint64_t); 307} 308 309static int 310vmbus_dma_alloc(struct vmbus_softc *sc) 311{ 312 int cpu; 313 314 CPU_FOREACH(cpu) { 315 void *ptr; 316 317 /* 318 * Per-cpu messages and event flags. 319 */ 320 ptr = hyperv_dmamem_alloc(bus_get_dma_tag(sc->vmbus_dev), 321 PAGE_SIZE, 0, PAGE_SIZE, 322 VMBUS_PCPU_PTR(sc, message_dma, cpu), 323 BUS_DMA_WAITOK | BUS_DMA_ZERO); 324 if (ptr == NULL) 325 return ENOMEM; 326 VMBUS_PCPU_GET(sc, message, cpu) = ptr; 327 328 ptr = hyperv_dmamem_alloc(bus_get_dma_tag(sc->vmbus_dev), 329 PAGE_SIZE, 0, PAGE_SIZE, 330 VMBUS_PCPU_PTR(sc, event_flag_dma, cpu), 331 BUS_DMA_WAITOK | BUS_DMA_ZERO); 332 if (ptr == NULL) 333 return ENOMEM; 334 VMBUS_PCPU_GET(sc, event_flag, cpu) = ptr; 335 } 336 return 0; 337} 338 339static void 340vmbus_dma_free(struct vmbus_softc *sc) 341{ 342 int cpu; 343 344 CPU_FOREACH(cpu) { 345 if (VMBUS_PCPU_GET(sc, message, cpu) != NULL) { 346 hyperv_dmamem_free( 347 VMBUS_PCPU_PTR(sc, message_dma, cpu), 348 VMBUS_PCPU_GET(sc, message, cpu)); 349 VMBUS_PCPU_GET(sc, message, cpu) = NULL; 350 } 351 if (VMBUS_PCPU_GET(sc, event_flag, cpu) != NULL) { 352 hyperv_dmamem_free( 353 VMBUS_PCPU_PTR(sc, event_flag_dma, cpu), 354 VMBUS_PCPU_GET(sc, event_flag, cpu)); 355 VMBUS_PCPU_GET(sc, event_flag, cpu) = NULL; 356 } 357 } 358} 359 360static int 361vmbus_intr_setup(struct vmbus_softc *sc) 362{ 363 int cpu; 364 365 CPU_FOREACH(cpu) { 366 char buf[MAXCOMLEN + 1]; 367 cpuset_t cpu_mask; 368 369 /* Allocate an interrupt counter for Hyper-V interrupt */ 370 snprintf(buf, sizeof(buf), "cpu%d:hyperv", cpu); 371 intrcnt_add(buf, VMBUS_PCPU_PTR(sc, intr_cnt, cpu)); 372 373 /* 374 * Setup taskqueue to handle events. Task will be per- 375 * channel. 376 */ 377 VMBUS_PCPU_GET(sc, event_tq, cpu) = taskqueue_create_fast( 378 "hyperv event", M_WAITOK, taskqueue_thread_enqueue, 379 VMBUS_PCPU_PTR(sc, event_tq, cpu)); 380 CPU_SETOF(cpu, &cpu_mask); 381 taskqueue_start_threads_cpuset( 382 VMBUS_PCPU_PTR(sc, event_tq, cpu), 1, PI_NET, &cpu_mask, 383 "hvevent%d", cpu); 384 385 /* 386 * Setup tasks and taskqueues to handle messages. 387 */ 388 VMBUS_PCPU_GET(sc, message_tq, cpu) = taskqueue_create_fast( 389 "hyperv msg", M_WAITOK, taskqueue_thread_enqueue, 390 VMBUS_PCPU_PTR(sc, message_tq, cpu)); 391 CPU_SETOF(cpu, &cpu_mask); 392 taskqueue_start_threads_cpuset( 393 VMBUS_PCPU_PTR(sc, message_tq, cpu), 1, PI_NET, &cpu_mask, 394 "hvmsg%d", cpu); 395 TASK_INIT(VMBUS_PCPU_PTR(sc, message_task, cpu), 0, 396 vmbus_msg_task, sc); 397 } 398 399 /* 400 * All Hyper-V ISR required resources are setup, now let's find a 401 * free IDT vector for Hyper-V ISR and set it up. 402 */ 403 sc->vmbus_idtvec = lapic_ipi_alloc(IDTVEC(hv_vmbus_callback)); 404 if (sc->vmbus_idtvec < 0) { 405 device_printf(sc->vmbus_dev, "cannot find free IDT vector\n"); 406 return ENXIO; 407 } 408 if(bootverbose) { 409 device_printf(sc->vmbus_dev, "vmbus IDT vector %d\n", 410 sc->vmbus_idtvec); 411 } 412 return 0; 413} 414 415static void 416vmbus_intr_teardown(struct vmbus_softc *sc) 417{ 418 int cpu; 419 420 if (sc->vmbus_idtvec >= 0) { 421 lapic_ipi_free(sc->vmbus_idtvec); 422 sc->vmbus_idtvec = -1; 423 } 424 425 CPU_FOREACH(cpu) { 426 if (VMBUS_PCPU_GET(sc, event_tq, cpu) != NULL) { 427 taskqueue_free(VMBUS_PCPU_GET(sc, event_tq, cpu)); 428 VMBUS_PCPU_GET(sc, event_tq, cpu) = NULL; 429 } 430 if (VMBUS_PCPU_GET(sc, message_tq, cpu) != NULL) { 431 taskqueue_drain(VMBUS_PCPU_GET(sc, message_tq, cpu), 432 VMBUS_PCPU_PTR(sc, message_task, cpu)); 433 taskqueue_free(VMBUS_PCPU_GET(sc, message_tq, cpu)); 434 VMBUS_PCPU_GET(sc, message_tq, cpu) = NULL; 435 } 436 } 437} 438 439static int 440vmbus_read_ivar(device_t dev, device_t child, int index, uintptr_t *result) 441{ 442 struct hv_device *child_dev_ctx = device_get_ivars(child); 443 444 switch (index) { 445 case HV_VMBUS_IVAR_TYPE: 446 *result = (uintptr_t) &child_dev_ctx->class_id; 447 return (0); 448 case HV_VMBUS_IVAR_INSTANCE: 449 *result = (uintptr_t) &child_dev_ctx->device_id; 450 return (0); 451 case HV_VMBUS_IVAR_DEVCTX: 452 *result = (uintptr_t) child_dev_ctx; 453 return (0); 454 case HV_VMBUS_IVAR_NODE: 455 *result = (uintptr_t) child_dev_ctx->device; 456 return (0); 457 } 458 return (ENOENT); 459} 460 461static int 462vmbus_write_ivar(device_t dev, device_t child, int index, uintptr_t value) 463{ 464 switch (index) { 465 case HV_VMBUS_IVAR_TYPE: 466 case HV_VMBUS_IVAR_INSTANCE: 467 case HV_VMBUS_IVAR_DEVCTX: 468 case HV_VMBUS_IVAR_NODE: 469 /* read-only */ 470 return (EINVAL); 471 } 472 return (ENOENT); 473} 474 475static int 476vmbus_child_pnpinfo_str(device_t dev, device_t child, char *buf, size_t buflen) 477{ 478 char guidbuf[40]; 479 struct hv_device *dev_ctx = device_get_ivars(child); 480 481 if (dev_ctx == NULL) 482 return (0); 483 484 strlcat(buf, "classid=", buflen); 485 snprintf_hv_guid(guidbuf, sizeof(guidbuf), &dev_ctx->class_id); 486 strlcat(buf, guidbuf, buflen); 487 488 strlcat(buf, " deviceid=", buflen); 489 snprintf_hv_guid(guidbuf, sizeof(guidbuf), &dev_ctx->device_id); 490 strlcat(buf, guidbuf, buflen); 491 492 return (0); 493} 494 495struct hv_device * 496hv_vmbus_child_device_create(hv_guid type, hv_guid instance, 497 hv_vmbus_channel *channel) 498{ 499 hv_device *child_dev; 500 501 /* 502 * Allocate the new child device 503 */ 504 child_dev = malloc(sizeof(hv_device), M_DEVBUF, M_WAITOK | M_ZERO); 505 506 child_dev->channel = channel; 507 memcpy(&child_dev->class_id, &type, sizeof(hv_guid)); 508 memcpy(&child_dev->device_id, &instance, sizeof(hv_guid)); 509 510 return (child_dev); 511} 512 513int 514snprintf_hv_guid(char *buf, size_t sz, const hv_guid *guid) 515{ 516 int cnt; 517 const unsigned char *d = guid->data; 518 519 cnt = snprintf(buf, sz, 520 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", 521 d[3], d[2], d[1], d[0], d[5], d[4], d[7], d[6], 522 d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]); 523 return (cnt); 524} 525 526int 527hv_vmbus_child_device_register(struct hv_device *child_dev) 528{ 529 device_t child; 530 531 if (bootverbose) { 532 char name[40]; 533 snprintf_hv_guid(name, sizeof(name), &child_dev->class_id); 534 printf("VMBUS: Class ID: %s\n", name); 535 } 536 537 child = device_add_child(vmbus_get_device(), NULL, -1); 538 child_dev->device = child; 539 device_set_ivars(child, child_dev); 540 541 return (0); 542} 543 544int 545hv_vmbus_child_device_unregister(struct hv_device *child_dev) 546{ 547 int ret = 0; 548 /* 549 * XXXKYS: Ensure that this is the opposite of 550 * device_add_child() 551 */ 552 mtx_lock(&Giant); 553 ret = device_delete_child(vmbus_get_device(), child_dev->device); 554 mtx_unlock(&Giant); 555 return(ret); 556} 557 558static int 559vmbus_probe(device_t dev) 560{ 561 if (ACPI_ID_PROBE(device_get_parent(dev), dev, vmbus_ids) == NULL || 562 device_get_unit(dev) != 0 || vm_guest != VM_GUEST_HV) 563 return (ENXIO); 564 565 device_set_desc(dev, "Hyper-V Vmbus"); 566 567 return (BUS_PROBE_DEFAULT); 568} 569 570/** 571 * @brief Main vmbus driver initialization routine. 572 * 573 * Here, we 574 * - initialize the vmbus driver context 575 * - setup various driver entry points 576 * - invoke the vmbus hv main init routine 577 * - get the irq resource 578 * - invoke the vmbus to add the vmbus root device 579 * - setup the vmbus root device 580 * - retrieve the channel offers 581 */ 582static int 583vmbus_bus_init(void) 584{ 585 struct vmbus_softc *sc = vmbus_get_softc(); 586 int ret; 587 588 if (sc->vmbus_flags & VMBUS_FLAG_ATTACHED) 589 return (0); 590 sc->vmbus_flags |= VMBUS_FLAG_ATTACHED; 591 592 /* 593 * Allocate DMA stuffs. 594 */ 595 ret = vmbus_dma_alloc(sc); 596 if (ret != 0) 597 goto cleanup; 598 599 /* 600 * Setup interrupt. 601 */ 602 ret = vmbus_intr_setup(sc); 603 if (ret != 0) 604 goto cleanup; 605 606 /* 607 * Setup SynIC. 608 */ 609 if (bootverbose) 610 device_printf(sc->vmbus_dev, "smp_started = %d\n", smp_started); 611 smp_rendezvous(NULL, vmbus_synic_setup, NULL, sc); 612 sc->vmbus_flags |= VMBUS_FLAG_SYNIC; 613 614 /* 615 * Connect to VMBus in the root partition 616 */ 617 ret = hv_vmbus_connect(); 618 619 if (ret != 0) 620 goto cleanup; 621 622 if (hv_vmbus_protocal_version == HV_VMBUS_VERSION_WS2008 || 623 hv_vmbus_protocal_version == HV_VMBUS_VERSION_WIN7) 624 sc->vmbus_event_proc = vmbus_event_proc_compat; 625 else 626 sc->vmbus_event_proc = vmbus_event_proc; 627 628 hv_vmbus_request_channel_offers(); 629 630 vmbus_scan(); 631 bus_generic_attach(sc->vmbus_dev); 632 device_printf(sc->vmbus_dev, "device scan, probe and attach done\n"); 633 634 return (ret); 635 636cleanup: 637 vmbus_intr_teardown(sc); 638 vmbus_dma_free(sc); 639 640 return (ret); 641} 642 643static void 644vmbus_event_proc_dummy(struct vmbus_softc *sc __unused, int cpu __unused) 645{ 646} 647 648static int 649vmbus_attach(device_t dev) 650{ 651 vmbus_sc = device_get_softc(dev); 652 vmbus_sc->vmbus_dev = dev; 653 vmbus_sc->vmbus_idtvec = -1; 654 655 /* 656 * Event processing logic will be configured: 657 * - After the vmbus protocol version negotiation. 658 * - Before we request channel offers. 659 */ 660 vmbus_sc->vmbus_event_proc = vmbus_event_proc_dummy; 661 662#ifndef EARLY_AP_STARTUP 663 /* 664 * If the system has already booted and thread 665 * scheduling is possible indicated by the global 666 * cold set to zero, we just call the driver 667 * initialization directly. 668 */ 669 if (!cold) 670#endif 671 vmbus_bus_init(); 672 673 bus_generic_probe(dev); 674 return (0); 675} 676 677static void 678vmbus_sysinit(void *arg __unused) 679{ 680 if (vm_guest != VM_GUEST_HV || vmbus_get_softc() == NULL) 681 return; 682 683#ifndef EARLY_AP_STARTUP 684 /* 685 * If the system has already booted and thread 686 * scheduling is possible, as indicated by the 687 * global cold set to zero, we just call the driver 688 * initialization directly. 689 */ 690 if (!cold) 691#endif 692 vmbus_bus_init(); 693} 694 695static int 696vmbus_detach(device_t dev) 697{ 698 struct vmbus_softc *sc = device_get_softc(dev); 699 700 hv_vmbus_release_unattached_channels(); 701 hv_vmbus_disconnect(); 702 703 if (sc->vmbus_flags & VMBUS_FLAG_SYNIC) { 704 sc->vmbus_flags &= ~VMBUS_FLAG_SYNIC; 705 smp_rendezvous(NULL, vmbus_synic_teardown, NULL, NULL); 706 } 707 708 vmbus_intr_teardown(sc); 709 vmbus_dma_free(sc); 710 711 return (0); 712} 713 714static device_method_t vmbus_methods[] = { 715 /* Device interface */ 716 DEVMETHOD(device_probe, vmbus_probe), 717 DEVMETHOD(device_attach, vmbus_attach), 718 DEVMETHOD(device_detach, vmbus_detach), 719 DEVMETHOD(device_shutdown, bus_generic_shutdown), 720 DEVMETHOD(device_suspend, bus_generic_suspend), 721 DEVMETHOD(device_resume, bus_generic_resume), 722 723 /* Bus interface */ 724 DEVMETHOD(bus_add_child, bus_generic_add_child), 725 DEVMETHOD(bus_print_child, bus_generic_print_child), 726 DEVMETHOD(bus_read_ivar, vmbus_read_ivar), 727 DEVMETHOD(bus_write_ivar, vmbus_write_ivar), 728 DEVMETHOD(bus_child_pnpinfo_str, vmbus_child_pnpinfo_str), 729 730 DEVMETHOD_END 731}; 732 733static driver_t vmbus_driver = { 734 "vmbus", 735 vmbus_methods, 736 sizeof(struct vmbus_softc) 737}; 738 739static devclass_t vmbus_devclass; 740 741DRIVER_MODULE(vmbus, acpi, vmbus_driver, vmbus_devclass, NULL, NULL); 742MODULE_DEPEND(vmbus, acpi, 1, 1, 1); 743MODULE_VERSION(vmbus, 1); 744 745#ifndef EARLY_AP_STARTUP 746/* 747 * NOTE: 748 * We have to start as the last step of SI_SUB_SMP, i.e. after SMP is 749 * initialized. 750 */ 751SYSINIT(vmbus_initialize, SI_SUB_SMP, SI_ORDER_ANY, vmbus_sysinit, NULL); 752#endif 753