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