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 72236764b1SSepherosa Ziehau /* 73236764b1SSepherosa Ziehau * NOTE: DO NOT CHANGE THESE 74236764b1SSepherosa Ziehau */ 75236764b1SSepherosa Ziehau #define VMBUS_CONNID_MESSAGE 1 76236764b1SSepherosa Ziehau #define VMBUS_CONNID_EVENT 2 77236764b1SSepherosa Ziehau 78236764b1SSepherosa Ziehau struct vmbus_msghc { 79236764b1SSepherosa Ziehau struct hypercall_postmsg_in *mh_inprm; 80236764b1SSepherosa Ziehau struct hypercall_postmsg_in mh_inprm_save; 81236764b1SSepherosa Ziehau struct hyperv_dma mh_inprm_dma; 82236764b1SSepherosa Ziehau 83236764b1SSepherosa Ziehau struct vmbus_message *mh_resp; 84236764b1SSepherosa Ziehau struct vmbus_message mh_resp0; 85236764b1SSepherosa Ziehau }; 86236764b1SSepherosa Ziehau 87236764b1SSepherosa Ziehau struct vmbus_msghc_ctx { 88236764b1SSepherosa Ziehau struct vmbus_msghc *mhc_free; 89236764b1SSepherosa Ziehau struct mtx mhc_free_lock; 90236764b1SSepherosa Ziehau uint32_t mhc_flags; 91236764b1SSepherosa Ziehau 92236764b1SSepherosa Ziehau struct vmbus_msghc *mhc_active; 93236764b1SSepherosa Ziehau struct mtx mhc_active_lock; 94236764b1SSepherosa Ziehau }; 95236764b1SSepherosa Ziehau 96236764b1SSepherosa Ziehau #define VMBUS_MSGHC_CTXF_DESTROY 0x0001 97236764b1SSepherosa Ziehau 98236764b1SSepherosa Ziehau static int vmbus_init(struct vmbus_softc *); 99236764b1SSepherosa Ziehau static int vmbus_init_contact(struct vmbus_softc *, 100236764b1SSepherosa Ziehau uint32_t); 101c1cc5bdfSSepherosa Ziehau static int vmbus_req_channels(struct vmbus_softc *sc); 102236764b1SSepherosa Ziehau 103236764b1SSepherosa Ziehau static struct vmbus_msghc_ctx *vmbus_msghc_ctx_create(bus_dma_tag_t); 104236764b1SSepherosa Ziehau static void vmbus_msghc_ctx_destroy( 105236764b1SSepherosa Ziehau struct vmbus_msghc_ctx *); 106236764b1SSepherosa Ziehau static void vmbus_msghc_ctx_free(struct vmbus_msghc_ctx *); 107236764b1SSepherosa Ziehau static struct vmbus_msghc *vmbus_msghc_alloc(bus_dma_tag_t); 108236764b1SSepherosa Ziehau static void vmbus_msghc_free(struct vmbus_msghc *); 109236764b1SSepherosa Ziehau static struct vmbus_msghc *vmbus_msghc_get1(struct vmbus_msghc_ctx *, 110236764b1SSepherosa Ziehau uint32_t); 111236764b1SSepherosa Ziehau 112b7bb4816SSepherosa Ziehau struct vmbus_softc *vmbus_sc; 113b7bb4816SSepherosa Ziehau 114b7bb4816SSepherosa Ziehau extern inthand_t IDTVEC(vmbus_isr); 115b7bb4816SSepherosa Ziehau 116236764b1SSepherosa Ziehau static const uint32_t vmbus_version[] = { 117236764b1SSepherosa Ziehau HV_VMBUS_VERSION_WIN8_1, 118236764b1SSepherosa Ziehau HV_VMBUS_VERSION_WIN8, 119236764b1SSepherosa Ziehau HV_VMBUS_VERSION_WIN7, 120236764b1SSepherosa Ziehau HV_VMBUS_VERSION_WS2008 121236764b1SSepherosa Ziehau }; 122236764b1SSepherosa Ziehau 123236764b1SSepherosa Ziehau static struct vmbus_msghc * 124236764b1SSepherosa Ziehau vmbus_msghc_alloc(bus_dma_tag_t parent_dtag) 125236764b1SSepherosa Ziehau { 126236764b1SSepherosa Ziehau struct vmbus_msghc *mh; 127236764b1SSepherosa Ziehau 128236764b1SSepherosa Ziehau mh = malloc(sizeof(*mh), M_DEVBUF, M_WAITOK | M_ZERO); 129236764b1SSepherosa Ziehau 130236764b1SSepherosa Ziehau mh->mh_inprm = hyperv_dmamem_alloc(parent_dtag, 131236764b1SSepherosa Ziehau HYPERCALL_POSTMSGIN_ALIGN, 0, HYPERCALL_POSTMSGIN_SIZE, 132236764b1SSepherosa Ziehau &mh->mh_inprm_dma, BUS_DMA_WAITOK); 133236764b1SSepherosa Ziehau if (mh->mh_inprm == NULL) { 134236764b1SSepherosa Ziehau free(mh, M_DEVBUF); 135236764b1SSepherosa Ziehau return NULL; 136236764b1SSepherosa Ziehau } 137236764b1SSepherosa Ziehau return mh; 138236764b1SSepherosa Ziehau } 139236764b1SSepherosa Ziehau 140236764b1SSepherosa Ziehau static void 141236764b1SSepherosa Ziehau vmbus_msghc_free(struct vmbus_msghc *mh) 142236764b1SSepherosa Ziehau { 143236764b1SSepherosa Ziehau hyperv_dmamem_free(&mh->mh_inprm_dma, mh->mh_inprm); 144236764b1SSepherosa Ziehau free(mh, M_DEVBUF); 145236764b1SSepherosa Ziehau } 146236764b1SSepherosa Ziehau 147236764b1SSepherosa Ziehau static void 148236764b1SSepherosa Ziehau vmbus_msghc_ctx_free(struct vmbus_msghc_ctx *mhc) 149236764b1SSepherosa Ziehau { 150236764b1SSepherosa Ziehau KASSERT(mhc->mhc_active == NULL, ("still have active msg hypercall")); 151236764b1SSepherosa Ziehau KASSERT(mhc->mhc_free == NULL, ("still have hypercall msg")); 152236764b1SSepherosa Ziehau 153236764b1SSepherosa Ziehau mtx_destroy(&mhc->mhc_free_lock); 154236764b1SSepherosa Ziehau mtx_destroy(&mhc->mhc_active_lock); 155236764b1SSepherosa Ziehau free(mhc, M_DEVBUF); 156236764b1SSepherosa Ziehau } 157236764b1SSepherosa Ziehau 158236764b1SSepherosa Ziehau static struct vmbus_msghc_ctx * 159236764b1SSepherosa Ziehau vmbus_msghc_ctx_create(bus_dma_tag_t parent_dtag) 160236764b1SSepherosa Ziehau { 161236764b1SSepherosa Ziehau struct vmbus_msghc_ctx *mhc; 162236764b1SSepherosa Ziehau 163236764b1SSepherosa Ziehau mhc = malloc(sizeof(*mhc), M_DEVBUF, M_WAITOK | M_ZERO); 164236764b1SSepherosa Ziehau mtx_init(&mhc->mhc_free_lock, "vmbus msghc free", NULL, MTX_DEF); 165236764b1SSepherosa Ziehau mtx_init(&mhc->mhc_active_lock, "vmbus msghc act", NULL, MTX_DEF); 166236764b1SSepherosa Ziehau 167236764b1SSepherosa Ziehau mhc->mhc_free = vmbus_msghc_alloc(parent_dtag); 168236764b1SSepherosa Ziehau if (mhc->mhc_free == NULL) { 169236764b1SSepherosa Ziehau vmbus_msghc_ctx_free(mhc); 170236764b1SSepherosa Ziehau return NULL; 171236764b1SSepherosa Ziehau } 172236764b1SSepherosa Ziehau return mhc; 173236764b1SSepherosa Ziehau } 174236764b1SSepherosa Ziehau 175236764b1SSepherosa Ziehau static struct vmbus_msghc * 176236764b1SSepherosa Ziehau vmbus_msghc_get1(struct vmbus_msghc_ctx *mhc, uint32_t dtor_flag) 177236764b1SSepherosa Ziehau { 178236764b1SSepherosa Ziehau struct vmbus_msghc *mh; 179236764b1SSepherosa Ziehau 180236764b1SSepherosa Ziehau mtx_lock(&mhc->mhc_free_lock); 181236764b1SSepherosa Ziehau 182236764b1SSepherosa Ziehau while ((mhc->mhc_flags & dtor_flag) == 0 && mhc->mhc_free == NULL) { 183236764b1SSepherosa Ziehau mtx_sleep(&mhc->mhc_free, &mhc->mhc_free_lock, 0, 184236764b1SSepherosa Ziehau "gmsghc", 0); 185236764b1SSepherosa Ziehau } 186236764b1SSepherosa Ziehau if (mhc->mhc_flags & dtor_flag) { 187236764b1SSepherosa Ziehau /* Being destroyed */ 188236764b1SSepherosa Ziehau mh = NULL; 189236764b1SSepherosa Ziehau } else { 190236764b1SSepherosa Ziehau mh = mhc->mhc_free; 191236764b1SSepherosa Ziehau KASSERT(mh != NULL, ("no free hypercall msg")); 192236764b1SSepherosa Ziehau KASSERT(mh->mh_resp == NULL, 193236764b1SSepherosa Ziehau ("hypercall msg has pending response")); 194236764b1SSepherosa Ziehau mhc->mhc_free = NULL; 195236764b1SSepherosa Ziehau } 196236764b1SSepherosa Ziehau 197236764b1SSepherosa Ziehau mtx_unlock(&mhc->mhc_free_lock); 198236764b1SSepherosa Ziehau 199236764b1SSepherosa Ziehau return mh; 200236764b1SSepherosa Ziehau } 201236764b1SSepherosa Ziehau 202236764b1SSepherosa Ziehau struct vmbus_msghc * 203236764b1SSepherosa Ziehau vmbus_msghc_get(struct vmbus_softc *sc, size_t dsize) 204236764b1SSepherosa Ziehau { 205236764b1SSepherosa Ziehau struct hypercall_postmsg_in *inprm; 206236764b1SSepherosa Ziehau struct vmbus_msghc *mh; 207236764b1SSepherosa Ziehau 208236764b1SSepherosa Ziehau if (dsize > HYPERCALL_POSTMSGIN_DSIZE_MAX) 209236764b1SSepherosa Ziehau return NULL; 210236764b1SSepherosa Ziehau 211236764b1SSepherosa Ziehau mh = vmbus_msghc_get1(sc->vmbus_msg_hc, VMBUS_MSGHC_CTXF_DESTROY); 212236764b1SSepherosa Ziehau if (mh == NULL) 213236764b1SSepherosa Ziehau return NULL; 214236764b1SSepherosa Ziehau 215236764b1SSepherosa Ziehau inprm = mh->mh_inprm; 216236764b1SSepherosa Ziehau memset(inprm, 0, HYPERCALL_POSTMSGIN_SIZE); 217236764b1SSepherosa Ziehau inprm->hc_connid = VMBUS_CONNID_MESSAGE; 218236764b1SSepherosa Ziehau inprm->hc_msgtype = HYPERV_MSGTYPE_CHANNEL; 219236764b1SSepherosa Ziehau inprm->hc_dsize = dsize; 220236764b1SSepherosa Ziehau 221236764b1SSepherosa Ziehau return mh; 222236764b1SSepherosa Ziehau } 223236764b1SSepherosa Ziehau 224236764b1SSepherosa Ziehau void 225236764b1SSepherosa Ziehau vmbus_msghc_put(struct vmbus_softc *sc, struct vmbus_msghc *mh) 226236764b1SSepherosa Ziehau { 227236764b1SSepherosa Ziehau struct vmbus_msghc_ctx *mhc = sc->vmbus_msg_hc; 228236764b1SSepherosa Ziehau 229236764b1SSepherosa Ziehau KASSERT(mhc->mhc_active == NULL, ("msg hypercall is active")); 230236764b1SSepherosa Ziehau mh->mh_resp = NULL; 231236764b1SSepherosa Ziehau 232236764b1SSepherosa Ziehau mtx_lock(&mhc->mhc_free_lock); 233236764b1SSepherosa Ziehau KASSERT(mhc->mhc_free == NULL, ("has free hypercall msg")); 234236764b1SSepherosa Ziehau mhc->mhc_free = mh; 235236764b1SSepherosa Ziehau mtx_unlock(&mhc->mhc_free_lock); 236236764b1SSepherosa Ziehau wakeup(&mhc->mhc_free); 237236764b1SSepherosa Ziehau } 238236764b1SSepherosa Ziehau 239236764b1SSepherosa Ziehau void * 240236764b1SSepherosa Ziehau vmbus_msghc_dataptr(struct vmbus_msghc *mh) 241236764b1SSepherosa Ziehau { 242236764b1SSepherosa Ziehau return mh->mh_inprm->hc_data; 243236764b1SSepherosa Ziehau } 244236764b1SSepherosa Ziehau 245236764b1SSepherosa Ziehau static void 246236764b1SSepherosa Ziehau vmbus_msghc_ctx_destroy(struct vmbus_msghc_ctx *mhc) 247236764b1SSepherosa Ziehau { 248236764b1SSepherosa Ziehau struct vmbus_msghc *mh; 249236764b1SSepherosa Ziehau 250236764b1SSepherosa Ziehau mtx_lock(&mhc->mhc_free_lock); 251236764b1SSepherosa Ziehau mhc->mhc_flags |= VMBUS_MSGHC_CTXF_DESTROY; 252236764b1SSepherosa Ziehau mtx_unlock(&mhc->mhc_free_lock); 253236764b1SSepherosa Ziehau wakeup(&mhc->mhc_free); 254236764b1SSepherosa Ziehau 255236764b1SSepherosa Ziehau mh = vmbus_msghc_get1(mhc, 0); 256236764b1SSepherosa Ziehau if (mh == NULL) 257236764b1SSepherosa Ziehau panic("can't get msghc"); 258236764b1SSepherosa Ziehau 259236764b1SSepherosa Ziehau vmbus_msghc_free(mh); 260236764b1SSepherosa Ziehau vmbus_msghc_ctx_free(mhc); 261236764b1SSepherosa Ziehau } 262236764b1SSepherosa Ziehau 263236764b1SSepherosa Ziehau int 264236764b1SSepherosa Ziehau vmbus_msghc_exec_noresult(struct vmbus_msghc *mh) 265236764b1SSepherosa Ziehau { 266236764b1SSepherosa Ziehau sbintime_t time = SBT_1MS; 267236764b1SSepherosa Ziehau int i; 268236764b1SSepherosa Ziehau 269236764b1SSepherosa Ziehau /* 270236764b1SSepherosa Ziehau * Save the input parameter so that we could restore the input 271236764b1SSepherosa Ziehau * parameter if the Hypercall failed. 272236764b1SSepherosa Ziehau * 273236764b1SSepherosa Ziehau * XXX 274236764b1SSepherosa Ziehau * Is this really necessary?! i.e. Will the Hypercall ever 275236764b1SSepherosa Ziehau * overwrite the input parameter? 276236764b1SSepherosa Ziehau */ 277236764b1SSepherosa Ziehau memcpy(&mh->mh_inprm_save, mh->mh_inprm, HYPERCALL_POSTMSGIN_SIZE); 278236764b1SSepherosa Ziehau 279236764b1SSepherosa Ziehau /* 280236764b1SSepherosa Ziehau * In order to cope with transient failures, e.g. insufficient 281236764b1SSepherosa Ziehau * resources on host side, we retry the post message Hypercall 282236764b1SSepherosa Ziehau * several times. 20 retries seem sufficient. 283236764b1SSepherosa Ziehau */ 284236764b1SSepherosa Ziehau #define HC_RETRY_MAX 20 285236764b1SSepherosa Ziehau 286236764b1SSepherosa Ziehau for (i = 0; i < HC_RETRY_MAX; ++i) { 287236764b1SSepherosa Ziehau uint64_t status; 288236764b1SSepherosa Ziehau 289236764b1SSepherosa Ziehau status = hypercall_post_message(mh->mh_inprm_dma.hv_paddr); 290236764b1SSepherosa Ziehau if (status == HYPERCALL_STATUS_SUCCESS) 291236764b1SSepherosa Ziehau return 0; 292236764b1SSepherosa Ziehau 293236764b1SSepherosa Ziehau pause_sbt("hcpmsg", time, 0, C_HARDCLOCK); 294236764b1SSepherosa Ziehau if (time < SBT_1S * 2) 295236764b1SSepherosa Ziehau time *= 2; 296236764b1SSepherosa Ziehau 297236764b1SSepherosa Ziehau /* Restore input parameter and try again */ 298236764b1SSepherosa Ziehau memcpy(mh->mh_inprm, &mh->mh_inprm_save, 299236764b1SSepherosa Ziehau HYPERCALL_POSTMSGIN_SIZE); 300236764b1SSepherosa Ziehau } 301236764b1SSepherosa Ziehau 302236764b1SSepherosa Ziehau #undef HC_RETRY_MAX 303236764b1SSepherosa Ziehau 304236764b1SSepherosa Ziehau return EIO; 305236764b1SSepherosa Ziehau } 306236764b1SSepherosa Ziehau 307236764b1SSepherosa Ziehau int 308236764b1SSepherosa Ziehau vmbus_msghc_exec(struct vmbus_softc *sc, struct vmbus_msghc *mh) 309236764b1SSepherosa Ziehau { 310236764b1SSepherosa Ziehau struct vmbus_msghc_ctx *mhc = sc->vmbus_msg_hc; 311236764b1SSepherosa Ziehau int error; 312236764b1SSepherosa Ziehau 313236764b1SSepherosa Ziehau KASSERT(mh->mh_resp == NULL, ("hypercall msg has pending response")); 314236764b1SSepherosa Ziehau 315236764b1SSepherosa Ziehau mtx_lock(&mhc->mhc_active_lock); 316236764b1SSepherosa Ziehau KASSERT(mhc->mhc_active == NULL, ("pending active msg hypercall")); 317236764b1SSepherosa Ziehau mhc->mhc_active = mh; 318236764b1SSepherosa Ziehau mtx_unlock(&mhc->mhc_active_lock); 319236764b1SSepherosa Ziehau 320236764b1SSepherosa Ziehau error = vmbus_msghc_exec_noresult(mh); 321236764b1SSepherosa Ziehau if (error) { 322236764b1SSepherosa Ziehau mtx_lock(&mhc->mhc_active_lock); 323236764b1SSepherosa Ziehau KASSERT(mhc->mhc_active == mh, ("msghc mismatch")); 324236764b1SSepherosa Ziehau mhc->mhc_active = NULL; 325236764b1SSepherosa Ziehau mtx_unlock(&mhc->mhc_active_lock); 326236764b1SSepherosa Ziehau } 327236764b1SSepherosa Ziehau return error; 328236764b1SSepherosa Ziehau } 329236764b1SSepherosa Ziehau 330236764b1SSepherosa Ziehau const struct vmbus_message * 331236764b1SSepherosa Ziehau vmbus_msghc_wait_result(struct vmbus_softc *sc, struct vmbus_msghc *mh) 332236764b1SSepherosa Ziehau { 333236764b1SSepherosa Ziehau struct vmbus_msghc_ctx *mhc = sc->vmbus_msg_hc; 334236764b1SSepherosa Ziehau 335236764b1SSepherosa Ziehau mtx_lock(&mhc->mhc_active_lock); 336236764b1SSepherosa Ziehau 337236764b1SSepherosa Ziehau KASSERT(mhc->mhc_active == mh, ("msghc mismatch")); 338236764b1SSepherosa Ziehau while (mh->mh_resp == NULL) { 339236764b1SSepherosa Ziehau mtx_sleep(&mhc->mhc_active, &mhc->mhc_active_lock, 0, 340236764b1SSepherosa Ziehau "wmsghc", 0); 341236764b1SSepherosa Ziehau } 342236764b1SSepherosa Ziehau mhc->mhc_active = NULL; 343236764b1SSepherosa Ziehau 344236764b1SSepherosa Ziehau mtx_unlock(&mhc->mhc_active_lock); 345236764b1SSepherosa Ziehau 346236764b1SSepherosa Ziehau return mh->mh_resp; 347236764b1SSepherosa Ziehau } 348236764b1SSepherosa Ziehau 349236764b1SSepherosa Ziehau void 350236764b1SSepherosa Ziehau vmbus_msghc_wakeup(struct vmbus_softc *sc, const struct vmbus_message *msg) 351236764b1SSepherosa Ziehau { 352236764b1SSepherosa Ziehau struct vmbus_msghc_ctx *mhc = sc->vmbus_msg_hc; 353236764b1SSepherosa Ziehau struct vmbus_msghc *mh; 354236764b1SSepherosa Ziehau 355236764b1SSepherosa Ziehau mtx_lock(&mhc->mhc_active_lock); 356236764b1SSepherosa Ziehau 357236764b1SSepherosa Ziehau mh = mhc->mhc_active; 358236764b1SSepherosa Ziehau KASSERT(mh != NULL, ("no pending msg hypercall")); 359236764b1SSepherosa Ziehau memcpy(&mh->mh_resp0, msg, sizeof(mh->mh_resp0)); 360236764b1SSepherosa Ziehau mh->mh_resp = &mh->mh_resp0; 361236764b1SSepherosa Ziehau 362236764b1SSepherosa Ziehau mtx_unlock(&mhc->mhc_active_lock); 363236764b1SSepherosa Ziehau wakeup(&mhc->mhc_active); 364236764b1SSepherosa Ziehau } 365236764b1SSepherosa Ziehau 366236764b1SSepherosa Ziehau static int 367236764b1SSepherosa Ziehau vmbus_init_contact(struct vmbus_softc *sc, uint32_t version) 368236764b1SSepherosa Ziehau { 369236764b1SSepherosa Ziehau struct vmbus_chanmsg_init_contact *req; 370236764b1SSepherosa Ziehau const struct vmbus_chanmsg_version_resp *resp; 371236764b1SSepherosa Ziehau const struct vmbus_message *msg; 372236764b1SSepherosa Ziehau struct vmbus_msghc *mh; 373236764b1SSepherosa Ziehau int error, supp = 0; 374236764b1SSepherosa Ziehau 375236764b1SSepherosa Ziehau mh = vmbus_msghc_get(sc, sizeof(*req)); 376236764b1SSepherosa Ziehau if (mh == NULL) 377236764b1SSepherosa Ziehau return ENXIO; 378236764b1SSepherosa Ziehau 379236764b1SSepherosa Ziehau req = vmbus_msghc_dataptr(mh); 380236764b1SSepherosa Ziehau req->chm_hdr.chm_type = VMBUS_CHANMSG_TYPE_INIT_CONTACT; 381236764b1SSepherosa Ziehau req->chm_ver = version; 382236764b1SSepherosa Ziehau req->chm_evtflags = sc->vmbus_evtflags_dma.hv_paddr; 383236764b1SSepherosa Ziehau req->chm_mnf1 = sc->vmbus_mnf1_dma.hv_paddr; 384236764b1SSepherosa Ziehau req->chm_mnf2 = sc->vmbus_mnf2_dma.hv_paddr; 385236764b1SSepherosa Ziehau 386236764b1SSepherosa Ziehau error = vmbus_msghc_exec(sc, mh); 387236764b1SSepherosa Ziehau if (error) { 388236764b1SSepherosa Ziehau vmbus_msghc_put(sc, mh); 389236764b1SSepherosa Ziehau return error; 390236764b1SSepherosa Ziehau } 391236764b1SSepherosa Ziehau 392236764b1SSepherosa Ziehau msg = vmbus_msghc_wait_result(sc, mh); 393236764b1SSepherosa Ziehau resp = (const struct vmbus_chanmsg_version_resp *)msg->msg_data; 394236764b1SSepherosa Ziehau supp = resp->chm_supp; 395236764b1SSepherosa Ziehau 396236764b1SSepherosa Ziehau vmbus_msghc_put(sc, mh); 397236764b1SSepherosa Ziehau 398236764b1SSepherosa Ziehau return (supp ? 0 : EOPNOTSUPP); 399236764b1SSepherosa Ziehau } 400236764b1SSepherosa Ziehau 401236764b1SSepherosa Ziehau static int 402236764b1SSepherosa Ziehau vmbus_init(struct vmbus_softc *sc) 403236764b1SSepherosa Ziehau { 404236764b1SSepherosa Ziehau int i; 405236764b1SSepherosa Ziehau 406236764b1SSepherosa Ziehau for (i = 0; i < nitems(vmbus_version); ++i) { 407236764b1SSepherosa Ziehau int error; 408236764b1SSepherosa Ziehau 409236764b1SSepherosa Ziehau error = vmbus_init_contact(sc, vmbus_version[i]); 410236764b1SSepherosa Ziehau if (!error) { 411236764b1SSepherosa Ziehau hv_vmbus_protocal_version = vmbus_version[i]; 412236764b1SSepherosa Ziehau device_printf(sc->vmbus_dev, "version %u.%u\n", 413236764b1SSepherosa Ziehau (hv_vmbus_protocal_version >> 16), 414236764b1SSepherosa Ziehau (hv_vmbus_protocal_version & 0xffff)); 415236764b1SSepherosa Ziehau return 0; 416236764b1SSepherosa Ziehau } 417236764b1SSepherosa Ziehau } 418236764b1SSepherosa Ziehau return ENXIO; 419236764b1SSepherosa Ziehau } 420236764b1SSepherosa Ziehau 421c1cc5bdfSSepherosa Ziehau static int 422c1cc5bdfSSepherosa Ziehau vmbus_req_channels(struct vmbus_softc *sc) 423c1cc5bdfSSepherosa Ziehau { 424c1cc5bdfSSepherosa Ziehau struct vmbus_chanmsg_channel_req *req; 425c1cc5bdfSSepherosa Ziehau struct vmbus_msghc *mh; 426c1cc5bdfSSepherosa Ziehau int error; 427c1cc5bdfSSepherosa Ziehau 428c1cc5bdfSSepherosa Ziehau mh = vmbus_msghc_get(sc, sizeof(*req)); 429c1cc5bdfSSepherosa Ziehau if (mh == NULL) 430c1cc5bdfSSepherosa Ziehau return ENXIO; 431c1cc5bdfSSepherosa Ziehau 432c1cc5bdfSSepherosa Ziehau req = vmbus_msghc_dataptr(mh); 433c1cc5bdfSSepherosa Ziehau req->chm_hdr.chm_type = VMBUS_CHANMSG_TYPE_CHANNEL_REQ; 434c1cc5bdfSSepherosa Ziehau 435c1cc5bdfSSepherosa Ziehau error = vmbus_msghc_exec_noresult(mh); 436c1cc5bdfSSepherosa Ziehau vmbus_msghc_put(sc, mh); 437c1cc5bdfSSepherosa Ziehau 438c1cc5bdfSSepherosa Ziehau return error; 439c1cc5bdfSSepherosa Ziehau } 440c1cc5bdfSSepherosa Ziehau 441b7bb4816SSepherosa Ziehau static void 442b7bb4816SSepherosa Ziehau vmbus_msg_task(void *xsc, int pending __unused) 443b7bb4816SSepherosa Ziehau { 444b7bb4816SSepherosa Ziehau struct vmbus_softc *sc = xsc; 445b7bb4816SSepherosa Ziehau volatile struct vmbus_message *msg; 446b7bb4816SSepherosa Ziehau 447b7bb4816SSepherosa Ziehau msg = VMBUS_PCPU_GET(sc, message, curcpu) + VMBUS_SINT_MESSAGE; 448b7bb4816SSepherosa Ziehau for (;;) { 449236764b1SSepherosa Ziehau if (msg->msg_type == HYPERV_MSGTYPE_NONE) { 450fa4828b0SSepherosa Ziehau /* No message */ 451fa4828b0SSepherosa Ziehau break; 452236764b1SSepherosa Ziehau } else if (msg->msg_type == HYPERV_MSGTYPE_CHANNEL) { 45312ea25aeSSepherosa Ziehau /* Channel message */ 45443926ba1SSepherosa Ziehau vmbus_chan_msgproc(sc, 45543926ba1SSepherosa Ziehau __DEVOLATILE(const struct vmbus_message *, msg)); 456fa4828b0SSepherosa Ziehau } 457b7bb4816SSepherosa Ziehau 458236764b1SSepherosa Ziehau msg->msg_type = HYPERV_MSGTYPE_NONE; 459b7bb4816SSepherosa Ziehau /* 460b7bb4816SSepherosa Ziehau * Make sure the write to msg_type (i.e. set to 461236764b1SSepherosa Ziehau * HYPERV_MSGTYPE_NONE) happens before we read the 462b7bb4816SSepherosa Ziehau * msg_flags and EOMing. Otherwise, the EOMing will 463b7bb4816SSepherosa Ziehau * not deliver any more messages since there is no 464b7bb4816SSepherosa Ziehau * empty slot 465b7bb4816SSepherosa Ziehau * 466b7bb4816SSepherosa Ziehau * NOTE: 467b7bb4816SSepherosa Ziehau * mb() is used here, since atomic_thread_fence_seq_cst() 468b7bb4816SSepherosa Ziehau * will become compiler fence on UP kernel. 469b7bb4816SSepherosa Ziehau */ 470b7bb4816SSepherosa Ziehau mb(); 471b7bb4816SSepherosa Ziehau if (msg->msg_flags & VMBUS_MSGFLAG_PENDING) { 472b7bb4816SSepherosa Ziehau /* 473b7bb4816SSepherosa Ziehau * This will cause message queue rescan to possibly 474b7bb4816SSepherosa Ziehau * deliver another msg from the hypervisor 475b7bb4816SSepherosa Ziehau */ 476b7bb4816SSepherosa Ziehau wrmsr(MSR_HV_EOM, 0); 477b7bb4816SSepherosa Ziehau } 478b7bb4816SSepherosa Ziehau } 479b7bb4816SSepherosa Ziehau } 480b7bb4816SSepherosa Ziehau 481b7bb4816SSepherosa Ziehau static __inline int 482b7bb4816SSepherosa Ziehau vmbus_handle_intr1(struct vmbus_softc *sc, struct trapframe *frame, int cpu) 483b7bb4816SSepherosa Ziehau { 484b7bb4816SSepherosa Ziehau volatile struct vmbus_message *msg; 485b7bb4816SSepherosa Ziehau struct vmbus_message *msg_base; 486b7bb4816SSepherosa Ziehau 487b7bb4816SSepherosa Ziehau msg_base = VMBUS_PCPU_GET(sc, message, cpu); 488b7bb4816SSepherosa Ziehau 489b7bb4816SSepherosa Ziehau /* 490b7bb4816SSepherosa Ziehau * Check event timer. 491b7bb4816SSepherosa Ziehau * 492b7bb4816SSepherosa Ziehau * TODO: move this to independent IDT vector. 493b7bb4816SSepherosa Ziehau */ 494b7bb4816SSepherosa Ziehau msg = msg_base + VMBUS_SINT_TIMER; 495236764b1SSepherosa Ziehau if (msg->msg_type == HYPERV_MSGTYPE_TIMER_EXPIRED) { 496236764b1SSepherosa Ziehau msg->msg_type = HYPERV_MSGTYPE_NONE; 497b7bb4816SSepherosa Ziehau 498b7bb4816SSepherosa Ziehau vmbus_et_intr(frame); 499b7bb4816SSepherosa Ziehau 500b7bb4816SSepherosa Ziehau /* 501b7bb4816SSepherosa Ziehau * Make sure the write to msg_type (i.e. set to 502236764b1SSepherosa Ziehau * HYPERV_MSGTYPE_NONE) happens before we read the 503b7bb4816SSepherosa Ziehau * msg_flags and EOMing. Otherwise, the EOMing will 504b7bb4816SSepherosa Ziehau * not deliver any more messages since there is no 505b7bb4816SSepherosa Ziehau * empty slot 506b7bb4816SSepherosa Ziehau * 507b7bb4816SSepherosa Ziehau * NOTE: 508b7bb4816SSepherosa Ziehau * mb() is used here, since atomic_thread_fence_seq_cst() 509b7bb4816SSepherosa Ziehau * will become compiler fence on UP kernel. 510b7bb4816SSepherosa Ziehau */ 511b7bb4816SSepherosa Ziehau mb(); 512b7bb4816SSepherosa Ziehau if (msg->msg_flags & VMBUS_MSGFLAG_PENDING) { 513b7bb4816SSepherosa Ziehau /* 514b7bb4816SSepherosa Ziehau * This will cause message queue rescan to possibly 515b7bb4816SSepherosa Ziehau * deliver another msg from the hypervisor 516b7bb4816SSepherosa Ziehau */ 517b7bb4816SSepherosa Ziehau wrmsr(MSR_HV_EOM, 0); 518b7bb4816SSepherosa Ziehau } 519b7bb4816SSepherosa Ziehau } 520b7bb4816SSepherosa Ziehau 521b7bb4816SSepherosa Ziehau /* 522b7bb4816SSepherosa Ziehau * Check events. Hot path for network and storage I/O data; high rate. 523b7bb4816SSepherosa Ziehau * 524b7bb4816SSepherosa Ziehau * NOTE: 525b7bb4816SSepherosa Ziehau * As recommended by the Windows guest fellows, we check events before 526b7bb4816SSepherosa Ziehau * checking messages. 527b7bb4816SSepherosa Ziehau */ 528b7bb4816SSepherosa Ziehau sc->vmbus_event_proc(sc, cpu); 529b7bb4816SSepherosa Ziehau 530b7bb4816SSepherosa Ziehau /* 531b7bb4816SSepherosa Ziehau * Check messages. Mainly management stuffs; ultra low rate. 532b7bb4816SSepherosa Ziehau */ 533b7bb4816SSepherosa Ziehau msg = msg_base + VMBUS_SINT_MESSAGE; 534236764b1SSepherosa Ziehau if (__predict_false(msg->msg_type != HYPERV_MSGTYPE_NONE)) { 535b7bb4816SSepherosa Ziehau taskqueue_enqueue(VMBUS_PCPU_GET(sc, message_tq, cpu), 536b7bb4816SSepherosa Ziehau VMBUS_PCPU_PTR(sc, message_task, cpu)); 537b7bb4816SSepherosa Ziehau } 538b7bb4816SSepherosa Ziehau 539b7bb4816SSepherosa Ziehau return (FILTER_HANDLED); 540b7bb4816SSepherosa Ziehau } 541b7bb4816SSepherosa Ziehau 542b7bb4816SSepherosa Ziehau void 543b7bb4816SSepherosa Ziehau vmbus_handle_intr(struct trapframe *trap_frame) 544b7bb4816SSepherosa Ziehau { 545b7bb4816SSepherosa Ziehau struct vmbus_softc *sc = vmbus_get_softc(); 546b7bb4816SSepherosa Ziehau int cpu = curcpu; 547b7bb4816SSepherosa Ziehau 548b7bb4816SSepherosa Ziehau /* 549b7bb4816SSepherosa Ziehau * Disable preemption. 550b7bb4816SSepherosa Ziehau */ 551b7bb4816SSepherosa Ziehau critical_enter(); 552b7bb4816SSepherosa Ziehau 553b7bb4816SSepherosa Ziehau /* 554b7bb4816SSepherosa Ziehau * Do a little interrupt counting. 555b7bb4816SSepherosa Ziehau */ 556b7bb4816SSepherosa Ziehau (*VMBUS_PCPU_GET(sc, intr_cnt, cpu))++; 557b7bb4816SSepherosa Ziehau 558b7bb4816SSepherosa Ziehau vmbus_handle_intr1(sc, trap_frame, cpu); 559b7bb4816SSepherosa Ziehau 560b7bb4816SSepherosa Ziehau /* 561b7bb4816SSepherosa Ziehau * Enable preemption. 562b7bb4816SSepherosa Ziehau */ 563b7bb4816SSepherosa Ziehau critical_exit(); 564b7bb4816SSepherosa Ziehau } 565b7bb4816SSepherosa Ziehau 566b7bb4816SSepherosa Ziehau static void 567b7bb4816SSepherosa Ziehau vmbus_synic_setup(void *xsc) 568b7bb4816SSepherosa Ziehau { 569b7bb4816SSepherosa Ziehau struct vmbus_softc *sc = xsc; 570b7bb4816SSepherosa Ziehau int cpu = curcpu; 571b7bb4816SSepherosa Ziehau uint64_t val, orig; 572b7bb4816SSepherosa Ziehau uint32_t sint; 573b7bb4816SSepherosa Ziehau 574b7bb4816SSepherosa Ziehau if (hyperv_features & CPUID_HV_MSR_VP_INDEX) { 575b7bb4816SSepherosa Ziehau /* 576b7bb4816SSepherosa Ziehau * Save virtual processor id. 577b7bb4816SSepherosa Ziehau */ 578b7bb4816SSepherosa Ziehau VMBUS_PCPU_GET(sc, vcpuid, cpu) = rdmsr(MSR_HV_VP_INDEX); 579b7bb4816SSepherosa Ziehau } else { 580b7bb4816SSepherosa Ziehau /* 581b7bb4816SSepherosa Ziehau * XXX 582b7bb4816SSepherosa Ziehau * Virtual processoor id is only used by a pretty broken 583b7bb4816SSepherosa Ziehau * channel selection code from storvsc. It's nothing 584b7bb4816SSepherosa Ziehau * critical even if CPUID_HV_MSR_VP_INDEX is not set; keep 585b7bb4816SSepherosa Ziehau * moving on. 586b7bb4816SSepherosa Ziehau */ 587b7bb4816SSepherosa Ziehau VMBUS_PCPU_GET(sc, vcpuid, cpu) = cpu; 588b7bb4816SSepherosa Ziehau } 589b7bb4816SSepherosa Ziehau 590b7bb4816SSepherosa Ziehau /* 591b7bb4816SSepherosa Ziehau * Setup the SynIC message. 592b7bb4816SSepherosa Ziehau */ 593b7bb4816SSepherosa Ziehau orig = rdmsr(MSR_HV_SIMP); 594b7bb4816SSepherosa Ziehau val = MSR_HV_SIMP_ENABLE | (orig & MSR_HV_SIMP_RSVD_MASK) | 595b7bb4816SSepherosa Ziehau ((VMBUS_PCPU_GET(sc, message_dma.hv_paddr, cpu) >> PAGE_SHIFT) << 596b7bb4816SSepherosa Ziehau MSR_HV_SIMP_PGSHIFT); 597b7bb4816SSepherosa Ziehau wrmsr(MSR_HV_SIMP, val); 598b7bb4816SSepherosa Ziehau 599b7bb4816SSepherosa Ziehau /* 600b7bb4816SSepherosa Ziehau * Setup the SynIC event flags. 601b7bb4816SSepherosa Ziehau */ 602b7bb4816SSepherosa Ziehau orig = rdmsr(MSR_HV_SIEFP); 603b7bb4816SSepherosa Ziehau val = MSR_HV_SIEFP_ENABLE | (orig & MSR_HV_SIEFP_RSVD_MASK) | 604b7bb4816SSepherosa Ziehau ((VMBUS_PCPU_GET(sc, event_flags_dma.hv_paddr, cpu) 605b7bb4816SSepherosa Ziehau >> PAGE_SHIFT) << MSR_HV_SIEFP_PGSHIFT); 606b7bb4816SSepherosa Ziehau wrmsr(MSR_HV_SIEFP, val); 607b7bb4816SSepherosa Ziehau 608b7bb4816SSepherosa Ziehau 609b7bb4816SSepherosa Ziehau /* 610b7bb4816SSepherosa Ziehau * Configure and unmask SINT for message and event flags. 611b7bb4816SSepherosa Ziehau */ 612b7bb4816SSepherosa Ziehau sint = MSR_HV_SINT0 + VMBUS_SINT_MESSAGE; 613b7bb4816SSepherosa Ziehau orig = rdmsr(sint); 614b7bb4816SSepherosa Ziehau val = sc->vmbus_idtvec | MSR_HV_SINT_AUTOEOI | 615b7bb4816SSepherosa Ziehau (orig & MSR_HV_SINT_RSVD_MASK); 616b7bb4816SSepherosa Ziehau wrmsr(sint, val); 617b7bb4816SSepherosa Ziehau 618b7bb4816SSepherosa Ziehau /* 619b7bb4816SSepherosa Ziehau * Configure and unmask SINT for timer. 620b7bb4816SSepherosa Ziehau */ 621b7bb4816SSepherosa Ziehau sint = MSR_HV_SINT0 + VMBUS_SINT_TIMER; 622b7bb4816SSepherosa Ziehau orig = rdmsr(sint); 623b7bb4816SSepherosa Ziehau val = sc->vmbus_idtvec | MSR_HV_SINT_AUTOEOI | 624b7bb4816SSepherosa Ziehau (orig & MSR_HV_SINT_RSVD_MASK); 625b7bb4816SSepherosa Ziehau wrmsr(sint, val); 626b7bb4816SSepherosa Ziehau 627b7bb4816SSepherosa Ziehau /* 628b7bb4816SSepherosa Ziehau * All done; enable SynIC. 629b7bb4816SSepherosa Ziehau */ 630b7bb4816SSepherosa Ziehau orig = rdmsr(MSR_HV_SCONTROL); 631b7bb4816SSepherosa Ziehau val = MSR_HV_SCTRL_ENABLE | (orig & MSR_HV_SCTRL_RSVD_MASK); 632b7bb4816SSepherosa Ziehau wrmsr(MSR_HV_SCONTROL, val); 633b7bb4816SSepherosa Ziehau } 634b7bb4816SSepherosa Ziehau 635b7bb4816SSepherosa Ziehau static void 636b7bb4816SSepherosa Ziehau vmbus_synic_teardown(void *arg) 637b7bb4816SSepherosa Ziehau { 638b7bb4816SSepherosa Ziehau uint64_t orig; 639b7bb4816SSepherosa Ziehau uint32_t sint; 640b7bb4816SSepherosa Ziehau 641b7bb4816SSepherosa Ziehau /* 642b7bb4816SSepherosa Ziehau * Disable SynIC. 643b7bb4816SSepherosa Ziehau */ 644b7bb4816SSepherosa Ziehau orig = rdmsr(MSR_HV_SCONTROL); 645b7bb4816SSepherosa Ziehau wrmsr(MSR_HV_SCONTROL, (orig & MSR_HV_SCTRL_RSVD_MASK)); 646b7bb4816SSepherosa Ziehau 647b7bb4816SSepherosa Ziehau /* 648b7bb4816SSepherosa Ziehau * Mask message and event flags SINT. 649b7bb4816SSepherosa Ziehau */ 650b7bb4816SSepherosa Ziehau sint = MSR_HV_SINT0 + VMBUS_SINT_MESSAGE; 651b7bb4816SSepherosa Ziehau orig = rdmsr(sint); 652b7bb4816SSepherosa Ziehau wrmsr(sint, orig | MSR_HV_SINT_MASKED); 653b7bb4816SSepherosa Ziehau 654b7bb4816SSepherosa Ziehau /* 655b7bb4816SSepherosa Ziehau * Mask timer SINT. 656b7bb4816SSepherosa Ziehau */ 657b7bb4816SSepherosa Ziehau sint = MSR_HV_SINT0 + VMBUS_SINT_TIMER; 658b7bb4816SSepherosa Ziehau orig = rdmsr(sint); 659b7bb4816SSepherosa Ziehau wrmsr(sint, orig | MSR_HV_SINT_MASKED); 660b7bb4816SSepherosa Ziehau 661b7bb4816SSepherosa Ziehau /* 662b7bb4816SSepherosa Ziehau * Teardown SynIC message. 663b7bb4816SSepherosa Ziehau */ 664b7bb4816SSepherosa Ziehau orig = rdmsr(MSR_HV_SIMP); 665b7bb4816SSepherosa Ziehau wrmsr(MSR_HV_SIMP, (orig & MSR_HV_SIMP_RSVD_MASK)); 666b7bb4816SSepherosa Ziehau 667b7bb4816SSepherosa Ziehau /* 668b7bb4816SSepherosa Ziehau * Teardown SynIC event flags. 669b7bb4816SSepherosa Ziehau */ 670b7bb4816SSepherosa Ziehau orig = rdmsr(MSR_HV_SIEFP); 671b7bb4816SSepherosa Ziehau wrmsr(MSR_HV_SIEFP, (orig & MSR_HV_SIEFP_RSVD_MASK)); 672b7bb4816SSepherosa Ziehau } 673b7bb4816SSepherosa Ziehau 674b7bb4816SSepherosa Ziehau static int 675b7bb4816SSepherosa Ziehau vmbus_dma_alloc(struct vmbus_softc *sc) 676b7bb4816SSepherosa Ziehau { 6776523ab7eSSepherosa Ziehau bus_dma_tag_t parent_dtag; 6786523ab7eSSepherosa Ziehau uint8_t *evtflags; 679b7bb4816SSepherosa Ziehau int cpu; 680b7bb4816SSepherosa Ziehau 6816523ab7eSSepherosa Ziehau parent_dtag = bus_get_dma_tag(sc->vmbus_dev); 682b7bb4816SSepherosa Ziehau CPU_FOREACH(cpu) { 683b7bb4816SSepherosa Ziehau void *ptr; 684b7bb4816SSepherosa Ziehau 685b7bb4816SSepherosa Ziehau /* 686b7bb4816SSepherosa Ziehau * Per-cpu messages and event flags. 687b7bb4816SSepherosa Ziehau */ 6886523ab7eSSepherosa Ziehau ptr = hyperv_dmamem_alloc(parent_dtag, PAGE_SIZE, 0, 6896523ab7eSSepherosa Ziehau PAGE_SIZE, VMBUS_PCPU_PTR(sc, message_dma, cpu), 690b7bb4816SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO); 691b7bb4816SSepherosa Ziehau if (ptr == NULL) 692b7bb4816SSepherosa Ziehau return ENOMEM; 693b7bb4816SSepherosa Ziehau VMBUS_PCPU_GET(sc, message, cpu) = ptr; 694b7bb4816SSepherosa Ziehau 6956523ab7eSSepherosa Ziehau ptr = hyperv_dmamem_alloc(parent_dtag, PAGE_SIZE, 0, 6966523ab7eSSepherosa Ziehau PAGE_SIZE, VMBUS_PCPU_PTR(sc, event_flags_dma, cpu), 697b7bb4816SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO); 698b7bb4816SSepherosa Ziehau if (ptr == NULL) 699b7bb4816SSepherosa Ziehau return ENOMEM; 700b7bb4816SSepherosa Ziehau VMBUS_PCPU_GET(sc, event_flags, cpu) = ptr; 701b7bb4816SSepherosa Ziehau } 7026523ab7eSSepherosa Ziehau 7036523ab7eSSepherosa Ziehau evtflags = hyperv_dmamem_alloc(parent_dtag, PAGE_SIZE, 0, 7046523ab7eSSepherosa Ziehau PAGE_SIZE, &sc->vmbus_evtflags_dma, BUS_DMA_WAITOK | BUS_DMA_ZERO); 7056523ab7eSSepherosa Ziehau if (evtflags == NULL) 7066523ab7eSSepherosa Ziehau return ENOMEM; 7076523ab7eSSepherosa Ziehau sc->vmbus_rx_evtflags = (u_long *)evtflags; 70851a9a000SSepherosa Ziehau sc->vmbus_tx_evtflags = (u_long *)(evtflags + (PAGE_SIZE / 2)); 7096523ab7eSSepherosa Ziehau sc->vmbus_evtflags = evtflags; 7106523ab7eSSepherosa Ziehau 7116523ab7eSSepherosa Ziehau sc->vmbus_mnf1 = hyperv_dmamem_alloc(parent_dtag, PAGE_SIZE, 0, 7126523ab7eSSepherosa Ziehau PAGE_SIZE, &sc->vmbus_mnf1_dma, BUS_DMA_WAITOK | BUS_DMA_ZERO); 7136523ab7eSSepherosa Ziehau if (sc->vmbus_mnf1 == NULL) 7146523ab7eSSepherosa Ziehau return ENOMEM; 7156523ab7eSSepherosa Ziehau 7166523ab7eSSepherosa Ziehau sc->vmbus_mnf2 = hyperv_dmamem_alloc(parent_dtag, PAGE_SIZE, 0, 7176523ab7eSSepherosa Ziehau PAGE_SIZE, &sc->vmbus_mnf2_dma, BUS_DMA_WAITOK | BUS_DMA_ZERO); 7186523ab7eSSepherosa Ziehau if (sc->vmbus_mnf2 == NULL) 7196523ab7eSSepherosa Ziehau return ENOMEM; 7206523ab7eSSepherosa Ziehau 721b7bb4816SSepherosa Ziehau return 0; 722b7bb4816SSepherosa Ziehau } 723b7bb4816SSepherosa Ziehau 724b7bb4816SSepherosa Ziehau static void 725b7bb4816SSepherosa Ziehau vmbus_dma_free(struct vmbus_softc *sc) 726b7bb4816SSepherosa Ziehau { 727b7bb4816SSepherosa Ziehau int cpu; 728b7bb4816SSepherosa Ziehau 7296523ab7eSSepherosa Ziehau if (sc->vmbus_evtflags != NULL) { 7306523ab7eSSepherosa Ziehau hyperv_dmamem_free(&sc->vmbus_evtflags_dma, sc->vmbus_evtflags); 7316523ab7eSSepherosa Ziehau sc->vmbus_evtflags = NULL; 7326523ab7eSSepherosa Ziehau sc->vmbus_rx_evtflags = NULL; 7336523ab7eSSepherosa Ziehau sc->vmbus_tx_evtflags = NULL; 7346523ab7eSSepherosa Ziehau } 7356523ab7eSSepherosa Ziehau if (sc->vmbus_mnf1 != NULL) { 7366523ab7eSSepherosa Ziehau hyperv_dmamem_free(&sc->vmbus_mnf1_dma, sc->vmbus_mnf1); 7376523ab7eSSepherosa Ziehau sc->vmbus_mnf1 = NULL; 7386523ab7eSSepherosa Ziehau } 7396523ab7eSSepherosa Ziehau if (sc->vmbus_mnf2 != NULL) { 7406523ab7eSSepherosa Ziehau hyperv_dmamem_free(&sc->vmbus_mnf2_dma, sc->vmbus_mnf2); 7416523ab7eSSepherosa Ziehau sc->vmbus_mnf2 = NULL; 7426523ab7eSSepherosa Ziehau } 7436523ab7eSSepherosa Ziehau 744b7bb4816SSepherosa Ziehau CPU_FOREACH(cpu) { 745b7bb4816SSepherosa Ziehau if (VMBUS_PCPU_GET(sc, message, cpu) != NULL) { 746b7bb4816SSepherosa Ziehau hyperv_dmamem_free( 747b7bb4816SSepherosa Ziehau VMBUS_PCPU_PTR(sc, message_dma, cpu), 748b7bb4816SSepherosa Ziehau VMBUS_PCPU_GET(sc, message, cpu)); 749b7bb4816SSepherosa Ziehau VMBUS_PCPU_GET(sc, message, cpu) = NULL; 750b7bb4816SSepherosa Ziehau } 751b7bb4816SSepherosa Ziehau if (VMBUS_PCPU_GET(sc, event_flags, cpu) != NULL) { 752b7bb4816SSepherosa Ziehau hyperv_dmamem_free( 753b7bb4816SSepherosa Ziehau VMBUS_PCPU_PTR(sc, event_flags_dma, cpu), 754b7bb4816SSepherosa Ziehau VMBUS_PCPU_GET(sc, event_flags, cpu)); 755b7bb4816SSepherosa Ziehau VMBUS_PCPU_GET(sc, event_flags, cpu) = NULL; 756b7bb4816SSepherosa Ziehau } 757b7bb4816SSepherosa Ziehau } 758b7bb4816SSepherosa Ziehau } 759b7bb4816SSepherosa Ziehau 760b7bb4816SSepherosa Ziehau static int 761b7bb4816SSepherosa Ziehau vmbus_intr_setup(struct vmbus_softc *sc) 762b7bb4816SSepherosa Ziehau { 763b7bb4816SSepherosa Ziehau int cpu; 764b7bb4816SSepherosa Ziehau 765b7bb4816SSepherosa Ziehau CPU_FOREACH(cpu) { 766b7bb4816SSepherosa Ziehau char buf[MAXCOMLEN + 1]; 767b7bb4816SSepherosa Ziehau cpuset_t cpu_mask; 768b7bb4816SSepherosa Ziehau 769b7bb4816SSepherosa Ziehau /* Allocate an interrupt counter for Hyper-V interrupt */ 770b7bb4816SSepherosa Ziehau snprintf(buf, sizeof(buf), "cpu%d:hyperv", cpu); 771b7bb4816SSepherosa Ziehau intrcnt_add(buf, VMBUS_PCPU_PTR(sc, intr_cnt, cpu)); 772b7bb4816SSepherosa Ziehau 773b7bb4816SSepherosa Ziehau /* 774b7bb4816SSepherosa Ziehau * Setup taskqueue to handle events. Task will be per- 775b7bb4816SSepherosa Ziehau * channel. 776b7bb4816SSepherosa Ziehau */ 777b7bb4816SSepherosa Ziehau VMBUS_PCPU_GET(sc, event_tq, cpu) = taskqueue_create_fast( 778b7bb4816SSepherosa Ziehau "hyperv event", M_WAITOK, taskqueue_thread_enqueue, 779b7bb4816SSepherosa Ziehau VMBUS_PCPU_PTR(sc, event_tq, cpu)); 780b7bb4816SSepherosa Ziehau CPU_SETOF(cpu, &cpu_mask); 781b7bb4816SSepherosa Ziehau taskqueue_start_threads_cpuset( 782b7bb4816SSepherosa Ziehau VMBUS_PCPU_PTR(sc, event_tq, cpu), 1, PI_NET, &cpu_mask, 783b7bb4816SSepherosa Ziehau "hvevent%d", cpu); 784b7bb4816SSepherosa Ziehau 785b7bb4816SSepherosa Ziehau /* 786b7bb4816SSepherosa Ziehau * Setup tasks and taskqueues to handle messages. 787b7bb4816SSepherosa Ziehau */ 788b7bb4816SSepherosa Ziehau VMBUS_PCPU_GET(sc, message_tq, cpu) = taskqueue_create_fast( 789b7bb4816SSepherosa Ziehau "hyperv msg", M_WAITOK, taskqueue_thread_enqueue, 790b7bb4816SSepherosa Ziehau VMBUS_PCPU_PTR(sc, message_tq, cpu)); 791b7bb4816SSepherosa Ziehau CPU_SETOF(cpu, &cpu_mask); 792b7bb4816SSepherosa Ziehau taskqueue_start_threads_cpuset( 793b7bb4816SSepherosa Ziehau VMBUS_PCPU_PTR(sc, message_tq, cpu), 1, PI_NET, &cpu_mask, 794b7bb4816SSepherosa Ziehau "hvmsg%d", cpu); 795b7bb4816SSepherosa Ziehau TASK_INIT(VMBUS_PCPU_PTR(sc, message_task, cpu), 0, 796b7bb4816SSepherosa Ziehau vmbus_msg_task, sc); 797b7bb4816SSepherosa Ziehau } 798b7bb4816SSepherosa Ziehau 799b7bb4816SSepherosa Ziehau /* 800b7bb4816SSepherosa Ziehau * All Hyper-V ISR required resources are setup, now let's find a 801b7bb4816SSepherosa Ziehau * free IDT vector for Hyper-V ISR and set it up. 802b7bb4816SSepherosa Ziehau */ 803b7bb4816SSepherosa Ziehau sc->vmbus_idtvec = lapic_ipi_alloc(IDTVEC(vmbus_isr)); 804b7bb4816SSepherosa Ziehau if (sc->vmbus_idtvec < 0) { 805b7bb4816SSepherosa Ziehau device_printf(sc->vmbus_dev, "cannot find free IDT vector\n"); 806b7bb4816SSepherosa Ziehau return ENXIO; 807b7bb4816SSepherosa Ziehau } 808b7bb4816SSepherosa Ziehau if(bootverbose) { 809b7bb4816SSepherosa Ziehau device_printf(sc->vmbus_dev, "vmbus IDT vector %d\n", 810b7bb4816SSepherosa Ziehau sc->vmbus_idtvec); 811b7bb4816SSepherosa Ziehau } 812b7bb4816SSepherosa Ziehau return 0; 813b7bb4816SSepherosa Ziehau } 814b7bb4816SSepherosa Ziehau 815b7bb4816SSepherosa Ziehau static void 816b7bb4816SSepherosa Ziehau vmbus_intr_teardown(struct vmbus_softc *sc) 817b7bb4816SSepherosa Ziehau { 818b7bb4816SSepherosa Ziehau int cpu; 819b7bb4816SSepherosa Ziehau 820b7bb4816SSepherosa Ziehau if (sc->vmbus_idtvec >= 0) { 821b7bb4816SSepherosa Ziehau lapic_ipi_free(sc->vmbus_idtvec); 822b7bb4816SSepherosa Ziehau sc->vmbus_idtvec = -1; 823b7bb4816SSepherosa Ziehau } 824b7bb4816SSepherosa Ziehau 825b7bb4816SSepherosa Ziehau CPU_FOREACH(cpu) { 826b7bb4816SSepherosa Ziehau if (VMBUS_PCPU_GET(sc, event_tq, cpu) != NULL) { 827b7bb4816SSepherosa Ziehau taskqueue_free(VMBUS_PCPU_GET(sc, event_tq, cpu)); 828b7bb4816SSepherosa Ziehau VMBUS_PCPU_GET(sc, event_tq, cpu) = NULL; 829b7bb4816SSepherosa Ziehau } 830b7bb4816SSepherosa Ziehau if (VMBUS_PCPU_GET(sc, message_tq, cpu) != NULL) { 831b7bb4816SSepherosa Ziehau taskqueue_drain(VMBUS_PCPU_GET(sc, message_tq, cpu), 832b7bb4816SSepherosa Ziehau VMBUS_PCPU_PTR(sc, message_task, cpu)); 833b7bb4816SSepherosa Ziehau taskqueue_free(VMBUS_PCPU_GET(sc, message_tq, cpu)); 834b7bb4816SSepherosa Ziehau VMBUS_PCPU_GET(sc, message_tq, cpu) = NULL; 835b7bb4816SSepherosa Ziehau } 836b7bb4816SSepherosa Ziehau } 837b7bb4816SSepherosa Ziehau } 838b7bb4816SSepherosa Ziehau 839b7bb4816SSepherosa Ziehau static int 840b7bb4816SSepherosa Ziehau vmbus_read_ivar(device_t dev, device_t child, int index, uintptr_t *result) 841b7bb4816SSepherosa Ziehau { 842b7bb4816SSepherosa Ziehau struct hv_device *child_dev_ctx = device_get_ivars(child); 843b7bb4816SSepherosa Ziehau 844b7bb4816SSepherosa Ziehau switch (index) { 845b7bb4816SSepherosa Ziehau case HV_VMBUS_IVAR_TYPE: 846b7bb4816SSepherosa Ziehau *result = (uintptr_t)&child_dev_ctx->class_id; 847b7bb4816SSepherosa Ziehau return (0); 848b7bb4816SSepherosa Ziehau 849b7bb4816SSepherosa Ziehau case HV_VMBUS_IVAR_INSTANCE: 850b7bb4816SSepherosa Ziehau *result = (uintptr_t)&child_dev_ctx->device_id; 851b7bb4816SSepherosa Ziehau return (0); 852b7bb4816SSepherosa Ziehau 853b7bb4816SSepherosa Ziehau case HV_VMBUS_IVAR_DEVCTX: 854b7bb4816SSepherosa Ziehau *result = (uintptr_t)child_dev_ctx; 855b7bb4816SSepherosa Ziehau return (0); 856b7bb4816SSepherosa Ziehau 857b7bb4816SSepherosa Ziehau case HV_VMBUS_IVAR_NODE: 858b7bb4816SSepherosa Ziehau *result = (uintptr_t)child_dev_ctx->device; 859b7bb4816SSepherosa Ziehau return (0); 860b7bb4816SSepherosa Ziehau } 861b7bb4816SSepherosa Ziehau return (ENOENT); 862b7bb4816SSepherosa Ziehau } 863b7bb4816SSepherosa Ziehau 864b7bb4816SSepherosa Ziehau static int 865b7bb4816SSepherosa Ziehau vmbus_write_ivar(device_t dev, device_t child, int index, uintptr_t value) 866b7bb4816SSepherosa Ziehau { 867b7bb4816SSepherosa Ziehau switch (index) { 868b7bb4816SSepherosa Ziehau case HV_VMBUS_IVAR_TYPE: 869b7bb4816SSepherosa Ziehau case HV_VMBUS_IVAR_INSTANCE: 870b7bb4816SSepherosa Ziehau case HV_VMBUS_IVAR_DEVCTX: 871b7bb4816SSepherosa Ziehau case HV_VMBUS_IVAR_NODE: 872b7bb4816SSepherosa Ziehau /* read-only */ 873b7bb4816SSepherosa Ziehau return (EINVAL); 874b7bb4816SSepherosa Ziehau } 875b7bb4816SSepherosa Ziehau return (ENOENT); 876b7bb4816SSepherosa Ziehau } 877b7bb4816SSepherosa Ziehau 878b7bb4816SSepherosa Ziehau static int 879b7bb4816SSepherosa Ziehau vmbus_child_pnpinfo_str(device_t dev, device_t child, char *buf, size_t buflen) 880b7bb4816SSepherosa Ziehau { 881b7bb4816SSepherosa Ziehau struct hv_device *dev_ctx = device_get_ivars(child); 882b7bb4816SSepherosa Ziehau char guidbuf[HYPERV_GUID_STRLEN]; 883b7bb4816SSepherosa Ziehau 884b7bb4816SSepherosa Ziehau if (dev_ctx == NULL) 885b7bb4816SSepherosa Ziehau return (0); 886b7bb4816SSepherosa Ziehau 887b7bb4816SSepherosa Ziehau strlcat(buf, "classid=", buflen); 888b7bb4816SSepherosa Ziehau hyperv_guid2str(&dev_ctx->class_id, guidbuf, sizeof(guidbuf)); 889b7bb4816SSepherosa Ziehau strlcat(buf, guidbuf, buflen); 890b7bb4816SSepherosa Ziehau 891b7bb4816SSepherosa Ziehau strlcat(buf, " deviceid=", buflen); 892b7bb4816SSepherosa Ziehau hyperv_guid2str(&dev_ctx->device_id, guidbuf, sizeof(guidbuf)); 893b7bb4816SSepherosa Ziehau strlcat(buf, guidbuf, buflen); 894b7bb4816SSepherosa Ziehau 895b7bb4816SSepherosa Ziehau return (0); 896b7bb4816SSepherosa Ziehau } 897b7bb4816SSepherosa Ziehau 898b7bb4816SSepherosa Ziehau struct hv_device * 899b7bb4816SSepherosa Ziehau hv_vmbus_child_device_create(hv_guid type, hv_guid instance, 900b7bb4816SSepherosa Ziehau hv_vmbus_channel *channel) 901b7bb4816SSepherosa Ziehau { 902b7bb4816SSepherosa Ziehau hv_device *child_dev; 903b7bb4816SSepherosa Ziehau 904b7bb4816SSepherosa Ziehau /* 905b7bb4816SSepherosa Ziehau * Allocate the new child device 906b7bb4816SSepherosa Ziehau */ 907b7bb4816SSepherosa Ziehau child_dev = malloc(sizeof(hv_device), M_DEVBUF, M_WAITOK | M_ZERO); 908b7bb4816SSepherosa Ziehau 909b7bb4816SSepherosa Ziehau child_dev->channel = channel; 910b7bb4816SSepherosa Ziehau memcpy(&child_dev->class_id, &type, sizeof(hv_guid)); 911b7bb4816SSepherosa Ziehau memcpy(&child_dev->device_id, &instance, sizeof(hv_guid)); 912b7bb4816SSepherosa Ziehau 913b7bb4816SSepherosa Ziehau return (child_dev); 914b7bb4816SSepherosa Ziehau } 915b7bb4816SSepherosa Ziehau 916b7bb4816SSepherosa Ziehau int 917b7bb4816SSepherosa Ziehau hv_vmbus_child_device_register(struct hv_device *child_dev) 918b7bb4816SSepherosa Ziehau { 919b7bb4816SSepherosa Ziehau device_t child, parent; 920b7bb4816SSepherosa Ziehau 921b7bb4816SSepherosa Ziehau parent = vmbus_get_device(); 922b7bb4816SSepherosa Ziehau if (bootverbose) { 923b7bb4816SSepherosa Ziehau char name[HYPERV_GUID_STRLEN]; 924b7bb4816SSepherosa Ziehau 925b7bb4816SSepherosa Ziehau hyperv_guid2str(&child_dev->class_id, name, sizeof(name)); 926b7bb4816SSepherosa Ziehau device_printf(parent, "add device, classid: %s\n", name); 927b7bb4816SSepherosa Ziehau } 928b7bb4816SSepherosa Ziehau 929b7bb4816SSepherosa Ziehau child = device_add_child(parent, NULL, -1); 930b7bb4816SSepherosa Ziehau child_dev->device = child; 931b7bb4816SSepherosa Ziehau device_set_ivars(child, child_dev); 932b7bb4816SSepherosa Ziehau 933b7bb4816SSepherosa Ziehau return (0); 934b7bb4816SSepherosa Ziehau } 935b7bb4816SSepherosa Ziehau 936b7bb4816SSepherosa Ziehau int 937b7bb4816SSepherosa Ziehau hv_vmbus_child_device_unregister(struct hv_device *child_dev) 938b7bb4816SSepherosa Ziehau { 939b7bb4816SSepherosa Ziehau int ret = 0; 940b7bb4816SSepherosa Ziehau /* 941b7bb4816SSepherosa Ziehau * XXXKYS: Ensure that this is the opposite of 942b7bb4816SSepherosa Ziehau * device_add_child() 943b7bb4816SSepherosa Ziehau */ 944b7bb4816SSepherosa Ziehau mtx_lock(&Giant); 945b7bb4816SSepherosa Ziehau ret = device_delete_child(vmbus_get_device(), child_dev->device); 946b7bb4816SSepherosa Ziehau mtx_unlock(&Giant); 947b7bb4816SSepherosa Ziehau return(ret); 948b7bb4816SSepherosa Ziehau } 949b7bb4816SSepherosa Ziehau 950b7bb4816SSepherosa Ziehau static int 951b7bb4816SSepherosa Ziehau vmbus_probe(device_t dev) 952b7bb4816SSepherosa Ziehau { 953b7bb4816SSepherosa Ziehau char *id[] = { "VMBUS", NULL }; 954b7bb4816SSepherosa Ziehau 955b7bb4816SSepherosa Ziehau if (ACPI_ID_PROBE(device_get_parent(dev), dev, id) == NULL || 956b7bb4816SSepherosa Ziehau device_get_unit(dev) != 0 || vm_guest != VM_GUEST_HV || 957b7bb4816SSepherosa Ziehau (hyperv_features & CPUID_HV_MSR_SYNIC) == 0) 958b7bb4816SSepherosa Ziehau return (ENXIO); 959b7bb4816SSepherosa Ziehau 960b7bb4816SSepherosa Ziehau device_set_desc(dev, "Hyper-V Vmbus"); 961b7bb4816SSepherosa Ziehau 962b7bb4816SSepherosa Ziehau return (BUS_PROBE_DEFAULT); 963b7bb4816SSepherosa Ziehau } 964b7bb4816SSepherosa Ziehau 965b7bb4816SSepherosa Ziehau /** 966b7bb4816SSepherosa Ziehau * @brief Main vmbus driver initialization routine. 967b7bb4816SSepherosa Ziehau * 968b7bb4816SSepherosa Ziehau * Here, we 969b7bb4816SSepherosa Ziehau * - initialize the vmbus driver context 970b7bb4816SSepherosa Ziehau * - setup various driver entry points 971b7bb4816SSepherosa Ziehau * - invoke the vmbus hv main init routine 972b7bb4816SSepherosa Ziehau * - get the irq resource 973b7bb4816SSepherosa Ziehau * - invoke the vmbus to add the vmbus root device 974b7bb4816SSepherosa Ziehau * - setup the vmbus root device 975b7bb4816SSepherosa Ziehau * - retrieve the channel offers 976b7bb4816SSepherosa Ziehau */ 977b7bb4816SSepherosa Ziehau static int 978*dd012a57SSepherosa Ziehau vmbus_doattach(struct vmbus_softc *sc) 979b7bb4816SSepherosa Ziehau { 980b7bb4816SSepherosa Ziehau int ret; 981b7bb4816SSepherosa Ziehau 982b7bb4816SSepherosa Ziehau if (sc->vmbus_flags & VMBUS_FLAG_ATTACHED) 983b7bb4816SSepherosa Ziehau return (0); 984b7bb4816SSepherosa Ziehau sc->vmbus_flags |= VMBUS_FLAG_ATTACHED; 985b7bb4816SSepherosa Ziehau 986b7bb4816SSepherosa Ziehau /* 987236764b1SSepherosa Ziehau * Create context for "post message" Hypercalls 988236764b1SSepherosa Ziehau */ 989236764b1SSepherosa Ziehau sc->vmbus_msg_hc = vmbus_msghc_ctx_create( 990236764b1SSepherosa Ziehau bus_get_dma_tag(sc->vmbus_dev)); 991236764b1SSepherosa Ziehau if (sc->vmbus_msg_hc == NULL) { 992236764b1SSepherosa Ziehau ret = ENXIO; 993236764b1SSepherosa Ziehau goto cleanup; 994236764b1SSepherosa Ziehau } 995236764b1SSepherosa Ziehau 996236764b1SSepherosa Ziehau /* 997b7bb4816SSepherosa Ziehau * Allocate DMA stuffs. 998b7bb4816SSepherosa Ziehau */ 999b7bb4816SSepherosa Ziehau ret = vmbus_dma_alloc(sc); 1000b7bb4816SSepherosa Ziehau if (ret != 0) 1001b7bb4816SSepherosa Ziehau goto cleanup; 1002b7bb4816SSepherosa Ziehau 1003b7bb4816SSepherosa Ziehau /* 1004b7bb4816SSepherosa Ziehau * Setup interrupt. 1005b7bb4816SSepherosa Ziehau */ 1006b7bb4816SSepherosa Ziehau ret = vmbus_intr_setup(sc); 1007b7bb4816SSepherosa Ziehau if (ret != 0) 1008b7bb4816SSepherosa Ziehau goto cleanup; 1009b7bb4816SSepherosa Ziehau 1010b7bb4816SSepherosa Ziehau /* 1011b7bb4816SSepherosa Ziehau * Setup SynIC. 1012b7bb4816SSepherosa Ziehau */ 1013b7bb4816SSepherosa Ziehau if (bootverbose) 1014b7bb4816SSepherosa Ziehau device_printf(sc->vmbus_dev, "smp_started = %d\n", smp_started); 1015b7bb4816SSepherosa Ziehau smp_rendezvous(NULL, vmbus_synic_setup, NULL, sc); 1016b7bb4816SSepherosa Ziehau sc->vmbus_flags |= VMBUS_FLAG_SYNIC; 1017b7bb4816SSepherosa Ziehau 1018b7bb4816SSepherosa Ziehau /* 1019b7bb4816SSepherosa Ziehau * Connect to VMBus in the root partition 1020b7bb4816SSepherosa Ziehau */ 10216523ab7eSSepherosa Ziehau ret = hv_vmbus_connect(sc); 1022b7bb4816SSepherosa Ziehau if (ret != 0) 1023b7bb4816SSepherosa Ziehau goto cleanup; 1024b7bb4816SSepherosa Ziehau 1025236764b1SSepherosa Ziehau ret = vmbus_init(sc); 1026236764b1SSepherosa Ziehau if (ret != 0) 1027236764b1SSepherosa Ziehau goto cleanup; 1028236764b1SSepherosa Ziehau 1029b7bb4816SSepherosa Ziehau if (hv_vmbus_protocal_version == HV_VMBUS_VERSION_WS2008 || 1030b7bb4816SSepherosa Ziehau hv_vmbus_protocal_version == HV_VMBUS_VERSION_WIN7) 1031b7bb4816SSepherosa Ziehau sc->vmbus_event_proc = vmbus_event_proc_compat; 1032b7bb4816SSepherosa Ziehau else 1033b7bb4816SSepherosa Ziehau sc->vmbus_event_proc = vmbus_event_proc; 1034b7bb4816SSepherosa Ziehau 1035c1cc5bdfSSepherosa Ziehau ret = vmbus_req_channels(sc); 1036c1cc5bdfSSepherosa Ziehau if (ret != 0) 1037c1cc5bdfSSepherosa Ziehau goto cleanup; 1038b7bb4816SSepherosa Ziehau 1039b7bb4816SSepherosa Ziehau vmbus_scan(); 1040b7bb4816SSepherosa Ziehau bus_generic_attach(sc->vmbus_dev); 1041b7bb4816SSepherosa Ziehau device_printf(sc->vmbus_dev, "device scan, probe and attach done\n"); 1042b7bb4816SSepherosa Ziehau 1043b7bb4816SSepherosa Ziehau return (ret); 1044b7bb4816SSepherosa Ziehau 1045b7bb4816SSepherosa Ziehau cleanup: 1046b7bb4816SSepherosa Ziehau vmbus_intr_teardown(sc); 1047b7bb4816SSepherosa Ziehau vmbus_dma_free(sc); 1048236764b1SSepherosa Ziehau if (sc->vmbus_msg_hc != NULL) { 1049236764b1SSepherosa Ziehau vmbus_msghc_ctx_destroy(sc->vmbus_msg_hc); 1050236764b1SSepherosa Ziehau sc->vmbus_msg_hc = NULL; 1051236764b1SSepherosa Ziehau } 1052b7bb4816SSepherosa Ziehau 1053b7bb4816SSepherosa Ziehau return (ret); 1054b7bb4816SSepherosa Ziehau } 1055b7bb4816SSepherosa Ziehau 1056b7bb4816SSepherosa Ziehau static void 1057b7bb4816SSepherosa Ziehau vmbus_event_proc_dummy(struct vmbus_softc *sc __unused, int cpu __unused) 1058b7bb4816SSepherosa Ziehau { 1059b7bb4816SSepherosa Ziehau } 1060b7bb4816SSepherosa Ziehau 1061b7bb4816SSepherosa Ziehau static int 1062b7bb4816SSepherosa Ziehau vmbus_attach(device_t dev) 1063b7bb4816SSepherosa Ziehau { 1064b7bb4816SSepherosa Ziehau vmbus_sc = device_get_softc(dev); 1065b7bb4816SSepherosa Ziehau vmbus_sc->vmbus_dev = dev; 1066b7bb4816SSepherosa Ziehau vmbus_sc->vmbus_idtvec = -1; 1067b7bb4816SSepherosa Ziehau 1068b7bb4816SSepherosa Ziehau /* 1069b7bb4816SSepherosa Ziehau * Event processing logic will be configured: 1070b7bb4816SSepherosa Ziehau * - After the vmbus protocol version negotiation. 1071b7bb4816SSepherosa Ziehau * - Before we request channel offers. 1072b7bb4816SSepherosa Ziehau */ 1073b7bb4816SSepherosa Ziehau vmbus_sc->vmbus_event_proc = vmbus_event_proc_dummy; 1074b7bb4816SSepherosa Ziehau 1075b7bb4816SSepherosa Ziehau #ifndef EARLY_AP_STARTUP 1076b7bb4816SSepherosa Ziehau /* 1077b7bb4816SSepherosa Ziehau * If the system has already booted and thread 1078b7bb4816SSepherosa Ziehau * scheduling is possible indicated by the global 1079b7bb4816SSepherosa Ziehau * cold set to zero, we just call the driver 1080b7bb4816SSepherosa Ziehau * initialization directly. 1081b7bb4816SSepherosa Ziehau */ 1082b7bb4816SSepherosa Ziehau if (!cold) 1083b7bb4816SSepherosa Ziehau #endif 1084*dd012a57SSepherosa Ziehau vmbus_doattach(vmbus_sc); 1085b7bb4816SSepherosa Ziehau 1086b7bb4816SSepherosa Ziehau bus_generic_probe(dev); 1087b7bb4816SSepherosa Ziehau return (0); 1088b7bb4816SSepherosa Ziehau } 1089b7bb4816SSepherosa Ziehau 1090b7bb4816SSepherosa Ziehau static void 1091b7bb4816SSepherosa Ziehau vmbus_sysinit(void *arg __unused) 1092b7bb4816SSepherosa Ziehau { 1093*dd012a57SSepherosa Ziehau struct vmbus_softc *sc = vmbus_get_softc(); 1094*dd012a57SSepherosa Ziehau 1095*dd012a57SSepherosa Ziehau if (vm_guest != VM_GUEST_HV || sc == NULL) 1096b7bb4816SSepherosa Ziehau return; 1097b7bb4816SSepherosa Ziehau 1098b7bb4816SSepherosa Ziehau #ifndef EARLY_AP_STARTUP 1099b7bb4816SSepherosa Ziehau /* 1100b7bb4816SSepherosa Ziehau * If the system has already booted and thread 1101b7bb4816SSepherosa Ziehau * scheduling is possible, as indicated by the 1102b7bb4816SSepherosa Ziehau * global cold set to zero, we just call the driver 1103b7bb4816SSepherosa Ziehau * initialization directly. 1104b7bb4816SSepherosa Ziehau */ 1105b7bb4816SSepherosa Ziehau if (!cold) 1106b7bb4816SSepherosa Ziehau #endif 1107*dd012a57SSepherosa Ziehau vmbus_doattach(sc); 1108b7bb4816SSepherosa Ziehau } 1109b7bb4816SSepherosa Ziehau 1110b7bb4816SSepherosa Ziehau static int 1111b7bb4816SSepherosa Ziehau vmbus_detach(device_t dev) 1112b7bb4816SSepherosa Ziehau { 1113b7bb4816SSepherosa Ziehau struct vmbus_softc *sc = device_get_softc(dev); 1114b7bb4816SSepherosa Ziehau 1115b7bb4816SSepherosa Ziehau hv_vmbus_release_unattached_channels(); 1116b7bb4816SSepherosa Ziehau hv_vmbus_disconnect(); 1117b7bb4816SSepherosa Ziehau 1118b7bb4816SSepherosa Ziehau if (sc->vmbus_flags & VMBUS_FLAG_SYNIC) { 1119b7bb4816SSepherosa Ziehau sc->vmbus_flags &= ~VMBUS_FLAG_SYNIC; 1120b7bb4816SSepherosa Ziehau smp_rendezvous(NULL, vmbus_synic_teardown, NULL, NULL); 1121b7bb4816SSepherosa Ziehau } 1122b7bb4816SSepherosa Ziehau 1123b7bb4816SSepherosa Ziehau vmbus_intr_teardown(sc); 1124b7bb4816SSepherosa Ziehau vmbus_dma_free(sc); 1125b7bb4816SSepherosa Ziehau 1126236764b1SSepherosa Ziehau if (sc->vmbus_msg_hc != NULL) { 1127236764b1SSepherosa Ziehau vmbus_msghc_ctx_destroy(sc->vmbus_msg_hc); 1128236764b1SSepherosa Ziehau sc->vmbus_msg_hc = NULL; 1129236764b1SSepherosa Ziehau } 1130236764b1SSepherosa Ziehau 1131b7bb4816SSepherosa Ziehau return (0); 1132b7bb4816SSepherosa Ziehau } 1133b7bb4816SSepherosa Ziehau 1134b7bb4816SSepherosa Ziehau static device_method_t vmbus_methods[] = { 1135b7bb4816SSepherosa Ziehau /* Device interface */ 1136b7bb4816SSepherosa Ziehau DEVMETHOD(device_probe, vmbus_probe), 1137b7bb4816SSepherosa Ziehau DEVMETHOD(device_attach, vmbus_attach), 1138b7bb4816SSepherosa Ziehau DEVMETHOD(device_detach, vmbus_detach), 1139b7bb4816SSepherosa Ziehau DEVMETHOD(device_shutdown, bus_generic_shutdown), 1140b7bb4816SSepherosa Ziehau DEVMETHOD(device_suspend, bus_generic_suspend), 1141b7bb4816SSepherosa Ziehau DEVMETHOD(device_resume, bus_generic_resume), 1142b7bb4816SSepherosa Ziehau 1143b7bb4816SSepherosa Ziehau /* Bus interface */ 1144b7bb4816SSepherosa Ziehau DEVMETHOD(bus_add_child, bus_generic_add_child), 1145b7bb4816SSepherosa Ziehau DEVMETHOD(bus_print_child, bus_generic_print_child), 1146b7bb4816SSepherosa Ziehau DEVMETHOD(bus_read_ivar, vmbus_read_ivar), 1147b7bb4816SSepherosa Ziehau DEVMETHOD(bus_write_ivar, vmbus_write_ivar), 1148b7bb4816SSepherosa Ziehau DEVMETHOD(bus_child_pnpinfo_str, vmbus_child_pnpinfo_str), 1149b7bb4816SSepherosa Ziehau 1150b7bb4816SSepherosa Ziehau DEVMETHOD_END 1151b7bb4816SSepherosa Ziehau }; 1152b7bb4816SSepherosa Ziehau 1153b7bb4816SSepherosa Ziehau static driver_t vmbus_driver = { 1154b7bb4816SSepherosa Ziehau "vmbus", 1155b7bb4816SSepherosa Ziehau vmbus_methods, 1156b7bb4816SSepherosa Ziehau sizeof(struct vmbus_softc) 1157b7bb4816SSepherosa Ziehau }; 1158b7bb4816SSepherosa Ziehau 1159b7bb4816SSepherosa Ziehau static devclass_t vmbus_devclass; 1160b7bb4816SSepherosa Ziehau 1161b7bb4816SSepherosa Ziehau DRIVER_MODULE(vmbus, acpi, vmbus_driver, vmbus_devclass, NULL, NULL); 1162b7bb4816SSepherosa Ziehau MODULE_DEPEND(vmbus, acpi, 1, 1, 1); 1163b7bb4816SSepherosa Ziehau MODULE_VERSION(vmbus, 1); 1164b7bb4816SSepherosa Ziehau 1165b7bb4816SSepherosa Ziehau #ifndef EARLY_AP_STARTUP 1166b7bb4816SSepherosa Ziehau /* 1167b7bb4816SSepherosa Ziehau * NOTE: 1168b7bb4816SSepherosa Ziehau * We have to start as the last step of SI_SUB_SMP, i.e. after SMP is 1169b7bb4816SSepherosa Ziehau * initialized. 1170b7bb4816SSepherosa Ziehau */ 1171b7bb4816SSepherosa Ziehau SYSINIT(vmbus_initialize, SI_SUB_SMP, SI_ORDER_ANY, vmbus_sysinit, NULL); 1172b7bb4816SSepherosa Ziehau #endif 1173