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 * Two additionally required features:
60 * - SynIC is needed for interrupt generation.
61 * - Time reference counter is needed to set ABS reference count to
64 #define CPUID_HV_TIMER_MASK (CPUID_HV_MSR_TIME_REFCNT | \
65 CPUID_HV_MSR_SYNIC | \
66 CPUID_HV_MSR_SYNTIMER)
69 * NOTE: DO NOT CHANGE THIS.
71 #define VMBUS_SINT_MESSAGE 2
74 * - DO NOT set it to the same value as VMBUS_SINT_MESSAGE.
75 * - DO NOT set it to 0.
77 #define VMBUS_SINT_TIMER 4
80 * NOTE: DO NOT CHANGE THESE
82 #define VMBUS_CONNID_MESSAGE 1
83 #define VMBUS_CONNID_EVENT 2
86 struct hypercall_postmsg_in
*mh_inprm
;
87 struct hypercall_postmsg_in mh_inprm_save
;
88 struct hyperv_dma mh_inprm_dma
;
90 struct vmbus_message
*mh_resp
;
91 struct vmbus_message mh_resp0
;
94 struct vmbus_msghc_ctx
{
95 struct vmbus_msghc
*mhc_free
;
96 struct lwkt_token mhc_free_token
;
99 struct vmbus_msghc
*mhc_active
;
100 struct lwkt_token mhc_active_token
;
103 #define VMBUS_MSGHC_CTXF_DESTROY 0x0001
105 static int vmbus_probe(device_t
);
106 static int vmbus_attach(device_t
);
107 static int vmbus_detach(device_t
);
108 static void vmbus_intr(void *);
109 static void vmbus_timer_intr_reload(struct cputimer_intr
*,
111 static void vmbus_timer_intr_pcpuhand(
112 struct cputimer_intr
*);
113 static void vmbus_timer_intr_restart(
114 struct cputimer_intr
*);
116 static int vmbus_dma_alloc(struct vmbus_softc
*);
117 static void vmbus_dma_free(struct vmbus_softc
*);
118 static int vmbus_intr_setup(struct vmbus_softc
*);
119 static void vmbus_intr_teardown(struct vmbus_softc
*);
120 static void vmbus_synic_setup(void *);
121 static void vmbus_synic_teardown(void *);
122 static void vmbus_timer_stop(void *);
123 static void vmbus_timer_config(void *);
124 static int vmbus_init(struct vmbus_softc
*);
125 static int vmbus_init_contact(struct vmbus_softc
*,
127 static void vmbus_timer_restart(void *);
128 static void vmbus_timer_msgintr(struct vmbus_pcpu_data
*);
130 static void vmbus_chan_msgproc(struct vmbus_softc
*,
131 const struct vmbus_message
*);
133 static struct vmbus_msghc_ctx
*vmbus_msghc_ctx_create(bus_dma_tag_t
);
134 static void vmbus_msghc_ctx_destroy(
135 struct vmbus_msghc_ctx
*);
136 static void vmbus_msghc_ctx_free(struct vmbus_msghc_ctx
*);
137 static struct vmbus_msghc
*vmbus_msghc_alloc(bus_dma_tag_t
);
138 static void vmbus_msghc_free(struct vmbus_msghc
*);
139 static struct vmbus_msghc
*vmbus_msghc_get1(struct vmbus_msghc_ctx
*,
142 static device_method_t vmbus_methods
[] = {
143 /* Device interface */
144 DEVMETHOD(device_probe
, vmbus_probe
),
145 DEVMETHOD(device_attach
, vmbus_attach
),
146 DEVMETHOD(device_detach
, vmbus_detach
),
147 DEVMETHOD(device_shutdown
, bus_generic_shutdown
),
148 DEVMETHOD(device_suspend
, bus_generic_suspend
),
149 DEVMETHOD(device_resume
, bus_generic_resume
),
154 static driver_t vmbus_driver
= {
157 sizeof(struct vmbus_softc
)
160 static devclass_t vmbus_devclass
;
162 DRIVER_MODULE(vmbus
, acpi
, vmbus_driver
, vmbus_devclass
, NULL
, NULL
);
163 MODULE_DEPEND(vmbus
, acpi
, 1, 1, 1);
164 MODULE_VERSION(vmbus
, 1);
166 static struct cputimer_intr vmbus_cputimer_intr
= {
167 .freq
= HYPERV_TIMER_FREQ
,
168 .reload
= vmbus_timer_intr_reload
,
169 .enable
= cputimer_intr_default_enable
,
170 .config
= cputimer_intr_default_config
,
171 .restart
= vmbus_timer_intr_restart
,
172 .pmfixup
= cputimer_intr_default_pmfixup
,
173 .initclock
= cputimer_intr_default_initclock
,
174 .pcpuhand
= vmbus_timer_intr_pcpuhand
,
175 .next
= SLIST_ENTRY_INITIALIZER
,
177 .type
= CPUTIMER_INTR_VMM
,
178 .prio
= CPUTIMER_INTR_PRIO_VMM
,
179 .caps
= CPUTIMER_INTR_CAP_PS
,
183 static const uint32_t vmbus_version
[] = {
184 VMBUS_VERSION_WIN8_1
,
190 static int vmbus_timer_intr_enable
= 1;
191 TUNABLE_INT("hw.vmbus.timer_intr.enable", &vmbus_timer_intr_enable
);
194 vmbus_probe(device_t dev
)
196 char *id
[] = { "VMBUS", NULL
};
198 if (ACPI_ID_PROBE(device_get_parent(dev
), dev
, id
) == NULL
||
199 device_get_unit(dev
) != 0 || vmm_guest
!= VMM_GUEST_HYPERV
||
200 (hyperv_features
& CPUID_HV_MSR_SYNIC
) == 0)
203 device_set_desc(dev
, "Hyper-V vmbus");
209 vmbus_attach(device_t dev
)
211 struct vmbus_softc
*sc
= device_get_softc(dev
);
212 int error
, cpu
, use_timer
;
218 for (cpu
= 0; cpu
< ncpus
; ++cpu
) {
219 struct vmbus_pcpu_data
*psc
= VMBUS_PCPU(sc
, cpu
);
223 psc
->timer_last
= UINT64_MAX
;
227 * Should we use interrupt timer?
230 if (device_get_unit(dev
) == 0 &&
231 (hyperv_features
& CPUID_HV_TIMER_MASK
) == CPUID_HV_TIMER_MASK
)
235 * Create context for "post message" Hypercalls
237 sc
->vmbus_msg_hc
= vmbus_msghc_ctx_create(
238 bus_get_dma_tag(sc
->vmbus_dev
));
239 if (sc
->vmbus_msg_hc
== NULL
)
243 * Allocate DMA stuffs.
245 error
= vmbus_dma_alloc(sc
);
252 error
= vmbus_intr_setup(sc
);
258 * Make sure that interrupt timer is stopped.
260 lwkt_cpusync_simple(smp_active_mask
, vmbus_timer_stop
, sc
);
266 lwkt_cpusync_simple(smp_active_mask
, vmbus_synic_setup
, sc
);
267 sc
->vmbus_flags
|= VMBUS_FLAG_SYNIC
;
272 error
= vmbus_init(sc
);
278 * Configure and register vmbus interrupt timer.
280 lwkt_cpusync_simple(smp_active_mask
, vmbus_timer_config
, sc
);
281 vmbus_cputimer_intr
.priv
= sc
;
282 cputimer_intr_register(&vmbus_cputimer_intr
);
283 if (vmbus_timer_intr_enable
)
284 cputimer_intr_select(&vmbus_cputimer_intr
, 0);
294 vmbus_detach(device_t dev
)
296 struct vmbus_softc
*sc
= device_get_softc(dev
);
298 /* TODO: uninitialize vmbus. */
299 /* TODO: stop and deregister timer */
301 if (sc
->vmbus_flags
& VMBUS_FLAG_SYNIC
)
302 lwkt_cpusync_simple(smp_active_mask
, vmbus_synic_teardown
, sc
);
303 vmbus_intr_teardown(sc
);
306 if (sc
->vmbus_msg_hc
!= NULL
) {
307 vmbus_msghc_ctx_destroy(sc
->vmbus_msg_hc
);
308 sc
->vmbus_msg_hc
= NULL
;
314 vmbus_msg_reset(volatile struct vmbus_message
*msg
)
316 msg
->msg_type
= HYPERV_MSGTYPE_NONE
;
318 * Make sure that the write to msg_type (i.e. set to
319 * HYPERV_MSGTYPE_NONE) happens before we read the
320 * msg_flags and send EOM to the hypervisor.
323 if (msg
->msg_flags
& VMBUS_MSGFLAG_PENDING
) {
325 * Ask the hypervisor to rescan message queue,
326 * and deliver new message if any.
328 wrmsr(MSR_HV_EOM
, 0);
333 vmbus_intr(void *xpsc
)
335 struct vmbus_pcpu_data
*psc
= xpsc
;
336 volatile struct vmbus_message
*msg
;
338 msg
= psc
->message
+ VMBUS_SINT_MESSAGE
;
339 while (__predict_false(msg
->msg_type
!= HYPERV_MSGTYPE_NONE
)) {
340 if (msg
->msg_type
== HYPERV_MSGTYPE_CHANNEL
) {
341 /* Channel message */
342 vmbus_chan_msgproc(psc
->sc
,
343 __DEVOLATILE(const struct vmbus_message
*, msg
));
345 vmbus_msg_reset(msg
);
350 vmbus_timer_oneshot(struct vmbus_pcpu_data
*psc
, uint64_t current
)
352 psc
->timer_last
= current
;
353 wrmsr(MSR_HV_STIMER0_COUNT
, current
);
357 vmbus_timer_intr_reload(struct cputimer_intr
*cti
, sysclock_t reload
)
359 struct globaldata
*gd
= mycpu
;
360 struct vmbus_softc
*sc
= cti
->priv
;
361 struct vmbus_pcpu_data
*psc
= VMBUS_PCPU(sc
, gd
->gd_cpuid
);
364 reload
= (uint64_t)reload
* cti
->freq
/ sys_cputimer
->freq
;
365 current
= rdmsr(MSR_HV_TIME_REF_COUNT
) + reload
;
367 if (gd
->gd_timer_running
) {
368 if (current
< psc
->timer_last
)
369 vmbus_timer_oneshot(psc
, current
);
371 gd
->gd_timer_running
= 1;
372 vmbus_timer_oneshot(psc
, current
);
377 vmbus_timer_intr_pcpuhand(struct cputimer_intr
*cti
)
379 struct vmbus_softc
*sc
= cti
->priv
;
380 struct vmbus_pcpu_data
*psc
= VMBUS_PCPU(sc
, mycpuid
);
382 vmbus_timer_msgintr(psc
);
386 vmbus_timer_intr_restart(struct cputimer_intr
*cti
)
388 lwkt_send_ipiq_mask(smp_active_mask
, vmbus_timer_restart
, cti
->priv
);
391 static struct vmbus_msghc
*
392 vmbus_msghc_alloc(bus_dma_tag_t parent_dtag
)
394 struct vmbus_msghc
*mh
;
396 mh
= kmalloc(sizeof(*mh
), M_DEVBUF
, M_WAITOK
| M_ZERO
);
398 mh
->mh_inprm
= hyperv_dmamem_alloc(parent_dtag
,
399 HYPERCALL_POSTMSGIN_ALIGN
, 0, HYPERCALL_POSTMSGIN_SIZE
,
400 &mh
->mh_inprm_dma
, BUS_DMA_WAITOK
);
401 if (mh
->mh_inprm
== NULL
) {
409 vmbus_msghc_free(struct vmbus_msghc
*mh
)
411 hyperv_dmamem_free(&mh
->mh_inprm_dma
, mh
->mh_inprm
);
416 vmbus_msghc_ctx_free(struct vmbus_msghc_ctx
*mhc
)
418 KASSERT(mhc
->mhc_active
== NULL
, ("still have active msg hypercall"));
419 KASSERT(mhc
->mhc_free
== NULL
, ("still have hypercall msg"));
421 lwkt_token_uninit(&mhc
->mhc_free_token
);
422 lwkt_token_uninit(&mhc
->mhc_active_token
);
423 kfree(mhc
, M_DEVBUF
);
426 static struct vmbus_msghc_ctx
*
427 vmbus_msghc_ctx_create(bus_dma_tag_t parent_dtag
)
429 struct vmbus_msghc_ctx
*mhc
;
431 mhc
= kmalloc(sizeof(*mhc
), M_DEVBUF
, M_WAITOK
| M_ZERO
);
432 lwkt_token_init(&mhc
->mhc_free_token
, "msghcf");
433 lwkt_token_init(&mhc
->mhc_active_token
, "msghca");
435 mhc
->mhc_free
= vmbus_msghc_alloc(parent_dtag
);
436 if (mhc
->mhc_free
== NULL
) {
437 vmbus_msghc_ctx_free(mhc
);
443 static struct vmbus_msghc
*
444 vmbus_msghc_get1(struct vmbus_msghc_ctx
*mhc
, uint32_t dtor_flag
)
446 struct vmbus_msghc
*mh
;
448 lwkt_gettoken(&mhc
->mhc_free_token
);
450 while ((mhc
->mhc_flags
& dtor_flag
) == 0 && mhc
->mhc_free
== NULL
)
451 tsleep(&mhc
->mhc_free
, 0, "gmsghc", 0);
452 if (mhc
->mhc_flags
& dtor_flag
) {
453 /* Being destroyed */
457 KASSERT(mh
!= NULL
, ("no free hypercall msg"));
458 KASSERT(mh
->mh_resp
== NULL
,
459 ("hypercall msg has pending response"));
460 mhc
->mhc_free
= NULL
;
463 lwkt_reltoken(&mhc
->mhc_free_token
);
469 vmbus_msghc_get(struct vmbus_softc
*sc
, size_t dsize
)
471 struct hypercall_postmsg_in
*inprm
;
472 struct vmbus_msghc
*mh
;
474 if (dsize
> HYPERCALL_POSTMSGIN_DSIZE_MAX
)
477 mh
= vmbus_msghc_get1(sc
->vmbus_msg_hc
, VMBUS_MSGHC_CTXF_DESTROY
);
481 inprm
= mh
->mh_inprm
;
482 memset(inprm
, 0, HYPERCALL_POSTMSGIN_SIZE
);
483 inprm
->hc_connid
= VMBUS_CONNID_MESSAGE
;
484 inprm
->hc_msgtype
= HYPERV_MSGTYPE_CHANNEL
;
485 inprm
->hc_dsize
= dsize
;
491 vmbus_msghc_put(struct vmbus_softc
*sc
, struct vmbus_msghc
*mh
)
493 struct vmbus_msghc_ctx
*mhc
= sc
->vmbus_msg_hc
;
495 KASSERT(mhc
->mhc_active
== NULL
, ("msg hypercall is active"));
498 lwkt_gettoken(&mhc
->mhc_free_token
);
499 KASSERT(mhc
->mhc_free
== NULL
, ("has free hypercall msg"));
501 lwkt_reltoken(&mhc
->mhc_free_token
);
502 wakeup(&mhc
->mhc_free
);
506 vmbus_msghc_dataptr(struct vmbus_msghc
*mh
)
508 return mh
->mh_inprm
->hc_data
;
512 vmbus_msghc_ctx_destroy(struct vmbus_msghc_ctx
*mhc
)
514 struct vmbus_msghc
*mh
;
516 lwkt_gettoken(&mhc
->mhc_free_token
);
517 mhc
->mhc_flags
|= VMBUS_MSGHC_CTXF_DESTROY
;
518 lwkt_reltoken(&mhc
->mhc_free_token
);
519 wakeup(&mhc
->mhc_free
);
521 mh
= vmbus_msghc_get1(mhc
, 0);
523 panic("can't get msghc");
525 vmbus_msghc_free(mh
);
526 vmbus_msghc_ctx_free(mhc
);
530 vmbus_msghc_exec_noresult(struct vmbus_msghc
*mh
)
532 int i
, wait_ticks
= 1;
535 * Save the input parameter so that we could restore the input
536 * parameter if the Hypercall failed.
539 * Is this really necessary?! i.e. Will the Hypercall ever
540 * overwrite the input parameter?
542 memcpy(&mh
->mh_inprm_save
, mh
->mh_inprm
, HYPERCALL_POSTMSGIN_SIZE
);
545 * In order to cope with transient failures, e.g. insufficient
546 * resources on host side, we retry the post message Hypercall
547 * several times. 20 retries seem sufficient.
549 #define HC_RETRY_MAX 20
551 for (i
= 0; i
< HC_RETRY_MAX
; ++i
) {
554 status
= hypercall_post_message(mh
->mh_inprm_dma
.hv_paddr
);
555 if (status
== HYPERCALL_STATUS_SUCCESS
)
558 tsleep(&status
, 0, "hcpmsg", wait_ticks
);
562 /* Restore input parameter and try again */
563 memcpy(mh
->mh_inprm
, &mh
->mh_inprm_save
,
564 HYPERCALL_POSTMSGIN_SIZE
);
573 vmbus_msghc_exec(struct vmbus_softc
*sc
, struct vmbus_msghc
*mh
)
575 struct vmbus_msghc_ctx
*mhc
= sc
->vmbus_msg_hc
;
578 KASSERT(mh
->mh_resp
== NULL
, ("hypercall msg has pending response"));
580 lwkt_gettoken(&mhc
->mhc_active_token
);
581 KASSERT(mhc
->mhc_active
== NULL
, ("pending active msg hypercall"));
582 mhc
->mhc_active
= mh
;
583 lwkt_reltoken(&mhc
->mhc_active_token
);
585 error
= vmbus_msghc_exec_noresult(mh
);
587 lwkt_gettoken(&mhc
->mhc_active_token
);
588 KASSERT(mhc
->mhc_active
== mh
, ("msghc mismatch"));
589 mhc
->mhc_active
= NULL
;
590 lwkt_reltoken(&mhc
->mhc_active_token
);
595 const struct vmbus_message
*
596 vmbus_msghc_wait_result(struct vmbus_softc
*sc
, struct vmbus_msghc
*mh
)
598 struct vmbus_msghc_ctx
*mhc
= sc
->vmbus_msg_hc
;
600 lwkt_gettoken(&mhc
->mhc_active_token
);
602 KASSERT(mhc
->mhc_active
== mh
, ("msghc mismatch"));
603 while (mh
->mh_resp
== NULL
)
604 tsleep(&mhc
->mhc_active
, 0, "wmsghc", 0);
605 mhc
->mhc_active
= NULL
;
607 lwkt_reltoken(&mhc
->mhc_active_token
);
613 vmbus_msghc_wakeup(struct vmbus_softc
*sc
, const struct vmbus_message
*msg
)
615 struct vmbus_msghc_ctx
*mhc
= sc
->vmbus_msg_hc
;
616 struct vmbus_msghc
*mh
;
618 lwkt_gettoken(&mhc
->mhc_active_token
);
620 mh
= mhc
->mhc_active
;
621 KASSERT(mh
!= NULL
, ("no pending msg hypercall"));
622 memcpy(&mh
->mh_resp0
, msg
, sizeof(mh
->mh_resp0
));
623 mh
->mh_resp
= &mh
->mh_resp0
;
625 lwkt_reltoken(&mhc
->mhc_active_token
);
626 wakeup(&mhc
->mhc_active
);
630 vmbus_dma_alloc(struct vmbus_softc
*sc
)
632 bus_dma_tag_t parent_dtag
;
636 parent_dtag
= bus_get_dma_tag(sc
->vmbus_dev
);
637 for (cpu
= 0; cpu
< ncpus
; ++cpu
) {
638 struct vmbus_pcpu_data
*psc
= VMBUS_PCPU(sc
, cpu
);
641 * Per-cpu messages and event flags.
643 psc
->message
= hyperv_dmamem_alloc(parent_dtag
,
644 PAGE_SIZE
, 0, PAGE_SIZE
, &psc
->message_dma
,
645 BUS_DMA_WAITOK
| BUS_DMA_ZERO
);
646 if (psc
->message
== NULL
)
649 psc
->event_flags
= hyperv_dmamem_alloc(parent_dtag
,
650 PAGE_SIZE
, 0, PAGE_SIZE
, &psc
->event_flags_dma
,
651 BUS_DMA_WAITOK
| BUS_DMA_ZERO
);
652 if (psc
->event_flags
== NULL
)
656 evtflags
= hyperv_dmamem_alloc(parent_dtag
, PAGE_SIZE
, 0,
657 PAGE_SIZE
, &sc
->vmbus_evtflags_dma
, BUS_DMA_WAITOK
| BUS_DMA_ZERO
);
658 if (evtflags
== NULL
)
660 sc
->vmbus_rx_evtflags
= (u_long
*)evtflags
;
661 sc
->vmbus_tx_evtflags
= (u_long
*)(evtflags
+ (PAGE_SIZE
/ 2));
662 sc
->vmbus_evtflags
= evtflags
;
664 sc
->vmbus_mnf1
= hyperv_dmamem_alloc(parent_dtag
, PAGE_SIZE
, 0,
665 PAGE_SIZE
, &sc
->vmbus_mnf1_dma
, BUS_DMA_WAITOK
| BUS_DMA_ZERO
);
666 if (sc
->vmbus_mnf1
== NULL
)
669 sc
->vmbus_mnf2
= hyperv_dmamem_alloc(parent_dtag
, PAGE_SIZE
, 0,
670 PAGE_SIZE
, &sc
->vmbus_mnf2_dma
, BUS_DMA_WAITOK
| BUS_DMA_ZERO
);
671 if (sc
->vmbus_mnf2
== NULL
)
678 vmbus_dma_free(struct vmbus_softc
*sc
)
682 if (sc
->vmbus_evtflags
!= NULL
) {
683 hyperv_dmamem_free(&sc
->vmbus_evtflags_dma
, sc
->vmbus_evtflags
);
684 sc
->vmbus_evtflags
= NULL
;
685 sc
->vmbus_rx_evtflags
= NULL
;
686 sc
->vmbus_tx_evtflags
= NULL
;
688 if (sc
->vmbus_mnf1
!= NULL
) {
689 hyperv_dmamem_free(&sc
->vmbus_mnf1_dma
, sc
->vmbus_mnf1
);
690 sc
->vmbus_mnf1
= NULL
;
692 if (sc
->vmbus_mnf2
!= NULL
) {
693 hyperv_dmamem_free(&sc
->vmbus_mnf2_dma
, sc
->vmbus_mnf2
);
694 sc
->vmbus_mnf2
= NULL
;
697 for (cpu
= 0; cpu
< ncpus
; ++cpu
) {
698 struct vmbus_pcpu_data
*psc
= VMBUS_PCPU(sc
, cpu
);
700 if (psc
->message
!= NULL
) {
701 hyperv_dmamem_free(&psc
->message_dma
, psc
->message
);
704 if (psc
->event_flags
!= NULL
) {
705 hyperv_dmamem_free(&psc
->event_flags_dma
,
707 psc
->event_flags
= NULL
;
713 vmbus_intr_setup(struct vmbus_softc
*sc
)
715 device_t dev
= sc
->vmbus_dev
;
716 device_t bus
= device_get_parent(device_get_parent(dev
));
720 for (cpu
= 0; cpu
< ncpus
; ++cpu
) {
721 struct vmbus_pcpu_data
*psc
= VMBUS_PCPU(sc
, cpu
);
726 error
= PCIB_ALLOC_MSIX(bus
, dev
, &psc
->intr_irq
, cpu
);
728 device_printf(dev
, "alloc vector on cpu%d failed: %d\n",
732 psc
->intr_rid
= ++rid
;
734 psc
->intr_res
= BUS_ALLOC_RESOURCE(bus
, dev
, SYS_RES_IRQ
,
735 &psc
->intr_rid
, psc
->intr_irq
, psc
->intr_irq
, 1,
737 if (psc
->intr_res
== NULL
) {
738 device_printf(dev
, "alloc irq on cpu%d failed: %d\n",
743 error
= PCIB_MAP_MSI(bus
, dev
, rman_get_start(psc
->intr_res
),
744 &msi_addr
, &msi_data
, cpu
);
746 device_printf(dev
, "map irq on cpu%d failed: %d\n",
750 psc
->intr_vec
= hyperv_msi2vector(msi_addr
, msi_data
);
753 device_printf(dev
, "vector %d irq %d on cpu%d\n",
754 psc
->intr_vec
, psc
->intr_irq
, cpu
);
757 ksnprintf(psc
->intr_desc
, sizeof(psc
->intr_desc
), "%s cpu%d",
758 device_get_nameunit(dev
), cpu
);
759 error
= bus_setup_intr_descr(dev
, psc
->intr_res
, INTR_MPSAFE
,
760 vmbus_intr
, psc
, &psc
->intr_hand
, NULL
, psc
->intr_desc
);
762 device_printf(dev
, "setup intr on cpu%d failed: %d\n",
771 vmbus_intr_teardown(struct vmbus_softc
*sc
)
773 device_t dev
= sc
->vmbus_dev
;
774 device_t bus
= device_get_parent(device_get_parent(dev
));
777 for (cpu
= 0; cpu
< ncpus
; ++cpu
) {
778 struct vmbus_pcpu_data
*psc
= VMBUS_PCPU(sc
, cpu
);
780 if (psc
->intr_hand
!= NULL
) {
781 bus_teardown_intr(dev
, psc
->intr_res
, psc
->intr_hand
);
782 psc
->intr_hand
= NULL
;
785 if (psc
->intr_res
!= NULL
) {
786 BUS_RELEASE_RESOURCE(bus
, dev
, SYS_RES_IRQ
,
787 psc
->intr_rid
, psc
->intr_res
);
788 psc
->intr_res
= NULL
;
791 if (psc
->intr_rid
!= 0) {
792 PCIB_RELEASE_MSIX(bus
, dev
, psc
->intr_irq
, psc
->cpuid
);
799 vmbus_synic_setup(void *xsc
)
801 struct vmbus_softc
*sc
= xsc
;
802 struct vmbus_pcpu_data
*psc
= VMBUS_PCPU(sc
, mycpuid
);
806 if (hyperv_features
& CPUID_HV_MSR_VP_INDEX
) {
808 * Save virtual processor id.
810 psc
->vcpuid
= rdmsr(MSR_HV_VP_INDEX
);
814 * Virtual processoor id is only used by a pretty broken
815 * channel selection code from storvsc. It's nothing
816 * critical even if CPUID_HV_MSR_VP_INDEX is not set; keep
819 psc
->vcpuid
= mycpuid
;
823 * Setup the SynIC message.
825 orig
= rdmsr(MSR_HV_SIMP
);
826 val
= MSR_HV_SIMP_ENABLE
| (orig
& MSR_HV_SIMP_RSVD_MASK
) |
827 ((psc
->message_dma
.hv_paddr
>> PAGE_SHIFT
) << MSR_HV_SIMP_PGSHIFT
);
828 wrmsr(MSR_HV_SIMP
, val
);
831 * Setup the SynIC event flags.
833 orig
= rdmsr(MSR_HV_SIEFP
);
834 val
= MSR_HV_SIEFP_ENABLE
| (orig
& MSR_HV_SIEFP_RSVD_MASK
) |
835 ((psc
->event_flags_dma
.hv_paddr
>> PAGE_SHIFT
) <<
836 MSR_HV_SIEFP_PGSHIFT
);
837 wrmsr(MSR_HV_SIEFP
, val
);
841 * Configure and unmask SINT for message and event flags.
843 sint
= MSR_HV_SINT0
+ VMBUS_SINT_MESSAGE
;
845 val
= psc
->intr_vec
| /* MSR_HV_SINT_AUTOEOI | notyet */
846 (orig
& MSR_HV_SINT_RSVD_MASK
);
850 * Configure and unmask SINT for timer.
852 sint
= MSR_HV_SINT0
+ VMBUS_SINT_TIMER
;
854 val
= XTIMER_OFFSET
| /* MSR_HV_SINT_AUTOEOI | notyet */
855 (orig
& MSR_HV_SINT_RSVD_MASK
);
859 * All done; enable SynIC.
861 orig
= rdmsr(MSR_HV_SCONTROL
);
862 val
= MSR_HV_SCTRL_ENABLE
| (orig
& MSR_HV_SCTRL_RSVD_MASK
);
863 wrmsr(MSR_HV_SCONTROL
, val
);
867 vmbus_timer_stop(void *arg __unused
)
872 /* Stop counting, and this also implies disabling STIMER0 */
873 wrmsr(MSR_HV_STIMER0_COUNT
, 0);
875 val
= rdmsr(MSR_HV_STIMER0_CONFIG
);
876 if ((val
& MSR_HV_STIMER_CFG_ENABLE
) == 0)
883 vmbus_timer_config(void *arg __unused
)
886 * Make sure that STIMER0 is really disabled before writing
889 * "Writing to the configuration register of a timer that
890 * is already enabled may result in undefined behaviour."
892 vmbus_timer_stop(arg
);
893 wrmsr(MSR_HV_STIMER0_CONFIG
,
894 MSR_HV_STIMER_CFG_AUTOEN
| MSR_HV_STIMER0_CFG_SINT
);
898 vmbus_timer_msgintr(struct vmbus_pcpu_data
*psc
)
900 volatile struct vmbus_message
*msg
;
902 msg
= psc
->message
+ VMBUS_SINT_TIMER
;
903 if (msg
->msg_type
== HYPERV_MSGTYPE_TIMER_EXPIRED
)
904 vmbus_msg_reset(msg
);
908 vmbus_timer_restart(void *xsc
)
910 struct vmbus_softc
*sc
= xsc
;
911 struct vmbus_pcpu_data
*psc
= VMBUS_PCPU(sc
, mycpuid
);
914 vmbus_timer_msgintr(psc
);
915 vmbus_timer_oneshot(psc
, rdmsr(MSR_HV_TIME_REF_COUNT
) + 1);
920 vmbus_synic_teardown(void *arg __unused
)
928 orig
= rdmsr(MSR_HV_SCONTROL
);
929 wrmsr(MSR_HV_SCONTROL
, (orig
& MSR_HV_SCTRL_RSVD_MASK
));
932 * Mask message and event flags SINT.
934 sint
= MSR_HV_SINT0
+ VMBUS_SINT_MESSAGE
;
936 wrmsr(sint
, orig
| MSR_HV_SINT_MASKED
);
941 sint
= MSR_HV_SINT0
+ VMBUS_SINT_TIMER
;
943 wrmsr(sint
, orig
| MSR_HV_SINT_MASKED
);
946 * Teardown SynIC message.
948 orig
= rdmsr(MSR_HV_SIMP
);
949 wrmsr(MSR_HV_SIMP
, (orig
& MSR_HV_SIMP_RSVD_MASK
));
952 * Teardown SynIC event flags.
954 orig
= rdmsr(MSR_HV_SIEFP
);
955 wrmsr(MSR_HV_SIEFP
, (orig
& MSR_HV_SIEFP_RSVD_MASK
));
959 vmbus_init_contact(struct vmbus_softc
*sc
, uint32_t version
)
961 struct vmbus_chanmsg_init_contact
*req
;
962 const struct vmbus_chanmsg_version_resp
*resp
;
963 const struct vmbus_message
*msg
;
964 struct vmbus_msghc
*mh
;
967 mh
= vmbus_msghc_get(sc
, sizeof(*req
));
971 req
= vmbus_msghc_dataptr(mh
);
972 req
->chm_hdr
.chm_type
= VMBUS_CHANMSG_TYPE_INIT_CONTACT
;
973 req
->chm_ver
= version
;
974 req
->chm_evtflags
= sc
->vmbus_evtflags_dma
.hv_paddr
;
975 req
->chm_mnf1
= sc
->vmbus_mnf1_dma
.hv_paddr
;
976 req
->chm_mnf2
= sc
->vmbus_mnf2_dma
.hv_paddr
;
978 error
= vmbus_msghc_exec(sc
, mh
);
980 vmbus_msghc_put(sc
, mh
);
984 msg
= vmbus_msghc_wait_result(sc
, mh
);
985 resp
= (const struct vmbus_chanmsg_version_resp
*)msg
->msg_data
;
986 supp
= resp
->chm_supp
;
988 vmbus_msghc_put(sc
, mh
);
990 return (supp
? 0 : EOPNOTSUPP
);
994 vmbus_init(struct vmbus_softc
*sc
)
998 for (i
= 0; i
< nitems(vmbus_version
); ++i
) {
1001 error
= vmbus_init_contact(sc
, vmbus_version
[i
]);
1003 sc
->vmbus_version
= vmbus_version
[i
];
1004 device_printf(sc
->vmbus_dev
, "version %u.%u\n",
1005 (sc
->vmbus_version
>> 16),
1006 (sc
->vmbus_version
& 0xffff));
1014 vmbus_chan_msgproc(struct vmbus_softc
*sc
, const struct vmbus_message
*msg
)
1016 const struct vmbus_chanmsg_hdr
*hdr
;
1018 hdr
= (const struct vmbus_chanmsg_hdr
*)msg
->msg_data
;
1021 if (hdr
->chm_type
== VMBUS_CHANMSG_TYPE_VERSION_RESP
)
1022 vmbus_msghc_wakeup(sc
, msg
);