1b7bb4816SSepherosa Ziehau /*- 2b7bb4816SSepherosa Ziehau * Copyright (c) 2009-2012,2016 Microsoft Corp. 3b7bb4816SSepherosa Ziehau * Copyright (c) 2012 NetApp Inc. 4b7bb4816SSepherosa Ziehau * Copyright (c) 2012 Citrix Inc. 5b7bb4816SSepherosa Ziehau * All rights reserved. 6b7bb4816SSepherosa Ziehau * 7b7bb4816SSepherosa Ziehau * Redistribution and use in source and binary forms, with or without 8b7bb4816SSepherosa Ziehau * modification, are permitted provided that the following conditions 9b7bb4816SSepherosa Ziehau * are met: 10b7bb4816SSepherosa Ziehau * 1. Redistributions of source code must retain the above copyright 11b7bb4816SSepherosa Ziehau * notice unmodified, this list of conditions, and the following 12b7bb4816SSepherosa Ziehau * disclaimer. 13b7bb4816SSepherosa Ziehau * 2. Redistributions in binary form must reproduce the above copyright 14b7bb4816SSepherosa Ziehau * notice, this list of conditions and the following disclaimer in the 15b7bb4816SSepherosa Ziehau * documentation and/or other materials provided with the distribution. 16b7bb4816SSepherosa Ziehau * 17b7bb4816SSepherosa Ziehau * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18b7bb4816SSepherosa Ziehau * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19b7bb4816SSepherosa Ziehau * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20b7bb4816SSepherosa Ziehau * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21b7bb4816SSepherosa Ziehau * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22b7bb4816SSepherosa Ziehau * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23b7bb4816SSepherosa Ziehau * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24b7bb4816SSepherosa Ziehau * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25b7bb4816SSepherosa Ziehau * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26b7bb4816SSepherosa Ziehau * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27b7bb4816SSepherosa Ziehau */ 28b7bb4816SSepherosa Ziehau 29b7bb4816SSepherosa Ziehau /* 30b7bb4816SSepherosa Ziehau * VM Bus Driver Implementation 31b7bb4816SSepherosa Ziehau */ 32b7bb4816SSepherosa Ziehau #include <sys/cdefs.h> 33b7bb4816SSepherosa Ziehau __FBSDID("$FreeBSD$"); 34b7bb4816SSepherosa Ziehau 35b7bb4816SSepherosa Ziehau #include <sys/param.h> 36b7bb4816SSepherosa Ziehau #include <sys/bus.h> 37b7bb4816SSepherosa Ziehau #include <sys/kernel.h> 38b7bb4816SSepherosa Ziehau #include <sys/lock.h> 39b7bb4816SSepherosa Ziehau #include <sys/malloc.h> 40b7bb4816SSepherosa Ziehau #include <sys/module.h> 41b7bb4816SSepherosa Ziehau #include <sys/proc.h> 42b7bb4816SSepherosa Ziehau #include <sys/sysctl.h> 43b7bb4816SSepherosa Ziehau #include <sys/syslog.h> 44b7bb4816SSepherosa Ziehau #include <sys/systm.h> 45b7bb4816SSepherosa Ziehau #include <sys/rtprio.h> 46b7bb4816SSepherosa Ziehau #include <sys/interrupt.h> 47b7bb4816SSepherosa Ziehau #include <sys/sx.h> 48b7bb4816SSepherosa Ziehau #include <sys/taskqueue.h> 49b7bb4816SSepherosa Ziehau #include <sys/mutex.h> 50b7bb4816SSepherosa Ziehau #include <sys/smp.h> 51b7bb4816SSepherosa Ziehau 52b7bb4816SSepherosa Ziehau #include <machine/resource.h> 53b7bb4816SSepherosa Ziehau #include <sys/rman.h> 54b7bb4816SSepherosa Ziehau 55b7bb4816SSepherosa Ziehau #include <machine/stdarg.h> 56b7bb4816SSepherosa Ziehau #include <machine/intr_machdep.h> 57b7bb4816SSepherosa Ziehau #include <machine/md_var.h> 58b7bb4816SSepherosa Ziehau #include <machine/segments.h> 59b7bb4816SSepherosa Ziehau #include <sys/pcpu.h> 60b7bb4816SSepherosa Ziehau #include <x86/apicvar.h> 61b7bb4816SSepherosa Ziehau 62b7bb4816SSepherosa Ziehau #include <dev/hyperv/include/hyperv.h> 63b7bb4816SSepherosa Ziehau #include <dev/hyperv/vmbus/hv_vmbus_priv.h> 64b7bb4816SSepherosa Ziehau #include <dev/hyperv/vmbus/hyperv_reg.h> 65b7bb4816SSepherosa Ziehau #include <dev/hyperv/vmbus/hyperv_var.h> 66b7bb4816SSepherosa Ziehau #include <dev/hyperv/vmbus/vmbus_reg.h> 67b7bb4816SSepherosa Ziehau #include <dev/hyperv/vmbus/vmbus_var.h> 68b7bb4816SSepherosa Ziehau 69b7bb4816SSepherosa Ziehau #include <contrib/dev/acpica/include/acpi.h> 70b7bb4816SSepherosa Ziehau #include "acpi_if.h" 71b7bb4816SSepherosa Ziehau 72*236764b1SSepherosa Ziehau /* 73*236764b1SSepherosa Ziehau * NOTE: DO NOT CHANGE THESE 74*236764b1SSepherosa Ziehau */ 75*236764b1SSepherosa Ziehau #define VMBUS_CONNID_MESSAGE 1 76*236764b1SSepherosa Ziehau #define VMBUS_CONNID_EVENT 2 77*236764b1SSepherosa Ziehau 78*236764b1SSepherosa Ziehau struct vmbus_msghc { 79*236764b1SSepherosa Ziehau struct hypercall_postmsg_in *mh_inprm; 80*236764b1SSepherosa Ziehau struct hypercall_postmsg_in mh_inprm_save; 81*236764b1SSepherosa Ziehau struct hyperv_dma mh_inprm_dma; 82*236764b1SSepherosa Ziehau 83*236764b1SSepherosa Ziehau struct vmbus_message *mh_resp; 84*236764b1SSepherosa Ziehau struct vmbus_message mh_resp0; 85*236764b1SSepherosa Ziehau }; 86*236764b1SSepherosa Ziehau 87*236764b1SSepherosa Ziehau struct vmbus_msghc_ctx { 88*236764b1SSepherosa Ziehau struct vmbus_msghc *mhc_free; 89*236764b1SSepherosa Ziehau struct mtx mhc_free_lock; 90*236764b1SSepherosa Ziehau uint32_t mhc_flags; 91*236764b1SSepherosa Ziehau 92*236764b1SSepherosa Ziehau struct vmbus_msghc *mhc_active; 93*236764b1SSepherosa Ziehau struct mtx mhc_active_lock; 94*236764b1SSepherosa Ziehau }; 95*236764b1SSepherosa Ziehau 96*236764b1SSepherosa Ziehau #define VMBUS_MSGHC_CTXF_DESTROY 0x0001 97*236764b1SSepherosa Ziehau 98*236764b1SSepherosa Ziehau static int vmbus_init(struct vmbus_softc *); 99*236764b1SSepherosa Ziehau static int vmbus_init_contact(struct vmbus_softc *, 100*236764b1SSepherosa Ziehau uint32_t); 101*236764b1SSepherosa Ziehau 102*236764b1SSepherosa Ziehau static struct vmbus_msghc_ctx *vmbus_msghc_ctx_create(bus_dma_tag_t); 103*236764b1SSepherosa Ziehau static void vmbus_msghc_ctx_destroy( 104*236764b1SSepherosa Ziehau struct vmbus_msghc_ctx *); 105*236764b1SSepherosa Ziehau static void vmbus_msghc_ctx_free(struct vmbus_msghc_ctx *); 106*236764b1SSepherosa Ziehau static struct vmbus_msghc *vmbus_msghc_alloc(bus_dma_tag_t); 107*236764b1SSepherosa Ziehau static void vmbus_msghc_free(struct vmbus_msghc *); 108*236764b1SSepherosa Ziehau static struct vmbus_msghc *vmbus_msghc_get1(struct vmbus_msghc_ctx *, 109*236764b1SSepherosa Ziehau uint32_t); 110*236764b1SSepherosa Ziehau 111b7bb4816SSepherosa Ziehau struct vmbus_softc *vmbus_sc; 112b7bb4816SSepherosa Ziehau 113b7bb4816SSepherosa Ziehau extern inthand_t IDTVEC(vmbus_isr); 114b7bb4816SSepherosa Ziehau 115*236764b1SSepherosa Ziehau static const uint32_t vmbus_version[] = { 116*236764b1SSepherosa Ziehau HV_VMBUS_VERSION_WIN8_1, 117*236764b1SSepherosa Ziehau HV_VMBUS_VERSION_WIN8, 118*236764b1SSepherosa Ziehau HV_VMBUS_VERSION_WIN7, 119*236764b1SSepherosa Ziehau HV_VMBUS_VERSION_WS2008 120*236764b1SSepherosa Ziehau }; 121*236764b1SSepherosa Ziehau 122*236764b1SSepherosa Ziehau static struct vmbus_msghc * 123*236764b1SSepherosa Ziehau vmbus_msghc_alloc(bus_dma_tag_t parent_dtag) 124*236764b1SSepherosa Ziehau { 125*236764b1SSepherosa Ziehau struct vmbus_msghc *mh; 126*236764b1SSepherosa Ziehau 127*236764b1SSepherosa Ziehau mh = malloc(sizeof(*mh), M_DEVBUF, M_WAITOK | M_ZERO); 128*236764b1SSepherosa Ziehau 129*236764b1SSepherosa Ziehau mh->mh_inprm = hyperv_dmamem_alloc(parent_dtag, 130*236764b1SSepherosa Ziehau HYPERCALL_POSTMSGIN_ALIGN, 0, HYPERCALL_POSTMSGIN_SIZE, 131*236764b1SSepherosa Ziehau &mh->mh_inprm_dma, BUS_DMA_WAITOK); 132*236764b1SSepherosa Ziehau if (mh->mh_inprm == NULL) { 133*236764b1SSepherosa Ziehau free(mh, M_DEVBUF); 134*236764b1SSepherosa Ziehau return NULL; 135*236764b1SSepherosa Ziehau } 136*236764b1SSepherosa Ziehau return mh; 137*236764b1SSepherosa Ziehau } 138*236764b1SSepherosa Ziehau 139*236764b1SSepherosa Ziehau static void 140*236764b1SSepherosa Ziehau vmbus_msghc_free(struct vmbus_msghc *mh) 141*236764b1SSepherosa Ziehau { 142*236764b1SSepherosa Ziehau hyperv_dmamem_free(&mh->mh_inprm_dma, mh->mh_inprm); 143*236764b1SSepherosa Ziehau free(mh, M_DEVBUF); 144*236764b1SSepherosa Ziehau } 145*236764b1SSepherosa Ziehau 146*236764b1SSepherosa Ziehau static void 147*236764b1SSepherosa Ziehau vmbus_msghc_ctx_free(struct vmbus_msghc_ctx *mhc) 148*236764b1SSepherosa Ziehau { 149*236764b1SSepherosa Ziehau KASSERT(mhc->mhc_active == NULL, ("still have active msg hypercall")); 150*236764b1SSepherosa Ziehau KASSERT(mhc->mhc_free == NULL, ("still have hypercall msg")); 151*236764b1SSepherosa Ziehau 152*236764b1SSepherosa Ziehau mtx_destroy(&mhc->mhc_free_lock); 153*236764b1SSepherosa Ziehau mtx_destroy(&mhc->mhc_active_lock); 154*236764b1SSepherosa Ziehau free(mhc, M_DEVBUF); 155*236764b1SSepherosa Ziehau } 156*236764b1SSepherosa Ziehau 157*236764b1SSepherosa Ziehau static struct vmbus_msghc_ctx * 158*236764b1SSepherosa Ziehau vmbus_msghc_ctx_create(bus_dma_tag_t parent_dtag) 159*236764b1SSepherosa Ziehau { 160*236764b1SSepherosa Ziehau struct vmbus_msghc_ctx *mhc; 161*236764b1SSepherosa Ziehau 162*236764b1SSepherosa Ziehau mhc = malloc(sizeof(*mhc), M_DEVBUF, M_WAITOK | M_ZERO); 163*236764b1SSepherosa Ziehau mtx_init(&mhc->mhc_free_lock, "vmbus msghc free", NULL, MTX_DEF); 164*236764b1SSepherosa Ziehau mtx_init(&mhc->mhc_active_lock, "vmbus msghc act", NULL, MTX_DEF); 165*236764b1SSepherosa Ziehau 166*236764b1SSepherosa Ziehau mhc->mhc_free = vmbus_msghc_alloc(parent_dtag); 167*236764b1SSepherosa Ziehau if (mhc->mhc_free == NULL) { 168*236764b1SSepherosa Ziehau vmbus_msghc_ctx_free(mhc); 169*236764b1SSepherosa Ziehau return NULL; 170*236764b1SSepherosa Ziehau } 171*236764b1SSepherosa Ziehau return mhc; 172*236764b1SSepherosa Ziehau } 173*236764b1SSepherosa Ziehau 174*236764b1SSepherosa Ziehau static struct vmbus_msghc * 175*236764b1SSepherosa Ziehau vmbus_msghc_get1(struct vmbus_msghc_ctx *mhc, uint32_t dtor_flag) 176*236764b1SSepherosa Ziehau { 177*236764b1SSepherosa Ziehau struct vmbus_msghc *mh; 178*236764b1SSepherosa Ziehau 179*236764b1SSepherosa Ziehau mtx_lock(&mhc->mhc_free_lock); 180*236764b1SSepherosa Ziehau 181*236764b1SSepherosa Ziehau while ((mhc->mhc_flags & dtor_flag) == 0 && mhc->mhc_free == NULL) { 182*236764b1SSepherosa Ziehau mtx_sleep(&mhc->mhc_free, &mhc->mhc_free_lock, 0, 183*236764b1SSepherosa Ziehau "gmsghc", 0); 184*236764b1SSepherosa Ziehau } 185*236764b1SSepherosa Ziehau if (mhc->mhc_flags & dtor_flag) { 186*236764b1SSepherosa Ziehau /* Being destroyed */ 187*236764b1SSepherosa Ziehau mh = NULL; 188*236764b1SSepherosa Ziehau } else { 189*236764b1SSepherosa Ziehau mh = mhc->mhc_free; 190*236764b1SSepherosa Ziehau KASSERT(mh != NULL, ("no free hypercall msg")); 191*236764b1SSepherosa Ziehau KASSERT(mh->mh_resp == NULL, 192*236764b1SSepherosa Ziehau ("hypercall msg has pending response")); 193*236764b1SSepherosa Ziehau mhc->mhc_free = NULL; 194*236764b1SSepherosa Ziehau } 195*236764b1SSepherosa Ziehau 196*236764b1SSepherosa Ziehau mtx_unlock(&mhc->mhc_free_lock); 197*236764b1SSepherosa Ziehau 198*236764b1SSepherosa Ziehau return mh; 199*236764b1SSepherosa Ziehau } 200*236764b1SSepherosa Ziehau 201*236764b1SSepherosa Ziehau struct vmbus_msghc * 202*236764b1SSepherosa Ziehau vmbus_msghc_get(struct vmbus_softc *sc, size_t dsize) 203*236764b1SSepherosa Ziehau { 204*236764b1SSepherosa Ziehau struct hypercall_postmsg_in *inprm; 205*236764b1SSepherosa Ziehau struct vmbus_msghc *mh; 206*236764b1SSepherosa Ziehau 207*236764b1SSepherosa Ziehau if (dsize > HYPERCALL_POSTMSGIN_DSIZE_MAX) 208*236764b1SSepherosa Ziehau return NULL; 209*236764b1SSepherosa Ziehau 210*236764b1SSepherosa Ziehau mh = vmbus_msghc_get1(sc->vmbus_msg_hc, VMBUS_MSGHC_CTXF_DESTROY); 211*236764b1SSepherosa Ziehau if (mh == NULL) 212*236764b1SSepherosa Ziehau return NULL; 213*236764b1SSepherosa Ziehau 214*236764b1SSepherosa Ziehau inprm = mh->mh_inprm; 215*236764b1SSepherosa Ziehau memset(inprm, 0, HYPERCALL_POSTMSGIN_SIZE); 216*236764b1SSepherosa Ziehau inprm->hc_connid = VMBUS_CONNID_MESSAGE; 217*236764b1SSepherosa Ziehau inprm->hc_msgtype = HYPERV_MSGTYPE_CHANNEL; 218*236764b1SSepherosa Ziehau inprm->hc_dsize = dsize; 219*236764b1SSepherosa Ziehau 220*236764b1SSepherosa Ziehau return mh; 221*236764b1SSepherosa Ziehau } 222*236764b1SSepherosa Ziehau 223*236764b1SSepherosa Ziehau void 224*236764b1SSepherosa Ziehau vmbus_msghc_put(struct vmbus_softc *sc, struct vmbus_msghc *mh) 225*236764b1SSepherosa Ziehau { 226*236764b1SSepherosa Ziehau struct vmbus_msghc_ctx *mhc = sc->vmbus_msg_hc; 227*236764b1SSepherosa Ziehau 228*236764b1SSepherosa Ziehau KASSERT(mhc->mhc_active == NULL, ("msg hypercall is active")); 229*236764b1SSepherosa Ziehau mh->mh_resp = NULL; 230*236764b1SSepherosa Ziehau 231*236764b1SSepherosa Ziehau mtx_lock(&mhc->mhc_free_lock); 232*236764b1SSepherosa Ziehau KASSERT(mhc->mhc_free == NULL, ("has free hypercall msg")); 233*236764b1SSepherosa Ziehau mhc->mhc_free = mh; 234*236764b1SSepherosa Ziehau mtx_unlock(&mhc->mhc_free_lock); 235*236764b1SSepherosa Ziehau wakeup(&mhc->mhc_free); 236*236764b1SSepherosa Ziehau } 237*236764b1SSepherosa Ziehau 238*236764b1SSepherosa Ziehau void * 239*236764b1SSepherosa Ziehau vmbus_msghc_dataptr(struct vmbus_msghc *mh) 240*236764b1SSepherosa Ziehau { 241*236764b1SSepherosa Ziehau return mh->mh_inprm->hc_data; 242*236764b1SSepherosa Ziehau } 243*236764b1SSepherosa Ziehau 244*236764b1SSepherosa Ziehau static void 245*236764b1SSepherosa Ziehau vmbus_msghc_ctx_destroy(struct vmbus_msghc_ctx *mhc) 246*236764b1SSepherosa Ziehau { 247*236764b1SSepherosa Ziehau struct vmbus_msghc *mh; 248*236764b1SSepherosa Ziehau 249*236764b1SSepherosa Ziehau mtx_lock(&mhc->mhc_free_lock); 250*236764b1SSepherosa Ziehau mhc->mhc_flags |= VMBUS_MSGHC_CTXF_DESTROY; 251*236764b1SSepherosa Ziehau mtx_unlock(&mhc->mhc_free_lock); 252*236764b1SSepherosa Ziehau wakeup(&mhc->mhc_free); 253*236764b1SSepherosa Ziehau 254*236764b1SSepherosa Ziehau mh = vmbus_msghc_get1(mhc, 0); 255*236764b1SSepherosa Ziehau if (mh == NULL) 256*236764b1SSepherosa Ziehau panic("can't get msghc"); 257*236764b1SSepherosa Ziehau 258*236764b1SSepherosa Ziehau vmbus_msghc_free(mh); 259*236764b1SSepherosa Ziehau vmbus_msghc_ctx_free(mhc); 260*236764b1SSepherosa Ziehau } 261*236764b1SSepherosa Ziehau 262*236764b1SSepherosa Ziehau int 263*236764b1SSepherosa Ziehau vmbus_msghc_exec_noresult(struct vmbus_msghc *mh) 264*236764b1SSepherosa Ziehau { 265*236764b1SSepherosa Ziehau sbintime_t time = SBT_1MS; 266*236764b1SSepherosa Ziehau int i; 267*236764b1SSepherosa Ziehau 268*236764b1SSepherosa Ziehau /* 269*236764b1SSepherosa Ziehau * Save the input parameter so that we could restore the input 270*236764b1SSepherosa Ziehau * parameter if the Hypercall failed. 271*236764b1SSepherosa Ziehau * 272*236764b1SSepherosa Ziehau * XXX 273*236764b1SSepherosa Ziehau * Is this really necessary?! i.e. Will the Hypercall ever 274*236764b1SSepherosa Ziehau * overwrite the input parameter? 275*236764b1SSepherosa Ziehau */ 276*236764b1SSepherosa Ziehau memcpy(&mh->mh_inprm_save, mh->mh_inprm, HYPERCALL_POSTMSGIN_SIZE); 277*236764b1SSepherosa Ziehau 278*236764b1SSepherosa Ziehau /* 279*236764b1SSepherosa Ziehau * In order to cope with transient failures, e.g. insufficient 280*236764b1SSepherosa Ziehau * resources on host side, we retry the post message Hypercall 281*236764b1SSepherosa Ziehau * several times. 20 retries seem sufficient. 282*236764b1SSepherosa Ziehau */ 283*236764b1SSepherosa Ziehau #define HC_RETRY_MAX 20 284*236764b1SSepherosa Ziehau 285*236764b1SSepherosa Ziehau for (i = 0; i < HC_RETRY_MAX; ++i) { 286*236764b1SSepherosa Ziehau uint64_t status; 287*236764b1SSepherosa Ziehau 288*236764b1SSepherosa Ziehau status = hypercall_post_message(mh->mh_inprm_dma.hv_paddr); 289*236764b1SSepherosa Ziehau if (status == HYPERCALL_STATUS_SUCCESS) 290*236764b1SSepherosa Ziehau return 0; 291*236764b1SSepherosa Ziehau 292*236764b1SSepherosa Ziehau pause_sbt("hcpmsg", time, 0, C_HARDCLOCK); 293*236764b1SSepherosa Ziehau if (time < SBT_1S * 2) 294*236764b1SSepherosa Ziehau time *= 2; 295*236764b1SSepherosa Ziehau 296*236764b1SSepherosa Ziehau /* Restore input parameter and try again */ 297*236764b1SSepherosa Ziehau memcpy(mh->mh_inprm, &mh->mh_inprm_save, 298*236764b1SSepherosa Ziehau HYPERCALL_POSTMSGIN_SIZE); 299*236764b1SSepherosa Ziehau } 300*236764b1SSepherosa Ziehau 301*236764b1SSepherosa Ziehau #undef HC_RETRY_MAX 302*236764b1SSepherosa Ziehau 303*236764b1SSepherosa Ziehau return EIO; 304*236764b1SSepherosa Ziehau } 305*236764b1SSepherosa Ziehau 306*236764b1SSepherosa Ziehau int 307*236764b1SSepherosa Ziehau vmbus_msghc_exec(struct vmbus_softc *sc, struct vmbus_msghc *mh) 308*236764b1SSepherosa Ziehau { 309*236764b1SSepherosa Ziehau struct vmbus_msghc_ctx *mhc = sc->vmbus_msg_hc; 310*236764b1SSepherosa Ziehau int error; 311*236764b1SSepherosa Ziehau 312*236764b1SSepherosa Ziehau KASSERT(mh->mh_resp == NULL, ("hypercall msg has pending response")); 313*236764b1SSepherosa Ziehau 314*236764b1SSepherosa Ziehau mtx_lock(&mhc->mhc_active_lock); 315*236764b1SSepherosa Ziehau KASSERT(mhc->mhc_active == NULL, ("pending active msg hypercall")); 316*236764b1SSepherosa Ziehau mhc->mhc_active = mh; 317*236764b1SSepherosa Ziehau mtx_unlock(&mhc->mhc_active_lock); 318*236764b1SSepherosa Ziehau 319*236764b1SSepherosa Ziehau error = vmbus_msghc_exec_noresult(mh); 320*236764b1SSepherosa Ziehau if (error) { 321*236764b1SSepherosa Ziehau mtx_lock(&mhc->mhc_active_lock); 322*236764b1SSepherosa Ziehau KASSERT(mhc->mhc_active == mh, ("msghc mismatch")); 323*236764b1SSepherosa Ziehau mhc->mhc_active = NULL; 324*236764b1SSepherosa Ziehau mtx_unlock(&mhc->mhc_active_lock); 325*236764b1SSepherosa Ziehau } 326*236764b1SSepherosa Ziehau return error; 327*236764b1SSepherosa Ziehau } 328*236764b1SSepherosa Ziehau 329*236764b1SSepherosa Ziehau const struct vmbus_message * 330*236764b1SSepherosa Ziehau vmbus_msghc_wait_result(struct vmbus_softc *sc, struct vmbus_msghc *mh) 331*236764b1SSepherosa Ziehau { 332*236764b1SSepherosa Ziehau struct vmbus_msghc_ctx *mhc = sc->vmbus_msg_hc; 333*236764b1SSepherosa Ziehau 334*236764b1SSepherosa Ziehau mtx_lock(&mhc->mhc_active_lock); 335*236764b1SSepherosa Ziehau 336*236764b1SSepherosa Ziehau KASSERT(mhc->mhc_active == mh, ("msghc mismatch")); 337*236764b1SSepherosa Ziehau while (mh->mh_resp == NULL) { 338*236764b1SSepherosa Ziehau mtx_sleep(&mhc->mhc_active, &mhc->mhc_active_lock, 0, 339*236764b1SSepherosa Ziehau "wmsghc", 0); 340*236764b1SSepherosa Ziehau } 341*236764b1SSepherosa Ziehau mhc->mhc_active = NULL; 342*236764b1SSepherosa Ziehau 343*236764b1SSepherosa Ziehau mtx_unlock(&mhc->mhc_active_lock); 344*236764b1SSepherosa Ziehau 345*236764b1SSepherosa Ziehau return mh->mh_resp; 346*236764b1SSepherosa Ziehau } 347*236764b1SSepherosa Ziehau 348*236764b1SSepherosa Ziehau void 349*236764b1SSepherosa Ziehau vmbus_msghc_wakeup(struct vmbus_softc *sc, const struct vmbus_message *msg) 350*236764b1SSepherosa Ziehau { 351*236764b1SSepherosa Ziehau struct vmbus_msghc_ctx *mhc = sc->vmbus_msg_hc; 352*236764b1SSepherosa Ziehau struct vmbus_msghc *mh; 353*236764b1SSepherosa Ziehau 354*236764b1SSepherosa Ziehau mtx_lock(&mhc->mhc_active_lock); 355*236764b1SSepherosa Ziehau 356*236764b1SSepherosa Ziehau mh = mhc->mhc_active; 357*236764b1SSepherosa Ziehau KASSERT(mh != NULL, ("no pending msg hypercall")); 358*236764b1SSepherosa Ziehau memcpy(&mh->mh_resp0, msg, sizeof(mh->mh_resp0)); 359*236764b1SSepherosa Ziehau mh->mh_resp = &mh->mh_resp0; 360*236764b1SSepherosa Ziehau 361*236764b1SSepherosa Ziehau mtx_unlock(&mhc->mhc_active_lock); 362*236764b1SSepherosa Ziehau wakeup(&mhc->mhc_active); 363*236764b1SSepherosa Ziehau } 364*236764b1SSepherosa Ziehau 365*236764b1SSepherosa Ziehau static int 366*236764b1SSepherosa Ziehau vmbus_init_contact(struct vmbus_softc *sc, uint32_t version) 367*236764b1SSepherosa Ziehau { 368*236764b1SSepherosa Ziehau struct vmbus_chanmsg_init_contact *req; 369*236764b1SSepherosa Ziehau const struct vmbus_chanmsg_version_resp *resp; 370*236764b1SSepherosa Ziehau const struct vmbus_message *msg; 371*236764b1SSepherosa Ziehau struct vmbus_msghc *mh; 372*236764b1SSepherosa Ziehau int error, supp = 0; 373*236764b1SSepherosa Ziehau 374*236764b1SSepherosa Ziehau mh = vmbus_msghc_get(sc, sizeof(*req)); 375*236764b1SSepherosa Ziehau if (mh == NULL) 376*236764b1SSepherosa Ziehau return ENXIO; 377*236764b1SSepherosa Ziehau 378*236764b1SSepherosa Ziehau req = vmbus_msghc_dataptr(mh); 379*236764b1SSepherosa Ziehau req->chm_hdr.chm_type = VMBUS_CHANMSG_TYPE_INIT_CONTACT; 380*236764b1SSepherosa Ziehau req->chm_ver = version; 381*236764b1SSepherosa Ziehau req->chm_evtflags = sc->vmbus_evtflags_dma.hv_paddr; 382*236764b1SSepherosa Ziehau req->chm_mnf1 = sc->vmbus_mnf1_dma.hv_paddr; 383*236764b1SSepherosa Ziehau req->chm_mnf2 = sc->vmbus_mnf2_dma.hv_paddr; 384*236764b1SSepherosa Ziehau 385*236764b1SSepherosa Ziehau error = vmbus_msghc_exec(sc, mh); 386*236764b1SSepherosa Ziehau if (error) { 387*236764b1SSepherosa Ziehau vmbus_msghc_put(sc, mh); 388*236764b1SSepherosa Ziehau return error; 389*236764b1SSepherosa Ziehau } 390*236764b1SSepherosa Ziehau 391*236764b1SSepherosa Ziehau msg = vmbus_msghc_wait_result(sc, mh); 392*236764b1SSepherosa Ziehau resp = (const struct vmbus_chanmsg_version_resp *)msg->msg_data; 393*236764b1SSepherosa Ziehau supp = resp->chm_supp; 394*236764b1SSepherosa Ziehau 395*236764b1SSepherosa Ziehau vmbus_msghc_put(sc, mh); 396*236764b1SSepherosa Ziehau 397*236764b1SSepherosa Ziehau return (supp ? 0 : EOPNOTSUPP); 398*236764b1SSepherosa Ziehau } 399*236764b1SSepherosa Ziehau 400*236764b1SSepherosa Ziehau static int 401*236764b1SSepherosa Ziehau vmbus_init(struct vmbus_softc *sc) 402*236764b1SSepherosa Ziehau { 403*236764b1SSepherosa Ziehau int i; 404*236764b1SSepherosa Ziehau 405*236764b1SSepherosa Ziehau for (i = 0; i < nitems(vmbus_version); ++i) { 406*236764b1SSepherosa Ziehau int error; 407*236764b1SSepherosa Ziehau 408*236764b1SSepherosa Ziehau error = vmbus_init_contact(sc, vmbus_version[i]); 409*236764b1SSepherosa Ziehau if (!error) { 410*236764b1SSepherosa Ziehau hv_vmbus_protocal_version = vmbus_version[i]; 411*236764b1SSepherosa Ziehau device_printf(sc->vmbus_dev, "version %u.%u\n", 412*236764b1SSepherosa Ziehau (hv_vmbus_protocal_version >> 16), 413*236764b1SSepherosa Ziehau (hv_vmbus_protocal_version & 0xffff)); 414*236764b1SSepherosa Ziehau return 0; 415*236764b1SSepherosa Ziehau } 416*236764b1SSepherosa Ziehau } 417*236764b1SSepherosa Ziehau return ENXIO; 418*236764b1SSepherosa Ziehau } 419*236764b1SSepherosa Ziehau 420b7bb4816SSepherosa Ziehau static void 421b7bb4816SSepherosa Ziehau vmbus_msg_task(void *xsc, int pending __unused) 422b7bb4816SSepherosa Ziehau { 423b7bb4816SSepherosa Ziehau struct vmbus_softc *sc = xsc; 424b7bb4816SSepherosa Ziehau volatile struct vmbus_message *msg; 425b7bb4816SSepherosa Ziehau 426b7bb4816SSepherosa Ziehau msg = VMBUS_PCPU_GET(sc, message, curcpu) + VMBUS_SINT_MESSAGE; 427b7bb4816SSepherosa Ziehau for (;;) { 428*236764b1SSepherosa Ziehau if (msg->msg_type == HYPERV_MSGTYPE_NONE) { 429fa4828b0SSepherosa Ziehau /* No message */ 430fa4828b0SSepherosa Ziehau break; 431*236764b1SSepherosa Ziehau } else if (msg->msg_type == HYPERV_MSGTYPE_CHANNEL) { 43212ea25aeSSepherosa Ziehau /* Channel message */ 43343926ba1SSepherosa Ziehau vmbus_chan_msgproc(sc, 43443926ba1SSepherosa Ziehau __DEVOLATILE(const struct vmbus_message *, msg)); 435fa4828b0SSepherosa Ziehau } 436b7bb4816SSepherosa Ziehau 437*236764b1SSepherosa Ziehau msg->msg_type = HYPERV_MSGTYPE_NONE; 438b7bb4816SSepherosa Ziehau /* 439b7bb4816SSepherosa Ziehau * Make sure the write to msg_type (i.e. set to 440*236764b1SSepherosa Ziehau * HYPERV_MSGTYPE_NONE) happens before we read the 441b7bb4816SSepherosa Ziehau * msg_flags and EOMing. Otherwise, the EOMing will 442b7bb4816SSepherosa Ziehau * not deliver any more messages since there is no 443b7bb4816SSepherosa Ziehau * empty slot 444b7bb4816SSepherosa Ziehau * 445b7bb4816SSepherosa Ziehau * NOTE: 446b7bb4816SSepherosa Ziehau * mb() is used here, since atomic_thread_fence_seq_cst() 447b7bb4816SSepherosa Ziehau * will become compiler fence on UP kernel. 448b7bb4816SSepherosa Ziehau */ 449b7bb4816SSepherosa Ziehau mb(); 450b7bb4816SSepherosa Ziehau if (msg->msg_flags & VMBUS_MSGFLAG_PENDING) { 451b7bb4816SSepherosa Ziehau /* 452b7bb4816SSepherosa Ziehau * This will cause message queue rescan to possibly 453b7bb4816SSepherosa Ziehau * deliver another msg from the hypervisor 454b7bb4816SSepherosa Ziehau */ 455b7bb4816SSepherosa Ziehau wrmsr(MSR_HV_EOM, 0); 456b7bb4816SSepherosa Ziehau } 457b7bb4816SSepherosa Ziehau } 458b7bb4816SSepherosa Ziehau } 459b7bb4816SSepherosa Ziehau 460b7bb4816SSepherosa Ziehau static __inline int 461b7bb4816SSepherosa Ziehau vmbus_handle_intr1(struct vmbus_softc *sc, struct trapframe *frame, int cpu) 462b7bb4816SSepherosa Ziehau { 463b7bb4816SSepherosa Ziehau volatile struct vmbus_message *msg; 464b7bb4816SSepherosa Ziehau struct vmbus_message *msg_base; 465b7bb4816SSepherosa Ziehau 466b7bb4816SSepherosa Ziehau msg_base = VMBUS_PCPU_GET(sc, message, cpu); 467b7bb4816SSepherosa Ziehau 468b7bb4816SSepherosa Ziehau /* 469b7bb4816SSepherosa Ziehau * Check event timer. 470b7bb4816SSepherosa Ziehau * 471b7bb4816SSepherosa Ziehau * TODO: move this to independent IDT vector. 472b7bb4816SSepherosa Ziehau */ 473b7bb4816SSepherosa Ziehau msg = msg_base + VMBUS_SINT_TIMER; 474*236764b1SSepherosa Ziehau if (msg->msg_type == HYPERV_MSGTYPE_TIMER_EXPIRED) { 475*236764b1SSepherosa Ziehau msg->msg_type = HYPERV_MSGTYPE_NONE; 476b7bb4816SSepherosa Ziehau 477b7bb4816SSepherosa Ziehau vmbus_et_intr(frame); 478b7bb4816SSepherosa Ziehau 479b7bb4816SSepherosa Ziehau /* 480b7bb4816SSepherosa Ziehau * Make sure the write to msg_type (i.e. set to 481*236764b1SSepherosa Ziehau * HYPERV_MSGTYPE_NONE) happens before we read the 482b7bb4816SSepherosa Ziehau * msg_flags and EOMing. Otherwise, the EOMing will 483b7bb4816SSepherosa Ziehau * not deliver any more messages since there is no 484b7bb4816SSepherosa Ziehau * empty slot 485b7bb4816SSepherosa Ziehau * 486b7bb4816SSepherosa Ziehau * NOTE: 487b7bb4816SSepherosa Ziehau * mb() is used here, since atomic_thread_fence_seq_cst() 488b7bb4816SSepherosa Ziehau * will become compiler fence on UP kernel. 489b7bb4816SSepherosa Ziehau */ 490b7bb4816SSepherosa Ziehau mb(); 491b7bb4816SSepherosa Ziehau if (msg->msg_flags & VMBUS_MSGFLAG_PENDING) { 492b7bb4816SSepherosa Ziehau /* 493b7bb4816SSepherosa Ziehau * This will cause message queue rescan to possibly 494b7bb4816SSepherosa Ziehau * deliver another msg from the hypervisor 495b7bb4816SSepherosa Ziehau */ 496b7bb4816SSepherosa Ziehau wrmsr(MSR_HV_EOM, 0); 497b7bb4816SSepherosa Ziehau } 498b7bb4816SSepherosa Ziehau } 499b7bb4816SSepherosa Ziehau 500b7bb4816SSepherosa Ziehau /* 501b7bb4816SSepherosa Ziehau * Check events. Hot path for network and storage I/O data; high rate. 502b7bb4816SSepherosa Ziehau * 503b7bb4816SSepherosa Ziehau * NOTE: 504b7bb4816SSepherosa Ziehau * As recommended by the Windows guest fellows, we check events before 505b7bb4816SSepherosa Ziehau * checking messages. 506b7bb4816SSepherosa Ziehau */ 507b7bb4816SSepherosa Ziehau sc->vmbus_event_proc(sc, cpu); 508b7bb4816SSepherosa Ziehau 509b7bb4816SSepherosa Ziehau /* 510b7bb4816SSepherosa Ziehau * Check messages. Mainly management stuffs; ultra low rate. 511b7bb4816SSepherosa Ziehau */ 512b7bb4816SSepherosa Ziehau msg = msg_base + VMBUS_SINT_MESSAGE; 513*236764b1SSepherosa Ziehau if (__predict_false(msg->msg_type != HYPERV_MSGTYPE_NONE)) { 514b7bb4816SSepherosa Ziehau taskqueue_enqueue(VMBUS_PCPU_GET(sc, message_tq, cpu), 515b7bb4816SSepherosa Ziehau VMBUS_PCPU_PTR(sc, message_task, cpu)); 516b7bb4816SSepherosa Ziehau } 517b7bb4816SSepherosa Ziehau 518b7bb4816SSepherosa Ziehau return (FILTER_HANDLED); 519b7bb4816SSepherosa Ziehau } 520b7bb4816SSepherosa Ziehau 521b7bb4816SSepherosa Ziehau void 522b7bb4816SSepherosa Ziehau vmbus_handle_intr(struct trapframe *trap_frame) 523b7bb4816SSepherosa Ziehau { 524b7bb4816SSepherosa Ziehau struct vmbus_softc *sc = vmbus_get_softc(); 525b7bb4816SSepherosa Ziehau int cpu = curcpu; 526b7bb4816SSepherosa Ziehau 527b7bb4816SSepherosa Ziehau /* 528b7bb4816SSepherosa Ziehau * Disable preemption. 529b7bb4816SSepherosa Ziehau */ 530b7bb4816SSepherosa Ziehau critical_enter(); 531b7bb4816SSepherosa Ziehau 532b7bb4816SSepherosa Ziehau /* 533b7bb4816SSepherosa Ziehau * Do a little interrupt counting. 534b7bb4816SSepherosa Ziehau */ 535b7bb4816SSepherosa Ziehau (*VMBUS_PCPU_GET(sc, intr_cnt, cpu))++; 536b7bb4816SSepherosa Ziehau 537b7bb4816SSepherosa Ziehau vmbus_handle_intr1(sc, trap_frame, cpu); 538b7bb4816SSepherosa Ziehau 539b7bb4816SSepherosa Ziehau /* 540b7bb4816SSepherosa Ziehau * Enable preemption. 541b7bb4816SSepherosa Ziehau */ 542b7bb4816SSepherosa Ziehau critical_exit(); 543b7bb4816SSepherosa Ziehau } 544b7bb4816SSepherosa Ziehau 545b7bb4816SSepherosa Ziehau static void 546b7bb4816SSepherosa Ziehau vmbus_synic_setup(void *xsc) 547b7bb4816SSepherosa Ziehau { 548b7bb4816SSepherosa Ziehau struct vmbus_softc *sc = xsc; 549b7bb4816SSepherosa Ziehau int cpu = curcpu; 550b7bb4816SSepherosa Ziehau uint64_t val, orig; 551b7bb4816SSepherosa Ziehau uint32_t sint; 552b7bb4816SSepherosa Ziehau 553b7bb4816SSepherosa Ziehau if (hyperv_features & CPUID_HV_MSR_VP_INDEX) { 554b7bb4816SSepherosa Ziehau /* 555b7bb4816SSepherosa Ziehau * Save virtual processor id. 556b7bb4816SSepherosa Ziehau */ 557b7bb4816SSepherosa Ziehau VMBUS_PCPU_GET(sc, vcpuid, cpu) = rdmsr(MSR_HV_VP_INDEX); 558b7bb4816SSepherosa Ziehau } else { 559b7bb4816SSepherosa Ziehau /* 560b7bb4816SSepherosa Ziehau * XXX 561b7bb4816SSepherosa Ziehau * Virtual processoor id is only used by a pretty broken 562b7bb4816SSepherosa Ziehau * channel selection code from storvsc. It's nothing 563b7bb4816SSepherosa Ziehau * critical even if CPUID_HV_MSR_VP_INDEX is not set; keep 564b7bb4816SSepherosa Ziehau * moving on. 565b7bb4816SSepherosa Ziehau */ 566b7bb4816SSepherosa Ziehau VMBUS_PCPU_GET(sc, vcpuid, cpu) = cpu; 567b7bb4816SSepherosa Ziehau } 568b7bb4816SSepherosa Ziehau 569b7bb4816SSepherosa Ziehau /* 570b7bb4816SSepherosa Ziehau * Setup the SynIC message. 571b7bb4816SSepherosa Ziehau */ 572b7bb4816SSepherosa Ziehau orig = rdmsr(MSR_HV_SIMP); 573b7bb4816SSepherosa Ziehau val = MSR_HV_SIMP_ENABLE | (orig & MSR_HV_SIMP_RSVD_MASK) | 574b7bb4816SSepherosa Ziehau ((VMBUS_PCPU_GET(sc, message_dma.hv_paddr, cpu) >> PAGE_SHIFT) << 575b7bb4816SSepherosa Ziehau MSR_HV_SIMP_PGSHIFT); 576b7bb4816SSepherosa Ziehau wrmsr(MSR_HV_SIMP, val); 577b7bb4816SSepherosa Ziehau 578b7bb4816SSepherosa Ziehau /* 579b7bb4816SSepherosa Ziehau * Setup the SynIC event flags. 580b7bb4816SSepherosa Ziehau */ 581b7bb4816SSepherosa Ziehau orig = rdmsr(MSR_HV_SIEFP); 582b7bb4816SSepherosa Ziehau val = MSR_HV_SIEFP_ENABLE | (orig & MSR_HV_SIEFP_RSVD_MASK) | 583b7bb4816SSepherosa Ziehau ((VMBUS_PCPU_GET(sc, event_flags_dma.hv_paddr, cpu) 584b7bb4816SSepherosa Ziehau >> PAGE_SHIFT) << MSR_HV_SIEFP_PGSHIFT); 585b7bb4816SSepherosa Ziehau wrmsr(MSR_HV_SIEFP, val); 586b7bb4816SSepherosa Ziehau 587b7bb4816SSepherosa Ziehau 588b7bb4816SSepherosa Ziehau /* 589b7bb4816SSepherosa Ziehau * Configure and unmask SINT for message and event flags. 590b7bb4816SSepherosa Ziehau */ 591b7bb4816SSepherosa Ziehau sint = MSR_HV_SINT0 + VMBUS_SINT_MESSAGE; 592b7bb4816SSepherosa Ziehau orig = rdmsr(sint); 593b7bb4816SSepherosa Ziehau val = sc->vmbus_idtvec | MSR_HV_SINT_AUTOEOI | 594b7bb4816SSepherosa Ziehau (orig & MSR_HV_SINT_RSVD_MASK); 595b7bb4816SSepherosa Ziehau wrmsr(sint, val); 596b7bb4816SSepherosa Ziehau 597b7bb4816SSepherosa Ziehau /* 598b7bb4816SSepherosa Ziehau * Configure and unmask SINT for timer. 599b7bb4816SSepherosa Ziehau */ 600b7bb4816SSepherosa Ziehau sint = MSR_HV_SINT0 + VMBUS_SINT_TIMER; 601b7bb4816SSepherosa Ziehau orig = rdmsr(sint); 602b7bb4816SSepherosa Ziehau val = sc->vmbus_idtvec | MSR_HV_SINT_AUTOEOI | 603b7bb4816SSepherosa Ziehau (orig & MSR_HV_SINT_RSVD_MASK); 604b7bb4816SSepherosa Ziehau wrmsr(sint, val); 605b7bb4816SSepherosa Ziehau 606b7bb4816SSepherosa Ziehau /* 607b7bb4816SSepherosa Ziehau * All done; enable SynIC. 608b7bb4816SSepherosa Ziehau */ 609b7bb4816SSepherosa Ziehau orig = rdmsr(MSR_HV_SCONTROL); 610b7bb4816SSepherosa Ziehau val = MSR_HV_SCTRL_ENABLE | (orig & MSR_HV_SCTRL_RSVD_MASK); 611b7bb4816SSepherosa Ziehau wrmsr(MSR_HV_SCONTROL, val); 612b7bb4816SSepherosa Ziehau } 613b7bb4816SSepherosa Ziehau 614b7bb4816SSepherosa Ziehau static void 615b7bb4816SSepherosa Ziehau vmbus_synic_teardown(void *arg) 616b7bb4816SSepherosa Ziehau { 617b7bb4816SSepherosa Ziehau uint64_t orig; 618b7bb4816SSepherosa Ziehau uint32_t sint; 619b7bb4816SSepherosa Ziehau 620b7bb4816SSepherosa Ziehau /* 621b7bb4816SSepherosa Ziehau * Disable SynIC. 622b7bb4816SSepherosa Ziehau */ 623b7bb4816SSepherosa Ziehau orig = rdmsr(MSR_HV_SCONTROL); 624b7bb4816SSepherosa Ziehau wrmsr(MSR_HV_SCONTROL, (orig & MSR_HV_SCTRL_RSVD_MASK)); 625b7bb4816SSepherosa Ziehau 626b7bb4816SSepherosa Ziehau /* 627b7bb4816SSepherosa Ziehau * Mask message and event flags SINT. 628b7bb4816SSepherosa Ziehau */ 629b7bb4816SSepherosa Ziehau sint = MSR_HV_SINT0 + VMBUS_SINT_MESSAGE; 630b7bb4816SSepherosa Ziehau orig = rdmsr(sint); 631b7bb4816SSepherosa Ziehau wrmsr(sint, orig | MSR_HV_SINT_MASKED); 632b7bb4816SSepherosa Ziehau 633b7bb4816SSepherosa Ziehau /* 634b7bb4816SSepherosa Ziehau * Mask timer SINT. 635b7bb4816SSepherosa Ziehau */ 636b7bb4816SSepherosa Ziehau sint = MSR_HV_SINT0 + VMBUS_SINT_TIMER; 637b7bb4816SSepherosa Ziehau orig = rdmsr(sint); 638b7bb4816SSepherosa Ziehau wrmsr(sint, orig | MSR_HV_SINT_MASKED); 639b7bb4816SSepherosa Ziehau 640b7bb4816SSepherosa Ziehau /* 641b7bb4816SSepherosa Ziehau * Teardown SynIC message. 642b7bb4816SSepherosa Ziehau */ 643b7bb4816SSepherosa Ziehau orig = rdmsr(MSR_HV_SIMP); 644b7bb4816SSepherosa Ziehau wrmsr(MSR_HV_SIMP, (orig & MSR_HV_SIMP_RSVD_MASK)); 645b7bb4816SSepherosa Ziehau 646b7bb4816SSepherosa Ziehau /* 647b7bb4816SSepherosa Ziehau * Teardown SynIC event flags. 648b7bb4816SSepherosa Ziehau */ 649b7bb4816SSepherosa Ziehau orig = rdmsr(MSR_HV_SIEFP); 650b7bb4816SSepherosa Ziehau wrmsr(MSR_HV_SIEFP, (orig & MSR_HV_SIEFP_RSVD_MASK)); 651b7bb4816SSepherosa Ziehau } 652b7bb4816SSepherosa Ziehau 653b7bb4816SSepherosa Ziehau static int 654b7bb4816SSepherosa Ziehau vmbus_dma_alloc(struct vmbus_softc *sc) 655b7bb4816SSepherosa Ziehau { 6566523ab7eSSepherosa Ziehau bus_dma_tag_t parent_dtag; 6576523ab7eSSepherosa Ziehau uint8_t *evtflags; 658b7bb4816SSepherosa Ziehau int cpu; 659b7bb4816SSepherosa Ziehau 6606523ab7eSSepherosa Ziehau parent_dtag = bus_get_dma_tag(sc->vmbus_dev); 661b7bb4816SSepherosa Ziehau CPU_FOREACH(cpu) { 662b7bb4816SSepherosa Ziehau void *ptr; 663b7bb4816SSepherosa Ziehau 664b7bb4816SSepherosa Ziehau /* 665b7bb4816SSepherosa Ziehau * Per-cpu messages and event flags. 666b7bb4816SSepherosa Ziehau */ 6676523ab7eSSepherosa Ziehau ptr = hyperv_dmamem_alloc(parent_dtag, PAGE_SIZE, 0, 6686523ab7eSSepherosa Ziehau PAGE_SIZE, VMBUS_PCPU_PTR(sc, message_dma, cpu), 669b7bb4816SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO); 670b7bb4816SSepherosa Ziehau if (ptr == NULL) 671b7bb4816SSepherosa Ziehau return ENOMEM; 672b7bb4816SSepherosa Ziehau VMBUS_PCPU_GET(sc, message, cpu) = ptr; 673b7bb4816SSepherosa Ziehau 6746523ab7eSSepherosa Ziehau ptr = hyperv_dmamem_alloc(parent_dtag, PAGE_SIZE, 0, 6756523ab7eSSepherosa Ziehau PAGE_SIZE, VMBUS_PCPU_PTR(sc, event_flags_dma, cpu), 676b7bb4816SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO); 677b7bb4816SSepherosa Ziehau if (ptr == NULL) 678b7bb4816SSepherosa Ziehau return ENOMEM; 679b7bb4816SSepherosa Ziehau VMBUS_PCPU_GET(sc, event_flags, cpu) = ptr; 680b7bb4816SSepherosa Ziehau } 6816523ab7eSSepherosa Ziehau 6826523ab7eSSepherosa Ziehau evtflags = hyperv_dmamem_alloc(parent_dtag, PAGE_SIZE, 0, 6836523ab7eSSepherosa Ziehau PAGE_SIZE, &sc->vmbus_evtflags_dma, BUS_DMA_WAITOK | BUS_DMA_ZERO); 6846523ab7eSSepherosa Ziehau if (evtflags == NULL) 6856523ab7eSSepherosa Ziehau return ENOMEM; 6866523ab7eSSepherosa Ziehau sc->vmbus_rx_evtflags = (u_long *)evtflags; 68751a9a000SSepherosa Ziehau sc->vmbus_tx_evtflags = (u_long *)(evtflags + (PAGE_SIZE / 2)); 6886523ab7eSSepherosa Ziehau sc->vmbus_evtflags = evtflags; 6896523ab7eSSepherosa Ziehau 6906523ab7eSSepherosa Ziehau sc->vmbus_mnf1 = hyperv_dmamem_alloc(parent_dtag, PAGE_SIZE, 0, 6916523ab7eSSepherosa Ziehau PAGE_SIZE, &sc->vmbus_mnf1_dma, BUS_DMA_WAITOK | BUS_DMA_ZERO); 6926523ab7eSSepherosa Ziehau if (sc->vmbus_mnf1 == NULL) 6936523ab7eSSepherosa Ziehau return ENOMEM; 6946523ab7eSSepherosa Ziehau 6956523ab7eSSepherosa Ziehau sc->vmbus_mnf2 = hyperv_dmamem_alloc(parent_dtag, PAGE_SIZE, 0, 6966523ab7eSSepherosa Ziehau PAGE_SIZE, &sc->vmbus_mnf2_dma, BUS_DMA_WAITOK | BUS_DMA_ZERO); 6976523ab7eSSepherosa Ziehau if (sc->vmbus_mnf2 == NULL) 6986523ab7eSSepherosa Ziehau return ENOMEM; 6996523ab7eSSepherosa Ziehau 700b7bb4816SSepherosa Ziehau return 0; 701b7bb4816SSepherosa Ziehau } 702b7bb4816SSepherosa Ziehau 703b7bb4816SSepherosa Ziehau static void 704b7bb4816SSepherosa Ziehau vmbus_dma_free(struct vmbus_softc *sc) 705b7bb4816SSepherosa Ziehau { 706b7bb4816SSepherosa Ziehau int cpu; 707b7bb4816SSepherosa Ziehau 7086523ab7eSSepherosa Ziehau if (sc->vmbus_evtflags != NULL) { 7096523ab7eSSepherosa Ziehau hyperv_dmamem_free(&sc->vmbus_evtflags_dma, sc->vmbus_evtflags); 7106523ab7eSSepherosa Ziehau sc->vmbus_evtflags = NULL; 7116523ab7eSSepherosa Ziehau sc->vmbus_rx_evtflags = NULL; 7126523ab7eSSepherosa Ziehau sc->vmbus_tx_evtflags = NULL; 7136523ab7eSSepherosa Ziehau } 7146523ab7eSSepherosa Ziehau if (sc->vmbus_mnf1 != NULL) { 7156523ab7eSSepherosa Ziehau hyperv_dmamem_free(&sc->vmbus_mnf1_dma, sc->vmbus_mnf1); 7166523ab7eSSepherosa Ziehau sc->vmbus_mnf1 = NULL; 7176523ab7eSSepherosa Ziehau } 7186523ab7eSSepherosa Ziehau if (sc->vmbus_mnf2 != NULL) { 7196523ab7eSSepherosa Ziehau hyperv_dmamem_free(&sc->vmbus_mnf2_dma, sc->vmbus_mnf2); 7206523ab7eSSepherosa Ziehau sc->vmbus_mnf2 = NULL; 7216523ab7eSSepherosa Ziehau } 7226523ab7eSSepherosa Ziehau 723b7bb4816SSepherosa Ziehau CPU_FOREACH(cpu) { 724b7bb4816SSepherosa Ziehau if (VMBUS_PCPU_GET(sc, message, cpu) != NULL) { 725b7bb4816SSepherosa Ziehau hyperv_dmamem_free( 726b7bb4816SSepherosa Ziehau VMBUS_PCPU_PTR(sc, message_dma, cpu), 727b7bb4816SSepherosa Ziehau VMBUS_PCPU_GET(sc, message, cpu)); 728b7bb4816SSepherosa Ziehau VMBUS_PCPU_GET(sc, message, cpu) = NULL; 729b7bb4816SSepherosa Ziehau } 730b7bb4816SSepherosa Ziehau if (VMBUS_PCPU_GET(sc, event_flags, cpu) != NULL) { 731b7bb4816SSepherosa Ziehau hyperv_dmamem_free( 732b7bb4816SSepherosa Ziehau VMBUS_PCPU_PTR(sc, event_flags_dma, cpu), 733b7bb4816SSepherosa Ziehau VMBUS_PCPU_GET(sc, event_flags, cpu)); 734b7bb4816SSepherosa Ziehau VMBUS_PCPU_GET(sc, event_flags, cpu) = NULL; 735b7bb4816SSepherosa Ziehau } 736b7bb4816SSepherosa Ziehau } 737b7bb4816SSepherosa Ziehau } 738b7bb4816SSepherosa Ziehau 739b7bb4816SSepherosa Ziehau static int 740b7bb4816SSepherosa Ziehau vmbus_intr_setup(struct vmbus_softc *sc) 741b7bb4816SSepherosa Ziehau { 742b7bb4816SSepherosa Ziehau int cpu; 743b7bb4816SSepherosa Ziehau 744b7bb4816SSepherosa Ziehau CPU_FOREACH(cpu) { 745b7bb4816SSepherosa Ziehau char buf[MAXCOMLEN + 1]; 746b7bb4816SSepherosa Ziehau cpuset_t cpu_mask; 747b7bb4816SSepherosa Ziehau 748b7bb4816SSepherosa Ziehau /* Allocate an interrupt counter for Hyper-V interrupt */ 749b7bb4816SSepherosa Ziehau snprintf(buf, sizeof(buf), "cpu%d:hyperv", cpu); 750b7bb4816SSepherosa Ziehau intrcnt_add(buf, VMBUS_PCPU_PTR(sc, intr_cnt, cpu)); 751b7bb4816SSepherosa Ziehau 752b7bb4816SSepherosa Ziehau /* 753b7bb4816SSepherosa Ziehau * Setup taskqueue to handle events. Task will be per- 754b7bb4816SSepherosa Ziehau * channel. 755b7bb4816SSepherosa Ziehau */ 756b7bb4816SSepherosa Ziehau VMBUS_PCPU_GET(sc, event_tq, cpu) = taskqueue_create_fast( 757b7bb4816SSepherosa Ziehau "hyperv event", M_WAITOK, taskqueue_thread_enqueue, 758b7bb4816SSepherosa Ziehau VMBUS_PCPU_PTR(sc, event_tq, cpu)); 759b7bb4816SSepherosa Ziehau CPU_SETOF(cpu, &cpu_mask); 760b7bb4816SSepherosa Ziehau taskqueue_start_threads_cpuset( 761b7bb4816SSepherosa Ziehau VMBUS_PCPU_PTR(sc, event_tq, cpu), 1, PI_NET, &cpu_mask, 762b7bb4816SSepherosa Ziehau "hvevent%d", cpu); 763b7bb4816SSepherosa Ziehau 764b7bb4816SSepherosa Ziehau /* 765b7bb4816SSepherosa Ziehau * Setup tasks and taskqueues to handle messages. 766b7bb4816SSepherosa Ziehau */ 767b7bb4816SSepherosa Ziehau VMBUS_PCPU_GET(sc, message_tq, cpu) = taskqueue_create_fast( 768b7bb4816SSepherosa Ziehau "hyperv msg", M_WAITOK, taskqueue_thread_enqueue, 769b7bb4816SSepherosa Ziehau VMBUS_PCPU_PTR(sc, message_tq, cpu)); 770b7bb4816SSepherosa Ziehau CPU_SETOF(cpu, &cpu_mask); 771b7bb4816SSepherosa Ziehau taskqueue_start_threads_cpuset( 772b7bb4816SSepherosa Ziehau VMBUS_PCPU_PTR(sc, message_tq, cpu), 1, PI_NET, &cpu_mask, 773b7bb4816SSepherosa Ziehau "hvmsg%d", cpu); 774b7bb4816SSepherosa Ziehau TASK_INIT(VMBUS_PCPU_PTR(sc, message_task, cpu), 0, 775b7bb4816SSepherosa Ziehau vmbus_msg_task, sc); 776b7bb4816SSepherosa Ziehau } 777b7bb4816SSepherosa Ziehau 778b7bb4816SSepherosa Ziehau /* 779b7bb4816SSepherosa Ziehau * All Hyper-V ISR required resources are setup, now let's find a 780b7bb4816SSepherosa Ziehau * free IDT vector for Hyper-V ISR and set it up. 781b7bb4816SSepherosa Ziehau */ 782b7bb4816SSepherosa Ziehau sc->vmbus_idtvec = lapic_ipi_alloc(IDTVEC(vmbus_isr)); 783b7bb4816SSepherosa Ziehau if (sc->vmbus_idtvec < 0) { 784b7bb4816SSepherosa Ziehau device_printf(sc->vmbus_dev, "cannot find free IDT vector\n"); 785b7bb4816SSepherosa Ziehau return ENXIO; 786b7bb4816SSepherosa Ziehau } 787b7bb4816SSepherosa Ziehau if(bootverbose) { 788b7bb4816SSepherosa Ziehau device_printf(sc->vmbus_dev, "vmbus IDT vector %d\n", 789b7bb4816SSepherosa Ziehau sc->vmbus_idtvec); 790b7bb4816SSepherosa Ziehau } 791b7bb4816SSepherosa Ziehau return 0; 792b7bb4816SSepherosa Ziehau } 793b7bb4816SSepherosa Ziehau 794b7bb4816SSepherosa Ziehau static void 795b7bb4816SSepherosa Ziehau vmbus_intr_teardown(struct vmbus_softc *sc) 796b7bb4816SSepherosa Ziehau { 797b7bb4816SSepherosa Ziehau int cpu; 798b7bb4816SSepherosa Ziehau 799b7bb4816SSepherosa Ziehau if (sc->vmbus_idtvec >= 0) { 800b7bb4816SSepherosa Ziehau lapic_ipi_free(sc->vmbus_idtvec); 801b7bb4816SSepherosa Ziehau sc->vmbus_idtvec = -1; 802b7bb4816SSepherosa Ziehau } 803b7bb4816SSepherosa Ziehau 804b7bb4816SSepherosa Ziehau CPU_FOREACH(cpu) { 805b7bb4816SSepherosa Ziehau if (VMBUS_PCPU_GET(sc, event_tq, cpu) != NULL) { 806b7bb4816SSepherosa Ziehau taskqueue_free(VMBUS_PCPU_GET(sc, event_tq, cpu)); 807b7bb4816SSepherosa Ziehau VMBUS_PCPU_GET(sc, event_tq, cpu) = NULL; 808b7bb4816SSepherosa Ziehau } 809b7bb4816SSepherosa Ziehau if (VMBUS_PCPU_GET(sc, message_tq, cpu) != NULL) { 810b7bb4816SSepherosa Ziehau taskqueue_drain(VMBUS_PCPU_GET(sc, message_tq, cpu), 811b7bb4816SSepherosa Ziehau VMBUS_PCPU_PTR(sc, message_task, cpu)); 812b7bb4816SSepherosa Ziehau taskqueue_free(VMBUS_PCPU_GET(sc, message_tq, cpu)); 813b7bb4816SSepherosa Ziehau VMBUS_PCPU_GET(sc, message_tq, cpu) = NULL; 814b7bb4816SSepherosa Ziehau } 815b7bb4816SSepherosa Ziehau } 816b7bb4816SSepherosa Ziehau } 817b7bb4816SSepherosa Ziehau 818b7bb4816SSepherosa Ziehau static int 819b7bb4816SSepherosa Ziehau vmbus_read_ivar(device_t dev, device_t child, int index, uintptr_t *result) 820b7bb4816SSepherosa Ziehau { 821b7bb4816SSepherosa Ziehau struct hv_device *child_dev_ctx = device_get_ivars(child); 822b7bb4816SSepherosa Ziehau 823b7bb4816SSepherosa Ziehau switch (index) { 824b7bb4816SSepherosa Ziehau case HV_VMBUS_IVAR_TYPE: 825b7bb4816SSepherosa Ziehau *result = (uintptr_t)&child_dev_ctx->class_id; 826b7bb4816SSepherosa Ziehau return (0); 827b7bb4816SSepherosa Ziehau 828b7bb4816SSepherosa Ziehau case HV_VMBUS_IVAR_INSTANCE: 829b7bb4816SSepherosa Ziehau *result = (uintptr_t)&child_dev_ctx->device_id; 830b7bb4816SSepherosa Ziehau return (0); 831b7bb4816SSepherosa Ziehau 832b7bb4816SSepherosa Ziehau case HV_VMBUS_IVAR_DEVCTX: 833b7bb4816SSepherosa Ziehau *result = (uintptr_t)child_dev_ctx; 834b7bb4816SSepherosa Ziehau return (0); 835b7bb4816SSepherosa Ziehau 836b7bb4816SSepherosa Ziehau case HV_VMBUS_IVAR_NODE: 837b7bb4816SSepherosa Ziehau *result = (uintptr_t)child_dev_ctx->device; 838b7bb4816SSepherosa Ziehau return (0); 839b7bb4816SSepherosa Ziehau } 840b7bb4816SSepherosa Ziehau return (ENOENT); 841b7bb4816SSepherosa Ziehau } 842b7bb4816SSepherosa Ziehau 843b7bb4816SSepherosa Ziehau static int 844b7bb4816SSepherosa Ziehau vmbus_write_ivar(device_t dev, device_t child, int index, uintptr_t value) 845b7bb4816SSepherosa Ziehau { 846b7bb4816SSepherosa Ziehau switch (index) { 847b7bb4816SSepherosa Ziehau case HV_VMBUS_IVAR_TYPE: 848b7bb4816SSepherosa Ziehau case HV_VMBUS_IVAR_INSTANCE: 849b7bb4816SSepherosa Ziehau case HV_VMBUS_IVAR_DEVCTX: 850b7bb4816SSepherosa Ziehau case HV_VMBUS_IVAR_NODE: 851b7bb4816SSepherosa Ziehau /* read-only */ 852b7bb4816SSepherosa Ziehau return (EINVAL); 853b7bb4816SSepherosa Ziehau } 854b7bb4816SSepherosa Ziehau return (ENOENT); 855b7bb4816SSepherosa Ziehau } 856b7bb4816SSepherosa Ziehau 857b7bb4816SSepherosa Ziehau static int 858b7bb4816SSepherosa Ziehau vmbus_child_pnpinfo_str(device_t dev, device_t child, char *buf, size_t buflen) 859b7bb4816SSepherosa Ziehau { 860b7bb4816SSepherosa Ziehau struct hv_device *dev_ctx = device_get_ivars(child); 861b7bb4816SSepherosa Ziehau char guidbuf[HYPERV_GUID_STRLEN]; 862b7bb4816SSepherosa Ziehau 863b7bb4816SSepherosa Ziehau if (dev_ctx == NULL) 864b7bb4816SSepherosa Ziehau return (0); 865b7bb4816SSepherosa Ziehau 866b7bb4816SSepherosa Ziehau strlcat(buf, "classid=", buflen); 867b7bb4816SSepherosa Ziehau hyperv_guid2str(&dev_ctx->class_id, guidbuf, sizeof(guidbuf)); 868b7bb4816SSepherosa Ziehau strlcat(buf, guidbuf, buflen); 869b7bb4816SSepherosa Ziehau 870b7bb4816SSepherosa Ziehau strlcat(buf, " deviceid=", buflen); 871b7bb4816SSepherosa Ziehau hyperv_guid2str(&dev_ctx->device_id, guidbuf, sizeof(guidbuf)); 872b7bb4816SSepherosa Ziehau strlcat(buf, guidbuf, buflen); 873b7bb4816SSepherosa Ziehau 874b7bb4816SSepherosa Ziehau return (0); 875b7bb4816SSepherosa Ziehau } 876b7bb4816SSepherosa Ziehau 877b7bb4816SSepherosa Ziehau struct hv_device * 878b7bb4816SSepherosa Ziehau hv_vmbus_child_device_create(hv_guid type, hv_guid instance, 879b7bb4816SSepherosa Ziehau hv_vmbus_channel *channel) 880b7bb4816SSepherosa Ziehau { 881b7bb4816SSepherosa Ziehau hv_device *child_dev; 882b7bb4816SSepherosa Ziehau 883b7bb4816SSepherosa Ziehau /* 884b7bb4816SSepherosa Ziehau * Allocate the new child device 885b7bb4816SSepherosa Ziehau */ 886b7bb4816SSepherosa Ziehau child_dev = malloc(sizeof(hv_device), M_DEVBUF, M_WAITOK | M_ZERO); 887b7bb4816SSepherosa Ziehau 888b7bb4816SSepherosa Ziehau child_dev->channel = channel; 889b7bb4816SSepherosa Ziehau memcpy(&child_dev->class_id, &type, sizeof(hv_guid)); 890b7bb4816SSepherosa Ziehau memcpy(&child_dev->device_id, &instance, sizeof(hv_guid)); 891b7bb4816SSepherosa Ziehau 892b7bb4816SSepherosa Ziehau return (child_dev); 893b7bb4816SSepherosa Ziehau } 894b7bb4816SSepherosa Ziehau 895b7bb4816SSepherosa Ziehau int 896b7bb4816SSepherosa Ziehau hv_vmbus_child_device_register(struct hv_device *child_dev) 897b7bb4816SSepherosa Ziehau { 898b7bb4816SSepherosa Ziehau device_t child, parent; 899b7bb4816SSepherosa Ziehau 900b7bb4816SSepherosa Ziehau parent = vmbus_get_device(); 901b7bb4816SSepherosa Ziehau if (bootverbose) { 902b7bb4816SSepherosa Ziehau char name[HYPERV_GUID_STRLEN]; 903b7bb4816SSepherosa Ziehau 904b7bb4816SSepherosa Ziehau hyperv_guid2str(&child_dev->class_id, name, sizeof(name)); 905b7bb4816SSepherosa Ziehau device_printf(parent, "add device, classid: %s\n", name); 906b7bb4816SSepherosa Ziehau } 907b7bb4816SSepherosa Ziehau 908b7bb4816SSepherosa Ziehau child = device_add_child(parent, NULL, -1); 909b7bb4816SSepherosa Ziehau child_dev->device = child; 910b7bb4816SSepherosa Ziehau device_set_ivars(child, child_dev); 911b7bb4816SSepherosa Ziehau 912b7bb4816SSepherosa Ziehau return (0); 913b7bb4816SSepherosa Ziehau } 914b7bb4816SSepherosa Ziehau 915b7bb4816SSepherosa Ziehau int 916b7bb4816SSepherosa Ziehau hv_vmbus_child_device_unregister(struct hv_device *child_dev) 917b7bb4816SSepherosa Ziehau { 918b7bb4816SSepherosa Ziehau int ret = 0; 919b7bb4816SSepherosa Ziehau /* 920b7bb4816SSepherosa Ziehau * XXXKYS: Ensure that this is the opposite of 921b7bb4816SSepherosa Ziehau * device_add_child() 922b7bb4816SSepherosa Ziehau */ 923b7bb4816SSepherosa Ziehau mtx_lock(&Giant); 924b7bb4816SSepherosa Ziehau ret = device_delete_child(vmbus_get_device(), child_dev->device); 925b7bb4816SSepherosa Ziehau mtx_unlock(&Giant); 926b7bb4816SSepherosa Ziehau return(ret); 927b7bb4816SSepherosa Ziehau } 928b7bb4816SSepherosa Ziehau 929b7bb4816SSepherosa Ziehau static int 930b7bb4816SSepherosa Ziehau vmbus_probe(device_t dev) 931b7bb4816SSepherosa Ziehau { 932b7bb4816SSepherosa Ziehau char *id[] = { "VMBUS", NULL }; 933b7bb4816SSepherosa Ziehau 934b7bb4816SSepherosa Ziehau if (ACPI_ID_PROBE(device_get_parent(dev), dev, id) == NULL || 935b7bb4816SSepherosa Ziehau device_get_unit(dev) != 0 || vm_guest != VM_GUEST_HV || 936b7bb4816SSepherosa Ziehau (hyperv_features & CPUID_HV_MSR_SYNIC) == 0) 937b7bb4816SSepherosa Ziehau return (ENXIO); 938b7bb4816SSepherosa Ziehau 939b7bb4816SSepherosa Ziehau device_set_desc(dev, "Hyper-V Vmbus"); 940b7bb4816SSepherosa Ziehau 941b7bb4816SSepherosa Ziehau return (BUS_PROBE_DEFAULT); 942b7bb4816SSepherosa Ziehau } 943b7bb4816SSepherosa Ziehau 944b7bb4816SSepherosa Ziehau /** 945b7bb4816SSepherosa Ziehau * @brief Main vmbus driver initialization routine. 946b7bb4816SSepherosa Ziehau * 947b7bb4816SSepherosa Ziehau * Here, we 948b7bb4816SSepherosa Ziehau * - initialize the vmbus driver context 949b7bb4816SSepherosa Ziehau * - setup various driver entry points 950b7bb4816SSepherosa Ziehau * - invoke the vmbus hv main init routine 951b7bb4816SSepherosa Ziehau * - get the irq resource 952b7bb4816SSepherosa Ziehau * - invoke the vmbus to add the vmbus root device 953b7bb4816SSepherosa Ziehau * - setup the vmbus root device 954b7bb4816SSepherosa Ziehau * - retrieve the channel offers 955b7bb4816SSepherosa Ziehau */ 956b7bb4816SSepherosa Ziehau static int 957b7bb4816SSepherosa Ziehau vmbus_bus_init(void) 958b7bb4816SSepherosa Ziehau { 959b7bb4816SSepherosa Ziehau struct vmbus_softc *sc = vmbus_get_softc(); 960b7bb4816SSepherosa Ziehau int ret; 961b7bb4816SSepherosa Ziehau 962b7bb4816SSepherosa Ziehau if (sc->vmbus_flags & VMBUS_FLAG_ATTACHED) 963b7bb4816SSepherosa Ziehau return (0); 964b7bb4816SSepherosa Ziehau sc->vmbus_flags |= VMBUS_FLAG_ATTACHED; 965b7bb4816SSepherosa Ziehau 966b7bb4816SSepherosa Ziehau /* 967*236764b1SSepherosa Ziehau * Create context for "post message" Hypercalls 968*236764b1SSepherosa Ziehau */ 969*236764b1SSepherosa Ziehau sc->vmbus_msg_hc = vmbus_msghc_ctx_create( 970*236764b1SSepherosa Ziehau bus_get_dma_tag(sc->vmbus_dev)); 971*236764b1SSepherosa Ziehau if (sc->vmbus_msg_hc == NULL) { 972*236764b1SSepherosa Ziehau ret = ENXIO; 973*236764b1SSepherosa Ziehau goto cleanup; 974*236764b1SSepherosa Ziehau } 975*236764b1SSepherosa Ziehau 976*236764b1SSepherosa Ziehau /* 977b7bb4816SSepherosa Ziehau * Allocate DMA stuffs. 978b7bb4816SSepherosa Ziehau */ 979b7bb4816SSepherosa Ziehau ret = vmbus_dma_alloc(sc); 980b7bb4816SSepherosa Ziehau if (ret != 0) 981b7bb4816SSepherosa Ziehau goto cleanup; 982b7bb4816SSepherosa Ziehau 983b7bb4816SSepherosa Ziehau /* 984b7bb4816SSepherosa Ziehau * Setup interrupt. 985b7bb4816SSepherosa Ziehau */ 986b7bb4816SSepherosa Ziehau ret = vmbus_intr_setup(sc); 987b7bb4816SSepherosa Ziehau if (ret != 0) 988b7bb4816SSepherosa Ziehau goto cleanup; 989b7bb4816SSepherosa Ziehau 990b7bb4816SSepherosa Ziehau /* 991b7bb4816SSepherosa Ziehau * Setup SynIC. 992b7bb4816SSepherosa Ziehau */ 993b7bb4816SSepherosa Ziehau if (bootverbose) 994b7bb4816SSepherosa Ziehau device_printf(sc->vmbus_dev, "smp_started = %d\n", smp_started); 995b7bb4816SSepherosa Ziehau smp_rendezvous(NULL, vmbus_synic_setup, NULL, sc); 996b7bb4816SSepherosa Ziehau sc->vmbus_flags |= VMBUS_FLAG_SYNIC; 997b7bb4816SSepherosa Ziehau 998b7bb4816SSepherosa Ziehau /* 999b7bb4816SSepherosa Ziehau * Connect to VMBus in the root partition 1000b7bb4816SSepherosa Ziehau */ 10016523ab7eSSepherosa Ziehau ret = hv_vmbus_connect(sc); 1002b7bb4816SSepherosa Ziehau if (ret != 0) 1003b7bb4816SSepherosa Ziehau goto cleanup; 1004b7bb4816SSepherosa Ziehau 1005*236764b1SSepherosa Ziehau ret = vmbus_init(sc); 1006*236764b1SSepherosa Ziehau if (ret != 0) 1007*236764b1SSepherosa Ziehau goto cleanup; 1008*236764b1SSepherosa Ziehau 1009b7bb4816SSepherosa Ziehau if (hv_vmbus_protocal_version == HV_VMBUS_VERSION_WS2008 || 1010b7bb4816SSepherosa Ziehau hv_vmbus_protocal_version == HV_VMBUS_VERSION_WIN7) 1011b7bb4816SSepherosa Ziehau sc->vmbus_event_proc = vmbus_event_proc_compat; 1012b7bb4816SSepherosa Ziehau else 1013b7bb4816SSepherosa Ziehau sc->vmbus_event_proc = vmbus_event_proc; 1014b7bb4816SSepherosa Ziehau 1015b7bb4816SSepherosa Ziehau hv_vmbus_request_channel_offers(); 1016b7bb4816SSepherosa Ziehau 1017b7bb4816SSepherosa Ziehau vmbus_scan(); 1018b7bb4816SSepherosa Ziehau bus_generic_attach(sc->vmbus_dev); 1019b7bb4816SSepherosa Ziehau device_printf(sc->vmbus_dev, "device scan, probe and attach done\n"); 1020b7bb4816SSepherosa Ziehau 1021b7bb4816SSepherosa Ziehau return (ret); 1022b7bb4816SSepherosa Ziehau 1023b7bb4816SSepherosa Ziehau cleanup: 1024b7bb4816SSepherosa Ziehau vmbus_intr_teardown(sc); 1025b7bb4816SSepherosa Ziehau vmbus_dma_free(sc); 1026*236764b1SSepherosa Ziehau if (sc->vmbus_msg_hc != NULL) { 1027*236764b1SSepherosa Ziehau vmbus_msghc_ctx_destroy(sc->vmbus_msg_hc); 1028*236764b1SSepherosa Ziehau sc->vmbus_msg_hc = NULL; 1029*236764b1SSepherosa Ziehau } 1030b7bb4816SSepherosa Ziehau 1031b7bb4816SSepherosa Ziehau return (ret); 1032b7bb4816SSepherosa Ziehau } 1033b7bb4816SSepherosa Ziehau 1034b7bb4816SSepherosa Ziehau static void 1035b7bb4816SSepherosa Ziehau vmbus_event_proc_dummy(struct vmbus_softc *sc __unused, int cpu __unused) 1036b7bb4816SSepherosa Ziehau { 1037b7bb4816SSepherosa Ziehau } 1038b7bb4816SSepherosa Ziehau 1039b7bb4816SSepherosa Ziehau static int 1040b7bb4816SSepherosa Ziehau vmbus_attach(device_t dev) 1041b7bb4816SSepherosa Ziehau { 1042b7bb4816SSepherosa Ziehau vmbus_sc = device_get_softc(dev); 1043b7bb4816SSepherosa Ziehau vmbus_sc->vmbus_dev = dev; 1044b7bb4816SSepherosa Ziehau vmbus_sc->vmbus_idtvec = -1; 1045b7bb4816SSepherosa Ziehau 1046b7bb4816SSepherosa Ziehau /* 1047b7bb4816SSepherosa Ziehau * Event processing logic will be configured: 1048b7bb4816SSepherosa Ziehau * - After the vmbus protocol version negotiation. 1049b7bb4816SSepherosa Ziehau * - Before we request channel offers. 1050b7bb4816SSepherosa Ziehau */ 1051b7bb4816SSepherosa Ziehau vmbus_sc->vmbus_event_proc = vmbus_event_proc_dummy; 1052b7bb4816SSepherosa Ziehau 1053b7bb4816SSepherosa Ziehau #ifndef EARLY_AP_STARTUP 1054b7bb4816SSepherosa Ziehau /* 1055b7bb4816SSepherosa Ziehau * If the system has already booted and thread 1056b7bb4816SSepherosa Ziehau * scheduling is possible indicated by the global 1057b7bb4816SSepherosa Ziehau * cold set to zero, we just call the driver 1058b7bb4816SSepherosa Ziehau * initialization directly. 1059b7bb4816SSepherosa Ziehau */ 1060b7bb4816SSepherosa Ziehau if (!cold) 1061b7bb4816SSepherosa Ziehau #endif 1062b7bb4816SSepherosa Ziehau vmbus_bus_init(); 1063b7bb4816SSepherosa Ziehau 1064b7bb4816SSepherosa Ziehau bus_generic_probe(dev); 1065b7bb4816SSepherosa Ziehau return (0); 1066b7bb4816SSepherosa Ziehau } 1067b7bb4816SSepherosa Ziehau 1068b7bb4816SSepherosa Ziehau static void 1069b7bb4816SSepherosa Ziehau vmbus_sysinit(void *arg __unused) 1070b7bb4816SSepherosa Ziehau { 1071b7bb4816SSepherosa Ziehau if (vm_guest != VM_GUEST_HV || vmbus_get_softc() == NULL) 1072b7bb4816SSepherosa Ziehau return; 1073b7bb4816SSepherosa Ziehau 1074b7bb4816SSepherosa Ziehau #ifndef EARLY_AP_STARTUP 1075b7bb4816SSepherosa Ziehau /* 1076b7bb4816SSepherosa Ziehau * If the system has already booted and thread 1077b7bb4816SSepherosa Ziehau * scheduling is possible, as indicated by the 1078b7bb4816SSepherosa Ziehau * global cold set to zero, we just call the driver 1079b7bb4816SSepherosa Ziehau * initialization directly. 1080b7bb4816SSepherosa Ziehau */ 1081b7bb4816SSepherosa Ziehau if (!cold) 1082b7bb4816SSepherosa Ziehau #endif 1083b7bb4816SSepherosa Ziehau vmbus_bus_init(); 1084b7bb4816SSepherosa Ziehau } 1085b7bb4816SSepherosa Ziehau 1086b7bb4816SSepherosa Ziehau static int 1087b7bb4816SSepherosa Ziehau vmbus_detach(device_t dev) 1088b7bb4816SSepherosa Ziehau { 1089b7bb4816SSepherosa Ziehau struct vmbus_softc *sc = device_get_softc(dev); 1090b7bb4816SSepherosa Ziehau 1091b7bb4816SSepherosa Ziehau hv_vmbus_release_unattached_channels(); 1092b7bb4816SSepherosa Ziehau hv_vmbus_disconnect(); 1093b7bb4816SSepherosa Ziehau 1094b7bb4816SSepherosa Ziehau if (sc->vmbus_flags & VMBUS_FLAG_SYNIC) { 1095b7bb4816SSepherosa Ziehau sc->vmbus_flags &= ~VMBUS_FLAG_SYNIC; 1096b7bb4816SSepherosa Ziehau smp_rendezvous(NULL, vmbus_synic_teardown, NULL, NULL); 1097b7bb4816SSepherosa Ziehau } 1098b7bb4816SSepherosa Ziehau 1099b7bb4816SSepherosa Ziehau vmbus_intr_teardown(sc); 1100b7bb4816SSepherosa Ziehau vmbus_dma_free(sc); 1101b7bb4816SSepherosa Ziehau 1102*236764b1SSepherosa Ziehau if (sc->vmbus_msg_hc != NULL) { 1103*236764b1SSepherosa Ziehau vmbus_msghc_ctx_destroy(sc->vmbus_msg_hc); 1104*236764b1SSepherosa Ziehau sc->vmbus_msg_hc = NULL; 1105*236764b1SSepherosa Ziehau } 1106*236764b1SSepherosa Ziehau 1107b7bb4816SSepherosa Ziehau return (0); 1108b7bb4816SSepherosa Ziehau } 1109b7bb4816SSepherosa Ziehau 1110b7bb4816SSepherosa Ziehau static device_method_t vmbus_methods[] = { 1111b7bb4816SSepherosa Ziehau /* Device interface */ 1112b7bb4816SSepherosa Ziehau DEVMETHOD(device_probe, vmbus_probe), 1113b7bb4816SSepherosa Ziehau DEVMETHOD(device_attach, vmbus_attach), 1114b7bb4816SSepherosa Ziehau DEVMETHOD(device_detach, vmbus_detach), 1115b7bb4816SSepherosa Ziehau DEVMETHOD(device_shutdown, bus_generic_shutdown), 1116b7bb4816SSepherosa Ziehau DEVMETHOD(device_suspend, bus_generic_suspend), 1117b7bb4816SSepherosa Ziehau DEVMETHOD(device_resume, bus_generic_resume), 1118b7bb4816SSepherosa Ziehau 1119b7bb4816SSepherosa Ziehau /* Bus interface */ 1120b7bb4816SSepherosa Ziehau DEVMETHOD(bus_add_child, bus_generic_add_child), 1121b7bb4816SSepherosa Ziehau DEVMETHOD(bus_print_child, bus_generic_print_child), 1122b7bb4816SSepherosa Ziehau DEVMETHOD(bus_read_ivar, vmbus_read_ivar), 1123b7bb4816SSepherosa Ziehau DEVMETHOD(bus_write_ivar, vmbus_write_ivar), 1124b7bb4816SSepherosa Ziehau DEVMETHOD(bus_child_pnpinfo_str, vmbus_child_pnpinfo_str), 1125b7bb4816SSepherosa Ziehau 1126b7bb4816SSepherosa Ziehau DEVMETHOD_END 1127b7bb4816SSepherosa Ziehau }; 1128b7bb4816SSepherosa Ziehau 1129b7bb4816SSepherosa Ziehau static driver_t vmbus_driver = { 1130b7bb4816SSepherosa Ziehau "vmbus", 1131b7bb4816SSepherosa Ziehau vmbus_methods, 1132b7bb4816SSepherosa Ziehau sizeof(struct vmbus_softc) 1133b7bb4816SSepherosa Ziehau }; 1134b7bb4816SSepherosa Ziehau 1135b7bb4816SSepherosa Ziehau static devclass_t vmbus_devclass; 1136b7bb4816SSepherosa Ziehau 1137b7bb4816SSepherosa Ziehau DRIVER_MODULE(vmbus, acpi, vmbus_driver, vmbus_devclass, NULL, NULL); 1138b7bb4816SSepherosa Ziehau MODULE_DEPEND(vmbus, acpi, 1, 1, 1); 1139b7bb4816SSepherosa Ziehau MODULE_VERSION(vmbus, 1); 1140b7bb4816SSepherosa Ziehau 1141b7bb4816SSepherosa Ziehau #ifndef EARLY_AP_STARTUP 1142b7bb4816SSepherosa Ziehau /* 1143b7bb4816SSepherosa Ziehau * NOTE: 1144b7bb4816SSepherosa Ziehau * We have to start as the last step of SI_SUB_SMP, i.e. after SMP is 1145b7bb4816SSepherosa Ziehau * initialized. 1146b7bb4816SSepherosa Ziehau */ 1147b7bb4816SSepherosa Ziehau SYSINIT(vmbus_initialize, SI_SUB_SMP, SI_ORDER_ANY, vmbus_sysinit, NULL); 1148b7bb4816SSepherosa Ziehau #endif 1149