2 * Copyright (c) 2009-2012,2016 Microsoft Corp.
3 * Copyright (c) 2012 NetApp Inc.
4 * Copyright (c) 2012 Citrix Inc.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice unmodified, this list of conditions, and the following
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include <sys/param.h>
33 #include <sys/kernel.h>
34 #include <sys/malloc.h>
35 #include <sys/module.h>
37 #include <sys/systimer.h>
38 #include <sys/thread.h>
39 #include <sys/thread2.h>
41 #include <machine/intr_machdep.h>
42 #include <machine/smp.h>
44 #include <dev/virtual/hyperv/hyperv_busdma.h>
45 #include <dev/virtual/hyperv/hyperv_machdep.h>
46 #include <dev/virtual/hyperv/hyperv_reg.h>
47 #include <dev/virtual/hyperv/hyperv_var.h>
48 #include <dev/virtual/hyperv/vmbus/vmbus_reg.h>
49 #include <dev/virtual/hyperv/vmbus/vmbus_var.h>
55 #define MSR_HV_STIMER0_CFG_SINT \
56 ((((uint64_t)VMBUS_SINT_TIMER) << MSR_HV_STIMER_CFG_SINT_SHIFT) & \
57 MSR_HV_STIMER_CFG_SINT_MASK)
60 * Additionally required feature:
61 * - SynIC is needed for interrupt generation.
63 #define CPUID_HV_TIMER_MASK (CPUID_HV_MSR_SYNIC | \
64 CPUID_HV_MSR_SYNTIMER)
67 * NOTE: DO NOT CHANGE THIS.
69 #define VMBUS_SINT_MESSAGE 2
72 * - DO NOT set it to the same value as VMBUS_SINT_MESSAGE.
73 * - DO NOT set it to 0.
75 #define VMBUS_SINT_TIMER 4
78 * NOTE: DO NOT CHANGE THESE
80 #define VMBUS_CONNID_MESSAGE 1
81 #define VMBUS_CONNID_EVENT 2
84 struct hypercall_postmsg_in *mh_inprm;
85 struct hypercall_postmsg_in mh_inprm_save;
86 struct hyperv_dma mh_inprm_dma;
88 struct vmbus_message *mh_resp;
89 struct vmbus_message mh_resp0;
92 struct vmbus_msghc_ctx {
93 struct vmbus_msghc *mhc_free;
94 struct lwkt_token mhc_free_token;
97 struct vmbus_msghc *mhc_active;
98 struct lwkt_token mhc_active_token;
101 #define VMBUS_MSGHC_CTXF_DESTROY 0x0001
103 static int vmbus_probe(device_t);
104 static int vmbus_attach(device_t);
105 static int vmbus_detach(device_t);
106 static void vmbus_intr(void *);
107 static void vmbus_timer_intr_reload(struct cputimer_intr *,
109 static void vmbus_timer_intr_pcpuhand(
110 struct cputimer_intr *);
111 static void vmbus_timer_intr_restart(
112 struct cputimer_intr *);
114 static int vmbus_dma_alloc(struct vmbus_softc *);
115 static void vmbus_dma_free(struct vmbus_softc *);
116 static int vmbus_intr_setup(struct vmbus_softc *);
117 static void vmbus_intr_teardown(struct vmbus_softc *);
118 static void vmbus_synic_setup(void *);
119 static void vmbus_synic_teardown(void *);
120 static void vmbus_timer_stop(void *);
121 static void vmbus_timer_config(void *);
122 static int vmbus_init(struct vmbus_softc *);
123 static int vmbus_init_contact(struct vmbus_softc *,
125 static void vmbus_timer_restart(void *);
126 static void vmbus_timer_msgintr(struct vmbus_pcpu_data *);
128 static void vmbus_chan_msgproc(struct vmbus_softc *,
129 const struct vmbus_message *);
131 static struct vmbus_msghc_ctx *vmbus_msghc_ctx_create(bus_dma_tag_t);
132 static void vmbus_msghc_ctx_destroy(
133 struct vmbus_msghc_ctx *);
134 static void vmbus_msghc_ctx_free(struct vmbus_msghc_ctx *);
135 static struct vmbus_msghc *vmbus_msghc_alloc(bus_dma_tag_t);
136 static void vmbus_msghc_free(struct vmbus_msghc *);
137 static struct vmbus_msghc *vmbus_msghc_get1(struct vmbus_msghc_ctx *,
140 static device_method_t vmbus_methods[] = {
141 /* Device interface */
142 DEVMETHOD(device_probe, vmbus_probe),
143 DEVMETHOD(device_attach, vmbus_attach),
144 DEVMETHOD(device_detach, vmbus_detach),
145 DEVMETHOD(device_shutdown, bus_generic_shutdown),
146 DEVMETHOD(device_suspend, bus_generic_suspend),
147 DEVMETHOD(device_resume, bus_generic_resume),
152 static driver_t vmbus_driver = {
155 sizeof(struct vmbus_softc)
158 static devclass_t vmbus_devclass;
160 DRIVER_MODULE(vmbus, acpi, vmbus_driver, vmbus_devclass, NULL, NULL);
161 MODULE_DEPEND(vmbus, acpi, 1, 1, 1);
162 MODULE_VERSION(vmbus, 1);
164 static struct cputimer_intr vmbus_cputimer_intr = {
165 .freq = HYPERV_TIMER_FREQ,
166 .reload = vmbus_timer_intr_reload,
167 .enable = cputimer_intr_default_enable,
168 .config = cputimer_intr_default_config,
169 .restart = vmbus_timer_intr_restart,
170 .pmfixup = cputimer_intr_default_pmfixup,
171 .initclock = cputimer_intr_default_initclock,
172 .pcpuhand = vmbus_timer_intr_pcpuhand,
173 .next = SLIST_ENTRY_INITIALIZER,
175 .type = CPUTIMER_INTR_VMM,
176 .prio = CPUTIMER_INTR_PRIO_VMM,
177 .caps = CPUTIMER_INTR_CAP_PS,
181 static const uint32_t vmbus_version[] = {
182 VMBUS_VERSION_WIN8_1,
188 static int vmbus_timer_intr_enable = 1;
189 TUNABLE_INT("hw.vmbus.timer_intr.enable", &vmbus_timer_intr_enable);
192 vmbus_probe(device_t dev)
194 char *id[] = { "VMBUS", NULL };
196 if (ACPI_ID_PROBE(device_get_parent(dev), dev, id) == NULL ||
197 device_get_unit(dev) != 0 || vmm_guest != VMM_GUEST_HYPERV ||
198 (hyperv_features & CPUID_HV_MSR_SYNIC) == 0)
201 device_set_desc(dev, "Hyper-V vmbus");
207 vmbus_attach(device_t dev)
209 struct vmbus_softc *sc = device_get_softc(dev);
210 int error, cpu, use_timer;
216 for (cpu = 0; cpu < ncpus; ++cpu) {
217 struct vmbus_pcpu_data *psc = VMBUS_PCPU(sc, cpu);
221 psc->timer_last = UINT64_MAX;
225 * Should we use interrupt timer?
228 if (device_get_unit(dev) == 0 &&
229 (hyperv_features & CPUID_HV_TIMER_MASK) == CPUID_HV_TIMER_MASK &&
234 * Create context for "post message" Hypercalls
236 sc->vmbus_msg_hc = vmbus_msghc_ctx_create(
237 bus_get_dma_tag(sc->vmbus_dev));
238 if (sc->vmbus_msg_hc == NULL)
242 * Allocate DMA stuffs.
244 error = vmbus_dma_alloc(sc);
251 error = vmbus_intr_setup(sc);
257 * Make sure that interrupt timer is stopped.
259 lwkt_cpusync_simple(smp_active_mask, vmbus_timer_stop, sc);
265 lwkt_cpusync_simple(smp_active_mask, vmbus_synic_setup, sc);
266 sc->vmbus_flags |= VMBUS_FLAG_SYNIC;
271 error = vmbus_init(sc);
277 * Configure and register vmbus interrupt timer.
279 lwkt_cpusync_simple(smp_active_mask, vmbus_timer_config, sc);
280 vmbus_cputimer_intr.priv = sc;
281 cputimer_intr_register(&vmbus_cputimer_intr);
282 if (vmbus_timer_intr_enable)
283 cputimer_intr_select(&vmbus_cputimer_intr, 0);
293 vmbus_detach(device_t dev)
295 struct vmbus_softc *sc = device_get_softc(dev);
297 /* TODO: uninitialize vmbus. */
298 /* TODO: stop and deregister timer */
300 if (sc->vmbus_flags & VMBUS_FLAG_SYNIC)
301 lwkt_cpusync_simple(smp_active_mask, vmbus_synic_teardown, sc);
302 vmbus_intr_teardown(sc);
305 if (sc->vmbus_msg_hc != NULL) {
306 vmbus_msghc_ctx_destroy(sc->vmbus_msg_hc);
307 sc->vmbus_msg_hc = NULL;
313 vmbus_msg_reset(volatile struct vmbus_message *msg)
315 msg->msg_type = HYPERV_MSGTYPE_NONE;
317 * Make sure that the write to msg_type (i.e. set to
318 * HYPERV_MSGTYPE_NONE) happens before we read the
319 * msg_flags and send EOM to the hypervisor.
322 if (msg->msg_flags & VMBUS_MSGFLAG_PENDING) {
324 * Ask the hypervisor to rescan message queue,
325 * and deliver new message if any.
327 wrmsr(MSR_HV_EOM, 0);
332 vmbus_intr(void *xpsc)
334 struct vmbus_pcpu_data *psc = xpsc;
335 volatile struct vmbus_message *msg;
337 msg = psc->message + VMBUS_SINT_MESSAGE;
338 while (__predict_false(msg->msg_type != HYPERV_MSGTYPE_NONE)) {
339 if (msg->msg_type == HYPERV_MSGTYPE_CHANNEL) {
340 /* Channel message */
341 vmbus_chan_msgproc(psc->sc,
342 __DEVOLATILE(const struct vmbus_message *, msg));
344 vmbus_msg_reset(msg);
349 vmbus_timer_oneshot(struct vmbus_pcpu_data *psc, uint64_t current)
351 psc->timer_last = current;
352 wrmsr(MSR_HV_STIMER0_COUNT, current);
356 vmbus_timer_intr_reload(struct cputimer_intr *cti, sysclock_t reload)
358 struct globaldata *gd = mycpu;
359 struct vmbus_softc *sc = cti->priv;
360 struct vmbus_pcpu_data *psc = VMBUS_PCPU(sc, gd->gd_cpuid);
363 if ((ssysclock_t)reload < 0) /* neg value */
365 reload = muldivu64(reload, cti->freq, sys_cputimer->freq);
366 current = hyperv_tc64() + reload;
368 if (gd->gd_timer_running) {
369 if (current < psc->timer_last)
370 vmbus_timer_oneshot(psc, current);
372 gd->gd_timer_running = 1;
373 vmbus_timer_oneshot(psc, current);
378 vmbus_timer_intr_pcpuhand(struct cputimer_intr *cti)
380 struct vmbus_softc *sc = cti->priv;
381 struct vmbus_pcpu_data *psc = VMBUS_PCPU(sc, mycpuid);
383 vmbus_timer_msgintr(psc);
387 vmbus_timer_intr_restart(struct cputimer_intr *cti)
389 lwkt_send_ipiq_mask(smp_active_mask, vmbus_timer_restart, cti->priv);
392 static struct vmbus_msghc *
393 vmbus_msghc_alloc(bus_dma_tag_t parent_dtag)
395 struct vmbus_msghc *mh;
397 mh = kmalloc(sizeof(*mh), M_DEVBUF, M_WAITOK | M_ZERO);
399 mh->mh_inprm = hyperv_dmamem_alloc(parent_dtag,
400 HYPERCALL_POSTMSGIN_ALIGN, 0, HYPERCALL_POSTMSGIN_SIZE,
401 &mh->mh_inprm_dma, BUS_DMA_WAITOK);
402 if (mh->mh_inprm == NULL) {
410 vmbus_msghc_free(struct vmbus_msghc *mh)
412 hyperv_dmamem_free(&mh->mh_inprm_dma, mh->mh_inprm);
417 vmbus_msghc_ctx_free(struct vmbus_msghc_ctx *mhc)
419 KASSERT(mhc->mhc_active == NULL, ("still have active msg hypercall"));
420 KASSERT(mhc->mhc_free == NULL, ("still have hypercall msg"));
422 lwkt_token_uninit(&mhc->mhc_free_token);
423 lwkt_token_uninit(&mhc->mhc_active_token);
424 kfree(mhc, M_DEVBUF);
427 static struct vmbus_msghc_ctx *
428 vmbus_msghc_ctx_create(bus_dma_tag_t parent_dtag)
430 struct vmbus_msghc_ctx *mhc;
432 mhc = kmalloc(sizeof(*mhc), M_DEVBUF, M_WAITOK | M_ZERO);
433 lwkt_token_init(&mhc->mhc_free_token, "msghcf");
434 lwkt_token_init(&mhc->mhc_active_token, "msghca");
436 mhc->mhc_free = vmbus_msghc_alloc(parent_dtag);
437 if (mhc->mhc_free == NULL) {
438 vmbus_msghc_ctx_free(mhc);
444 static struct vmbus_msghc *
445 vmbus_msghc_get1(struct vmbus_msghc_ctx *mhc, uint32_t dtor_flag)
447 struct vmbus_msghc *mh;
449 lwkt_gettoken(&mhc->mhc_free_token);
451 while ((mhc->mhc_flags & dtor_flag) == 0 && mhc->mhc_free == NULL)
452 tsleep(&mhc->mhc_free, 0, "gmsghc", 0);
453 if (mhc->mhc_flags & dtor_flag) {
454 /* Being destroyed */
458 KASSERT(mh != NULL, ("no free hypercall msg"));
459 KASSERT(mh->mh_resp == NULL,
460 ("hypercall msg has pending response"));
461 mhc->mhc_free = NULL;
464 lwkt_reltoken(&mhc->mhc_free_token);
470 vmbus_msghc_get(struct vmbus_softc *sc, size_t dsize)
472 struct hypercall_postmsg_in *inprm;
473 struct vmbus_msghc *mh;
475 if (dsize > HYPERCALL_POSTMSGIN_DSIZE_MAX)
478 mh = vmbus_msghc_get1(sc->vmbus_msg_hc, VMBUS_MSGHC_CTXF_DESTROY);
482 inprm = mh->mh_inprm;
483 memset(inprm, 0, HYPERCALL_POSTMSGIN_SIZE);
484 inprm->hc_connid = VMBUS_CONNID_MESSAGE;
485 inprm->hc_msgtype = HYPERV_MSGTYPE_CHANNEL;
486 inprm->hc_dsize = dsize;
492 vmbus_msghc_put(struct vmbus_softc *sc, struct vmbus_msghc *mh)
494 struct vmbus_msghc_ctx *mhc = sc->vmbus_msg_hc;
496 KASSERT(mhc->mhc_active == NULL, ("msg hypercall is active"));
499 lwkt_gettoken(&mhc->mhc_free_token);
500 KASSERT(mhc->mhc_free == NULL, ("has free hypercall msg"));
502 lwkt_reltoken(&mhc->mhc_free_token);
503 wakeup(&mhc->mhc_free);
507 vmbus_msghc_dataptr(struct vmbus_msghc *mh)
509 return mh->mh_inprm->hc_data;
513 vmbus_msghc_ctx_destroy(struct vmbus_msghc_ctx *mhc)
515 struct vmbus_msghc *mh;
517 lwkt_gettoken(&mhc->mhc_free_token);
518 mhc->mhc_flags |= VMBUS_MSGHC_CTXF_DESTROY;
519 lwkt_reltoken(&mhc->mhc_free_token);
520 wakeup(&mhc->mhc_free);
522 mh = vmbus_msghc_get1(mhc, 0);
524 panic("can't get msghc");
526 vmbus_msghc_free(mh);
527 vmbus_msghc_ctx_free(mhc);
531 vmbus_msghc_exec_noresult(struct vmbus_msghc *mh)
533 int i, wait_ticks = 1;
536 * Save the input parameter so that we could restore the input
537 * parameter if the Hypercall failed.
540 * Is this really necessary?! i.e. Will the Hypercall ever
541 * overwrite the input parameter?
543 memcpy(&mh->mh_inprm_save, mh->mh_inprm, HYPERCALL_POSTMSGIN_SIZE);
546 * In order to cope with transient failures, e.g. insufficient
547 * resources on host side, we retry the post message Hypercall
548 * several times. 20 retries seem sufficient.
550 #define HC_RETRY_MAX 20
552 for (i = 0; i < HC_RETRY_MAX; ++i) {
555 status = hypercall_post_message(mh->mh_inprm_dma.hv_paddr);
556 if (status == HYPERCALL_STATUS_SUCCESS)
559 tsleep(&status, 0, "hcpmsg", wait_ticks);
563 /* Restore input parameter and try again */
564 memcpy(mh->mh_inprm, &mh->mh_inprm_save,
565 HYPERCALL_POSTMSGIN_SIZE);
574 vmbus_msghc_exec(struct vmbus_softc *sc, struct vmbus_msghc *mh)
576 struct vmbus_msghc_ctx *mhc = sc->vmbus_msg_hc;
579 KASSERT(mh->mh_resp == NULL, ("hypercall msg has pending response"));
581 lwkt_gettoken(&mhc->mhc_active_token);
582 KASSERT(mhc->mhc_active == NULL, ("pending active msg hypercall"));
583 mhc->mhc_active = mh;
584 lwkt_reltoken(&mhc->mhc_active_token);
586 error = vmbus_msghc_exec_noresult(mh);
588 lwkt_gettoken(&mhc->mhc_active_token);
589 KASSERT(mhc->mhc_active == mh, ("msghc mismatch"));
590 mhc->mhc_active = NULL;
591 lwkt_reltoken(&mhc->mhc_active_token);
596 const struct vmbus_message *
597 vmbus_msghc_wait_result(struct vmbus_softc *sc, struct vmbus_msghc *mh)
599 struct vmbus_msghc_ctx *mhc = sc->vmbus_msg_hc;
601 lwkt_gettoken(&mhc->mhc_active_token);
603 KASSERT(mhc->mhc_active == mh, ("msghc mismatch"));
604 while (mh->mh_resp == NULL)
605 tsleep(&mhc->mhc_active, 0, "wmsghc", 0);
606 mhc->mhc_active = NULL;
608 lwkt_reltoken(&mhc->mhc_active_token);
614 vmbus_msghc_wakeup(struct vmbus_softc *sc, const struct vmbus_message *msg)
616 struct vmbus_msghc_ctx *mhc = sc->vmbus_msg_hc;
617 struct vmbus_msghc *mh;
619 lwkt_gettoken(&mhc->mhc_active_token);
621 mh = mhc->mhc_active;
622 KASSERT(mh != NULL, ("no pending msg hypercall"));
623 memcpy(&mh->mh_resp0, msg, sizeof(mh->mh_resp0));
624 mh->mh_resp = &mh->mh_resp0;
626 lwkt_reltoken(&mhc->mhc_active_token);
627 wakeup(&mhc->mhc_active);
631 vmbus_dma_alloc(struct vmbus_softc *sc)
633 bus_dma_tag_t parent_dtag;
637 parent_dtag = bus_get_dma_tag(sc->vmbus_dev);
638 for (cpu = 0; cpu < ncpus; ++cpu) {
639 struct vmbus_pcpu_data *psc = VMBUS_PCPU(sc, cpu);
642 * Per-cpu messages and event flags.
644 psc->message = hyperv_dmamem_alloc(parent_dtag,
645 PAGE_SIZE, 0, PAGE_SIZE, &psc->message_dma,
646 BUS_DMA_WAITOK | BUS_DMA_ZERO);
647 if (psc->message == NULL)
650 psc->event_flags = hyperv_dmamem_alloc(parent_dtag,
651 PAGE_SIZE, 0, PAGE_SIZE, &psc->event_flags_dma,
652 BUS_DMA_WAITOK | BUS_DMA_ZERO);
653 if (psc->event_flags == NULL)
657 evtflags = hyperv_dmamem_alloc(parent_dtag, PAGE_SIZE, 0,
658 PAGE_SIZE, &sc->vmbus_evtflags_dma, BUS_DMA_WAITOK | BUS_DMA_ZERO);
659 if (evtflags == NULL)
661 sc->vmbus_rx_evtflags = (u_long *)evtflags;
662 sc->vmbus_tx_evtflags = (u_long *)(evtflags + (PAGE_SIZE / 2));
663 sc->vmbus_evtflags = evtflags;
665 sc->vmbus_mnf1 = hyperv_dmamem_alloc(parent_dtag, PAGE_SIZE, 0,
666 PAGE_SIZE, &sc->vmbus_mnf1_dma, BUS_DMA_WAITOK | BUS_DMA_ZERO);
667 if (sc->vmbus_mnf1 == NULL)
670 sc->vmbus_mnf2 = hyperv_dmamem_alloc(parent_dtag, PAGE_SIZE, 0,
671 PAGE_SIZE, &sc->vmbus_mnf2_dma, BUS_DMA_WAITOK | BUS_DMA_ZERO);
672 if (sc->vmbus_mnf2 == NULL)
679 vmbus_dma_free(struct vmbus_softc *sc)
683 if (sc->vmbus_evtflags != NULL) {
684 hyperv_dmamem_free(&sc->vmbus_evtflags_dma, sc->vmbus_evtflags);
685 sc->vmbus_evtflags = NULL;
686 sc->vmbus_rx_evtflags = NULL;
687 sc->vmbus_tx_evtflags = NULL;
689 if (sc->vmbus_mnf1 != NULL) {
690 hyperv_dmamem_free(&sc->vmbus_mnf1_dma, sc->vmbus_mnf1);
691 sc->vmbus_mnf1 = NULL;
693 if (sc->vmbus_mnf2 != NULL) {
694 hyperv_dmamem_free(&sc->vmbus_mnf2_dma, sc->vmbus_mnf2);
695 sc->vmbus_mnf2 = NULL;
698 for (cpu = 0; cpu < ncpus; ++cpu) {
699 struct vmbus_pcpu_data *psc = VMBUS_PCPU(sc, cpu);
701 if (psc->message != NULL) {
702 hyperv_dmamem_free(&psc->message_dma, psc->message);
705 if (psc->event_flags != NULL) {
706 hyperv_dmamem_free(&psc->event_flags_dma,
708 psc->event_flags = NULL;
714 vmbus_intr_setup(struct vmbus_softc *sc)
716 device_t dev = sc->vmbus_dev;
717 device_t bus = device_get_parent(device_get_parent(dev));
721 for (cpu = 0; cpu < ncpus; ++cpu) {
722 struct vmbus_pcpu_data *psc = VMBUS_PCPU(sc, cpu);
727 error = PCIB_ALLOC_MSIX(bus, dev, &psc->intr_irq, cpu);
729 device_printf(dev, "alloc vector on cpu%d failed: %d\n",
733 psc->intr_rid = ++rid;
735 psc->intr_res = BUS_ALLOC_RESOURCE(bus, dev, SYS_RES_IRQ,
736 &psc->intr_rid, psc->intr_irq, psc->intr_irq, 1,
738 if (psc->intr_res == NULL) {
739 device_printf(dev, "alloc irq on cpu%d failed: %d\n",
744 error = PCIB_MAP_MSI(bus, dev, rman_get_start(psc->intr_res),
745 &msi_addr, &msi_data, cpu);
747 device_printf(dev, "map irq on cpu%d failed: %d\n",
751 psc->intr_vec = hyperv_msi2vector(msi_addr, msi_data);
754 device_printf(dev, "vector %d irq %d on cpu%d\n",
755 psc->intr_vec, psc->intr_irq, cpu);
758 ksnprintf(psc->intr_desc, sizeof(psc->intr_desc), "%s cpu%d",
759 device_get_nameunit(dev), cpu);
760 error = bus_setup_intr_descr(dev, psc->intr_res, INTR_MPSAFE,
761 vmbus_intr, psc, &psc->intr_hand, NULL, psc->intr_desc);
763 device_printf(dev, "setup intr on cpu%d failed: %d\n",
772 vmbus_intr_teardown(struct vmbus_softc *sc)
774 device_t dev = sc->vmbus_dev;
775 device_t bus = device_get_parent(device_get_parent(dev));
778 for (cpu = 0; cpu < ncpus; ++cpu) {
779 struct vmbus_pcpu_data *psc = VMBUS_PCPU(sc, cpu);
781 if (psc->intr_hand != NULL) {
782 bus_teardown_intr(dev, psc->intr_res, psc->intr_hand);
783 psc->intr_hand = NULL;
786 if (psc->intr_res != NULL) {
787 BUS_RELEASE_RESOURCE(bus, dev, SYS_RES_IRQ,
788 psc->intr_rid, psc->intr_res);
789 psc->intr_res = NULL;
792 if (psc->intr_rid != 0) {
793 PCIB_RELEASE_MSIX(bus, dev, psc->intr_irq, psc->cpuid);
800 vmbus_synic_setup(void *xsc)
802 struct vmbus_softc *sc = xsc;
803 struct vmbus_pcpu_data *psc = VMBUS_PCPU(sc, mycpuid);
807 if (hyperv_features & CPUID_HV_MSR_VP_INDEX) {
809 * Save virtual processor id.
811 psc->vcpuid = rdmsr(MSR_HV_VP_INDEX);
815 * Virtual processoor id is only used by a pretty broken
816 * channel selection code from storvsc. It's nothing
817 * critical even if CPUID_HV_MSR_VP_INDEX is not set; keep
820 psc->vcpuid = mycpuid;
824 * Setup the SynIC message.
826 orig = rdmsr(MSR_HV_SIMP);
827 val = MSR_HV_SIMP_ENABLE | (orig & MSR_HV_SIMP_RSVD_MASK) |
828 ((psc->message_dma.hv_paddr >> PAGE_SHIFT) << MSR_HV_SIMP_PGSHIFT);
829 wrmsr(MSR_HV_SIMP, val);
832 * Setup the SynIC event flags.
834 orig = rdmsr(MSR_HV_SIEFP);
835 val = MSR_HV_SIEFP_ENABLE | (orig & MSR_HV_SIEFP_RSVD_MASK) |
836 ((psc->event_flags_dma.hv_paddr >> PAGE_SHIFT) <<
837 MSR_HV_SIEFP_PGSHIFT);
838 wrmsr(MSR_HV_SIEFP, val);
842 * Configure and unmask SINT for message and event flags.
844 sint = MSR_HV_SINT0 + VMBUS_SINT_MESSAGE;
846 val = psc->intr_vec | /* MSR_HV_SINT_AUTOEOI | notyet */
847 (orig & MSR_HV_SINT_RSVD_MASK);
851 * Configure and unmask SINT for timer.
853 sint = MSR_HV_SINT0 + VMBUS_SINT_TIMER;
855 val = XTIMER_OFFSET | /* MSR_HV_SINT_AUTOEOI | notyet */
856 (orig & MSR_HV_SINT_RSVD_MASK);
860 * All done; enable SynIC.
862 orig = rdmsr(MSR_HV_SCONTROL);
863 val = MSR_HV_SCTRL_ENABLE | (orig & MSR_HV_SCTRL_RSVD_MASK);
864 wrmsr(MSR_HV_SCONTROL, val);
868 vmbus_timer_stop(void *arg __unused)
873 /* Stop counting, and this also implies disabling STIMER0 */
874 wrmsr(MSR_HV_STIMER0_COUNT, 0);
876 val = rdmsr(MSR_HV_STIMER0_CONFIG);
877 if ((val & MSR_HV_STIMER_CFG_ENABLE) == 0)
884 vmbus_timer_config(void *arg __unused)
887 * Make sure that STIMER0 is really disabled before writing
890 * "Writing to the configuration register of a timer that
891 * is already enabled may result in undefined behaviour."
893 vmbus_timer_stop(arg);
894 wrmsr(MSR_HV_STIMER0_CONFIG,
895 MSR_HV_STIMER_CFG_AUTOEN | MSR_HV_STIMER0_CFG_SINT);
899 vmbus_timer_msgintr(struct vmbus_pcpu_data *psc)
901 volatile struct vmbus_message *msg;
903 msg = psc->message + VMBUS_SINT_TIMER;
904 if (msg->msg_type == HYPERV_MSGTYPE_TIMER_EXPIRED)
905 vmbus_msg_reset(msg);
909 vmbus_timer_restart(void *xsc)
911 struct vmbus_softc *sc = xsc;
912 struct vmbus_pcpu_data *psc = VMBUS_PCPU(sc, mycpuid);
915 vmbus_timer_msgintr(psc);
916 vmbus_timer_oneshot(psc, hyperv_tc64() + 1);
921 vmbus_synic_teardown(void *arg __unused)
929 orig = rdmsr(MSR_HV_SCONTROL);
930 wrmsr(MSR_HV_SCONTROL, (orig & MSR_HV_SCTRL_RSVD_MASK));
933 * Mask message and event flags SINT.
935 sint = MSR_HV_SINT0 + VMBUS_SINT_MESSAGE;
937 wrmsr(sint, orig | MSR_HV_SINT_MASKED);
942 sint = MSR_HV_SINT0 + VMBUS_SINT_TIMER;
944 wrmsr(sint, orig | MSR_HV_SINT_MASKED);
947 * Teardown SynIC message.
949 orig = rdmsr(MSR_HV_SIMP);
950 wrmsr(MSR_HV_SIMP, (orig & MSR_HV_SIMP_RSVD_MASK));
953 * Teardown SynIC event flags.
955 orig = rdmsr(MSR_HV_SIEFP);
956 wrmsr(MSR_HV_SIEFP, (orig & MSR_HV_SIEFP_RSVD_MASK));
960 vmbus_init_contact(struct vmbus_softc *sc, uint32_t version)
962 struct vmbus_chanmsg_init_contact *req;
963 const struct vmbus_chanmsg_version_resp *resp;
964 const struct vmbus_message *msg;
965 struct vmbus_msghc *mh;
968 mh = vmbus_msghc_get(sc, sizeof(*req));
972 req = vmbus_msghc_dataptr(mh);
973 req->chm_hdr.chm_type = VMBUS_CHANMSG_TYPE_INIT_CONTACT;
974 req->chm_ver = version;
975 req->chm_evtflags = sc->vmbus_evtflags_dma.hv_paddr;
976 req->chm_mnf1 = sc->vmbus_mnf1_dma.hv_paddr;
977 req->chm_mnf2 = sc->vmbus_mnf2_dma.hv_paddr;
979 error = vmbus_msghc_exec(sc, mh);
981 vmbus_msghc_put(sc, mh);
985 msg = vmbus_msghc_wait_result(sc, mh);
986 resp = (const struct vmbus_chanmsg_version_resp *)msg->msg_data;
987 supp = resp->chm_supp;
989 vmbus_msghc_put(sc, mh);
991 return (supp ? 0 : EOPNOTSUPP);
995 vmbus_init(struct vmbus_softc *sc)
999 for (i = 0; i < nitems(vmbus_version); ++i) {
1002 error = vmbus_init_contact(sc, vmbus_version[i]);
1004 sc->vmbus_version = vmbus_version[i];
1005 device_printf(sc->vmbus_dev, "version %u.%u\n",
1006 (sc->vmbus_version >> 16),
1007 (sc->vmbus_version & 0xffff));
1015 vmbus_chan_msgproc(struct vmbus_softc *sc, const struct vmbus_message *msg)
1017 const struct vmbus_chanmsg_hdr *hdr;
1019 hdr = (const struct vmbus_chanmsg_hdr *)msg->msg_data;
1022 if (hdr->chm_type == VMBUS_CHANMSG_TYPE_VERSION_RESP)
1023 vmbus_msghc_wakeup(sc, msg);