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/module.h>
36 #include <sys/systimer.h>
37 #include <sys/thread.h>
38 #include <sys/thread2.h>
40 #include <machine/intr_machdep.h>
41 #include <machine/smp.h>
43 #include <dev/virtual/hyperv/hyperv_busdma.h>
44 #include <dev/virtual/hyperv/vmbus/hyperv_machdep.h>
45 #include <dev/virtual/hyperv/vmbus/hyperv_reg.h>
46 #include <dev/virtual/hyperv/vmbus/hyperv_var.h>
47 #include <dev/virtual/hyperv/vmbus/vmbus_reg.h>
48 #include <dev/virtual/hyperv/vmbus/vmbus_var.h>
54 #define MSR_HV_STIMER0_CFG_SINT \
55 ((((uint64_t)VMBUS_SINT_TIMER) << MSR_HV_STIMER_CFG_SINT_SHIFT) & \
56 MSR_HV_STIMER_CFG_SINT_MASK)
59 * Additionally required feature:
60 * - SynIC is needed for interrupt generation.
62 #define CPUID_HV_TIMER_MASK (CPUID_HV_MSR_SYNIC | \
63 CPUID_HV_MSR_SYNTIMER)
66 * NOTE: DO NOT CHANGE THIS.
68 #define VMBUS_SINT_MESSAGE 2
71 * - DO NOT set it to the same value as VMBUS_SINT_MESSAGE.
72 * - DO NOT set it to 0.
74 #define VMBUS_SINT_TIMER 4
77 * NOTE: DO NOT CHANGE THESE
79 #define VMBUS_CONNID_MESSAGE 1
80 #define VMBUS_CONNID_EVENT 2
83 struct hypercall_postmsg_in
*mh_inprm
;
84 struct hypercall_postmsg_in mh_inprm_save
;
85 struct hyperv_dma mh_inprm_dma
;
87 struct vmbus_message
*mh_resp
;
88 struct vmbus_message mh_resp0
;
91 struct vmbus_msghc_ctx
{
92 struct vmbus_msghc
*mhc_free
;
93 struct lwkt_token mhc_free_token
;
96 struct vmbus_msghc
*mhc_active
;
97 struct lwkt_token mhc_active_token
;
100 #define VMBUS_MSGHC_CTXF_DESTROY 0x0001
102 static int vmbus_probe(device_t
);
103 static int vmbus_attach(device_t
);
104 static int vmbus_detach(device_t
);
105 static void vmbus_intr(void *);
106 static void vmbus_timer_intr_reload(struct cputimer_intr
*,
108 static void vmbus_timer_intr_pcpuhand(
109 struct cputimer_intr
*);
110 static void vmbus_timer_intr_restart(
111 struct cputimer_intr
*);
113 static int vmbus_dma_alloc(struct vmbus_softc
*);
114 static void vmbus_dma_free(struct vmbus_softc
*);
115 static int vmbus_intr_setup(struct vmbus_softc
*);
116 static void vmbus_intr_teardown(struct vmbus_softc
*);
117 static void vmbus_synic_setup(void *);
118 static void vmbus_synic_teardown(void *);
119 static void vmbus_timer_stop(void *);
120 static void vmbus_timer_config(void *);
121 static int vmbus_init(struct vmbus_softc
*);
122 static int vmbus_init_contact(struct vmbus_softc
*,
124 static void vmbus_timer_restart(void *);
125 static void vmbus_timer_msgintr(struct vmbus_pcpu_data
*);
127 static void vmbus_chan_msgproc(struct vmbus_softc
*,
128 const struct vmbus_message
*);
130 static struct vmbus_msghc_ctx
*vmbus_msghc_ctx_create(bus_dma_tag_t
);
131 static void vmbus_msghc_ctx_destroy(
132 struct vmbus_msghc_ctx
*);
133 static void vmbus_msghc_ctx_free(struct vmbus_msghc_ctx
*);
134 static struct vmbus_msghc
*vmbus_msghc_alloc(bus_dma_tag_t
);
135 static void vmbus_msghc_free(struct vmbus_msghc
*);
136 static struct vmbus_msghc
*vmbus_msghc_get1(struct vmbus_msghc_ctx
*,
139 static device_method_t vmbus_methods
[] = {
140 /* Device interface */
141 DEVMETHOD(device_probe
, vmbus_probe
),
142 DEVMETHOD(device_attach
, vmbus_attach
),
143 DEVMETHOD(device_detach
, vmbus_detach
),
144 DEVMETHOD(device_shutdown
, bus_generic_shutdown
),
145 DEVMETHOD(device_suspend
, bus_generic_suspend
),
146 DEVMETHOD(device_resume
, bus_generic_resume
),
151 static driver_t vmbus_driver
= {
154 sizeof(struct vmbus_softc
)
157 static devclass_t vmbus_devclass
;
159 DRIVER_MODULE(vmbus
, acpi
, vmbus_driver
, vmbus_devclass
, NULL
, NULL
);
160 MODULE_DEPEND(vmbus
, acpi
, 1, 1, 1);
161 MODULE_VERSION(vmbus
, 1);
163 static struct cputimer_intr vmbus_cputimer_intr
= {
164 .freq
= HYPERV_TIMER_FREQ
,
165 .reload
= vmbus_timer_intr_reload
,
166 .enable
= cputimer_intr_default_enable
,
167 .config
= cputimer_intr_default_config
,
168 .restart
= vmbus_timer_intr_restart
,
169 .pmfixup
= cputimer_intr_default_pmfixup
,
170 .initclock
= cputimer_intr_default_initclock
,
171 .pcpuhand
= vmbus_timer_intr_pcpuhand
,
172 .next
= SLIST_ENTRY_INITIALIZER
,
174 .type
= CPUTIMER_INTR_VMM
,
175 .prio
= CPUTIMER_INTR_PRIO_VMM
,
176 .caps
= CPUTIMER_INTR_CAP_PS
,
180 static const uint32_t vmbus_version
[] = {
181 VMBUS_VERSION_WIN8_1
,
187 static int vmbus_timer_intr_enable
= 1;
188 TUNABLE_INT("hw.vmbus.timer_intr.enable", &vmbus_timer_intr_enable
);
191 vmbus_probe(device_t dev
)
193 char *id
[] = { "VMBUS", NULL
};
195 if (ACPI_ID_PROBE(device_get_parent(dev
), dev
, id
) == NULL
||
196 device_get_unit(dev
) != 0 || vmm_guest
!= VMM_GUEST_HYPERV
||
197 (hyperv_features
& CPUID_HV_MSR_SYNIC
) == 0)
200 device_set_desc(dev
, "Hyper-V vmbus");
206 vmbus_attach(device_t dev
)
208 struct vmbus_softc
*sc
= device_get_softc(dev
);
209 int error
, cpu
, use_timer
;
215 for (cpu
= 0; cpu
< ncpus
; ++cpu
) {
216 struct vmbus_pcpu_data
*psc
= VMBUS_PCPU(sc
, cpu
);
220 psc
->timer_last
= UINT64_MAX
;
224 * Should we use interrupt timer?
227 if (device_get_unit(dev
) == 0 &&
228 (hyperv_features
& CPUID_HV_TIMER_MASK
) == CPUID_HV_TIMER_MASK
&&
233 * Create context for "post message" Hypercalls
235 sc
->vmbus_msg_hc
= vmbus_msghc_ctx_create(
236 bus_get_dma_tag(sc
->vmbus_dev
));
237 if (sc
->vmbus_msg_hc
== NULL
)
241 * Allocate DMA stuffs.
243 error
= vmbus_dma_alloc(sc
);
250 error
= vmbus_intr_setup(sc
);
256 * Make sure that interrupt timer is stopped.
258 lwkt_cpusync_simple(smp_active_mask
, vmbus_timer_stop
, sc
);
264 lwkt_cpusync_simple(smp_active_mask
, vmbus_synic_setup
, sc
);
265 sc
->vmbus_flags
|= VMBUS_FLAG_SYNIC
;
270 error
= vmbus_init(sc
);
276 * Configure and register vmbus interrupt timer.
278 lwkt_cpusync_simple(smp_active_mask
, vmbus_timer_config
, sc
);
279 vmbus_cputimer_intr
.priv
= sc
;
280 cputimer_intr_register(&vmbus_cputimer_intr
);
281 if (vmbus_timer_intr_enable
)
282 cputimer_intr_select(&vmbus_cputimer_intr
, 0);
292 vmbus_detach(device_t dev
)
294 struct vmbus_softc
*sc
= device_get_softc(dev
);
296 /* TODO: uninitialize vmbus. */
297 /* TODO: stop and deregister timer */
299 if (sc
->vmbus_flags
& VMBUS_FLAG_SYNIC
)
300 lwkt_cpusync_simple(smp_active_mask
, vmbus_synic_teardown
, sc
);
301 vmbus_intr_teardown(sc
);
304 if (sc
->vmbus_msg_hc
!= NULL
) {
305 vmbus_msghc_ctx_destroy(sc
->vmbus_msg_hc
);
306 sc
->vmbus_msg_hc
= NULL
;
312 vmbus_msg_reset(volatile struct vmbus_message
*msg
)
314 msg
->msg_type
= HYPERV_MSGTYPE_NONE
;
316 * Make sure that the write to msg_type (i.e. set to
317 * HYPERV_MSGTYPE_NONE) happens before we read the
318 * msg_flags and send EOM to the hypervisor.
321 if (msg
->msg_flags
& VMBUS_MSGFLAG_PENDING
) {
323 * Ask the hypervisor to rescan message queue,
324 * and deliver new message if any.
326 wrmsr(MSR_HV_EOM
, 0);
331 vmbus_intr(void *xpsc
)
333 struct vmbus_pcpu_data
*psc
= xpsc
;
334 volatile struct vmbus_message
*msg
;
336 msg
= psc
->message
+ VMBUS_SINT_MESSAGE
;
337 while (__predict_false(msg
->msg_type
!= HYPERV_MSGTYPE_NONE
)) {
338 if (msg
->msg_type
== HYPERV_MSGTYPE_CHANNEL
) {
339 /* Channel message */
340 vmbus_chan_msgproc(psc
->sc
,
341 __DEVOLATILE(const struct vmbus_message
*, msg
));
343 vmbus_msg_reset(msg
);
348 vmbus_timer_oneshot(struct vmbus_pcpu_data
*psc
, uint64_t current
)
350 psc
->timer_last
= current
;
351 wrmsr(MSR_HV_STIMER0_COUNT
, current
);
355 vmbus_timer_intr_reload(struct cputimer_intr
*cti
, sysclock_t reload
)
357 struct globaldata
*gd
= mycpu
;
358 struct vmbus_softc
*sc
= cti
->priv
;
359 struct vmbus_pcpu_data
*psc
= VMBUS_PCPU(sc
, gd
->gd_cpuid
);
362 reload
= (uint64_t)reload
* cti
->freq
/ sys_cputimer
->freq
;
363 current
= hyperv_tc64() + reload
;
365 if (gd
->gd_timer_running
) {
366 if (current
< psc
->timer_last
)
367 vmbus_timer_oneshot(psc
, current
);
369 gd
->gd_timer_running
= 1;
370 vmbus_timer_oneshot(psc
, current
);
375 vmbus_timer_intr_pcpuhand(struct cputimer_intr
*cti
)
377 struct vmbus_softc
*sc
= cti
->priv
;
378 struct vmbus_pcpu_data
*psc
= VMBUS_PCPU(sc
, mycpuid
);
380 vmbus_timer_msgintr(psc
);
384 vmbus_timer_intr_restart(struct cputimer_intr
*cti
)
386 lwkt_send_ipiq_mask(smp_active_mask
, vmbus_timer_restart
, cti
->priv
);
389 static struct vmbus_msghc
*
390 vmbus_msghc_alloc(bus_dma_tag_t parent_dtag
)
392 struct vmbus_msghc
*mh
;
394 mh
= kmalloc(sizeof(*mh
), M_DEVBUF
, M_WAITOK
| M_ZERO
);
396 mh
->mh_inprm
= hyperv_dmamem_alloc(parent_dtag
,
397 HYPERCALL_POSTMSGIN_ALIGN
, 0, HYPERCALL_POSTMSGIN_SIZE
,
398 &mh
->mh_inprm_dma
, BUS_DMA_WAITOK
);
399 if (mh
->mh_inprm
== NULL
) {
407 vmbus_msghc_free(struct vmbus_msghc
*mh
)
409 hyperv_dmamem_free(&mh
->mh_inprm_dma
, mh
->mh_inprm
);
414 vmbus_msghc_ctx_free(struct vmbus_msghc_ctx
*mhc
)
416 KASSERT(mhc
->mhc_active
== NULL
, ("still have active msg hypercall"));
417 KASSERT(mhc
->mhc_free
== NULL
, ("still have hypercall msg"));
419 lwkt_token_uninit(&mhc
->mhc_free_token
);
420 lwkt_token_uninit(&mhc
->mhc_active_token
);
421 kfree(mhc
, M_DEVBUF
);
424 static struct vmbus_msghc_ctx
*
425 vmbus_msghc_ctx_create(bus_dma_tag_t parent_dtag
)
427 struct vmbus_msghc_ctx
*mhc
;
429 mhc
= kmalloc(sizeof(*mhc
), M_DEVBUF
, M_WAITOK
| M_ZERO
);
430 lwkt_token_init(&mhc
->mhc_free_token
, "msghcf");
431 lwkt_token_init(&mhc
->mhc_active_token
, "msghca");
433 mhc
->mhc_free
= vmbus_msghc_alloc(parent_dtag
);
434 if (mhc
->mhc_free
== NULL
) {
435 vmbus_msghc_ctx_free(mhc
);
441 static struct vmbus_msghc
*
442 vmbus_msghc_get1(struct vmbus_msghc_ctx
*mhc
, uint32_t dtor_flag
)
444 struct vmbus_msghc
*mh
;
446 lwkt_gettoken(&mhc
->mhc_free_token
);
448 while ((mhc
->mhc_flags
& dtor_flag
) == 0 && mhc
->mhc_free
== NULL
)
449 tsleep(&mhc
->mhc_free
, 0, "gmsghc", 0);
450 if (mhc
->mhc_flags
& dtor_flag
) {
451 /* Being destroyed */
455 KASSERT(mh
!= NULL
, ("no free hypercall msg"));
456 KASSERT(mh
->mh_resp
== NULL
,
457 ("hypercall msg has pending response"));
458 mhc
->mhc_free
= NULL
;
461 lwkt_reltoken(&mhc
->mhc_free_token
);
467 vmbus_msghc_get(struct vmbus_softc
*sc
, size_t dsize
)
469 struct hypercall_postmsg_in
*inprm
;
470 struct vmbus_msghc
*mh
;
472 if (dsize
> HYPERCALL_POSTMSGIN_DSIZE_MAX
)
475 mh
= vmbus_msghc_get1(sc
->vmbus_msg_hc
, VMBUS_MSGHC_CTXF_DESTROY
);
479 inprm
= mh
->mh_inprm
;
480 memset(inprm
, 0, HYPERCALL_POSTMSGIN_SIZE
);
481 inprm
->hc_connid
= VMBUS_CONNID_MESSAGE
;
482 inprm
->hc_msgtype
= HYPERV_MSGTYPE_CHANNEL
;
483 inprm
->hc_dsize
= dsize
;
489 vmbus_msghc_put(struct vmbus_softc
*sc
, struct vmbus_msghc
*mh
)
491 struct vmbus_msghc_ctx
*mhc
= sc
->vmbus_msg_hc
;
493 KASSERT(mhc
->mhc_active
== NULL
, ("msg hypercall is active"));
496 lwkt_gettoken(&mhc
->mhc_free_token
);
497 KASSERT(mhc
->mhc_free
== NULL
, ("has free hypercall msg"));
499 lwkt_reltoken(&mhc
->mhc_free_token
);
500 wakeup(&mhc
->mhc_free
);
504 vmbus_msghc_dataptr(struct vmbus_msghc
*mh
)
506 return mh
->mh_inprm
->hc_data
;
510 vmbus_msghc_ctx_destroy(struct vmbus_msghc_ctx
*mhc
)
512 struct vmbus_msghc
*mh
;
514 lwkt_gettoken(&mhc
->mhc_free_token
);
515 mhc
->mhc_flags
|= VMBUS_MSGHC_CTXF_DESTROY
;
516 lwkt_reltoken(&mhc
->mhc_free_token
);
517 wakeup(&mhc
->mhc_free
);
519 mh
= vmbus_msghc_get1(mhc
, 0);
521 panic("can't get msghc");
523 vmbus_msghc_free(mh
);
524 vmbus_msghc_ctx_free(mhc
);
528 vmbus_msghc_exec_noresult(struct vmbus_msghc
*mh
)
530 int i
, wait_ticks
= 1;
533 * Save the input parameter so that we could restore the input
534 * parameter if the Hypercall failed.
537 * Is this really necessary?! i.e. Will the Hypercall ever
538 * overwrite the input parameter?
540 memcpy(&mh
->mh_inprm_save
, mh
->mh_inprm
, HYPERCALL_POSTMSGIN_SIZE
);
543 * In order to cope with transient failures, e.g. insufficient
544 * resources on host side, we retry the post message Hypercall
545 * several times. 20 retries seem sufficient.
547 #define HC_RETRY_MAX 20
549 for (i
= 0; i
< HC_RETRY_MAX
; ++i
) {
552 status
= hypercall_post_message(mh
->mh_inprm_dma
.hv_paddr
);
553 if (status
== HYPERCALL_STATUS_SUCCESS
)
556 tsleep(&status
, 0, "hcpmsg", wait_ticks
);
560 /* Restore input parameter and try again */
561 memcpy(mh
->mh_inprm
, &mh
->mh_inprm_save
,
562 HYPERCALL_POSTMSGIN_SIZE
);
571 vmbus_msghc_exec(struct vmbus_softc
*sc
, struct vmbus_msghc
*mh
)
573 struct vmbus_msghc_ctx
*mhc
= sc
->vmbus_msg_hc
;
576 KASSERT(mh
->mh_resp
== NULL
, ("hypercall msg has pending response"));
578 lwkt_gettoken(&mhc
->mhc_active_token
);
579 KASSERT(mhc
->mhc_active
== NULL
, ("pending active msg hypercall"));
580 mhc
->mhc_active
= mh
;
581 lwkt_reltoken(&mhc
->mhc_active_token
);
583 error
= vmbus_msghc_exec_noresult(mh
);
585 lwkt_gettoken(&mhc
->mhc_active_token
);
586 KASSERT(mhc
->mhc_active
== mh
, ("msghc mismatch"));
587 mhc
->mhc_active
= NULL
;
588 lwkt_reltoken(&mhc
->mhc_active_token
);
593 const struct vmbus_message
*
594 vmbus_msghc_wait_result(struct vmbus_softc
*sc
, struct vmbus_msghc
*mh
)
596 struct vmbus_msghc_ctx
*mhc
= sc
->vmbus_msg_hc
;
598 lwkt_gettoken(&mhc
->mhc_active_token
);
600 KASSERT(mhc
->mhc_active
== mh
, ("msghc mismatch"));
601 while (mh
->mh_resp
== NULL
)
602 tsleep(&mhc
->mhc_active
, 0, "wmsghc", 0);
603 mhc
->mhc_active
= NULL
;
605 lwkt_reltoken(&mhc
->mhc_active_token
);
611 vmbus_msghc_wakeup(struct vmbus_softc
*sc
, const struct vmbus_message
*msg
)
613 struct vmbus_msghc_ctx
*mhc
= sc
->vmbus_msg_hc
;
614 struct vmbus_msghc
*mh
;
616 lwkt_gettoken(&mhc
->mhc_active_token
);
618 mh
= mhc
->mhc_active
;
619 KASSERT(mh
!= NULL
, ("no pending msg hypercall"));
620 memcpy(&mh
->mh_resp0
, msg
, sizeof(mh
->mh_resp0
));
621 mh
->mh_resp
= &mh
->mh_resp0
;
623 lwkt_reltoken(&mhc
->mhc_active_token
);
624 wakeup(&mhc
->mhc_active
);
628 vmbus_dma_alloc(struct vmbus_softc
*sc
)
630 bus_dma_tag_t parent_dtag
;
634 parent_dtag
= bus_get_dma_tag(sc
->vmbus_dev
);
635 for (cpu
= 0; cpu
< ncpus
; ++cpu
) {
636 struct vmbus_pcpu_data
*psc
= VMBUS_PCPU(sc
, cpu
);
639 * Per-cpu messages and event flags.
641 psc
->message
= hyperv_dmamem_alloc(parent_dtag
,
642 PAGE_SIZE
, 0, PAGE_SIZE
, &psc
->message_dma
,
643 BUS_DMA_WAITOK
| BUS_DMA_ZERO
);
644 if (psc
->message
== NULL
)
647 psc
->event_flags
= hyperv_dmamem_alloc(parent_dtag
,
648 PAGE_SIZE
, 0, PAGE_SIZE
, &psc
->event_flags_dma
,
649 BUS_DMA_WAITOK
| BUS_DMA_ZERO
);
650 if (psc
->event_flags
== NULL
)
654 evtflags
= hyperv_dmamem_alloc(parent_dtag
, PAGE_SIZE
, 0,
655 PAGE_SIZE
, &sc
->vmbus_evtflags_dma
, BUS_DMA_WAITOK
| BUS_DMA_ZERO
);
656 if (evtflags
== NULL
)
658 sc
->vmbus_rx_evtflags
= (u_long
*)evtflags
;
659 sc
->vmbus_tx_evtflags
= (u_long
*)(evtflags
+ (PAGE_SIZE
/ 2));
660 sc
->vmbus_evtflags
= evtflags
;
662 sc
->vmbus_mnf1
= hyperv_dmamem_alloc(parent_dtag
, PAGE_SIZE
, 0,
663 PAGE_SIZE
, &sc
->vmbus_mnf1_dma
, BUS_DMA_WAITOK
| BUS_DMA_ZERO
);
664 if (sc
->vmbus_mnf1
== NULL
)
667 sc
->vmbus_mnf2
= hyperv_dmamem_alloc(parent_dtag
, PAGE_SIZE
, 0,
668 PAGE_SIZE
, &sc
->vmbus_mnf2_dma
, BUS_DMA_WAITOK
| BUS_DMA_ZERO
);
669 if (sc
->vmbus_mnf2
== NULL
)
676 vmbus_dma_free(struct vmbus_softc
*sc
)
680 if (sc
->vmbus_evtflags
!= NULL
) {
681 hyperv_dmamem_free(&sc
->vmbus_evtflags_dma
, sc
->vmbus_evtflags
);
682 sc
->vmbus_evtflags
= NULL
;
683 sc
->vmbus_rx_evtflags
= NULL
;
684 sc
->vmbus_tx_evtflags
= NULL
;
686 if (sc
->vmbus_mnf1
!= NULL
) {
687 hyperv_dmamem_free(&sc
->vmbus_mnf1_dma
, sc
->vmbus_mnf1
);
688 sc
->vmbus_mnf1
= NULL
;
690 if (sc
->vmbus_mnf2
!= NULL
) {
691 hyperv_dmamem_free(&sc
->vmbus_mnf2_dma
, sc
->vmbus_mnf2
);
692 sc
->vmbus_mnf2
= NULL
;
695 for (cpu
= 0; cpu
< ncpus
; ++cpu
) {
696 struct vmbus_pcpu_data
*psc
= VMBUS_PCPU(sc
, cpu
);
698 if (psc
->message
!= NULL
) {
699 hyperv_dmamem_free(&psc
->message_dma
, psc
->message
);
702 if (psc
->event_flags
!= NULL
) {
703 hyperv_dmamem_free(&psc
->event_flags_dma
,
705 psc
->event_flags
= NULL
;
711 vmbus_intr_setup(struct vmbus_softc
*sc
)
713 device_t dev
= sc
->vmbus_dev
;
714 device_t bus
= device_get_parent(device_get_parent(dev
));
718 for (cpu
= 0; cpu
< ncpus
; ++cpu
) {
719 struct vmbus_pcpu_data
*psc
= VMBUS_PCPU(sc
, cpu
);
724 error
= PCIB_ALLOC_MSIX(bus
, dev
, &psc
->intr_irq
, cpu
);
726 device_printf(dev
, "alloc vector on cpu%d failed: %d\n",
730 psc
->intr_rid
= ++rid
;
732 psc
->intr_res
= BUS_ALLOC_RESOURCE(bus
, dev
, SYS_RES_IRQ
,
733 &psc
->intr_rid
, psc
->intr_irq
, psc
->intr_irq
, 1,
735 if (psc
->intr_res
== NULL
) {
736 device_printf(dev
, "alloc irq on cpu%d failed: %d\n",
741 error
= PCIB_MAP_MSI(bus
, dev
, rman_get_start(psc
->intr_res
),
742 &msi_addr
, &msi_data
, cpu
);
744 device_printf(dev
, "map irq on cpu%d failed: %d\n",
748 psc
->intr_vec
= hyperv_msi2vector(msi_addr
, msi_data
);
751 device_printf(dev
, "vector %d irq %d on cpu%d\n",
752 psc
->intr_vec
, psc
->intr_irq
, cpu
);
755 ksnprintf(psc
->intr_desc
, sizeof(psc
->intr_desc
), "%s cpu%d",
756 device_get_nameunit(dev
), cpu
);
757 error
= bus_setup_intr_descr(dev
, psc
->intr_res
, INTR_MPSAFE
,
758 vmbus_intr
, psc
, &psc
->intr_hand
, NULL
, psc
->intr_desc
);
760 device_printf(dev
, "setup intr on cpu%d failed: %d\n",
769 vmbus_intr_teardown(struct vmbus_softc
*sc
)
771 device_t dev
= sc
->vmbus_dev
;
772 device_t bus
= device_get_parent(device_get_parent(dev
));
775 for (cpu
= 0; cpu
< ncpus
; ++cpu
) {
776 struct vmbus_pcpu_data
*psc
= VMBUS_PCPU(sc
, cpu
);
778 if (psc
->intr_hand
!= NULL
) {
779 bus_teardown_intr(dev
, psc
->intr_res
, psc
->intr_hand
);
780 psc
->intr_hand
= NULL
;
783 if (psc
->intr_res
!= NULL
) {
784 BUS_RELEASE_RESOURCE(bus
, dev
, SYS_RES_IRQ
,
785 psc
->intr_rid
, psc
->intr_res
);
786 psc
->intr_res
= NULL
;
789 if (psc
->intr_rid
!= 0) {
790 PCIB_RELEASE_MSIX(bus
, dev
, psc
->intr_irq
, psc
->cpuid
);
797 vmbus_synic_setup(void *xsc
)
799 struct vmbus_softc
*sc
= xsc
;
800 struct vmbus_pcpu_data
*psc
= VMBUS_PCPU(sc
, mycpuid
);
804 if (hyperv_features
& CPUID_HV_MSR_VP_INDEX
) {
806 * Save virtual processor id.
808 psc
->vcpuid
= rdmsr(MSR_HV_VP_INDEX
);
812 * Virtual processoor id is only used by a pretty broken
813 * channel selection code from storvsc. It's nothing
814 * critical even if CPUID_HV_MSR_VP_INDEX is not set; keep
817 psc
->vcpuid
= mycpuid
;
821 * Setup the SynIC message.
823 orig
= rdmsr(MSR_HV_SIMP
);
824 val
= MSR_HV_SIMP_ENABLE
| (orig
& MSR_HV_SIMP_RSVD_MASK
) |
825 ((psc
->message_dma
.hv_paddr
>> PAGE_SHIFT
) << MSR_HV_SIMP_PGSHIFT
);
826 wrmsr(MSR_HV_SIMP
, val
);
829 * Setup the SynIC event flags.
831 orig
= rdmsr(MSR_HV_SIEFP
);
832 val
= MSR_HV_SIEFP_ENABLE
| (orig
& MSR_HV_SIEFP_RSVD_MASK
) |
833 ((psc
->event_flags_dma
.hv_paddr
>> PAGE_SHIFT
) <<
834 MSR_HV_SIEFP_PGSHIFT
);
835 wrmsr(MSR_HV_SIEFP
, val
);
839 * Configure and unmask SINT for message and event flags.
841 sint
= MSR_HV_SINT0
+ VMBUS_SINT_MESSAGE
;
843 val
= psc
->intr_vec
| /* MSR_HV_SINT_AUTOEOI | notyet */
844 (orig
& MSR_HV_SINT_RSVD_MASK
);
848 * Configure and unmask SINT for timer.
850 sint
= MSR_HV_SINT0
+ VMBUS_SINT_TIMER
;
852 val
= XTIMER_OFFSET
| /* MSR_HV_SINT_AUTOEOI | notyet */
853 (orig
& MSR_HV_SINT_RSVD_MASK
);
857 * All done; enable SynIC.
859 orig
= rdmsr(MSR_HV_SCONTROL
);
860 val
= MSR_HV_SCTRL_ENABLE
| (orig
& MSR_HV_SCTRL_RSVD_MASK
);
861 wrmsr(MSR_HV_SCONTROL
, val
);
865 vmbus_timer_stop(void *arg __unused
)
870 /* Stop counting, and this also implies disabling STIMER0 */
871 wrmsr(MSR_HV_STIMER0_COUNT
, 0);
873 val
= rdmsr(MSR_HV_STIMER0_CONFIG
);
874 if ((val
& MSR_HV_STIMER_CFG_ENABLE
) == 0)
881 vmbus_timer_config(void *arg __unused
)
884 * Make sure that STIMER0 is really disabled before writing
887 * "Writing to the configuration register of a timer that
888 * is already enabled may result in undefined behaviour."
890 vmbus_timer_stop(arg
);
891 wrmsr(MSR_HV_STIMER0_CONFIG
,
892 MSR_HV_STIMER_CFG_AUTOEN
| MSR_HV_STIMER0_CFG_SINT
);
896 vmbus_timer_msgintr(struct vmbus_pcpu_data
*psc
)
898 volatile struct vmbus_message
*msg
;
900 msg
= psc
->message
+ VMBUS_SINT_TIMER
;
901 if (msg
->msg_type
== HYPERV_MSGTYPE_TIMER_EXPIRED
)
902 vmbus_msg_reset(msg
);
906 vmbus_timer_restart(void *xsc
)
908 struct vmbus_softc
*sc
= xsc
;
909 struct vmbus_pcpu_data
*psc
= VMBUS_PCPU(sc
, mycpuid
);
912 vmbus_timer_msgintr(psc
);
913 vmbus_timer_oneshot(psc
, hyperv_tc64() + 1);
918 vmbus_synic_teardown(void *arg __unused
)
926 orig
= rdmsr(MSR_HV_SCONTROL
);
927 wrmsr(MSR_HV_SCONTROL
, (orig
& MSR_HV_SCTRL_RSVD_MASK
));
930 * Mask message and event flags SINT.
932 sint
= MSR_HV_SINT0
+ VMBUS_SINT_MESSAGE
;
934 wrmsr(sint
, orig
| MSR_HV_SINT_MASKED
);
939 sint
= MSR_HV_SINT0
+ VMBUS_SINT_TIMER
;
941 wrmsr(sint
, orig
| MSR_HV_SINT_MASKED
);
944 * Teardown SynIC message.
946 orig
= rdmsr(MSR_HV_SIMP
);
947 wrmsr(MSR_HV_SIMP
, (orig
& MSR_HV_SIMP_RSVD_MASK
));
950 * Teardown SynIC event flags.
952 orig
= rdmsr(MSR_HV_SIEFP
);
953 wrmsr(MSR_HV_SIEFP
, (orig
& MSR_HV_SIEFP_RSVD_MASK
));
957 vmbus_init_contact(struct vmbus_softc
*sc
, uint32_t version
)
959 struct vmbus_chanmsg_init_contact
*req
;
960 const struct vmbus_chanmsg_version_resp
*resp
;
961 const struct vmbus_message
*msg
;
962 struct vmbus_msghc
*mh
;
965 mh
= vmbus_msghc_get(sc
, sizeof(*req
));
969 req
= vmbus_msghc_dataptr(mh
);
970 req
->chm_hdr
.chm_type
= VMBUS_CHANMSG_TYPE_INIT_CONTACT
;
971 req
->chm_ver
= version
;
972 req
->chm_evtflags
= sc
->vmbus_evtflags_dma
.hv_paddr
;
973 req
->chm_mnf1
= sc
->vmbus_mnf1_dma
.hv_paddr
;
974 req
->chm_mnf2
= sc
->vmbus_mnf2_dma
.hv_paddr
;
976 error
= vmbus_msghc_exec(sc
, mh
);
978 vmbus_msghc_put(sc
, mh
);
982 msg
= vmbus_msghc_wait_result(sc
, mh
);
983 resp
= (const struct vmbus_chanmsg_version_resp
*)msg
->msg_data
;
984 supp
= resp
->chm_supp
;
986 vmbus_msghc_put(sc
, mh
);
988 return (supp
? 0 : EOPNOTSUPP
);
992 vmbus_init(struct vmbus_softc
*sc
)
996 for (i
= 0; i
< nitems(vmbus_version
); ++i
) {
999 error
= vmbus_init_contact(sc
, vmbus_version
[i
]);
1001 sc
->vmbus_version
= vmbus_version
[i
];
1002 device_printf(sc
->vmbus_dev
, "version %u.%u\n",
1003 (sc
->vmbus_version
>> 16),
1004 (sc
->vmbus_version
& 0xffff));
1012 vmbus_chan_msgproc(struct vmbus_softc
*sc
, const struct vmbus_message
*msg
)
1014 const struct vmbus_chanmsg_hdr
*hdr
;
1016 hdr
= (const struct vmbus_chanmsg_hdr
*)msg
->msg_data
;
1019 if (hdr
->chm_type
== VMBUS_CHANMSG_TYPE_VERSION_RESP
)
1020 vmbus_msghc_wakeup(sc
, msg
);