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/include/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 * NOTE: DO NOT CHANGE THIS.
61 #define VMBUS_SINT_MESSAGE 2
64 * - DO NOT set it to the same value as VMBUS_SINT_MESSAGE.
65 * - DO NOT set it to 0.
67 #define VMBUS_SINT_TIMER 4
70 * NOTE: DO NOT CHANGE THESE
72 #define VMBUS_CONNID_MESSAGE 1
73 #define VMBUS_CONNID_EVENT 2
76 struct hypercall_postmsg_in
*mh_inprm
;
77 struct hypercall_postmsg_in mh_inprm_save
;
78 struct hyperv_dma mh_inprm_dma
;
80 struct vmbus_message
*mh_resp
;
81 struct vmbus_message mh_resp0
;
84 struct vmbus_msghc_ctx
{
85 struct vmbus_msghc
*mhc_free
;
86 struct lwkt_token mhc_free_token
;
89 struct vmbus_msghc
*mhc_active
;
90 struct lwkt_token mhc_active_token
;
93 #define VMBUS_MSGHC_CTXF_DESTROY 0x0001
95 static int vmbus_probe(device_t
);
96 static int vmbus_attach(device_t
);
97 static int vmbus_detach(device_t
);
98 static void vmbus_intr(void *);
99 static void vmbus_timer_intr_reload(struct cputimer_intr
*,
101 static void vmbus_timer_intr_pcpuhand(
102 struct cputimer_intr
*);
103 static void vmbus_timer_intr_restart(
104 struct cputimer_intr
*);
106 static int vmbus_dma_alloc(struct vmbus_softc
*);
107 static void vmbus_dma_free(struct vmbus_softc
*);
108 static int vmbus_intr_setup(struct vmbus_softc
*);
109 static void vmbus_intr_teardown(struct vmbus_softc
*);
110 static int vmbus_intr_rid(struct resource_list
*, int);
111 static void vmbus_synic_setup(void *);
112 static void vmbus_synic_teardown(void *);
113 static void vmbus_timer_stop(void *);
114 static void vmbus_timer_config(void *);
115 static int vmbus_init(struct vmbus_softc
*);
116 static int vmbus_init_contact(struct vmbus_softc
*,
118 static void vmbus_timer_restart(void *);
119 static void vmbus_timer_msgintr(struct vmbus_pcpu_data
*);
121 static void vmbus_chan_msgproc(struct vmbus_softc
*,
122 const struct vmbus_message
*);
124 static struct vmbus_msghc_ctx
*vmbus_msghc_ctx_create(bus_dma_tag_t
);
125 static void vmbus_msghc_ctx_destroy(
126 struct vmbus_msghc_ctx
*);
127 static void vmbus_msghc_ctx_free(struct vmbus_msghc_ctx
*);
128 static struct vmbus_msghc
*vmbus_msghc_alloc(bus_dma_tag_t
);
129 static void vmbus_msghc_free(struct vmbus_msghc
*);
130 static struct vmbus_msghc
*vmbus_msghc_get1(struct vmbus_msghc_ctx
*,
133 static device_method_t vmbus_methods
[] = {
134 /* Device interface */
135 DEVMETHOD(device_probe
, vmbus_probe
),
136 DEVMETHOD(device_attach
, vmbus_attach
),
137 DEVMETHOD(device_detach
, vmbus_detach
),
138 DEVMETHOD(device_shutdown
, bus_generic_shutdown
),
139 DEVMETHOD(device_suspend
, bus_generic_suspend
),
140 DEVMETHOD(device_resume
, bus_generic_resume
),
145 static driver_t vmbus_driver
= {
148 sizeof(struct vmbus_softc
)
151 static devclass_t vmbus_devclass
;
153 DRIVER_MODULE(vmbus
, acpi
, vmbus_driver
, vmbus_devclass
, NULL
, NULL
);
154 MODULE_DEPEND(vmbus
, acpi
, 1, 1, 1);
155 MODULE_VERSION(vmbus
, 1);
157 static struct cputimer_intr vmbus_cputimer_intr
= {
158 .freq
= HYPERV_TIMER_FREQ
,
159 .reload
= vmbus_timer_intr_reload
,
160 .enable
= cputimer_intr_default_enable
,
161 .config
= cputimer_intr_default_config
,
162 .restart
= vmbus_timer_intr_restart
,
163 .pmfixup
= cputimer_intr_default_pmfixup
,
164 .initclock
= cputimer_intr_default_initclock
,
165 .pcpuhand
= vmbus_timer_intr_pcpuhand
,
166 .next
= SLIST_ENTRY_INITIALIZER
,
168 .type
= CPUTIMER_INTR_VMM
,
169 .prio
= CPUTIMER_INTR_PRIO_VMM
,
170 .caps
= CPUTIMER_INTR_CAP_PS
,
174 static const uint32_t vmbus_version
[] = {
175 VMBUS_VERSION_WIN8_1
,
181 static int vmbus_timer_intr_enable
= 1;
182 TUNABLE_INT("hw.vmbus.timer_intr.enable", &vmbus_timer_intr_enable
);
185 vmbus_probe(device_t dev
)
187 char *id
[] = { "VMBUS", NULL
};
189 if (ACPI_ID_PROBE(device_get_parent(dev
), dev
, id
) == NULL
||
190 device_get_unit(dev
) != 0 || vmm_guest
!= VMM_GUEST_HYPERV
||
191 (hyperv_features
& CPUID_HV_MSR_SYNIC
) == 0)
194 device_set_desc(dev
, "Hyper-V vmbus");
200 vmbus_attach(device_t dev
)
202 struct vmbus_softc
*sc
= device_get_softc(dev
);
203 int error
, cpu
, unit
;
206 for (cpu
= 0; cpu
< ncpus
; ++cpu
) {
207 struct vmbus_pcpu_data
*psc
= VMBUS_PCPU(sc
, cpu
);
211 psc
->timer_last
= UINT64_MAX
;
213 unit
= device_get_unit(dev
);
216 * Create context for "post message" Hypercalls
218 sc
->vmbus_msg_hc
= vmbus_msghc_ctx_create(
219 bus_get_dma_tag(sc
->vmbus_dev
));
220 if (sc
->vmbus_msg_hc
== NULL
)
224 * Allocate DMA stuffs.
226 error
= vmbus_dma_alloc(sc
);
233 error
= vmbus_intr_setup(sc
);
239 * Make sure timer is stopped.
241 lwkt_cpusync_simple(smp_active_mask
, vmbus_timer_stop
, sc
);
247 lwkt_cpusync_simple(smp_active_mask
, vmbus_synic_setup
, sc
);
248 sc
->vmbus_flags
|= VMBUS_FLAG_SYNIC
;
253 error
= vmbus_init(sc
);
259 * Configure and register vmbus interrupt cputimer.
261 lwkt_cpusync_simple(smp_active_mask
, vmbus_timer_config
, sc
);
262 vmbus_cputimer_intr
.priv
= sc
;
263 cputimer_intr_register(&vmbus_cputimer_intr
);
264 if (vmbus_timer_intr_enable
)
265 cputimer_intr_select(&vmbus_cputimer_intr
, 0);
275 vmbus_detach(device_t dev
)
277 struct vmbus_softc
*sc
= device_get_softc(dev
);
279 /* TODO: uninitialize vmbus. */
280 /* TODO: stop and deregister timer */
282 if (sc
->vmbus_flags
& VMBUS_FLAG_SYNIC
)
283 lwkt_cpusync_simple(smp_active_mask
, vmbus_synic_teardown
, sc
);
284 vmbus_intr_teardown(sc
);
287 if (sc
->vmbus_msg_hc
!= NULL
) {
288 vmbus_msghc_ctx_destroy(sc
->vmbus_msg_hc
);
289 sc
->vmbus_msg_hc
= NULL
;
295 vmbus_intr(void *xpsc
)
297 struct vmbus_pcpu_data
*psc
= xpsc
;
298 volatile struct vmbus_message
*msg
;
300 msg
= psc
->message
+ VMBUS_SINT_MESSAGE
;
301 while (__predict_false(msg
->msg_type
!= HYPERV_MSGTYPE_NONE
)) {
302 if (msg
->msg_type
== HYPERV_MSGTYPE_CHANNEL
) {
303 /* Channel message */
304 vmbus_chan_msgproc(psc
->sc
,
305 __DEVOLATILE(const struct vmbus_message
*, msg
));
308 msg
->msg_type
= HYPERV_MSGTYPE_NONE
;
310 * Make sure the write to msg_type (i.e. set to
311 * HYPERV_MSGTYPE_NONE) happens before we read the
312 * msg_flags and EOMing. Otherwise, the EOMing will
313 * not deliver any more messages since there is no
317 if (msg
->msg_flags
& VMBUS_MSGFLAG_PENDING
) {
319 * This will cause message queue rescan to possibly
320 * deliver another msg from the hypervisor
322 wrmsr(MSR_HV_EOM
, 0);
328 vmbus_timer_oneshot(struct vmbus_pcpu_data
*psc
, uint64_t current
)
330 psc
->timer_last
= current
;
331 wrmsr(MSR_HV_STIMER0_COUNT
, current
);
335 vmbus_timer_intr_reload(struct cputimer_intr
*cti
, sysclock_t reload
)
337 struct globaldata
*gd
= mycpu
;
338 struct vmbus_softc
*sc
= cti
->priv
;
339 struct vmbus_pcpu_data
*psc
= VMBUS_PCPU(sc
, gd
->gd_cpuid
);
342 reload
= (uint64_t)reload
* cti
->freq
/ sys_cputimer
->freq
;
343 current
= rdmsr(MSR_HV_TIME_REF_COUNT
) + reload
;
345 if (gd
->gd_timer_running
) {
346 if (current
< psc
->timer_last
)
347 vmbus_timer_oneshot(psc
, current
);
349 gd
->gd_timer_running
= 1;
350 vmbus_timer_oneshot(psc
, current
);
355 vmbus_timer_intr_pcpuhand(struct cputimer_intr
*cti
)
357 struct vmbus_softc
*sc
= cti
->priv
;
358 struct vmbus_pcpu_data
*psc
= VMBUS_PCPU(sc
, mycpuid
);
360 vmbus_timer_msgintr(psc
);
364 vmbus_timer_intr_restart(struct cputimer_intr
*cti
)
366 lwkt_send_ipiq_mask(smp_active_mask
, vmbus_timer_restart
, cti
->priv
);
369 static struct vmbus_msghc
*
370 vmbus_msghc_alloc(bus_dma_tag_t parent_dtag
)
372 struct vmbus_msghc
*mh
;
374 mh
= kmalloc(sizeof(*mh
), M_DEVBUF
, M_WAITOK
| M_ZERO
);
376 mh
->mh_inprm
= hyperv_dmamem_alloc(parent_dtag
,
377 HYPERCALL_POSTMSGIN_ALIGN
, 0, HYPERCALL_POSTMSGIN_SIZE
,
378 &mh
->mh_inprm_dma
, BUS_DMA_WAITOK
);
379 if (mh
->mh_inprm
== NULL
) {
387 vmbus_msghc_free(struct vmbus_msghc
*mh
)
389 hyperv_dmamem_free(&mh
->mh_inprm_dma
, mh
->mh_inprm
);
394 vmbus_msghc_ctx_free(struct vmbus_msghc_ctx
*mhc
)
396 KASSERT(mhc
->mhc_active
== NULL
, ("still have active msg hypercall"));
397 KASSERT(mhc
->mhc_free
== NULL
, ("still have hypercall msg"));
399 lwkt_token_uninit(&mhc
->mhc_free_token
);
400 lwkt_token_uninit(&mhc
->mhc_active_token
);
401 kfree(mhc
, M_DEVBUF
);
404 static struct vmbus_msghc_ctx
*
405 vmbus_msghc_ctx_create(bus_dma_tag_t parent_dtag
)
407 struct vmbus_msghc_ctx
*mhc
;
409 mhc
= kmalloc(sizeof(*mhc
), M_DEVBUF
, M_WAITOK
| M_ZERO
);
410 lwkt_token_init(&mhc
->mhc_free_token
, "msghcf");
411 lwkt_token_init(&mhc
->mhc_active_token
, "msghca");
413 mhc
->mhc_free
= vmbus_msghc_alloc(parent_dtag
);
414 if (mhc
->mhc_free
== NULL
) {
415 vmbus_msghc_ctx_free(mhc
);
421 static struct vmbus_msghc
*
422 vmbus_msghc_get1(struct vmbus_msghc_ctx
*mhc
, uint32_t dtor_flag
)
424 struct vmbus_msghc
*mh
;
426 lwkt_gettoken(&mhc
->mhc_free_token
);
428 while ((mhc
->mhc_flags
& dtor_flag
) == 0 && mhc
->mhc_free
== NULL
)
429 tsleep(&mhc
->mhc_free
, 0, "gmsghc", 0);
430 if (mhc
->mhc_flags
& dtor_flag
) {
431 /* Being destroyed */
435 KASSERT(mh
!= NULL
, ("no free hypercall msg"));
436 KASSERT(mh
->mh_resp
== NULL
,
437 ("hypercall msg has pending response"));
438 mhc
->mhc_free
= NULL
;
441 lwkt_reltoken(&mhc
->mhc_free_token
);
447 vmbus_msghc_get(struct vmbus_softc
*sc
, size_t dsize
)
449 struct hypercall_postmsg_in
*inprm
;
450 struct vmbus_msghc
*mh
;
452 if (dsize
> HYPERCALL_POSTMSGIN_DSIZE_MAX
)
455 mh
= vmbus_msghc_get1(sc
->vmbus_msg_hc
, VMBUS_MSGHC_CTXF_DESTROY
);
459 inprm
= mh
->mh_inprm
;
460 memset(inprm
, 0, HYPERCALL_POSTMSGIN_SIZE
);
461 inprm
->hc_connid
= VMBUS_CONNID_MESSAGE
;
462 inprm
->hc_msgtype
= HYPERV_MSGTYPE_CHANNEL
;
463 inprm
->hc_dsize
= dsize
;
469 vmbus_msghc_put(struct vmbus_softc
*sc
, struct vmbus_msghc
*mh
)
471 struct vmbus_msghc_ctx
*mhc
= sc
->vmbus_msg_hc
;
473 KASSERT(mhc
->mhc_active
== NULL
, ("msg hypercall is active"));
476 lwkt_gettoken(&mhc
->mhc_free_token
);
477 KASSERT(mhc
->mhc_free
== NULL
, ("has free hypercall msg"));
479 lwkt_reltoken(&mhc
->mhc_free_token
);
480 wakeup(&mhc
->mhc_free
);
484 vmbus_msghc_dataptr(struct vmbus_msghc
*mh
)
486 return mh
->mh_inprm
->hc_data
;
490 vmbus_msghc_ctx_destroy(struct vmbus_msghc_ctx
*mhc
)
492 struct vmbus_msghc
*mh
;
494 lwkt_gettoken(&mhc
->mhc_free_token
);
495 mhc
->mhc_flags
|= VMBUS_MSGHC_CTXF_DESTROY
;
496 lwkt_reltoken(&mhc
->mhc_free_token
);
497 wakeup(&mhc
->mhc_free
);
499 mh
= vmbus_msghc_get1(mhc
, 0);
501 panic("can't get msghc");
503 vmbus_msghc_free(mh
);
504 vmbus_msghc_ctx_free(mhc
);
508 vmbus_msghc_exec_noresult(struct vmbus_msghc
*mh
)
510 int i
, wait_ticks
= 1;
513 * Save the input parameter so that we could restore the input
514 * parameter if the Hypercall failed.
517 * Is this really necessary?! i.e. Will the Hypercall ever
518 * overwrite the input parameter?
520 memcpy(&mh
->mh_inprm_save
, mh
->mh_inprm
, HYPERCALL_POSTMSGIN_SIZE
);
523 * In order to cope with transient failures, e.g. insufficient
524 * resources on host side, we retry the post message Hypercall
525 * several times. 20 retries seem sufficient.
527 #define HC_RETRY_MAX 20
529 for (i
= 0; i
< HC_RETRY_MAX
; ++i
) {
532 status
= hypercall_post_message(mh
->mh_inprm_dma
.hv_paddr
);
533 if (status
== HYPERCALL_STATUS_SUCCESS
)
536 tsleep(&status
, 0, "hcpmsg", wait_ticks
);
540 /* Restore input parameter and try again */
541 memcpy(mh
->mh_inprm
, &mh
->mh_inprm_save
,
542 HYPERCALL_POSTMSGIN_SIZE
);
551 vmbus_msghc_exec(struct vmbus_softc
*sc
, struct vmbus_msghc
*mh
)
553 struct vmbus_msghc_ctx
*mhc
= sc
->vmbus_msg_hc
;
556 KASSERT(mh
->mh_resp
== NULL
, ("hypercall msg has pending response"));
558 lwkt_gettoken(&mhc
->mhc_active_token
);
559 KASSERT(mhc
->mhc_active
== NULL
, ("pending active msg hypercall"));
560 mhc
->mhc_active
= mh
;
561 lwkt_reltoken(&mhc
->mhc_active_token
);
563 error
= vmbus_msghc_exec_noresult(mh
);
565 lwkt_gettoken(&mhc
->mhc_active_token
);
566 KASSERT(mhc
->mhc_active
== mh
, ("msghc mismatch"));
567 mhc
->mhc_active
= NULL
;
568 lwkt_reltoken(&mhc
->mhc_active_token
);
573 const struct vmbus_message
*
574 vmbus_msghc_wait_result(struct vmbus_softc
*sc
, struct vmbus_msghc
*mh
)
576 struct vmbus_msghc_ctx
*mhc
= sc
->vmbus_msg_hc
;
578 lwkt_gettoken(&mhc
->mhc_active_token
);
580 KASSERT(mhc
->mhc_active
== mh
, ("msghc mismatch"));
581 while (mh
->mh_resp
== NULL
)
582 tsleep(&mhc
->mhc_active
, 0, "wmsghc", 0);
583 mhc
->mhc_active
= NULL
;
585 lwkt_reltoken(&mhc
->mhc_active_token
);
591 vmbus_msghc_wakeup(struct vmbus_softc
*sc
, const struct vmbus_message
*msg
)
593 struct vmbus_msghc_ctx
*mhc
= sc
->vmbus_msg_hc
;
594 struct vmbus_msghc
*mh
;
596 lwkt_gettoken(&mhc
->mhc_active_token
);
598 mh
= mhc
->mhc_active
;
599 KASSERT(mh
!= NULL
, ("no pending msg hypercall"));
600 memcpy(&mh
->mh_resp0
, msg
, sizeof(mh
->mh_resp0
));
601 mh
->mh_resp
= &mh
->mh_resp0
;
603 lwkt_reltoken(&mhc
->mhc_active_token
);
604 wakeup(&mhc
->mhc_active
);
608 vmbus_dma_alloc(struct vmbus_softc
*sc
)
610 bus_dma_tag_t parent_dtag
;
614 parent_dtag
= bus_get_dma_tag(sc
->vmbus_dev
);
615 for (cpu
= 0; cpu
< ncpus
; ++cpu
) {
616 struct vmbus_pcpu_data
*psc
= VMBUS_PCPU(sc
, cpu
);
619 * Per-cpu messages and event flags.
621 psc
->message
= hyperv_dmamem_alloc(parent_dtag
,
622 PAGE_SIZE
, 0, PAGE_SIZE
, &psc
->message_dma
,
623 BUS_DMA_WAITOK
| BUS_DMA_ZERO
);
624 if (psc
->message
== NULL
)
627 psc
->event_flags
= hyperv_dmamem_alloc(parent_dtag
,
628 PAGE_SIZE
, 0, PAGE_SIZE
, &psc
->event_flags_dma
,
629 BUS_DMA_WAITOK
| BUS_DMA_ZERO
);
630 if (psc
->event_flags
== NULL
)
634 evtflags
= hyperv_dmamem_alloc(parent_dtag
, PAGE_SIZE
, 0,
635 PAGE_SIZE
, &sc
->vmbus_evtflags_dma
, BUS_DMA_WAITOK
| BUS_DMA_ZERO
);
636 if (evtflags
== NULL
)
638 sc
->vmbus_rx_evtflags
= (u_long
*)evtflags
;
639 sc
->vmbus_tx_evtflags
= (u_long
*)(evtflags
+ (PAGE_SIZE
/ 2));
640 sc
->vmbus_evtflags
= evtflags
;
642 sc
->vmbus_mnf1
= hyperv_dmamem_alloc(parent_dtag
, PAGE_SIZE
, 0,
643 PAGE_SIZE
, &sc
->vmbus_mnf1_dma
, BUS_DMA_WAITOK
| BUS_DMA_ZERO
);
644 if (sc
->vmbus_mnf1
== NULL
)
647 sc
->vmbus_mnf2
= hyperv_dmamem_alloc(parent_dtag
, PAGE_SIZE
, 0,
648 PAGE_SIZE
, &sc
->vmbus_mnf2_dma
, BUS_DMA_WAITOK
| BUS_DMA_ZERO
);
649 if (sc
->vmbus_mnf2
== NULL
)
656 vmbus_dma_free(struct vmbus_softc
*sc
)
660 if (sc
->vmbus_evtflags
!= NULL
) {
661 hyperv_dmamem_free(&sc
->vmbus_evtflags_dma
, sc
->vmbus_evtflags
);
662 sc
->vmbus_evtflags
= NULL
;
663 sc
->vmbus_rx_evtflags
= NULL
;
664 sc
->vmbus_tx_evtflags
= NULL
;
666 if (sc
->vmbus_mnf1
!= NULL
) {
667 hyperv_dmamem_free(&sc
->vmbus_mnf1_dma
, sc
->vmbus_mnf1
);
668 sc
->vmbus_mnf1
= NULL
;
670 if (sc
->vmbus_mnf2
!= NULL
) {
671 hyperv_dmamem_free(&sc
->vmbus_mnf2_dma
, sc
->vmbus_mnf2
);
672 sc
->vmbus_mnf2
= NULL
;
675 for (cpu
= 0; cpu
< ncpus
; ++cpu
) {
676 struct vmbus_pcpu_data
*psc
= VMBUS_PCPU(sc
, cpu
);
678 if (psc
->message
!= NULL
) {
679 hyperv_dmamem_free(&psc
->message_dma
, psc
->message
);
682 if (psc
->event_flags
!= NULL
) {
683 hyperv_dmamem_free(&psc
->event_flags_dma
,
685 psc
->event_flags
= NULL
;
691 vmbus_intr_rid(struct resource_list
*rl
, int rid
)
695 if (resource_list_find(rl
, SYS_RES_IRQ
, rid
) == NULL
)
702 vmbus_intr_setup(struct vmbus_softc
*sc
)
704 device_t dev
= sc
->vmbus_dev
;
705 device_t parent
= device_get_parent(dev
);
706 device_t bus
= device_get_parent(parent
);
707 struct resource_list
*rl
;
710 rl
= BUS_GET_RESOURCE_LIST(parent
, dev
);
715 for (cpu
= 0; cpu
< ncpus
; ++cpu
) {
716 struct vmbus_pcpu_data
*psc
= VMBUS_PCPU(sc
, cpu
);
717 struct resource
*res
;
722 error
= PCIB_ALLOC_MSIX(bus
, dev
, &irq
, cpu
);
724 device_printf(dev
, "alloc vector on cpu%d failed: %d\n",
728 rid
= vmbus_intr_rid(rl
, rid
);
729 resource_list_add(rl
, SYS_RES_IRQ
, rid
, irq
, irq
, 1, cpu
);
732 res
= bus_alloc_resource_any(dev
, SYS_RES_IRQ
, &rid
, RF_ACTIVE
);
734 device_printf(dev
, "alloc irq on cpu%d failed: %d\n",
740 error
= PCIB_MAP_MSI(bus
, dev
, rman_get_start(res
),
741 &msi_addr
, &msi_data
, cpu
);
743 device_printf(dev
, "map irq on cpu%d failed: %d\n",
747 psc
->intr_vec
= hyperv_msi2vector(msi_addr
, msi_data
);
750 device_printf(dev
, "vector %d irq %d on cpu%d\n",
751 psc
->intr_vec
, irq
, cpu
);
754 ksnprintf(psc
->intr_desc
, sizeof(psc
->intr_desc
), "%s cpu%d",
755 device_get_nameunit(dev
), cpu
);
756 error
= bus_setup_intr_descr(dev
, res
, INTR_MPSAFE
, vmbus_intr
,
757 psc
, &psc
->intr_hand
, NULL
, psc
->intr_desc
);
759 device_printf(dev
, "setup intr on cpu%d failed: %d\n",
768 vmbus_intr_teardown(struct vmbus_softc
*sc
)
770 device_t dev
= sc
->vmbus_dev
;
771 device_t parent
= device_get_parent(dev
);
772 struct resource_list
*rl
;
775 rl
= BUS_GET_RESOURCE_LIST(parent
, dev
);
779 for (cpu
= 0; cpu
< ncpus
; ++cpu
) {
780 struct vmbus_pcpu_data
*psc
= VMBUS_PCPU(sc
, cpu
);
782 if (psc
->intr_hand
!= NULL
) {
783 bus_teardown_intr(dev
, psc
->intr_res
, psc
->intr_hand
);
784 psc
->intr_hand
= NULL
;
787 if (psc
->intr_res
!= NULL
) {
788 bus_release_resource(dev
, SYS_RES_IRQ
, psc
->intr_rid
,
790 psc
->intr_res
= NULL
;
793 if (psc
->intr_rid
!= 0) {
794 struct resource_list_entry
*rle
;
797 rle
= resource_list_find(rl
, SYS_RES_IRQ
,
800 resource_list_delete(rl
, SYS_RES_IRQ
, psc
->intr_rid
);
802 PCIB_RELEASE_MSIX(device_get_parent(parent
), dev
, irq
,
810 vmbus_synic_setup(void *xsc
)
812 struct vmbus_softc
*sc
= xsc
;
813 struct vmbus_pcpu_data
*psc
= VMBUS_PCPU(sc
, mycpuid
);
817 if (hyperv_features
& CPUID_HV_MSR_VP_INDEX
) {
819 * Save virtual processor id.
821 psc
->vcpuid
= rdmsr(MSR_HV_VP_INDEX
);
825 * Virtual processoor id is only used by a pretty broken
826 * channel selection code from storvsc. It's nothing
827 * critical even if CPUID_HV_MSR_VP_INDEX is not set; keep
830 psc
->vcpuid
= mycpuid
;
834 * Setup the SynIC message.
836 orig
= rdmsr(MSR_HV_SIMP
);
837 val
= MSR_HV_SIMP_ENABLE
| (orig
& MSR_HV_SIMP_RSVD_MASK
) |
838 ((psc
->message_dma
.hv_paddr
>> PAGE_SHIFT
) << MSR_HV_SIMP_PGSHIFT
);
839 wrmsr(MSR_HV_SIMP
, val
);
842 * Setup the SynIC event flags.
844 orig
= rdmsr(MSR_HV_SIEFP
);
845 val
= MSR_HV_SIEFP_ENABLE
| (orig
& MSR_HV_SIEFP_RSVD_MASK
) |
846 ((psc
->event_flags_dma
.hv_paddr
>> PAGE_SHIFT
) <<
847 MSR_HV_SIEFP_PGSHIFT
);
848 wrmsr(MSR_HV_SIEFP
, val
);
852 * Configure and unmask SINT for message and event flags.
854 sint
= MSR_HV_SINT0
+ VMBUS_SINT_MESSAGE
;
856 val
= psc
->intr_vec
| /* MSR_HV_SINT_AUTOEOI | notyet */
857 (orig
& MSR_HV_SINT_RSVD_MASK
);
861 * Configure and unmask SINT for timer.
863 sint
= MSR_HV_SINT0
+ VMBUS_SINT_TIMER
;
865 val
= XTIMER_OFFSET
| /* MSR_HV_SINT_AUTOEOI | notyet */
866 (orig
& MSR_HV_SINT_RSVD_MASK
);
870 * All done; enable SynIC.
872 orig
= rdmsr(MSR_HV_SCONTROL
);
873 val
= MSR_HV_SCTRL_ENABLE
| (orig
& MSR_HV_SCTRL_RSVD_MASK
);
874 wrmsr(MSR_HV_SCONTROL
, val
);
878 vmbus_timer_stop(void *arg __unused
)
883 /* Stop counting, and this also implies disabling STIMER0 */
884 wrmsr(MSR_HV_STIMER0_COUNT
, 0);
886 val
= rdmsr(MSR_HV_STIMER0_CONFIG
);
887 if ((val
& MSR_HV_STIMER_CFG_ENABLE
) == 0)
894 vmbus_timer_config(void *arg __unused
)
897 * Make sure that STIMER0 is really disabled before writing
900 * "Writing to the configuration register of a timer that
901 * is already enabled may result in undefined behaviour."
903 vmbus_timer_stop(arg
);
904 wrmsr(MSR_HV_STIMER0_CONFIG
,
905 MSR_HV_STIMER_CFG_AUTOEN
| MSR_HV_STIMER0_CFG_SINT
);
909 vmbus_timer_msgintr(struct vmbus_pcpu_data
*psc
)
911 volatile struct vmbus_message
*msg
;
913 msg
= psc
->message
+ VMBUS_SINT_TIMER
;
914 if (msg
->msg_type
== HYPERV_MSGTYPE_TIMER_EXPIRED
) {
915 msg
->msg_type
= HYPERV_MSGTYPE_NONE
;
918 * Make sure the write to msg_type (i.e. set to
919 * HYPERV_MSGTYPE_NONE) happens before we read the
920 * msg_flags and EOMing. Otherwise, the EOMing will
921 * not deliver any more messages since there is no
925 if (msg
->msg_flags
& VMBUS_MSGFLAG_PENDING
) {
927 * This will cause message queue rescan to possibly
928 * deliver another msg from the hypervisor
930 wrmsr(MSR_HV_EOM
, 0);
936 vmbus_timer_restart(void *xsc
)
938 struct vmbus_softc
*sc
= xsc
;
939 struct vmbus_pcpu_data
*psc
= VMBUS_PCPU(sc
, mycpuid
);
942 vmbus_timer_msgintr(psc
);
943 vmbus_timer_oneshot(psc
, rdmsr(MSR_HV_TIME_REF_COUNT
) + 1);
948 vmbus_synic_teardown(void *arg __unused
)
956 orig
= rdmsr(MSR_HV_SCONTROL
);
957 wrmsr(MSR_HV_SCONTROL
, (orig
& MSR_HV_SCTRL_RSVD_MASK
));
960 * Mask message and event flags SINT.
962 sint
= MSR_HV_SINT0
+ VMBUS_SINT_MESSAGE
;
964 wrmsr(sint
, orig
| MSR_HV_SINT_MASKED
);
969 sint
= MSR_HV_SINT0
+ VMBUS_SINT_TIMER
;
971 wrmsr(sint
, orig
| MSR_HV_SINT_MASKED
);
974 * Teardown SynIC message.
976 orig
= rdmsr(MSR_HV_SIMP
);
977 wrmsr(MSR_HV_SIMP
, (orig
& MSR_HV_SIMP_RSVD_MASK
));
980 * Teardown SynIC event flags.
982 orig
= rdmsr(MSR_HV_SIEFP
);
983 wrmsr(MSR_HV_SIEFP
, (orig
& MSR_HV_SIEFP_RSVD_MASK
));
987 vmbus_init_contact(struct vmbus_softc
*sc
, uint32_t version
)
989 struct vmbus_chanmsg_init_contact
*req
;
990 const struct vmbus_chanmsg_version_resp
*resp
;
991 const struct vmbus_message
*msg
;
992 struct vmbus_msghc
*mh
;
995 mh
= vmbus_msghc_get(sc
, sizeof(*req
));
999 req
= vmbus_msghc_dataptr(mh
);
1000 req
->chm_hdr
.chm_type
= VMBUS_CHANMSG_TYPE_INIT_CONTACT
;
1001 req
->chm_ver
= version
;
1002 req
->chm_evtflags
= sc
->vmbus_evtflags_dma
.hv_paddr
;
1003 req
->chm_mnf1
= sc
->vmbus_mnf1_dma
.hv_paddr
;
1004 req
->chm_mnf2
= sc
->vmbus_mnf2_dma
.hv_paddr
;
1006 error
= vmbus_msghc_exec(sc
, mh
);
1008 vmbus_msghc_put(sc
, mh
);
1012 msg
= vmbus_msghc_wait_result(sc
, mh
);
1013 resp
= (const struct vmbus_chanmsg_version_resp
*)msg
->msg_data
;
1014 supp
= resp
->chm_supp
;
1016 vmbus_msghc_put(sc
, mh
);
1018 return (supp
? 0 : EOPNOTSUPP
);
1022 vmbus_init(struct vmbus_softc
*sc
)
1026 for (i
= 0; i
< nitems(vmbus_version
); ++i
) {
1029 error
= vmbus_init_contact(sc
, vmbus_version
[i
]);
1031 sc
->vmbus_version
= vmbus_version
[i
];
1032 device_printf(sc
->vmbus_dev
, "version %u.%u\n",
1033 (sc
->vmbus_version
>> 16),
1034 (sc
->vmbus_version
& 0xffff));
1042 vmbus_chan_msgproc(struct vmbus_softc
*sc
, const struct vmbus_message
*msg
)
1044 const struct vmbus_chanmsg_hdr
*hdr
;
1046 hdr
= (const struct vmbus_chanmsg_hdr
*)msg
->msg_data
;
1049 if (hdr
->chm_type
== VMBUS_CHANMSG_TYPE_VERSION_RESP
)
1050 vmbus_msghc_wakeup(sc
, msg
);