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 72b7bb4816SSepherosa Ziehau struct vmbus_softc *vmbus_sc; 73b7bb4816SSepherosa Ziehau 74b7bb4816SSepherosa Ziehau extern inthand_t IDTVEC(vmbus_isr); 75b7bb4816SSepherosa Ziehau 76b7bb4816SSepherosa Ziehau static void 77b7bb4816SSepherosa Ziehau vmbus_msg_task(void *xsc, int pending __unused) 78b7bb4816SSepherosa Ziehau { 79b7bb4816SSepherosa Ziehau struct vmbus_softc *sc = xsc; 80b7bb4816SSepherosa Ziehau volatile struct vmbus_message *msg; 81b7bb4816SSepherosa Ziehau 82b7bb4816SSepherosa Ziehau msg = VMBUS_PCPU_GET(sc, message, curcpu) + VMBUS_SINT_MESSAGE; 83b7bb4816SSepherosa Ziehau for (;;) { 84fa4828b0SSepherosa Ziehau if (msg->msg_type == VMBUS_MSGTYPE_NONE) { 85fa4828b0SSepherosa Ziehau /* No message */ 86fa4828b0SSepherosa Ziehau break; 87*12ea25aeSSepherosa Ziehau } else if (msg->msg_type == VMBUS_MSGTYPE_CHANNEL) { 88*12ea25aeSSepherosa Ziehau /* Channel message */ 89*12ea25aeSSepherosa Ziehau vmbus_chan_msgproc(sc, msg); 90fa4828b0SSepherosa Ziehau } 91b7bb4816SSepherosa Ziehau 92b7bb4816SSepherosa Ziehau msg->msg_type = VMBUS_MSGTYPE_NONE; 93b7bb4816SSepherosa Ziehau /* 94b7bb4816SSepherosa Ziehau * Make sure the write to msg_type (i.e. set to 95b7bb4816SSepherosa Ziehau * VMBUS_MSGTYPE_NONE) happens before we read the 96b7bb4816SSepherosa Ziehau * msg_flags and EOMing. Otherwise, the EOMing will 97b7bb4816SSepherosa Ziehau * not deliver any more messages since there is no 98b7bb4816SSepherosa Ziehau * empty slot 99b7bb4816SSepherosa Ziehau * 100b7bb4816SSepherosa Ziehau * NOTE: 101b7bb4816SSepherosa Ziehau * mb() is used here, since atomic_thread_fence_seq_cst() 102b7bb4816SSepherosa Ziehau * will become compiler fence on UP kernel. 103b7bb4816SSepherosa Ziehau */ 104b7bb4816SSepherosa Ziehau mb(); 105b7bb4816SSepherosa Ziehau if (msg->msg_flags & VMBUS_MSGFLAG_PENDING) { 106b7bb4816SSepherosa Ziehau /* 107b7bb4816SSepherosa Ziehau * This will cause message queue rescan to possibly 108b7bb4816SSepherosa Ziehau * deliver another msg from the hypervisor 109b7bb4816SSepherosa Ziehau */ 110b7bb4816SSepherosa Ziehau wrmsr(MSR_HV_EOM, 0); 111b7bb4816SSepherosa Ziehau } 112b7bb4816SSepherosa Ziehau } 113b7bb4816SSepherosa Ziehau } 114b7bb4816SSepherosa Ziehau 115b7bb4816SSepherosa Ziehau static __inline int 116b7bb4816SSepherosa Ziehau vmbus_handle_intr1(struct vmbus_softc *sc, struct trapframe *frame, int cpu) 117b7bb4816SSepherosa Ziehau { 118b7bb4816SSepherosa Ziehau volatile struct vmbus_message *msg; 119b7bb4816SSepherosa Ziehau struct vmbus_message *msg_base; 120b7bb4816SSepherosa Ziehau 121b7bb4816SSepherosa Ziehau msg_base = VMBUS_PCPU_GET(sc, message, cpu); 122b7bb4816SSepherosa Ziehau 123b7bb4816SSepherosa Ziehau /* 124b7bb4816SSepherosa Ziehau * Check event timer. 125b7bb4816SSepherosa Ziehau * 126b7bb4816SSepherosa Ziehau * TODO: move this to independent IDT vector. 127b7bb4816SSepherosa Ziehau */ 128b7bb4816SSepherosa Ziehau msg = msg_base + VMBUS_SINT_TIMER; 129b7bb4816SSepherosa Ziehau if (msg->msg_type == VMBUS_MSGTYPE_TIMER_EXPIRED) { 130b7bb4816SSepherosa Ziehau msg->msg_type = VMBUS_MSGTYPE_NONE; 131b7bb4816SSepherosa Ziehau 132b7bb4816SSepherosa Ziehau vmbus_et_intr(frame); 133b7bb4816SSepherosa Ziehau 134b7bb4816SSepherosa Ziehau /* 135b7bb4816SSepherosa Ziehau * Make sure the write to msg_type (i.e. set to 136b7bb4816SSepherosa Ziehau * VMBUS_MSGTYPE_NONE) happens before we read the 137b7bb4816SSepherosa Ziehau * msg_flags and EOMing. Otherwise, the EOMing will 138b7bb4816SSepherosa Ziehau * not deliver any more messages since there is no 139b7bb4816SSepherosa Ziehau * empty slot 140b7bb4816SSepherosa Ziehau * 141b7bb4816SSepherosa Ziehau * NOTE: 142b7bb4816SSepherosa Ziehau * mb() is used here, since atomic_thread_fence_seq_cst() 143b7bb4816SSepherosa Ziehau * will become compiler fence on UP kernel. 144b7bb4816SSepherosa Ziehau */ 145b7bb4816SSepherosa Ziehau mb(); 146b7bb4816SSepherosa Ziehau if (msg->msg_flags & VMBUS_MSGFLAG_PENDING) { 147b7bb4816SSepherosa Ziehau /* 148b7bb4816SSepherosa Ziehau * This will cause message queue rescan to possibly 149b7bb4816SSepherosa Ziehau * deliver another msg from the hypervisor 150b7bb4816SSepherosa Ziehau */ 151b7bb4816SSepherosa Ziehau wrmsr(MSR_HV_EOM, 0); 152b7bb4816SSepherosa Ziehau } 153b7bb4816SSepherosa Ziehau } 154b7bb4816SSepherosa Ziehau 155b7bb4816SSepherosa Ziehau /* 156b7bb4816SSepherosa Ziehau * Check events. Hot path for network and storage I/O data; high rate. 157b7bb4816SSepherosa Ziehau * 158b7bb4816SSepherosa Ziehau * NOTE: 159b7bb4816SSepherosa Ziehau * As recommended by the Windows guest fellows, we check events before 160b7bb4816SSepherosa Ziehau * checking messages. 161b7bb4816SSepherosa Ziehau */ 162b7bb4816SSepherosa Ziehau sc->vmbus_event_proc(sc, cpu); 163b7bb4816SSepherosa Ziehau 164b7bb4816SSepherosa Ziehau /* 165b7bb4816SSepherosa Ziehau * Check messages. Mainly management stuffs; ultra low rate. 166b7bb4816SSepherosa Ziehau */ 167b7bb4816SSepherosa Ziehau msg = msg_base + VMBUS_SINT_MESSAGE; 168b7bb4816SSepherosa Ziehau if (__predict_false(msg->msg_type != VMBUS_MSGTYPE_NONE)) { 169b7bb4816SSepherosa Ziehau taskqueue_enqueue(VMBUS_PCPU_GET(sc, message_tq, cpu), 170b7bb4816SSepherosa Ziehau VMBUS_PCPU_PTR(sc, message_task, cpu)); 171b7bb4816SSepherosa Ziehau } 172b7bb4816SSepherosa Ziehau 173b7bb4816SSepherosa Ziehau return (FILTER_HANDLED); 174b7bb4816SSepherosa Ziehau } 175b7bb4816SSepherosa Ziehau 176b7bb4816SSepherosa Ziehau void 177b7bb4816SSepherosa Ziehau vmbus_handle_intr(struct trapframe *trap_frame) 178b7bb4816SSepherosa Ziehau { 179b7bb4816SSepherosa Ziehau struct vmbus_softc *sc = vmbus_get_softc(); 180b7bb4816SSepherosa Ziehau int cpu = curcpu; 181b7bb4816SSepherosa Ziehau 182b7bb4816SSepherosa Ziehau /* 183b7bb4816SSepherosa Ziehau * Disable preemption. 184b7bb4816SSepherosa Ziehau */ 185b7bb4816SSepherosa Ziehau critical_enter(); 186b7bb4816SSepherosa Ziehau 187b7bb4816SSepherosa Ziehau /* 188b7bb4816SSepherosa Ziehau * Do a little interrupt counting. 189b7bb4816SSepherosa Ziehau */ 190b7bb4816SSepherosa Ziehau (*VMBUS_PCPU_GET(sc, intr_cnt, cpu))++; 191b7bb4816SSepherosa Ziehau 192b7bb4816SSepherosa Ziehau vmbus_handle_intr1(sc, trap_frame, cpu); 193b7bb4816SSepherosa Ziehau 194b7bb4816SSepherosa Ziehau /* 195b7bb4816SSepherosa Ziehau * Enable preemption. 196b7bb4816SSepherosa Ziehau */ 197b7bb4816SSepherosa Ziehau critical_exit(); 198b7bb4816SSepherosa Ziehau } 199b7bb4816SSepherosa Ziehau 200b7bb4816SSepherosa Ziehau static void 201b7bb4816SSepherosa Ziehau vmbus_synic_setup(void *xsc) 202b7bb4816SSepherosa Ziehau { 203b7bb4816SSepherosa Ziehau struct vmbus_softc *sc = xsc; 204b7bb4816SSepherosa Ziehau int cpu = curcpu; 205b7bb4816SSepherosa Ziehau uint64_t val, orig; 206b7bb4816SSepherosa Ziehau uint32_t sint; 207b7bb4816SSepherosa Ziehau 208b7bb4816SSepherosa Ziehau if (hyperv_features & CPUID_HV_MSR_VP_INDEX) { 209b7bb4816SSepherosa Ziehau /* 210b7bb4816SSepherosa Ziehau * Save virtual processor id. 211b7bb4816SSepherosa Ziehau */ 212b7bb4816SSepherosa Ziehau VMBUS_PCPU_GET(sc, vcpuid, cpu) = rdmsr(MSR_HV_VP_INDEX); 213b7bb4816SSepherosa Ziehau } else { 214b7bb4816SSepherosa Ziehau /* 215b7bb4816SSepherosa Ziehau * XXX 216b7bb4816SSepherosa Ziehau * Virtual processoor id is only used by a pretty broken 217b7bb4816SSepherosa Ziehau * channel selection code from storvsc. It's nothing 218b7bb4816SSepherosa Ziehau * critical even if CPUID_HV_MSR_VP_INDEX is not set; keep 219b7bb4816SSepherosa Ziehau * moving on. 220b7bb4816SSepherosa Ziehau */ 221b7bb4816SSepherosa Ziehau VMBUS_PCPU_GET(sc, vcpuid, cpu) = cpu; 222b7bb4816SSepherosa Ziehau } 223b7bb4816SSepherosa Ziehau 224b7bb4816SSepherosa Ziehau /* 225b7bb4816SSepherosa Ziehau * Setup the SynIC message. 226b7bb4816SSepherosa Ziehau */ 227b7bb4816SSepherosa Ziehau orig = rdmsr(MSR_HV_SIMP); 228b7bb4816SSepherosa Ziehau val = MSR_HV_SIMP_ENABLE | (orig & MSR_HV_SIMP_RSVD_MASK) | 229b7bb4816SSepherosa Ziehau ((VMBUS_PCPU_GET(sc, message_dma.hv_paddr, cpu) >> PAGE_SHIFT) << 230b7bb4816SSepherosa Ziehau MSR_HV_SIMP_PGSHIFT); 231b7bb4816SSepherosa Ziehau wrmsr(MSR_HV_SIMP, val); 232b7bb4816SSepherosa Ziehau 233b7bb4816SSepherosa Ziehau /* 234b7bb4816SSepherosa Ziehau * Setup the SynIC event flags. 235b7bb4816SSepherosa Ziehau */ 236b7bb4816SSepherosa Ziehau orig = rdmsr(MSR_HV_SIEFP); 237b7bb4816SSepherosa Ziehau val = MSR_HV_SIEFP_ENABLE | (orig & MSR_HV_SIEFP_RSVD_MASK) | 238b7bb4816SSepherosa Ziehau ((VMBUS_PCPU_GET(sc, event_flags_dma.hv_paddr, cpu) 239b7bb4816SSepherosa Ziehau >> PAGE_SHIFT) << MSR_HV_SIEFP_PGSHIFT); 240b7bb4816SSepherosa Ziehau wrmsr(MSR_HV_SIEFP, val); 241b7bb4816SSepherosa Ziehau 242b7bb4816SSepherosa Ziehau 243b7bb4816SSepherosa Ziehau /* 244b7bb4816SSepherosa Ziehau * Configure and unmask SINT for message and event flags. 245b7bb4816SSepherosa Ziehau */ 246b7bb4816SSepherosa Ziehau sint = MSR_HV_SINT0 + VMBUS_SINT_MESSAGE; 247b7bb4816SSepherosa Ziehau orig = rdmsr(sint); 248b7bb4816SSepherosa Ziehau val = sc->vmbus_idtvec | MSR_HV_SINT_AUTOEOI | 249b7bb4816SSepherosa Ziehau (orig & MSR_HV_SINT_RSVD_MASK); 250b7bb4816SSepherosa Ziehau wrmsr(sint, val); 251b7bb4816SSepherosa Ziehau 252b7bb4816SSepherosa Ziehau /* 253b7bb4816SSepherosa Ziehau * Configure and unmask SINT for timer. 254b7bb4816SSepherosa Ziehau */ 255b7bb4816SSepherosa Ziehau sint = MSR_HV_SINT0 + VMBUS_SINT_TIMER; 256b7bb4816SSepherosa Ziehau orig = rdmsr(sint); 257b7bb4816SSepherosa Ziehau val = sc->vmbus_idtvec | MSR_HV_SINT_AUTOEOI | 258b7bb4816SSepherosa Ziehau (orig & MSR_HV_SINT_RSVD_MASK); 259b7bb4816SSepherosa Ziehau wrmsr(sint, val); 260b7bb4816SSepherosa Ziehau 261b7bb4816SSepherosa Ziehau /* 262b7bb4816SSepherosa Ziehau * All done; enable SynIC. 263b7bb4816SSepherosa Ziehau */ 264b7bb4816SSepherosa Ziehau orig = rdmsr(MSR_HV_SCONTROL); 265b7bb4816SSepherosa Ziehau val = MSR_HV_SCTRL_ENABLE | (orig & MSR_HV_SCTRL_RSVD_MASK); 266b7bb4816SSepherosa Ziehau wrmsr(MSR_HV_SCONTROL, val); 267b7bb4816SSepherosa Ziehau } 268b7bb4816SSepherosa Ziehau 269b7bb4816SSepherosa Ziehau static void 270b7bb4816SSepherosa Ziehau vmbus_synic_teardown(void *arg) 271b7bb4816SSepherosa Ziehau { 272b7bb4816SSepherosa Ziehau uint64_t orig; 273b7bb4816SSepherosa Ziehau uint32_t sint; 274b7bb4816SSepherosa Ziehau 275b7bb4816SSepherosa Ziehau /* 276b7bb4816SSepherosa Ziehau * Disable SynIC. 277b7bb4816SSepherosa Ziehau */ 278b7bb4816SSepherosa Ziehau orig = rdmsr(MSR_HV_SCONTROL); 279b7bb4816SSepherosa Ziehau wrmsr(MSR_HV_SCONTROL, (orig & MSR_HV_SCTRL_RSVD_MASK)); 280b7bb4816SSepherosa Ziehau 281b7bb4816SSepherosa Ziehau /* 282b7bb4816SSepherosa Ziehau * Mask message and event flags SINT. 283b7bb4816SSepherosa Ziehau */ 284b7bb4816SSepherosa Ziehau sint = MSR_HV_SINT0 + VMBUS_SINT_MESSAGE; 285b7bb4816SSepherosa Ziehau orig = rdmsr(sint); 286b7bb4816SSepherosa Ziehau wrmsr(sint, orig | MSR_HV_SINT_MASKED); 287b7bb4816SSepherosa Ziehau 288b7bb4816SSepherosa Ziehau /* 289b7bb4816SSepherosa Ziehau * Mask timer SINT. 290b7bb4816SSepherosa Ziehau */ 291b7bb4816SSepherosa Ziehau sint = MSR_HV_SINT0 + VMBUS_SINT_TIMER; 292b7bb4816SSepherosa Ziehau orig = rdmsr(sint); 293b7bb4816SSepherosa Ziehau wrmsr(sint, orig | MSR_HV_SINT_MASKED); 294b7bb4816SSepherosa Ziehau 295b7bb4816SSepherosa Ziehau /* 296b7bb4816SSepherosa Ziehau * Teardown SynIC message. 297b7bb4816SSepherosa Ziehau */ 298b7bb4816SSepherosa Ziehau orig = rdmsr(MSR_HV_SIMP); 299b7bb4816SSepherosa Ziehau wrmsr(MSR_HV_SIMP, (orig & MSR_HV_SIMP_RSVD_MASK)); 300b7bb4816SSepherosa Ziehau 301b7bb4816SSepherosa Ziehau /* 302b7bb4816SSepherosa Ziehau * Teardown SynIC event flags. 303b7bb4816SSepherosa Ziehau */ 304b7bb4816SSepherosa Ziehau orig = rdmsr(MSR_HV_SIEFP); 305b7bb4816SSepherosa Ziehau wrmsr(MSR_HV_SIEFP, (orig & MSR_HV_SIEFP_RSVD_MASK)); 306b7bb4816SSepherosa Ziehau } 307b7bb4816SSepherosa Ziehau 308b7bb4816SSepherosa Ziehau static int 309b7bb4816SSepherosa Ziehau vmbus_dma_alloc(struct vmbus_softc *sc) 310b7bb4816SSepherosa Ziehau { 311b7bb4816SSepherosa Ziehau int cpu; 312b7bb4816SSepherosa Ziehau 313b7bb4816SSepherosa Ziehau CPU_FOREACH(cpu) { 314b7bb4816SSepherosa Ziehau void *ptr; 315b7bb4816SSepherosa Ziehau 316b7bb4816SSepherosa Ziehau /* 317b7bb4816SSepherosa Ziehau * Per-cpu messages and event flags. 318b7bb4816SSepherosa Ziehau */ 319b7bb4816SSepherosa Ziehau ptr = hyperv_dmamem_alloc(bus_get_dma_tag(sc->vmbus_dev), 320b7bb4816SSepherosa Ziehau PAGE_SIZE, 0, PAGE_SIZE, 321b7bb4816SSepherosa Ziehau VMBUS_PCPU_PTR(sc, message_dma, cpu), 322b7bb4816SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO); 323b7bb4816SSepherosa Ziehau if (ptr == NULL) 324b7bb4816SSepherosa Ziehau return ENOMEM; 325b7bb4816SSepherosa Ziehau VMBUS_PCPU_GET(sc, message, cpu) = ptr; 326b7bb4816SSepherosa Ziehau 327b7bb4816SSepherosa Ziehau ptr = hyperv_dmamem_alloc(bus_get_dma_tag(sc->vmbus_dev), 328b7bb4816SSepherosa Ziehau PAGE_SIZE, 0, PAGE_SIZE, 329b7bb4816SSepherosa Ziehau VMBUS_PCPU_PTR(sc, event_flags_dma, cpu), 330b7bb4816SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO); 331b7bb4816SSepherosa Ziehau if (ptr == NULL) 332b7bb4816SSepherosa Ziehau return ENOMEM; 333b7bb4816SSepherosa Ziehau VMBUS_PCPU_GET(sc, event_flags, cpu) = ptr; 334b7bb4816SSepherosa Ziehau } 335b7bb4816SSepherosa Ziehau return 0; 336b7bb4816SSepherosa Ziehau } 337b7bb4816SSepherosa Ziehau 338b7bb4816SSepherosa Ziehau static void 339b7bb4816SSepherosa Ziehau vmbus_dma_free(struct vmbus_softc *sc) 340b7bb4816SSepherosa Ziehau { 341b7bb4816SSepherosa Ziehau int cpu; 342b7bb4816SSepherosa Ziehau 343b7bb4816SSepherosa Ziehau CPU_FOREACH(cpu) { 344b7bb4816SSepherosa Ziehau if (VMBUS_PCPU_GET(sc, message, cpu) != NULL) { 345b7bb4816SSepherosa Ziehau hyperv_dmamem_free( 346b7bb4816SSepherosa Ziehau VMBUS_PCPU_PTR(sc, message_dma, cpu), 347b7bb4816SSepherosa Ziehau VMBUS_PCPU_GET(sc, message, cpu)); 348b7bb4816SSepherosa Ziehau VMBUS_PCPU_GET(sc, message, cpu) = NULL; 349b7bb4816SSepherosa Ziehau } 350b7bb4816SSepherosa Ziehau if (VMBUS_PCPU_GET(sc, event_flags, cpu) != NULL) { 351b7bb4816SSepherosa Ziehau hyperv_dmamem_free( 352b7bb4816SSepherosa Ziehau VMBUS_PCPU_PTR(sc, event_flags_dma, cpu), 353b7bb4816SSepherosa Ziehau VMBUS_PCPU_GET(sc, event_flags, cpu)); 354b7bb4816SSepherosa Ziehau VMBUS_PCPU_GET(sc, event_flags, cpu) = NULL; 355b7bb4816SSepherosa Ziehau } 356b7bb4816SSepherosa Ziehau } 357b7bb4816SSepherosa Ziehau } 358b7bb4816SSepherosa Ziehau 359b7bb4816SSepherosa Ziehau static int 360b7bb4816SSepherosa Ziehau vmbus_intr_setup(struct vmbus_softc *sc) 361b7bb4816SSepherosa Ziehau { 362b7bb4816SSepherosa Ziehau int cpu; 363b7bb4816SSepherosa Ziehau 364b7bb4816SSepherosa Ziehau CPU_FOREACH(cpu) { 365b7bb4816SSepherosa Ziehau char buf[MAXCOMLEN + 1]; 366b7bb4816SSepherosa Ziehau cpuset_t cpu_mask; 367b7bb4816SSepherosa Ziehau 368b7bb4816SSepherosa Ziehau /* Allocate an interrupt counter for Hyper-V interrupt */ 369b7bb4816SSepherosa Ziehau snprintf(buf, sizeof(buf), "cpu%d:hyperv", cpu); 370b7bb4816SSepherosa Ziehau intrcnt_add(buf, VMBUS_PCPU_PTR(sc, intr_cnt, cpu)); 371b7bb4816SSepherosa Ziehau 372b7bb4816SSepherosa Ziehau /* 373b7bb4816SSepherosa Ziehau * Setup taskqueue to handle events. Task will be per- 374b7bb4816SSepherosa Ziehau * channel. 375b7bb4816SSepherosa Ziehau */ 376b7bb4816SSepherosa Ziehau VMBUS_PCPU_GET(sc, event_tq, cpu) = taskqueue_create_fast( 377b7bb4816SSepherosa Ziehau "hyperv event", M_WAITOK, taskqueue_thread_enqueue, 378b7bb4816SSepherosa Ziehau VMBUS_PCPU_PTR(sc, event_tq, cpu)); 379b7bb4816SSepherosa Ziehau CPU_SETOF(cpu, &cpu_mask); 380b7bb4816SSepherosa Ziehau taskqueue_start_threads_cpuset( 381b7bb4816SSepherosa Ziehau VMBUS_PCPU_PTR(sc, event_tq, cpu), 1, PI_NET, &cpu_mask, 382b7bb4816SSepherosa Ziehau "hvevent%d", cpu); 383b7bb4816SSepherosa Ziehau 384b7bb4816SSepherosa Ziehau /* 385b7bb4816SSepherosa Ziehau * Setup tasks and taskqueues to handle messages. 386b7bb4816SSepherosa Ziehau */ 387b7bb4816SSepherosa Ziehau VMBUS_PCPU_GET(sc, message_tq, cpu) = taskqueue_create_fast( 388b7bb4816SSepherosa Ziehau "hyperv msg", M_WAITOK, taskqueue_thread_enqueue, 389b7bb4816SSepherosa Ziehau VMBUS_PCPU_PTR(sc, message_tq, cpu)); 390b7bb4816SSepherosa Ziehau CPU_SETOF(cpu, &cpu_mask); 391b7bb4816SSepherosa Ziehau taskqueue_start_threads_cpuset( 392b7bb4816SSepherosa Ziehau VMBUS_PCPU_PTR(sc, message_tq, cpu), 1, PI_NET, &cpu_mask, 393b7bb4816SSepherosa Ziehau "hvmsg%d", cpu); 394b7bb4816SSepherosa Ziehau TASK_INIT(VMBUS_PCPU_PTR(sc, message_task, cpu), 0, 395b7bb4816SSepherosa Ziehau vmbus_msg_task, sc); 396b7bb4816SSepherosa Ziehau } 397b7bb4816SSepherosa Ziehau 398b7bb4816SSepherosa Ziehau /* 399b7bb4816SSepherosa Ziehau * All Hyper-V ISR required resources are setup, now let's find a 400b7bb4816SSepherosa Ziehau * free IDT vector for Hyper-V ISR and set it up. 401b7bb4816SSepherosa Ziehau */ 402b7bb4816SSepherosa Ziehau sc->vmbus_idtvec = lapic_ipi_alloc(IDTVEC(vmbus_isr)); 403b7bb4816SSepherosa Ziehau if (sc->vmbus_idtvec < 0) { 404b7bb4816SSepherosa Ziehau device_printf(sc->vmbus_dev, "cannot find free IDT vector\n"); 405b7bb4816SSepherosa Ziehau return ENXIO; 406b7bb4816SSepherosa Ziehau } 407b7bb4816SSepherosa Ziehau if(bootverbose) { 408b7bb4816SSepherosa Ziehau device_printf(sc->vmbus_dev, "vmbus IDT vector %d\n", 409b7bb4816SSepherosa Ziehau sc->vmbus_idtvec); 410b7bb4816SSepherosa Ziehau } 411b7bb4816SSepherosa Ziehau return 0; 412b7bb4816SSepherosa Ziehau } 413b7bb4816SSepherosa Ziehau 414b7bb4816SSepherosa Ziehau static void 415b7bb4816SSepherosa Ziehau vmbus_intr_teardown(struct vmbus_softc *sc) 416b7bb4816SSepherosa Ziehau { 417b7bb4816SSepherosa Ziehau int cpu; 418b7bb4816SSepherosa Ziehau 419b7bb4816SSepherosa Ziehau if (sc->vmbus_idtvec >= 0) { 420b7bb4816SSepherosa Ziehau lapic_ipi_free(sc->vmbus_idtvec); 421b7bb4816SSepherosa Ziehau sc->vmbus_idtvec = -1; 422b7bb4816SSepherosa Ziehau } 423b7bb4816SSepherosa Ziehau 424b7bb4816SSepherosa Ziehau CPU_FOREACH(cpu) { 425b7bb4816SSepherosa Ziehau if (VMBUS_PCPU_GET(sc, event_tq, cpu) != NULL) { 426b7bb4816SSepherosa Ziehau taskqueue_free(VMBUS_PCPU_GET(sc, event_tq, cpu)); 427b7bb4816SSepherosa Ziehau VMBUS_PCPU_GET(sc, event_tq, cpu) = NULL; 428b7bb4816SSepherosa Ziehau } 429b7bb4816SSepherosa Ziehau if (VMBUS_PCPU_GET(sc, message_tq, cpu) != NULL) { 430b7bb4816SSepherosa Ziehau taskqueue_drain(VMBUS_PCPU_GET(sc, message_tq, cpu), 431b7bb4816SSepherosa Ziehau VMBUS_PCPU_PTR(sc, message_task, cpu)); 432b7bb4816SSepherosa Ziehau taskqueue_free(VMBUS_PCPU_GET(sc, message_tq, cpu)); 433b7bb4816SSepherosa Ziehau VMBUS_PCPU_GET(sc, message_tq, cpu) = NULL; 434b7bb4816SSepherosa Ziehau } 435b7bb4816SSepherosa Ziehau } 436b7bb4816SSepherosa Ziehau } 437b7bb4816SSepherosa Ziehau 438b7bb4816SSepherosa Ziehau static int 439b7bb4816SSepherosa Ziehau vmbus_read_ivar(device_t dev, device_t child, int index, uintptr_t *result) 440b7bb4816SSepherosa Ziehau { 441b7bb4816SSepherosa Ziehau struct hv_device *child_dev_ctx = device_get_ivars(child); 442b7bb4816SSepherosa Ziehau 443b7bb4816SSepherosa Ziehau switch (index) { 444b7bb4816SSepherosa Ziehau case HV_VMBUS_IVAR_TYPE: 445b7bb4816SSepherosa Ziehau *result = (uintptr_t)&child_dev_ctx->class_id; 446b7bb4816SSepherosa Ziehau return (0); 447b7bb4816SSepherosa Ziehau 448b7bb4816SSepherosa Ziehau case HV_VMBUS_IVAR_INSTANCE: 449b7bb4816SSepherosa Ziehau *result = (uintptr_t)&child_dev_ctx->device_id; 450b7bb4816SSepherosa Ziehau return (0); 451b7bb4816SSepherosa Ziehau 452b7bb4816SSepherosa Ziehau case HV_VMBUS_IVAR_DEVCTX: 453b7bb4816SSepherosa Ziehau *result = (uintptr_t)child_dev_ctx; 454b7bb4816SSepherosa Ziehau return (0); 455b7bb4816SSepherosa Ziehau 456b7bb4816SSepherosa Ziehau case HV_VMBUS_IVAR_NODE: 457b7bb4816SSepherosa Ziehau *result = (uintptr_t)child_dev_ctx->device; 458b7bb4816SSepherosa Ziehau return (0); 459b7bb4816SSepherosa Ziehau } 460b7bb4816SSepherosa Ziehau return (ENOENT); 461b7bb4816SSepherosa Ziehau } 462b7bb4816SSepherosa Ziehau 463b7bb4816SSepherosa Ziehau static int 464b7bb4816SSepherosa Ziehau vmbus_write_ivar(device_t dev, device_t child, int index, uintptr_t value) 465b7bb4816SSepherosa Ziehau { 466b7bb4816SSepherosa Ziehau switch (index) { 467b7bb4816SSepherosa Ziehau case HV_VMBUS_IVAR_TYPE: 468b7bb4816SSepherosa Ziehau case HV_VMBUS_IVAR_INSTANCE: 469b7bb4816SSepherosa Ziehau case HV_VMBUS_IVAR_DEVCTX: 470b7bb4816SSepherosa Ziehau case HV_VMBUS_IVAR_NODE: 471b7bb4816SSepherosa Ziehau /* read-only */ 472b7bb4816SSepherosa Ziehau return (EINVAL); 473b7bb4816SSepherosa Ziehau } 474b7bb4816SSepherosa Ziehau return (ENOENT); 475b7bb4816SSepherosa Ziehau } 476b7bb4816SSepherosa Ziehau 477b7bb4816SSepherosa Ziehau static int 478b7bb4816SSepherosa Ziehau vmbus_child_pnpinfo_str(device_t dev, device_t child, char *buf, size_t buflen) 479b7bb4816SSepherosa Ziehau { 480b7bb4816SSepherosa Ziehau struct hv_device *dev_ctx = device_get_ivars(child); 481b7bb4816SSepherosa Ziehau char guidbuf[HYPERV_GUID_STRLEN]; 482b7bb4816SSepherosa Ziehau 483b7bb4816SSepherosa Ziehau if (dev_ctx == NULL) 484b7bb4816SSepherosa Ziehau return (0); 485b7bb4816SSepherosa Ziehau 486b7bb4816SSepherosa Ziehau strlcat(buf, "classid=", buflen); 487b7bb4816SSepherosa Ziehau hyperv_guid2str(&dev_ctx->class_id, guidbuf, sizeof(guidbuf)); 488b7bb4816SSepherosa Ziehau strlcat(buf, guidbuf, buflen); 489b7bb4816SSepherosa Ziehau 490b7bb4816SSepherosa Ziehau strlcat(buf, " deviceid=", buflen); 491b7bb4816SSepherosa Ziehau hyperv_guid2str(&dev_ctx->device_id, guidbuf, sizeof(guidbuf)); 492b7bb4816SSepherosa Ziehau strlcat(buf, guidbuf, buflen); 493b7bb4816SSepherosa Ziehau 494b7bb4816SSepherosa Ziehau return (0); 495b7bb4816SSepherosa Ziehau } 496b7bb4816SSepherosa Ziehau 497b7bb4816SSepherosa Ziehau struct hv_device * 498b7bb4816SSepherosa Ziehau hv_vmbus_child_device_create(hv_guid type, hv_guid instance, 499b7bb4816SSepherosa Ziehau hv_vmbus_channel *channel) 500b7bb4816SSepherosa Ziehau { 501b7bb4816SSepherosa Ziehau hv_device *child_dev; 502b7bb4816SSepherosa Ziehau 503b7bb4816SSepherosa Ziehau /* 504b7bb4816SSepherosa Ziehau * Allocate the new child device 505b7bb4816SSepherosa Ziehau */ 506b7bb4816SSepherosa Ziehau child_dev = malloc(sizeof(hv_device), M_DEVBUF, M_WAITOK | M_ZERO); 507b7bb4816SSepherosa Ziehau 508b7bb4816SSepherosa Ziehau child_dev->channel = channel; 509b7bb4816SSepherosa Ziehau memcpy(&child_dev->class_id, &type, sizeof(hv_guid)); 510b7bb4816SSepherosa Ziehau memcpy(&child_dev->device_id, &instance, sizeof(hv_guid)); 511b7bb4816SSepherosa Ziehau 512b7bb4816SSepherosa Ziehau return (child_dev); 513b7bb4816SSepherosa Ziehau } 514b7bb4816SSepherosa Ziehau 515b7bb4816SSepherosa Ziehau int 516b7bb4816SSepherosa Ziehau hv_vmbus_child_device_register(struct hv_device *child_dev) 517b7bb4816SSepherosa Ziehau { 518b7bb4816SSepherosa Ziehau device_t child, parent; 519b7bb4816SSepherosa Ziehau 520b7bb4816SSepherosa Ziehau parent = vmbus_get_device(); 521b7bb4816SSepherosa Ziehau if (bootverbose) { 522b7bb4816SSepherosa Ziehau char name[HYPERV_GUID_STRLEN]; 523b7bb4816SSepherosa Ziehau 524b7bb4816SSepherosa Ziehau hyperv_guid2str(&child_dev->class_id, name, sizeof(name)); 525b7bb4816SSepherosa Ziehau device_printf(parent, "add device, classid: %s\n", name); 526b7bb4816SSepherosa Ziehau } 527b7bb4816SSepherosa Ziehau 528b7bb4816SSepherosa Ziehau child = device_add_child(parent, NULL, -1); 529b7bb4816SSepherosa Ziehau child_dev->device = child; 530b7bb4816SSepherosa Ziehau device_set_ivars(child, child_dev); 531b7bb4816SSepherosa Ziehau 532b7bb4816SSepherosa Ziehau return (0); 533b7bb4816SSepherosa Ziehau } 534b7bb4816SSepherosa Ziehau 535b7bb4816SSepherosa Ziehau int 536b7bb4816SSepherosa Ziehau hv_vmbus_child_device_unregister(struct hv_device *child_dev) 537b7bb4816SSepherosa Ziehau { 538b7bb4816SSepherosa Ziehau int ret = 0; 539b7bb4816SSepherosa Ziehau /* 540b7bb4816SSepherosa Ziehau * XXXKYS: Ensure that this is the opposite of 541b7bb4816SSepherosa Ziehau * device_add_child() 542b7bb4816SSepherosa Ziehau */ 543b7bb4816SSepherosa Ziehau mtx_lock(&Giant); 544b7bb4816SSepherosa Ziehau ret = device_delete_child(vmbus_get_device(), child_dev->device); 545b7bb4816SSepherosa Ziehau mtx_unlock(&Giant); 546b7bb4816SSepherosa Ziehau return(ret); 547b7bb4816SSepherosa Ziehau } 548b7bb4816SSepherosa Ziehau 549b7bb4816SSepherosa Ziehau static int 550b7bb4816SSepherosa Ziehau vmbus_probe(device_t dev) 551b7bb4816SSepherosa Ziehau { 552b7bb4816SSepherosa Ziehau char *id[] = { "VMBUS", NULL }; 553b7bb4816SSepherosa Ziehau 554b7bb4816SSepherosa Ziehau if (ACPI_ID_PROBE(device_get_parent(dev), dev, id) == NULL || 555b7bb4816SSepherosa Ziehau device_get_unit(dev) != 0 || vm_guest != VM_GUEST_HV || 556b7bb4816SSepherosa Ziehau (hyperv_features & CPUID_HV_MSR_SYNIC) == 0) 557b7bb4816SSepherosa Ziehau return (ENXIO); 558b7bb4816SSepherosa Ziehau 559b7bb4816SSepherosa Ziehau device_set_desc(dev, "Hyper-V Vmbus"); 560b7bb4816SSepherosa Ziehau 561b7bb4816SSepherosa Ziehau return (BUS_PROBE_DEFAULT); 562b7bb4816SSepherosa Ziehau } 563b7bb4816SSepherosa Ziehau 564b7bb4816SSepherosa Ziehau /** 565b7bb4816SSepherosa Ziehau * @brief Main vmbus driver initialization routine. 566b7bb4816SSepherosa Ziehau * 567b7bb4816SSepherosa Ziehau * Here, we 568b7bb4816SSepherosa Ziehau * - initialize the vmbus driver context 569b7bb4816SSepherosa Ziehau * - setup various driver entry points 570b7bb4816SSepherosa Ziehau * - invoke the vmbus hv main init routine 571b7bb4816SSepherosa Ziehau * - get the irq resource 572b7bb4816SSepherosa Ziehau * - invoke the vmbus to add the vmbus root device 573b7bb4816SSepherosa Ziehau * - setup the vmbus root device 574b7bb4816SSepherosa Ziehau * - retrieve the channel offers 575b7bb4816SSepherosa Ziehau */ 576b7bb4816SSepherosa Ziehau static int 577b7bb4816SSepherosa Ziehau vmbus_bus_init(void) 578b7bb4816SSepherosa Ziehau { 579b7bb4816SSepherosa Ziehau struct vmbus_softc *sc = vmbus_get_softc(); 580b7bb4816SSepherosa Ziehau int ret; 581b7bb4816SSepherosa Ziehau 582b7bb4816SSepherosa Ziehau if (sc->vmbus_flags & VMBUS_FLAG_ATTACHED) 583b7bb4816SSepherosa Ziehau return (0); 584b7bb4816SSepherosa Ziehau sc->vmbus_flags |= VMBUS_FLAG_ATTACHED; 585b7bb4816SSepherosa Ziehau 586b7bb4816SSepherosa Ziehau /* 587b7bb4816SSepherosa Ziehau * Allocate DMA stuffs. 588b7bb4816SSepherosa Ziehau */ 589b7bb4816SSepherosa Ziehau ret = vmbus_dma_alloc(sc); 590b7bb4816SSepherosa Ziehau if (ret != 0) 591b7bb4816SSepherosa Ziehau goto cleanup; 592b7bb4816SSepherosa Ziehau 593b7bb4816SSepherosa Ziehau /* 594b7bb4816SSepherosa Ziehau * Setup interrupt. 595b7bb4816SSepherosa Ziehau */ 596b7bb4816SSepherosa Ziehau ret = vmbus_intr_setup(sc); 597b7bb4816SSepherosa Ziehau if (ret != 0) 598b7bb4816SSepherosa Ziehau goto cleanup; 599b7bb4816SSepherosa Ziehau 600b7bb4816SSepherosa Ziehau /* 601b7bb4816SSepherosa Ziehau * Setup SynIC. 602b7bb4816SSepherosa Ziehau */ 603b7bb4816SSepherosa Ziehau if (bootverbose) 604b7bb4816SSepherosa Ziehau device_printf(sc->vmbus_dev, "smp_started = %d\n", smp_started); 605b7bb4816SSepherosa Ziehau smp_rendezvous(NULL, vmbus_synic_setup, NULL, sc); 606b7bb4816SSepherosa Ziehau sc->vmbus_flags |= VMBUS_FLAG_SYNIC; 607b7bb4816SSepherosa Ziehau 608b7bb4816SSepherosa Ziehau /* 609b7bb4816SSepherosa Ziehau * Connect to VMBus in the root partition 610b7bb4816SSepherosa Ziehau */ 611b7bb4816SSepherosa Ziehau ret = hv_vmbus_connect(); 612b7bb4816SSepherosa Ziehau 613b7bb4816SSepherosa Ziehau if (ret != 0) 614b7bb4816SSepherosa Ziehau goto cleanup; 615b7bb4816SSepherosa Ziehau 616b7bb4816SSepherosa Ziehau if (hv_vmbus_protocal_version == HV_VMBUS_VERSION_WS2008 || 617b7bb4816SSepherosa Ziehau hv_vmbus_protocal_version == HV_VMBUS_VERSION_WIN7) 618b7bb4816SSepherosa Ziehau sc->vmbus_event_proc = vmbus_event_proc_compat; 619b7bb4816SSepherosa Ziehau else 620b7bb4816SSepherosa Ziehau sc->vmbus_event_proc = vmbus_event_proc; 621b7bb4816SSepherosa Ziehau 622b7bb4816SSepherosa Ziehau hv_vmbus_request_channel_offers(); 623b7bb4816SSepherosa Ziehau 624b7bb4816SSepherosa Ziehau vmbus_scan(); 625b7bb4816SSepherosa Ziehau bus_generic_attach(sc->vmbus_dev); 626b7bb4816SSepherosa Ziehau device_printf(sc->vmbus_dev, "device scan, probe and attach done\n"); 627b7bb4816SSepherosa Ziehau 628b7bb4816SSepherosa Ziehau return (ret); 629b7bb4816SSepherosa Ziehau 630b7bb4816SSepherosa Ziehau cleanup: 631b7bb4816SSepherosa Ziehau vmbus_intr_teardown(sc); 632b7bb4816SSepherosa Ziehau vmbus_dma_free(sc); 633b7bb4816SSepherosa Ziehau 634b7bb4816SSepherosa Ziehau return (ret); 635b7bb4816SSepherosa Ziehau } 636b7bb4816SSepherosa Ziehau 637b7bb4816SSepherosa Ziehau static void 638b7bb4816SSepherosa Ziehau vmbus_event_proc_dummy(struct vmbus_softc *sc __unused, int cpu __unused) 639b7bb4816SSepherosa Ziehau { 640b7bb4816SSepherosa Ziehau } 641b7bb4816SSepherosa Ziehau 642b7bb4816SSepherosa Ziehau static int 643b7bb4816SSepherosa Ziehau vmbus_attach(device_t dev) 644b7bb4816SSepherosa Ziehau { 645b7bb4816SSepherosa Ziehau vmbus_sc = device_get_softc(dev); 646b7bb4816SSepherosa Ziehau vmbus_sc->vmbus_dev = dev; 647b7bb4816SSepherosa Ziehau vmbus_sc->vmbus_idtvec = -1; 648b7bb4816SSepherosa Ziehau 649b7bb4816SSepherosa Ziehau /* 650b7bb4816SSepherosa Ziehau * Event processing logic will be configured: 651b7bb4816SSepherosa Ziehau * - After the vmbus protocol version negotiation. 652b7bb4816SSepherosa Ziehau * - Before we request channel offers. 653b7bb4816SSepherosa Ziehau */ 654b7bb4816SSepherosa Ziehau vmbus_sc->vmbus_event_proc = vmbus_event_proc_dummy; 655b7bb4816SSepherosa Ziehau 656b7bb4816SSepherosa Ziehau #ifndef EARLY_AP_STARTUP 657b7bb4816SSepherosa Ziehau /* 658b7bb4816SSepherosa Ziehau * If the system has already booted and thread 659b7bb4816SSepherosa Ziehau * scheduling is possible indicated by the global 660b7bb4816SSepherosa Ziehau * cold set to zero, we just call the driver 661b7bb4816SSepherosa Ziehau * initialization directly. 662b7bb4816SSepherosa Ziehau */ 663b7bb4816SSepherosa Ziehau if (!cold) 664b7bb4816SSepherosa Ziehau #endif 665b7bb4816SSepherosa Ziehau vmbus_bus_init(); 666b7bb4816SSepherosa Ziehau 667b7bb4816SSepherosa Ziehau bus_generic_probe(dev); 668b7bb4816SSepherosa Ziehau return (0); 669b7bb4816SSepherosa Ziehau } 670b7bb4816SSepherosa Ziehau 671b7bb4816SSepherosa Ziehau static void 672b7bb4816SSepherosa Ziehau vmbus_sysinit(void *arg __unused) 673b7bb4816SSepherosa Ziehau { 674b7bb4816SSepherosa Ziehau if (vm_guest != VM_GUEST_HV || vmbus_get_softc() == NULL) 675b7bb4816SSepherosa Ziehau return; 676b7bb4816SSepherosa Ziehau 677b7bb4816SSepherosa Ziehau #ifndef EARLY_AP_STARTUP 678b7bb4816SSepherosa Ziehau /* 679b7bb4816SSepherosa Ziehau * If the system has already booted and thread 680b7bb4816SSepherosa Ziehau * scheduling is possible, as indicated by the 681b7bb4816SSepherosa Ziehau * global cold set to zero, we just call the driver 682b7bb4816SSepherosa Ziehau * initialization directly. 683b7bb4816SSepherosa Ziehau */ 684b7bb4816SSepherosa Ziehau if (!cold) 685b7bb4816SSepherosa Ziehau #endif 686b7bb4816SSepherosa Ziehau vmbus_bus_init(); 687b7bb4816SSepherosa Ziehau } 688b7bb4816SSepherosa Ziehau 689b7bb4816SSepherosa Ziehau static int 690b7bb4816SSepherosa Ziehau vmbus_detach(device_t dev) 691b7bb4816SSepherosa Ziehau { 692b7bb4816SSepherosa Ziehau struct vmbus_softc *sc = device_get_softc(dev); 693b7bb4816SSepherosa Ziehau 694b7bb4816SSepherosa Ziehau hv_vmbus_release_unattached_channels(); 695b7bb4816SSepherosa Ziehau hv_vmbus_disconnect(); 696b7bb4816SSepherosa Ziehau 697b7bb4816SSepherosa Ziehau if (sc->vmbus_flags & VMBUS_FLAG_SYNIC) { 698b7bb4816SSepherosa Ziehau sc->vmbus_flags &= ~VMBUS_FLAG_SYNIC; 699b7bb4816SSepherosa Ziehau smp_rendezvous(NULL, vmbus_synic_teardown, NULL, NULL); 700b7bb4816SSepherosa Ziehau } 701b7bb4816SSepherosa Ziehau 702b7bb4816SSepherosa Ziehau vmbus_intr_teardown(sc); 703b7bb4816SSepherosa Ziehau vmbus_dma_free(sc); 704b7bb4816SSepherosa Ziehau 705b7bb4816SSepherosa Ziehau return (0); 706b7bb4816SSepherosa Ziehau } 707b7bb4816SSepherosa Ziehau 708b7bb4816SSepherosa Ziehau static device_method_t vmbus_methods[] = { 709b7bb4816SSepherosa Ziehau /* Device interface */ 710b7bb4816SSepherosa Ziehau DEVMETHOD(device_probe, vmbus_probe), 711b7bb4816SSepherosa Ziehau DEVMETHOD(device_attach, vmbus_attach), 712b7bb4816SSepherosa Ziehau DEVMETHOD(device_detach, vmbus_detach), 713b7bb4816SSepherosa Ziehau DEVMETHOD(device_shutdown, bus_generic_shutdown), 714b7bb4816SSepherosa Ziehau DEVMETHOD(device_suspend, bus_generic_suspend), 715b7bb4816SSepherosa Ziehau DEVMETHOD(device_resume, bus_generic_resume), 716b7bb4816SSepherosa Ziehau 717b7bb4816SSepherosa Ziehau /* Bus interface */ 718b7bb4816SSepherosa Ziehau DEVMETHOD(bus_add_child, bus_generic_add_child), 719b7bb4816SSepherosa Ziehau DEVMETHOD(bus_print_child, bus_generic_print_child), 720b7bb4816SSepherosa Ziehau DEVMETHOD(bus_read_ivar, vmbus_read_ivar), 721b7bb4816SSepherosa Ziehau DEVMETHOD(bus_write_ivar, vmbus_write_ivar), 722b7bb4816SSepherosa Ziehau DEVMETHOD(bus_child_pnpinfo_str, vmbus_child_pnpinfo_str), 723b7bb4816SSepherosa Ziehau 724b7bb4816SSepherosa Ziehau DEVMETHOD_END 725b7bb4816SSepherosa Ziehau }; 726b7bb4816SSepherosa Ziehau 727b7bb4816SSepherosa Ziehau static driver_t vmbus_driver = { 728b7bb4816SSepherosa Ziehau "vmbus", 729b7bb4816SSepherosa Ziehau vmbus_methods, 730b7bb4816SSepherosa Ziehau sizeof(struct vmbus_softc) 731b7bb4816SSepherosa Ziehau }; 732b7bb4816SSepherosa Ziehau 733b7bb4816SSepherosa Ziehau static devclass_t vmbus_devclass; 734b7bb4816SSepherosa Ziehau 735b7bb4816SSepherosa Ziehau DRIVER_MODULE(vmbus, acpi, vmbus_driver, vmbus_devclass, NULL, NULL); 736b7bb4816SSepherosa Ziehau MODULE_DEPEND(vmbus, acpi, 1, 1, 1); 737b7bb4816SSepherosa Ziehau MODULE_VERSION(vmbus, 1); 738b7bb4816SSepherosa Ziehau 739b7bb4816SSepherosa Ziehau #ifndef EARLY_AP_STARTUP 740b7bb4816SSepherosa Ziehau /* 741b7bb4816SSepherosa Ziehau * NOTE: 742b7bb4816SSepherosa Ziehau * We have to start as the last step of SI_SUB_SMP, i.e. after SMP is 743b7bb4816SSepherosa Ziehau * initialized. 744b7bb4816SSepherosa Ziehau */ 745b7bb4816SSepherosa Ziehau SYSINIT(vmbus_initialize, SI_SUB_SMP, SI_ORDER_ANY, vmbus_sysinit, NULL); 746b7bb4816SSepherosa Ziehau #endif 747