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