vmbus.c revision 307466
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/11/sys/dev/hyperv/vmbus/vmbus.c 307466 2016-10-17 03:48:22Z 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/mutex.h> 42#include <sys/smp.h> 43#include <sys/sysctl.h> 44#include <sys/systm.h> 45#include <sys/taskqueue.h> 46 47#include <machine/intr_machdep.h> 48#include <x86/include/apicvar.h> 49 50#include <contrib/dev/acpica/include/acpi.h> 51 52#include <dev/hyperv/include/hyperv.h> 53#include <dev/hyperv/vmbus/hyperv_reg.h> 54#include <dev/hyperv/vmbus/hyperv_var.h> 55#include <dev/hyperv/vmbus/vmbus_reg.h> 56#include <dev/hyperv/vmbus/vmbus_var.h> 57#include <dev/hyperv/vmbus/vmbus_chanvar.h> 58 59#include "acpi_if.h" 60#include "vmbus_if.h" 61 62#define VMBUS_GPADL_START 0xe1e10 63 64struct vmbus_msghc { 65 struct hypercall_postmsg_in *mh_inprm; 66 struct hypercall_postmsg_in mh_inprm_save; 67 struct hyperv_dma mh_inprm_dma; 68 69 struct vmbus_message *mh_resp; 70 struct vmbus_message mh_resp0; 71}; 72 73struct vmbus_msghc_ctx { 74 struct vmbus_msghc *mhc_free; 75 struct mtx mhc_free_lock; 76 uint32_t mhc_flags; 77 78 struct vmbus_msghc *mhc_active; 79 struct mtx mhc_active_lock; 80}; 81 82#define VMBUS_MSGHC_CTXF_DESTROY 0x0001 83 84static int vmbus_probe(device_t); 85static int vmbus_attach(device_t); 86static int vmbus_detach(device_t); 87static int vmbus_read_ivar(device_t, device_t, int, 88 uintptr_t *); 89static int vmbus_child_pnpinfo_str(device_t, device_t, 90 char *, size_t); 91static uint32_t vmbus_get_version_method(device_t, device_t); 92static int vmbus_probe_guid_method(device_t, device_t, 93 const struct hyperv_guid *); 94 95static int vmbus_init(struct vmbus_softc *); 96static int vmbus_connect(struct vmbus_softc *, uint32_t); 97static int vmbus_req_channels(struct vmbus_softc *sc); 98static void vmbus_disconnect(struct vmbus_softc *); 99static int vmbus_scan(struct vmbus_softc *); 100static void vmbus_scan_wait(struct vmbus_softc *); 101static void vmbus_scan_newchan(struct vmbus_softc *); 102static void vmbus_scan_newdev(struct vmbus_softc *); 103static void vmbus_scan_done(struct vmbus_softc *, 104 const struct vmbus_message *); 105static void vmbus_chanmsg_handle(struct vmbus_softc *, 106 const struct vmbus_message *); 107static void vmbus_msg_task(void *, int); 108static void vmbus_synic_setup(void *); 109static void vmbus_synic_teardown(void *); 110static int vmbus_sysctl_version(SYSCTL_HANDLER_ARGS); 111static int vmbus_dma_alloc(struct vmbus_softc *); 112static void vmbus_dma_free(struct vmbus_softc *); 113static int vmbus_intr_setup(struct vmbus_softc *); 114static void vmbus_intr_teardown(struct vmbus_softc *); 115static int vmbus_doattach(struct vmbus_softc *); 116static void vmbus_event_proc_dummy(struct vmbus_softc *, 117 int); 118 119static struct vmbus_msghc_ctx *vmbus_msghc_ctx_create(bus_dma_tag_t); 120static void vmbus_msghc_ctx_destroy( 121 struct vmbus_msghc_ctx *); 122static void vmbus_msghc_ctx_free(struct vmbus_msghc_ctx *); 123static struct vmbus_msghc *vmbus_msghc_alloc(bus_dma_tag_t); 124static void vmbus_msghc_free(struct vmbus_msghc *); 125static struct vmbus_msghc *vmbus_msghc_get1(struct vmbus_msghc_ctx *, 126 uint32_t); 127 128static struct vmbus_softc *vmbus_sc; 129 130extern inthand_t IDTVEC(vmbus_isr); 131 132static const uint32_t vmbus_version[] = { 133 VMBUS_VERSION_WIN8_1, 134 VMBUS_VERSION_WIN8, 135 VMBUS_VERSION_WIN7, 136 VMBUS_VERSION_WS2008 137}; 138 139static const vmbus_chanmsg_proc_t 140vmbus_chanmsg_handlers[VMBUS_CHANMSG_TYPE_MAX] = { 141 VMBUS_CHANMSG_PROC(CHOFFER_DONE, vmbus_scan_done), 142 VMBUS_CHANMSG_PROC_WAKEUP(CONNECT_RESP) 143}; 144 145static device_method_t vmbus_methods[] = { 146 /* Device interface */ 147 DEVMETHOD(device_probe, vmbus_probe), 148 DEVMETHOD(device_attach, vmbus_attach), 149 DEVMETHOD(device_detach, vmbus_detach), 150 DEVMETHOD(device_shutdown, bus_generic_shutdown), 151 DEVMETHOD(device_suspend, bus_generic_suspend), 152 DEVMETHOD(device_resume, bus_generic_resume), 153 154 /* Bus interface */ 155 DEVMETHOD(bus_add_child, bus_generic_add_child), 156 DEVMETHOD(bus_print_child, bus_generic_print_child), 157 DEVMETHOD(bus_read_ivar, vmbus_read_ivar), 158 DEVMETHOD(bus_child_pnpinfo_str, vmbus_child_pnpinfo_str), 159 160 /* Vmbus interface */ 161 DEVMETHOD(vmbus_get_version, vmbus_get_version_method), 162 DEVMETHOD(vmbus_probe_guid, vmbus_probe_guid_method), 163 164 DEVMETHOD_END 165}; 166 167static driver_t vmbus_driver = { 168 "vmbus", 169 vmbus_methods, 170 sizeof(struct vmbus_softc) 171}; 172 173static devclass_t vmbus_devclass; 174 175DRIVER_MODULE(vmbus, acpi, vmbus_driver, vmbus_devclass, NULL, NULL); 176MODULE_DEPEND(vmbus, acpi, 1, 1, 1); 177MODULE_VERSION(vmbus, 1); 178 179static __inline struct vmbus_softc * 180vmbus_get_softc(void) 181{ 182 return vmbus_sc; 183} 184 185static struct vmbus_msghc * 186vmbus_msghc_alloc(bus_dma_tag_t parent_dtag) 187{ 188 struct vmbus_msghc *mh; 189 190 mh = malloc(sizeof(*mh), M_DEVBUF, M_WAITOK | M_ZERO); 191 192 mh->mh_inprm = hyperv_dmamem_alloc(parent_dtag, 193 HYPERCALL_PARAM_ALIGN, 0, HYPERCALL_POSTMSGIN_SIZE, 194 &mh->mh_inprm_dma, BUS_DMA_WAITOK); 195 if (mh->mh_inprm == NULL) { 196 free(mh, M_DEVBUF); 197 return NULL; 198 } 199 return mh; 200} 201 202static void 203vmbus_msghc_free(struct vmbus_msghc *mh) 204{ 205 hyperv_dmamem_free(&mh->mh_inprm_dma, mh->mh_inprm); 206 free(mh, M_DEVBUF); 207} 208 209static void 210vmbus_msghc_ctx_free(struct vmbus_msghc_ctx *mhc) 211{ 212 KASSERT(mhc->mhc_active == NULL, ("still have active msg hypercall")); 213 KASSERT(mhc->mhc_free == NULL, ("still have hypercall msg")); 214 215 mtx_destroy(&mhc->mhc_free_lock); 216 mtx_destroy(&mhc->mhc_active_lock); 217 free(mhc, M_DEVBUF); 218} 219 220static struct vmbus_msghc_ctx * 221vmbus_msghc_ctx_create(bus_dma_tag_t parent_dtag) 222{ 223 struct vmbus_msghc_ctx *mhc; 224 225 mhc = malloc(sizeof(*mhc), M_DEVBUF, M_WAITOK | M_ZERO); 226 mtx_init(&mhc->mhc_free_lock, "vmbus msghc free", NULL, MTX_DEF); 227 mtx_init(&mhc->mhc_active_lock, "vmbus msghc act", NULL, MTX_DEF); 228 229 mhc->mhc_free = vmbus_msghc_alloc(parent_dtag); 230 if (mhc->mhc_free == NULL) { 231 vmbus_msghc_ctx_free(mhc); 232 return NULL; 233 } 234 return mhc; 235} 236 237static struct vmbus_msghc * 238vmbus_msghc_get1(struct vmbus_msghc_ctx *mhc, uint32_t dtor_flag) 239{ 240 struct vmbus_msghc *mh; 241 242 mtx_lock(&mhc->mhc_free_lock); 243 244 while ((mhc->mhc_flags & dtor_flag) == 0 && mhc->mhc_free == NULL) { 245 mtx_sleep(&mhc->mhc_free, &mhc->mhc_free_lock, 0, 246 "gmsghc", 0); 247 } 248 if (mhc->mhc_flags & dtor_flag) { 249 /* Being destroyed */ 250 mh = NULL; 251 } else { 252 mh = mhc->mhc_free; 253 KASSERT(mh != NULL, ("no free hypercall msg")); 254 KASSERT(mh->mh_resp == NULL, 255 ("hypercall msg has pending response")); 256 mhc->mhc_free = NULL; 257 } 258 259 mtx_unlock(&mhc->mhc_free_lock); 260 261 return mh; 262} 263 264void 265vmbus_msghc_reset(struct vmbus_msghc *mh, size_t dsize) 266{ 267 struct hypercall_postmsg_in *inprm; 268 269 if (dsize > HYPERCALL_POSTMSGIN_DSIZE_MAX) 270 panic("invalid data size %zu", dsize); 271 272 inprm = mh->mh_inprm; 273 memset(inprm, 0, HYPERCALL_POSTMSGIN_SIZE); 274 inprm->hc_connid = VMBUS_CONNID_MESSAGE; 275 inprm->hc_msgtype = HYPERV_MSGTYPE_CHANNEL; 276 inprm->hc_dsize = dsize; 277} 278 279struct vmbus_msghc * 280vmbus_msghc_get(struct vmbus_softc *sc, size_t dsize) 281{ 282 struct vmbus_msghc *mh; 283 284 if (dsize > HYPERCALL_POSTMSGIN_DSIZE_MAX) 285 panic("invalid data size %zu", dsize); 286 287 mh = vmbus_msghc_get1(sc->vmbus_msg_hc, VMBUS_MSGHC_CTXF_DESTROY); 288 if (mh == NULL) 289 return NULL; 290 291 vmbus_msghc_reset(mh, dsize); 292 return mh; 293} 294 295void 296vmbus_msghc_put(struct vmbus_softc *sc, struct vmbus_msghc *mh) 297{ 298 struct vmbus_msghc_ctx *mhc = sc->vmbus_msg_hc; 299 300 KASSERT(mhc->mhc_active == NULL, ("msg hypercall is active")); 301 mh->mh_resp = NULL; 302 303 mtx_lock(&mhc->mhc_free_lock); 304 KASSERT(mhc->mhc_free == NULL, ("has free hypercall msg")); 305 mhc->mhc_free = mh; 306 mtx_unlock(&mhc->mhc_free_lock); 307 wakeup(&mhc->mhc_free); 308} 309 310void * 311vmbus_msghc_dataptr(struct vmbus_msghc *mh) 312{ 313 return mh->mh_inprm->hc_data; 314} 315 316static void 317vmbus_msghc_ctx_destroy(struct vmbus_msghc_ctx *mhc) 318{ 319 struct vmbus_msghc *mh; 320 321 mtx_lock(&mhc->mhc_free_lock); 322 mhc->mhc_flags |= VMBUS_MSGHC_CTXF_DESTROY; 323 mtx_unlock(&mhc->mhc_free_lock); 324 wakeup(&mhc->mhc_free); 325 326 mh = vmbus_msghc_get1(mhc, 0); 327 if (mh == NULL) 328 panic("can't get msghc"); 329 330 vmbus_msghc_free(mh); 331 vmbus_msghc_ctx_free(mhc); 332} 333 334int 335vmbus_msghc_exec_noresult(struct vmbus_msghc *mh) 336{ 337 sbintime_t time = SBT_1MS; 338 int i; 339 340 /* 341 * Save the input parameter so that we could restore the input 342 * parameter if the Hypercall failed. 343 * 344 * XXX 345 * Is this really necessary?! i.e. Will the Hypercall ever 346 * overwrite the input parameter? 347 */ 348 memcpy(&mh->mh_inprm_save, mh->mh_inprm, HYPERCALL_POSTMSGIN_SIZE); 349 350 /* 351 * In order to cope with transient failures, e.g. insufficient 352 * resources on host side, we retry the post message Hypercall 353 * several times. 20 retries seem sufficient. 354 */ 355#define HC_RETRY_MAX 20 356 357 for (i = 0; i < HC_RETRY_MAX; ++i) { 358 uint64_t status; 359 360 status = hypercall_post_message(mh->mh_inprm_dma.hv_paddr); 361 if (status == HYPERCALL_STATUS_SUCCESS) 362 return 0; 363 364 pause_sbt("hcpmsg", time, 0, C_HARDCLOCK); 365 if (time < SBT_1S * 2) 366 time *= 2; 367 368 /* Restore input parameter and try again */ 369 memcpy(mh->mh_inprm, &mh->mh_inprm_save, 370 HYPERCALL_POSTMSGIN_SIZE); 371 } 372 373#undef HC_RETRY_MAX 374 375 return EIO; 376} 377 378int 379vmbus_msghc_exec(struct vmbus_softc *sc, struct vmbus_msghc *mh) 380{ 381 struct vmbus_msghc_ctx *mhc = sc->vmbus_msg_hc; 382 int error; 383 384 KASSERT(mh->mh_resp == NULL, ("hypercall msg has pending response")); 385 386 mtx_lock(&mhc->mhc_active_lock); 387 KASSERT(mhc->mhc_active == NULL, ("pending active msg hypercall")); 388 mhc->mhc_active = mh; 389 mtx_unlock(&mhc->mhc_active_lock); 390 391 error = vmbus_msghc_exec_noresult(mh); 392 if (error) { 393 mtx_lock(&mhc->mhc_active_lock); 394 KASSERT(mhc->mhc_active == mh, ("msghc mismatch")); 395 mhc->mhc_active = NULL; 396 mtx_unlock(&mhc->mhc_active_lock); 397 } 398 return error; 399} 400 401const struct vmbus_message * 402vmbus_msghc_wait_result(struct vmbus_softc *sc, struct vmbus_msghc *mh) 403{ 404 struct vmbus_msghc_ctx *mhc = sc->vmbus_msg_hc; 405 406 mtx_lock(&mhc->mhc_active_lock); 407 408 KASSERT(mhc->mhc_active == mh, ("msghc mismatch")); 409 while (mh->mh_resp == NULL) { 410 mtx_sleep(&mhc->mhc_active, &mhc->mhc_active_lock, 0, 411 "wmsghc", 0); 412 } 413 mhc->mhc_active = NULL; 414 415 mtx_unlock(&mhc->mhc_active_lock); 416 417 return mh->mh_resp; 418} 419 420void 421vmbus_msghc_wakeup(struct vmbus_softc *sc, const struct vmbus_message *msg) 422{ 423 struct vmbus_msghc_ctx *mhc = sc->vmbus_msg_hc; 424 struct vmbus_msghc *mh; 425 426 mtx_lock(&mhc->mhc_active_lock); 427 428 mh = mhc->mhc_active; 429 KASSERT(mh != NULL, ("no pending msg hypercall")); 430 memcpy(&mh->mh_resp0, msg, sizeof(mh->mh_resp0)); 431 mh->mh_resp = &mh->mh_resp0; 432 433 mtx_unlock(&mhc->mhc_active_lock); 434 wakeup(&mhc->mhc_active); 435} 436 437uint32_t 438vmbus_gpadl_alloc(struct vmbus_softc *sc) 439{ 440 return atomic_fetchadd_int(&sc->vmbus_gpadl, 1); 441} 442 443static int 444vmbus_connect(struct vmbus_softc *sc, uint32_t version) 445{ 446 struct vmbus_chanmsg_connect *req; 447 const struct vmbus_message *msg; 448 struct vmbus_msghc *mh; 449 int error, done = 0; 450 451 mh = vmbus_msghc_get(sc, sizeof(*req)); 452 if (mh == NULL) 453 return ENXIO; 454 455 req = vmbus_msghc_dataptr(mh); 456 req->chm_hdr.chm_type = VMBUS_CHANMSG_TYPE_CONNECT; 457 req->chm_ver = version; 458 req->chm_evtflags = sc->vmbus_evtflags_dma.hv_paddr; 459 req->chm_mnf1 = sc->vmbus_mnf1_dma.hv_paddr; 460 req->chm_mnf2 = sc->vmbus_mnf2_dma.hv_paddr; 461 462 error = vmbus_msghc_exec(sc, mh); 463 if (error) { 464 vmbus_msghc_put(sc, mh); 465 return error; 466 } 467 468 msg = vmbus_msghc_wait_result(sc, mh); 469 done = ((const struct vmbus_chanmsg_connect_resp *) 470 msg->msg_data)->chm_done; 471 472 vmbus_msghc_put(sc, mh); 473 474 return (done ? 0 : EOPNOTSUPP); 475} 476 477static int 478vmbus_init(struct vmbus_softc *sc) 479{ 480 int i; 481 482 for (i = 0; i < nitems(vmbus_version); ++i) { 483 int error; 484 485 error = vmbus_connect(sc, vmbus_version[i]); 486 if (!error) { 487 sc->vmbus_version = vmbus_version[i]; 488 device_printf(sc->vmbus_dev, "version %u.%u\n", 489 VMBUS_VERSION_MAJOR(sc->vmbus_version), 490 VMBUS_VERSION_MINOR(sc->vmbus_version)); 491 return 0; 492 } 493 } 494 return ENXIO; 495} 496 497static void 498vmbus_disconnect(struct vmbus_softc *sc) 499{ 500 struct vmbus_chanmsg_disconnect *req; 501 struct vmbus_msghc *mh; 502 int error; 503 504 mh = vmbus_msghc_get(sc, sizeof(*req)); 505 if (mh == NULL) { 506 device_printf(sc->vmbus_dev, 507 "can not get msg hypercall for disconnect\n"); 508 return; 509 } 510 511 req = vmbus_msghc_dataptr(mh); 512 req->chm_hdr.chm_type = VMBUS_CHANMSG_TYPE_DISCONNECT; 513 514 error = vmbus_msghc_exec_noresult(mh); 515 vmbus_msghc_put(sc, mh); 516 517 if (error) { 518 device_printf(sc->vmbus_dev, 519 "disconnect msg hypercall failed\n"); 520 } 521} 522 523static int 524vmbus_req_channels(struct vmbus_softc *sc) 525{ 526 struct vmbus_chanmsg_chrequest *req; 527 struct vmbus_msghc *mh; 528 int error; 529 530 mh = vmbus_msghc_get(sc, sizeof(*req)); 531 if (mh == NULL) 532 return ENXIO; 533 534 req = vmbus_msghc_dataptr(mh); 535 req->chm_hdr.chm_type = VMBUS_CHANMSG_TYPE_CHREQUEST; 536 537 error = vmbus_msghc_exec_noresult(mh); 538 vmbus_msghc_put(sc, mh); 539 540 return error; 541} 542 543static void 544vmbus_scan_newchan(struct vmbus_softc *sc) 545{ 546 mtx_lock(&sc->vmbus_scan_lock); 547 if ((sc->vmbus_scan_chcnt & VMBUS_SCAN_CHCNT_DONE) == 0) 548 sc->vmbus_scan_chcnt++; 549 mtx_unlock(&sc->vmbus_scan_lock); 550} 551 552static void 553vmbus_scan_done(struct vmbus_softc *sc, 554 const struct vmbus_message *msg __unused) 555{ 556 mtx_lock(&sc->vmbus_scan_lock); 557 sc->vmbus_scan_chcnt |= VMBUS_SCAN_CHCNT_DONE; 558 mtx_unlock(&sc->vmbus_scan_lock); 559 wakeup(&sc->vmbus_scan_chcnt); 560} 561 562static void 563vmbus_scan_newdev(struct vmbus_softc *sc) 564{ 565 mtx_lock(&sc->vmbus_scan_lock); 566 sc->vmbus_scan_devcnt++; 567 mtx_unlock(&sc->vmbus_scan_lock); 568 wakeup(&sc->vmbus_scan_devcnt); 569} 570 571static void 572vmbus_scan_wait(struct vmbus_softc *sc) 573{ 574 uint32_t chancnt; 575 576 mtx_lock(&sc->vmbus_scan_lock); 577 while ((sc->vmbus_scan_chcnt & VMBUS_SCAN_CHCNT_DONE) == 0) { 578 mtx_sleep(&sc->vmbus_scan_chcnt, &sc->vmbus_scan_lock, 0, 579 "waitch", 0); 580 } 581 chancnt = sc->vmbus_scan_chcnt & ~VMBUS_SCAN_CHCNT_DONE; 582 583 while (sc->vmbus_scan_devcnt != chancnt) { 584 mtx_sleep(&sc->vmbus_scan_devcnt, &sc->vmbus_scan_lock, 0, 585 "waitdev", 0); 586 } 587 mtx_unlock(&sc->vmbus_scan_lock); 588} 589 590static int 591vmbus_scan(struct vmbus_softc *sc) 592{ 593 int error; 594 595 /* 596 * Start vmbus scanning. 597 */ 598 error = vmbus_req_channels(sc); 599 if (error) { 600 device_printf(sc->vmbus_dev, "channel request failed: %d\n", 601 error); 602 return error; 603 } 604 605 /* 606 * Wait for all devices are added to vmbus. 607 */ 608 vmbus_scan_wait(sc); 609 610 /* 611 * Identify, probe and attach. 612 */ 613 bus_generic_probe(sc->vmbus_dev); 614 bus_generic_attach(sc->vmbus_dev); 615 616 if (bootverbose) { 617 device_printf(sc->vmbus_dev, "device scan, probe and attach " 618 "done\n"); 619 } 620 return 0; 621} 622 623static void 624vmbus_chanmsg_handle(struct vmbus_softc *sc, const struct vmbus_message *msg) 625{ 626 vmbus_chanmsg_proc_t msg_proc; 627 uint32_t msg_type; 628 629 msg_type = ((const struct vmbus_chanmsg_hdr *)msg->msg_data)->chm_type; 630 if (msg_type >= VMBUS_CHANMSG_TYPE_MAX) { 631 device_printf(sc->vmbus_dev, "unknown message type 0x%x\n", 632 msg_type); 633 return; 634 } 635 636 msg_proc = vmbus_chanmsg_handlers[msg_type]; 637 if (msg_proc != NULL) 638 msg_proc(sc, msg); 639 640 /* Channel specific processing */ 641 vmbus_chan_msgproc(sc, msg); 642} 643 644static void 645vmbus_msg_task(void *xsc, int pending __unused) 646{ 647 struct vmbus_softc *sc = xsc; 648 volatile struct vmbus_message *msg; 649 650 msg = VMBUS_PCPU_GET(sc, message, curcpu) + VMBUS_SINT_MESSAGE; 651 for (;;) { 652 if (msg->msg_type == HYPERV_MSGTYPE_NONE) { 653 /* No message */ 654 break; 655 } else if (msg->msg_type == HYPERV_MSGTYPE_CHANNEL) { 656 /* Channel message */ 657 vmbus_chanmsg_handle(sc, 658 __DEVOLATILE(const struct vmbus_message *, msg)); 659 } 660 661 msg->msg_type = HYPERV_MSGTYPE_NONE; 662 /* 663 * Make sure the write to msg_type (i.e. set to 664 * HYPERV_MSGTYPE_NONE) happens before we read the 665 * msg_flags and EOMing. Otherwise, the EOMing will 666 * not deliver any more messages since there is no 667 * empty slot 668 * 669 * NOTE: 670 * mb() is used here, since atomic_thread_fence_seq_cst() 671 * will become compiler fence on UP kernel. 672 */ 673 mb(); 674 if (msg->msg_flags & VMBUS_MSGFLAG_PENDING) { 675 /* 676 * This will cause message queue rescan to possibly 677 * deliver another msg from the hypervisor 678 */ 679 wrmsr(MSR_HV_EOM, 0); 680 } 681 } 682} 683 684static __inline int 685vmbus_handle_intr1(struct vmbus_softc *sc, struct trapframe *frame, int cpu) 686{ 687 volatile struct vmbus_message *msg; 688 struct vmbus_message *msg_base; 689 690 msg_base = VMBUS_PCPU_GET(sc, message, cpu); 691 692 /* 693 * Check event timer. 694 * 695 * TODO: move this to independent IDT vector. 696 */ 697 msg = msg_base + VMBUS_SINT_TIMER; 698 if (msg->msg_type == HYPERV_MSGTYPE_TIMER_EXPIRED) { 699 msg->msg_type = HYPERV_MSGTYPE_NONE; 700 701 vmbus_et_intr(frame); 702 703 /* 704 * Make sure the write to msg_type (i.e. set to 705 * HYPERV_MSGTYPE_NONE) happens before we read the 706 * msg_flags and EOMing. Otherwise, the EOMing will 707 * not deliver any more messages since there is no 708 * empty slot 709 * 710 * NOTE: 711 * mb() is used here, since atomic_thread_fence_seq_cst() 712 * will become compiler fence on UP kernel. 713 */ 714 mb(); 715 if (msg->msg_flags & VMBUS_MSGFLAG_PENDING) { 716 /* 717 * This will cause message queue rescan to possibly 718 * deliver another msg from the hypervisor 719 */ 720 wrmsr(MSR_HV_EOM, 0); 721 } 722 } 723 724 /* 725 * Check events. Hot path for network and storage I/O data; high rate. 726 * 727 * NOTE: 728 * As recommended by the Windows guest fellows, we check events before 729 * checking messages. 730 */ 731 sc->vmbus_event_proc(sc, cpu); 732 733 /* 734 * Check messages. Mainly management stuffs; ultra low rate. 735 */ 736 msg = msg_base + VMBUS_SINT_MESSAGE; 737 if (__predict_false(msg->msg_type != HYPERV_MSGTYPE_NONE)) { 738 taskqueue_enqueue(VMBUS_PCPU_GET(sc, message_tq, cpu), 739 VMBUS_PCPU_PTR(sc, message_task, cpu)); 740 } 741 742 return (FILTER_HANDLED); 743} 744 745void 746vmbus_handle_intr(struct trapframe *trap_frame) 747{ 748 struct vmbus_softc *sc = vmbus_get_softc(); 749 int cpu = curcpu; 750 751 /* 752 * Disable preemption. 753 */ 754 critical_enter(); 755 756 /* 757 * Do a little interrupt counting. 758 */ 759 (*VMBUS_PCPU_GET(sc, intr_cnt, cpu))++; 760 761 vmbus_handle_intr1(sc, trap_frame, cpu); 762 763 /* 764 * Enable preemption. 765 */ 766 critical_exit(); 767} 768 769static void 770vmbus_synic_setup(void *xsc) 771{ 772 struct vmbus_softc *sc = xsc; 773 int cpu = curcpu; 774 uint64_t val, orig; 775 uint32_t sint; 776 777 if (hyperv_features & CPUID_HV_MSR_VP_INDEX) { 778 /* Save virtual processor id. */ 779 VMBUS_PCPU_GET(sc, vcpuid, cpu) = rdmsr(MSR_HV_VP_INDEX); 780 } else { 781 /* Set virtual processor id to 0 for compatibility. */ 782 VMBUS_PCPU_GET(sc, vcpuid, cpu) = 0; 783 } 784 785 /* 786 * Setup the SynIC message. 787 */ 788 orig = rdmsr(MSR_HV_SIMP); 789 val = MSR_HV_SIMP_ENABLE | (orig & MSR_HV_SIMP_RSVD_MASK) | 790 ((VMBUS_PCPU_GET(sc, message_dma.hv_paddr, cpu) >> PAGE_SHIFT) << 791 MSR_HV_SIMP_PGSHIFT); 792 wrmsr(MSR_HV_SIMP, val); 793 794 /* 795 * Setup the SynIC event flags. 796 */ 797 orig = rdmsr(MSR_HV_SIEFP); 798 val = MSR_HV_SIEFP_ENABLE | (orig & MSR_HV_SIEFP_RSVD_MASK) | 799 ((VMBUS_PCPU_GET(sc, event_flags_dma.hv_paddr, cpu) 800 >> PAGE_SHIFT) << MSR_HV_SIEFP_PGSHIFT); 801 wrmsr(MSR_HV_SIEFP, val); 802 803 804 /* 805 * Configure and unmask SINT for message and event flags. 806 */ 807 sint = MSR_HV_SINT0 + VMBUS_SINT_MESSAGE; 808 orig = rdmsr(sint); 809 val = sc->vmbus_idtvec | MSR_HV_SINT_AUTOEOI | 810 (orig & MSR_HV_SINT_RSVD_MASK); 811 wrmsr(sint, val); 812 813 /* 814 * Configure and unmask SINT for timer. 815 */ 816 sint = MSR_HV_SINT0 + VMBUS_SINT_TIMER; 817 orig = rdmsr(sint); 818 val = sc->vmbus_idtvec | MSR_HV_SINT_AUTOEOI | 819 (orig & MSR_HV_SINT_RSVD_MASK); 820 wrmsr(sint, val); 821 822 /* 823 * All done; enable SynIC. 824 */ 825 orig = rdmsr(MSR_HV_SCONTROL); 826 val = MSR_HV_SCTRL_ENABLE | (orig & MSR_HV_SCTRL_RSVD_MASK); 827 wrmsr(MSR_HV_SCONTROL, val); 828} 829 830static void 831vmbus_synic_teardown(void *arg) 832{ 833 uint64_t orig; 834 uint32_t sint; 835 836 /* 837 * Disable SynIC. 838 */ 839 orig = rdmsr(MSR_HV_SCONTROL); 840 wrmsr(MSR_HV_SCONTROL, (orig & MSR_HV_SCTRL_RSVD_MASK)); 841 842 /* 843 * Mask message and event flags SINT. 844 */ 845 sint = MSR_HV_SINT0 + VMBUS_SINT_MESSAGE; 846 orig = rdmsr(sint); 847 wrmsr(sint, orig | MSR_HV_SINT_MASKED); 848 849 /* 850 * Mask timer SINT. 851 */ 852 sint = MSR_HV_SINT0 + VMBUS_SINT_TIMER; 853 orig = rdmsr(sint); 854 wrmsr(sint, orig | MSR_HV_SINT_MASKED); 855 856 /* 857 * Teardown SynIC message. 858 */ 859 orig = rdmsr(MSR_HV_SIMP); 860 wrmsr(MSR_HV_SIMP, (orig & MSR_HV_SIMP_RSVD_MASK)); 861 862 /* 863 * Teardown SynIC event flags. 864 */ 865 orig = rdmsr(MSR_HV_SIEFP); 866 wrmsr(MSR_HV_SIEFP, (orig & MSR_HV_SIEFP_RSVD_MASK)); 867} 868 869static int 870vmbus_dma_alloc(struct vmbus_softc *sc) 871{ 872 bus_dma_tag_t parent_dtag; 873 uint8_t *evtflags; 874 int cpu; 875 876 parent_dtag = bus_get_dma_tag(sc->vmbus_dev); 877 CPU_FOREACH(cpu) { 878 void *ptr; 879 880 /* 881 * Per-cpu messages and event flags. 882 */ 883 ptr = hyperv_dmamem_alloc(parent_dtag, PAGE_SIZE, 0, 884 PAGE_SIZE, VMBUS_PCPU_PTR(sc, message_dma, cpu), 885 BUS_DMA_WAITOK | BUS_DMA_ZERO); 886 if (ptr == NULL) 887 return ENOMEM; 888 VMBUS_PCPU_GET(sc, message, cpu) = ptr; 889 890 ptr = hyperv_dmamem_alloc(parent_dtag, PAGE_SIZE, 0, 891 PAGE_SIZE, VMBUS_PCPU_PTR(sc, event_flags_dma, cpu), 892 BUS_DMA_WAITOK | BUS_DMA_ZERO); 893 if (ptr == NULL) 894 return ENOMEM; 895 VMBUS_PCPU_GET(sc, event_flags, cpu) = ptr; 896 } 897 898 evtflags = hyperv_dmamem_alloc(parent_dtag, PAGE_SIZE, 0, 899 PAGE_SIZE, &sc->vmbus_evtflags_dma, BUS_DMA_WAITOK | BUS_DMA_ZERO); 900 if (evtflags == NULL) 901 return ENOMEM; 902 sc->vmbus_rx_evtflags = (u_long *)evtflags; 903 sc->vmbus_tx_evtflags = (u_long *)(evtflags + (PAGE_SIZE / 2)); 904 sc->vmbus_evtflags = evtflags; 905 906 sc->vmbus_mnf1 = hyperv_dmamem_alloc(parent_dtag, PAGE_SIZE, 0, 907 PAGE_SIZE, &sc->vmbus_mnf1_dma, BUS_DMA_WAITOK | BUS_DMA_ZERO); 908 if (sc->vmbus_mnf1 == NULL) 909 return ENOMEM; 910 911 sc->vmbus_mnf2 = hyperv_dmamem_alloc(parent_dtag, PAGE_SIZE, 0, 912 sizeof(struct vmbus_mnf), &sc->vmbus_mnf2_dma, 913 BUS_DMA_WAITOK | BUS_DMA_ZERO); 914 if (sc->vmbus_mnf2 == NULL) 915 return ENOMEM; 916 917 return 0; 918} 919 920static void 921vmbus_dma_free(struct vmbus_softc *sc) 922{ 923 int cpu; 924 925 if (sc->vmbus_evtflags != NULL) { 926 hyperv_dmamem_free(&sc->vmbus_evtflags_dma, sc->vmbus_evtflags); 927 sc->vmbus_evtflags = NULL; 928 sc->vmbus_rx_evtflags = NULL; 929 sc->vmbus_tx_evtflags = NULL; 930 } 931 if (sc->vmbus_mnf1 != NULL) { 932 hyperv_dmamem_free(&sc->vmbus_mnf1_dma, sc->vmbus_mnf1); 933 sc->vmbus_mnf1 = NULL; 934 } 935 if (sc->vmbus_mnf2 != NULL) { 936 hyperv_dmamem_free(&sc->vmbus_mnf2_dma, sc->vmbus_mnf2); 937 sc->vmbus_mnf2 = NULL; 938 } 939 940 CPU_FOREACH(cpu) { 941 if (VMBUS_PCPU_GET(sc, message, cpu) != NULL) { 942 hyperv_dmamem_free( 943 VMBUS_PCPU_PTR(sc, message_dma, cpu), 944 VMBUS_PCPU_GET(sc, message, cpu)); 945 VMBUS_PCPU_GET(sc, message, cpu) = NULL; 946 } 947 if (VMBUS_PCPU_GET(sc, event_flags, cpu) != NULL) { 948 hyperv_dmamem_free( 949 VMBUS_PCPU_PTR(sc, event_flags_dma, cpu), 950 VMBUS_PCPU_GET(sc, event_flags, cpu)); 951 VMBUS_PCPU_GET(sc, event_flags, cpu) = NULL; 952 } 953 } 954} 955 956static int 957vmbus_intr_setup(struct vmbus_softc *sc) 958{ 959 int cpu; 960 961 CPU_FOREACH(cpu) { 962 char buf[MAXCOMLEN + 1]; 963 cpuset_t cpu_mask; 964 965 /* Allocate an interrupt counter for Hyper-V interrupt */ 966 snprintf(buf, sizeof(buf), "cpu%d:hyperv", cpu); 967 intrcnt_add(buf, VMBUS_PCPU_PTR(sc, intr_cnt, cpu)); 968 969 /* 970 * Setup taskqueue to handle events. Task will be per- 971 * channel. 972 */ 973 VMBUS_PCPU_GET(sc, event_tq, cpu) = taskqueue_create_fast( 974 "hyperv event", M_WAITOK, taskqueue_thread_enqueue, 975 VMBUS_PCPU_PTR(sc, event_tq, cpu)); 976 CPU_SETOF(cpu, &cpu_mask); 977 taskqueue_start_threads_cpuset( 978 VMBUS_PCPU_PTR(sc, event_tq, cpu), 1, PI_NET, &cpu_mask, 979 "hvevent%d", cpu); 980 981 /* 982 * Setup tasks and taskqueues to handle messages. 983 */ 984 VMBUS_PCPU_GET(sc, message_tq, cpu) = taskqueue_create_fast( 985 "hyperv msg", M_WAITOK, taskqueue_thread_enqueue, 986 VMBUS_PCPU_PTR(sc, message_tq, cpu)); 987 CPU_SETOF(cpu, &cpu_mask); 988 taskqueue_start_threads_cpuset( 989 VMBUS_PCPU_PTR(sc, message_tq, cpu), 1, PI_NET, &cpu_mask, 990 "hvmsg%d", cpu); 991 TASK_INIT(VMBUS_PCPU_PTR(sc, message_task, cpu), 0, 992 vmbus_msg_task, sc); 993 } 994 995 /* 996 * All Hyper-V ISR required resources are setup, now let's find a 997 * free IDT vector for Hyper-V ISR and set it up. 998 */ 999 sc->vmbus_idtvec = lapic_ipi_alloc(IDTVEC(vmbus_isr)); 1000 if (sc->vmbus_idtvec < 0) { 1001 device_printf(sc->vmbus_dev, "cannot find free IDT vector\n"); 1002 return ENXIO; 1003 } 1004 if(bootverbose) { 1005 device_printf(sc->vmbus_dev, "vmbus IDT vector %d\n", 1006 sc->vmbus_idtvec); 1007 } 1008 return 0; 1009} 1010 1011static void 1012vmbus_intr_teardown(struct vmbus_softc *sc) 1013{ 1014 int cpu; 1015 1016 if (sc->vmbus_idtvec >= 0) { 1017 lapic_ipi_free(sc->vmbus_idtvec); 1018 sc->vmbus_idtvec = -1; 1019 } 1020 1021 CPU_FOREACH(cpu) { 1022 if (VMBUS_PCPU_GET(sc, event_tq, cpu) != NULL) { 1023 taskqueue_free(VMBUS_PCPU_GET(sc, event_tq, cpu)); 1024 VMBUS_PCPU_GET(sc, event_tq, cpu) = NULL; 1025 } 1026 if (VMBUS_PCPU_GET(sc, message_tq, cpu) != NULL) { 1027 taskqueue_drain(VMBUS_PCPU_GET(sc, message_tq, cpu), 1028 VMBUS_PCPU_PTR(sc, message_task, cpu)); 1029 taskqueue_free(VMBUS_PCPU_GET(sc, message_tq, cpu)); 1030 VMBUS_PCPU_GET(sc, message_tq, cpu) = NULL; 1031 } 1032 } 1033} 1034 1035static int 1036vmbus_read_ivar(device_t dev, device_t child, int index, uintptr_t *result) 1037{ 1038 return (ENOENT); 1039} 1040 1041static int 1042vmbus_child_pnpinfo_str(device_t dev, device_t child, char *buf, size_t buflen) 1043{ 1044 const struct vmbus_channel *chan; 1045 char guidbuf[HYPERV_GUID_STRLEN]; 1046 1047 chan = vmbus_get_channel(child); 1048 if (chan == NULL) { 1049 /* Event timer device, which does not belong to a channel */ 1050 return (0); 1051 } 1052 1053 strlcat(buf, "classid=", buflen); 1054 hyperv_guid2str(&chan->ch_guid_type, guidbuf, sizeof(guidbuf)); 1055 strlcat(buf, guidbuf, buflen); 1056 1057 strlcat(buf, " deviceid=", buflen); 1058 hyperv_guid2str(&chan->ch_guid_inst, guidbuf, sizeof(guidbuf)); 1059 strlcat(buf, guidbuf, buflen); 1060 1061 return (0); 1062} 1063 1064int 1065vmbus_add_child(struct vmbus_channel *chan) 1066{ 1067 struct vmbus_softc *sc = chan->ch_vmbus; 1068 device_t parent = sc->vmbus_dev; 1069 int error = 0; 1070 1071 /* New channel has been offered */ 1072 vmbus_scan_newchan(sc); 1073 1074 chan->ch_dev = device_add_child(parent, NULL, -1); 1075 if (chan->ch_dev == NULL) { 1076 device_printf(parent, "device_add_child for chan%u failed\n", 1077 chan->ch_id); 1078 error = ENXIO; 1079 goto done; 1080 } 1081 device_set_ivars(chan->ch_dev, chan); 1082 1083done: 1084 /* New device has been/should be added to vmbus. */ 1085 vmbus_scan_newdev(sc); 1086 return error; 1087} 1088 1089int 1090vmbus_delete_child(struct vmbus_channel *chan) 1091{ 1092 int error; 1093 1094 if (chan->ch_dev == NULL) { 1095 /* Failed to add a device. */ 1096 return 0; 1097 } 1098 1099 /* 1100 * XXXKYS: Ensure that this is the opposite of 1101 * device_add_child() 1102 */ 1103 mtx_lock(&Giant); 1104 error = device_delete_child(chan->ch_vmbus->vmbus_dev, chan->ch_dev); 1105 mtx_unlock(&Giant); 1106 1107 return error; 1108} 1109 1110static int 1111vmbus_sysctl_version(SYSCTL_HANDLER_ARGS) 1112{ 1113 struct vmbus_softc *sc = arg1; 1114 char verstr[16]; 1115 1116 snprintf(verstr, sizeof(verstr), "%u.%u", 1117 VMBUS_VERSION_MAJOR(sc->vmbus_version), 1118 VMBUS_VERSION_MINOR(sc->vmbus_version)); 1119 return sysctl_handle_string(oidp, verstr, sizeof(verstr), req); 1120} 1121 1122static uint32_t 1123vmbus_get_version_method(device_t bus, device_t dev) 1124{ 1125 struct vmbus_softc *sc = device_get_softc(bus); 1126 1127 return sc->vmbus_version; 1128} 1129 1130static int 1131vmbus_probe_guid_method(device_t bus, device_t dev, 1132 const struct hyperv_guid *guid) 1133{ 1134 const struct vmbus_channel *chan = vmbus_get_channel(dev); 1135 1136 if (memcmp(&chan->ch_guid_type, guid, sizeof(struct hyperv_guid)) == 0) 1137 return 0; 1138 return ENXIO; 1139} 1140 1141static int 1142vmbus_probe(device_t dev) 1143{ 1144 char *id[] = { "VMBUS", NULL }; 1145 1146 if (ACPI_ID_PROBE(device_get_parent(dev), dev, id) == NULL || 1147 device_get_unit(dev) != 0 || vm_guest != VM_GUEST_HV || 1148 (hyperv_features & CPUID_HV_MSR_SYNIC) == 0) 1149 return (ENXIO); 1150 1151 device_set_desc(dev, "Hyper-V Vmbus"); 1152 1153 return (BUS_PROBE_DEFAULT); 1154} 1155 1156/** 1157 * @brief Main vmbus driver initialization routine. 1158 * 1159 * Here, we 1160 * - initialize the vmbus driver context 1161 * - setup various driver entry points 1162 * - invoke the vmbus hv main init routine 1163 * - get the irq resource 1164 * - invoke the vmbus to add the vmbus root device 1165 * - setup the vmbus root device 1166 * - retrieve the channel offers 1167 */ 1168static int 1169vmbus_doattach(struct vmbus_softc *sc) 1170{ 1171 struct sysctl_oid_list *child; 1172 struct sysctl_ctx_list *ctx; 1173 int ret; 1174 1175 if (sc->vmbus_flags & VMBUS_FLAG_ATTACHED) 1176 return (0); 1177 sc->vmbus_flags |= VMBUS_FLAG_ATTACHED; 1178 1179 mtx_init(&sc->vmbus_scan_lock, "vmbus scan", NULL, MTX_DEF); 1180 sc->vmbus_gpadl = VMBUS_GPADL_START; 1181 mtx_init(&sc->vmbus_prichan_lock, "vmbus prichan", NULL, MTX_DEF); 1182 TAILQ_INIT(&sc->vmbus_prichans); 1183 sc->vmbus_chmap = malloc( 1184 sizeof(struct vmbus_channel *) * VMBUS_CHAN_MAX, M_DEVBUF, 1185 M_WAITOK | M_ZERO); 1186 1187 /* 1188 * Create context for "post message" Hypercalls 1189 */ 1190 sc->vmbus_msg_hc = vmbus_msghc_ctx_create( 1191 bus_get_dma_tag(sc->vmbus_dev)); 1192 if (sc->vmbus_msg_hc == NULL) { 1193 ret = ENXIO; 1194 goto cleanup; 1195 } 1196 1197 /* 1198 * Allocate DMA stuffs. 1199 */ 1200 ret = vmbus_dma_alloc(sc); 1201 if (ret != 0) 1202 goto cleanup; 1203 1204 /* 1205 * Setup interrupt. 1206 */ 1207 ret = vmbus_intr_setup(sc); 1208 if (ret != 0) 1209 goto cleanup; 1210 1211 /* 1212 * Setup SynIC. 1213 */ 1214 if (bootverbose) 1215 device_printf(sc->vmbus_dev, "smp_started = %d\n", smp_started); 1216 smp_rendezvous(NULL, vmbus_synic_setup, NULL, sc); 1217 sc->vmbus_flags |= VMBUS_FLAG_SYNIC; 1218 1219 /* 1220 * Initialize vmbus, e.g. connect to Hypervisor. 1221 */ 1222 ret = vmbus_init(sc); 1223 if (ret != 0) 1224 goto cleanup; 1225 1226 if (sc->vmbus_version == VMBUS_VERSION_WS2008 || 1227 sc->vmbus_version == VMBUS_VERSION_WIN7) 1228 sc->vmbus_event_proc = vmbus_event_proc_compat; 1229 else 1230 sc->vmbus_event_proc = vmbus_event_proc; 1231 1232 ret = vmbus_scan(sc); 1233 if (ret != 0) 1234 goto cleanup; 1235 1236 ctx = device_get_sysctl_ctx(sc->vmbus_dev); 1237 child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->vmbus_dev)); 1238 SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "version", 1239 CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, 1240 vmbus_sysctl_version, "A", "vmbus version"); 1241 1242 return (ret); 1243 1244cleanup: 1245 vmbus_intr_teardown(sc); 1246 vmbus_dma_free(sc); 1247 if (sc->vmbus_msg_hc != NULL) { 1248 vmbus_msghc_ctx_destroy(sc->vmbus_msg_hc); 1249 sc->vmbus_msg_hc = NULL; 1250 } 1251 free(sc->vmbus_chmap, M_DEVBUF); 1252 mtx_destroy(&sc->vmbus_scan_lock); 1253 mtx_destroy(&sc->vmbus_prichan_lock); 1254 1255 return (ret); 1256} 1257 1258static void 1259vmbus_event_proc_dummy(struct vmbus_softc *sc __unused, int cpu __unused) 1260{ 1261} 1262 1263static int 1264vmbus_attach(device_t dev) 1265{ 1266 vmbus_sc = device_get_softc(dev); 1267 vmbus_sc->vmbus_dev = dev; 1268 vmbus_sc->vmbus_idtvec = -1; 1269 1270 /* 1271 * Event processing logic will be configured: 1272 * - After the vmbus protocol version negotiation. 1273 * - Before we request channel offers. 1274 */ 1275 vmbus_sc->vmbus_event_proc = vmbus_event_proc_dummy; 1276 1277#ifndef EARLY_AP_STARTUP 1278 /* 1279 * If the system has already booted and thread 1280 * scheduling is possible indicated by the global 1281 * cold set to zero, we just call the driver 1282 * initialization directly. 1283 */ 1284 if (!cold) 1285#endif 1286 vmbus_doattach(vmbus_sc); 1287 1288 return (0); 1289} 1290 1291static int 1292vmbus_detach(device_t dev) 1293{ 1294 struct vmbus_softc *sc = device_get_softc(dev); 1295 1296 vmbus_chan_destroy_all(sc); 1297 1298 vmbus_disconnect(sc); 1299 1300 if (sc->vmbus_flags & VMBUS_FLAG_SYNIC) { 1301 sc->vmbus_flags &= ~VMBUS_FLAG_SYNIC; 1302 smp_rendezvous(NULL, vmbus_synic_teardown, NULL, NULL); 1303 } 1304 1305 vmbus_intr_teardown(sc); 1306 vmbus_dma_free(sc); 1307 1308 if (sc->vmbus_msg_hc != NULL) { 1309 vmbus_msghc_ctx_destroy(sc->vmbus_msg_hc); 1310 sc->vmbus_msg_hc = NULL; 1311 } 1312 1313 free(sc->vmbus_chmap, M_DEVBUF); 1314 mtx_destroy(&sc->vmbus_scan_lock); 1315 mtx_destroy(&sc->vmbus_prichan_lock); 1316 1317 return (0); 1318} 1319 1320#ifndef EARLY_AP_STARTUP 1321 1322static void 1323vmbus_sysinit(void *arg __unused) 1324{ 1325 struct vmbus_softc *sc = vmbus_get_softc(); 1326 1327 if (vm_guest != VM_GUEST_HV || sc == NULL) 1328 return; 1329 1330 /* 1331 * If the system has already booted and thread 1332 * scheduling is possible, as indicated by the 1333 * global cold set to zero, we just call the driver 1334 * initialization directly. 1335 */ 1336 if (!cold) 1337 vmbus_doattach(sc); 1338} 1339/* 1340 * NOTE: 1341 * We have to start as the last step of SI_SUB_SMP, i.e. after SMP is 1342 * initialized. 1343 */ 1344SYSINIT(vmbus_initialize, SI_SUB_SMP, SI_ORDER_ANY, vmbus_sysinit, NULL); 1345 1346#endif /* !EARLY_AP_STARTUP */ 1347