xref: /dragonfly/sys/dev/virtual/hyperv/vmbus/vmbus.c (revision feadd4aebbda9b86e4ce0aaf9d11f27596b42ddb)
1 /*-
2  * Copyright (c) 2009-2012,2016 Microsoft Corp.
3  * Copyright (c) 2012 NetApp Inc.
4  * Copyright (c) 2012 Citrix Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice unmodified, this list of conditions, and the following
12  *    disclaimer.
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.
16  *
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.
27  */
28 
29 #include "opt_acpi.h"
30 
31 #include <sys/param.h>
32 #include <sys/bus.h>
33 #include <sys/kernel.h>
34 #include <sys/malloc.h>
35 #include <sys/module.h>
36 #include <sys/rman.h>
37 #include <sys/systimer.h>
38 #include <sys/thread.h>
39 #include <sys/thread2.h>
40 
41 #include <machine/intr_machdep.h>
42 #include <machine/smp.h>
43 
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>
50 
51 #include "acpi.h"
52 #include "acpi_if.h"
53 #include "pcib_if.h"
54 
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)
58 
59 /*
60  * Additionally required feature:
61  * - SynIC is needed for interrupt generation.
62  */
63 #define CPUID_HV_TIMER_MASK             (CPUID_HV_MSR_SYNIC |                   \
64                                                    CPUID_HV_MSR_SYNTIMER)
65 
66 /*
67  * NOTE: DO NOT CHANGE THIS.
68  */
69 #define VMBUS_SINT_MESSAGE              2
70 /*
71  * NOTE:
72  * - DO NOT set it to the same value as VMBUS_SINT_MESSAGE.
73  * - DO NOT set it to 0.
74  */
75 #define VMBUS_SINT_TIMER                4
76 
77 /*
78  * NOTE: DO NOT CHANGE THESE
79  */
80 #define VMBUS_CONNID_MESSAGE            1
81 #define VMBUS_CONNID_EVENT              2
82 
83 struct vmbus_msghc {
84           struct hypercall_postmsg_in   *mh_inprm;
85           struct hypercall_postmsg_in   mh_inprm_save;
86           struct hyperv_dma             mh_inprm_dma;
87 
88           struct vmbus_message                    *mh_resp;
89           struct vmbus_message                    mh_resp0;
90 };
91 
92 struct vmbus_msghc_ctx {
93           struct vmbus_msghc            *mhc_free;
94           struct lwkt_token             mhc_free_token;
95           uint32_t                      mhc_flags;
96 
97           struct vmbus_msghc            *mhc_active;
98           struct lwkt_token             mhc_active_token;
99 };
100 
101 #define VMBUS_MSGHC_CTXF_DESTROY        0x0001
102 
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 *,
108                                             sysclock_t);
109 static void                             vmbus_timer_intr_pcpuhand(
110                                             struct cputimer_intr *);
111 static void                             vmbus_timer_intr_restart(
112                                             struct cputimer_intr *);
113 
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 *,
124                                             uint32_t);
125 static void                             vmbus_timer_restart(void *);
126 static void                             vmbus_timer_msgintr(struct vmbus_pcpu_data *);
127 
128 static void                             vmbus_chan_msgproc(struct vmbus_softc *,
129                                             const struct vmbus_message *);
130 
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 *,
138                                             uint32_t);
139 
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),
148 
149           DEVMETHOD_END
150 };
151 
152 static driver_t vmbus_driver = {
153           "vmbus",
154           vmbus_methods,
155           sizeof(struct vmbus_softc)
156 };
157 
158 static devclass_t vmbus_devclass;
159 
160 DRIVER_MODULE(vmbus, acpi, vmbus_driver, vmbus_devclass, NULL, NULL);
161 MODULE_DEPEND(vmbus, acpi, 1, 1, 1);
162 MODULE_VERSION(vmbus, 1);
163 
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,
174           .name = "hyperv",
175           .type = CPUTIMER_INTR_VMM,
176           .prio = CPUTIMER_INTR_PRIO_VMM,
177           .caps = CPUTIMER_INTR_CAP_PS,
178           .priv = NULL
179 };
180 
181 static const uint32_t         vmbus_version[] = {
182           VMBUS_VERSION_WIN8_1,
183           VMBUS_VERSION_WIN8,
184           VMBUS_VERSION_WIN7,
185           VMBUS_VERSION_WS2008
186 };
187 
188 static int                    vmbus_timer_intr_enable = 1;
189 TUNABLE_INT("hw.vmbus.timer_intr.enable", &vmbus_timer_intr_enable);
190 
191 static int
vmbus_probe(device_t dev)192 vmbus_probe(device_t dev)
193 {
194           char *id[] = { "VMBUS", NULL };
195 
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)
199                     return (ENXIO);
200 
201           device_set_desc(dev, "Hyper-V vmbus");
202 
203           return (0);
204 }
205 
206 static int
vmbus_attach(device_t dev)207 vmbus_attach(device_t dev)
208 {
209           struct vmbus_softc *sc = device_get_softc(dev);
210           int error, cpu, use_timer;
211 
212           /*
213            * Basic setup.
214            */
215           sc->vmbus_dev = dev;
216           for (cpu = 0; cpu < ncpus; ++cpu) {
217                     struct vmbus_pcpu_data *psc = VMBUS_PCPU(sc, cpu);
218 
219                     psc->sc = sc;
220                     psc->cpuid = cpu;
221                     psc->timer_last = UINT64_MAX;
222           }
223 
224           /*
225            * Should we use interrupt timer?
226            */
227           use_timer = 0;
228           if (device_get_unit(dev) == 0 &&
229               (hyperv_features & CPUID_HV_TIMER_MASK) == CPUID_HV_TIMER_MASK &&
230               hyperv_tc64 != NULL)
231                     use_timer = 1;
232 
233           /*
234            * Create context for "post message" Hypercalls
235            */
236           sc->vmbus_msg_hc = vmbus_msghc_ctx_create(
237               bus_get_dma_tag(sc->vmbus_dev));
238           if (sc->vmbus_msg_hc == NULL)
239                     return ENXIO;
240 
241           /*
242            * Allocate DMA stuffs.
243            */
244           error = vmbus_dma_alloc(sc);
245           if (error)
246                     goto failed;
247 
248           /*
249            * Setup interrupt.
250            */
251           error = vmbus_intr_setup(sc);
252           if (error)
253                     goto failed;
254 
255           if (use_timer) {
256                     /*
257                      * Make sure that interrupt timer is stopped.
258                      */
259                     lwkt_cpusync_simple(smp_active_mask, vmbus_timer_stop, sc);
260           }
261 
262           /*
263            * Setup SynIC.
264            */
265           lwkt_cpusync_simple(smp_active_mask, vmbus_synic_setup, sc);
266           sc->vmbus_flags |= VMBUS_FLAG_SYNIC;
267 
268           /*
269            * Initialize vmbus.
270            */
271           error = vmbus_init(sc);
272           if (error)
273                     goto failed;
274 
275           if (use_timer) {
276                     /*
277                      * Configure and register vmbus interrupt timer.
278                      */
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);
284           }
285 
286           return 0;
287 failed:
288           vmbus_detach(dev);
289           return error;
290 }
291 
292 static int
vmbus_detach(device_t dev)293 vmbus_detach(device_t dev)
294 {
295           struct vmbus_softc *sc = device_get_softc(dev);
296 
297           /* TODO: uninitialize vmbus. */
298           /* TODO: stop and deregister timer */
299 
300           if (sc->vmbus_flags & VMBUS_FLAG_SYNIC)
301                     lwkt_cpusync_simple(smp_active_mask, vmbus_synic_teardown, sc);
302           vmbus_intr_teardown(sc);
303           vmbus_dma_free(sc);
304 
305           if (sc->vmbus_msg_hc != NULL) {
306                     vmbus_msghc_ctx_destroy(sc->vmbus_msg_hc);
307                     sc->vmbus_msg_hc = NULL;
308           }
309           return (0);
310 }
311 
312 static __inline void
vmbus_msg_reset(volatile struct vmbus_message * msg)313 vmbus_msg_reset(volatile struct vmbus_message *msg)
314 {
315           msg->msg_type = HYPERV_MSGTYPE_NONE;
316           /*
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.
320            */
321           cpu_mfence();
322           if (msg->msg_flags & VMBUS_MSGFLAG_PENDING) {
323                     /*
324                      * Ask the hypervisor to rescan message queue,
325                      * and deliver new message if any.
326                      */
327                     wrmsr(MSR_HV_EOM, 0);
328           }
329 }
330 
331 static void
vmbus_intr(void * xpsc)332 vmbus_intr(void *xpsc)
333 {
334           struct vmbus_pcpu_data *psc = xpsc;
335           volatile struct vmbus_message *msg;
336 
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));
343                     }
344                     vmbus_msg_reset(msg);
345           }
346 }
347 
348 static __inline void
vmbus_timer_oneshot(struct vmbus_pcpu_data * psc,uint64_t current)349 vmbus_timer_oneshot(struct vmbus_pcpu_data *psc, uint64_t current)
350 {
351           psc->timer_last = current;
352           wrmsr(MSR_HV_STIMER0_COUNT, current);
353 }
354 
355 static void
vmbus_timer_intr_reload(struct cputimer_intr * cti,sysclock_t reload)356 vmbus_timer_intr_reload(struct cputimer_intr *cti, sysclock_t reload)
357 {
358           struct globaldata *gd = mycpu;
359           struct vmbus_softc *sc = cti->priv;
360           struct vmbus_pcpu_data *psc = VMBUS_PCPU(sc, gd->gd_cpuid);
361           uint64_t current;
362 
363           if ((ssysclock_t)reload < 0)            /* neg value */
364                     reload = 1;
365           reload = muldivu64(reload, cti->freq, sys_cputimer->freq);
366           current = hyperv_tc64() + reload;
367 
368           if (gd->gd_timer_running) {
369                     if (current < psc->timer_last)
370                               vmbus_timer_oneshot(psc, current);
371           } else {
372                     gd->gd_timer_running = 1;
373                     vmbus_timer_oneshot(psc, current);
374           }
375 }
376 
377 static void
vmbus_timer_intr_pcpuhand(struct cputimer_intr * cti)378 vmbus_timer_intr_pcpuhand(struct cputimer_intr *cti)
379 {
380           struct vmbus_softc *sc = cti->priv;
381           struct vmbus_pcpu_data *psc = VMBUS_PCPU(sc, mycpuid);
382 
383           vmbus_timer_msgintr(psc);
384 }
385 
386 static void
vmbus_timer_intr_restart(struct cputimer_intr * cti)387 vmbus_timer_intr_restart(struct cputimer_intr *cti)
388 {
389           lwkt_send_ipiq_mask(smp_active_mask, vmbus_timer_restart, cti->priv);
390 }
391 
392 static struct vmbus_msghc *
vmbus_msghc_alloc(bus_dma_tag_t parent_dtag)393 vmbus_msghc_alloc(bus_dma_tag_t parent_dtag)
394 {
395           struct vmbus_msghc *mh;
396 
397           mh = kmalloc(sizeof(*mh), M_DEVBUF, M_WAITOK | M_ZERO);
398 
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) {
403                     kfree(mh, M_DEVBUF);
404                     return NULL;
405           }
406           return mh;
407 }
408 
409 static void
vmbus_msghc_free(struct vmbus_msghc * mh)410 vmbus_msghc_free(struct vmbus_msghc *mh)
411 {
412           hyperv_dmamem_free(&mh->mh_inprm_dma, mh->mh_inprm);
413           kfree(mh, M_DEVBUF);
414 }
415 
416 static void
vmbus_msghc_ctx_free(struct vmbus_msghc_ctx * mhc)417 vmbus_msghc_ctx_free(struct vmbus_msghc_ctx *mhc)
418 {
419           KASSERT(mhc->mhc_active == NULL, ("still have active msg hypercall"));
420           KASSERT(mhc->mhc_free == NULL, ("still have hypercall msg"));
421 
422           lwkt_token_uninit(&mhc->mhc_free_token);
423           lwkt_token_uninit(&mhc->mhc_active_token);
424           kfree(mhc, M_DEVBUF);
425 }
426 
427 static struct vmbus_msghc_ctx *
vmbus_msghc_ctx_create(bus_dma_tag_t parent_dtag)428 vmbus_msghc_ctx_create(bus_dma_tag_t parent_dtag)
429 {
430           struct vmbus_msghc_ctx *mhc;
431 
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");
435 
436           mhc->mhc_free = vmbus_msghc_alloc(parent_dtag);
437           if (mhc->mhc_free == NULL) {
438                     vmbus_msghc_ctx_free(mhc);
439                     return NULL;
440           }
441           return mhc;
442 }
443 
444 static struct vmbus_msghc *
vmbus_msghc_get1(struct vmbus_msghc_ctx * mhc,uint32_t dtor_flag)445 vmbus_msghc_get1(struct vmbus_msghc_ctx *mhc, uint32_t dtor_flag)
446 {
447           struct vmbus_msghc *mh;
448 
449           lwkt_gettoken(&mhc->mhc_free_token);
450 
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 */
455                     mh = NULL;
456           } else {
457                     mh = mhc->mhc_free;
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;
462           }
463 
464           lwkt_reltoken(&mhc->mhc_free_token);
465 
466           return mh;
467 }
468 
469 struct vmbus_msghc *
vmbus_msghc_get(struct vmbus_softc * sc,size_t dsize)470 vmbus_msghc_get(struct vmbus_softc *sc, size_t dsize)
471 {
472           struct hypercall_postmsg_in *inprm;
473           struct vmbus_msghc *mh;
474 
475           if (dsize > HYPERCALL_POSTMSGIN_DSIZE_MAX)
476                     return NULL;
477 
478           mh = vmbus_msghc_get1(sc->vmbus_msg_hc, VMBUS_MSGHC_CTXF_DESTROY);
479           if (mh == NULL)
480                     return NULL;
481 
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;
487 
488           return mh;
489 }
490 
491 void
vmbus_msghc_put(struct vmbus_softc * sc,struct vmbus_msghc * mh)492 vmbus_msghc_put(struct vmbus_softc *sc, struct vmbus_msghc *mh)
493 {
494           struct vmbus_msghc_ctx *mhc = sc->vmbus_msg_hc;
495 
496           KASSERT(mhc->mhc_active == NULL, ("msg hypercall is active"));
497           mh->mh_resp = NULL;
498 
499           lwkt_gettoken(&mhc->mhc_free_token);
500           KASSERT(mhc->mhc_free == NULL, ("has free hypercall msg"));
501           mhc->mhc_free = mh;
502           lwkt_reltoken(&mhc->mhc_free_token);
503           wakeup(&mhc->mhc_free);
504 }
505 
506 void *
vmbus_msghc_dataptr(struct vmbus_msghc * mh)507 vmbus_msghc_dataptr(struct vmbus_msghc *mh)
508 {
509           return mh->mh_inprm->hc_data;
510 }
511 
512 static void
vmbus_msghc_ctx_destroy(struct vmbus_msghc_ctx * mhc)513 vmbus_msghc_ctx_destroy(struct vmbus_msghc_ctx *mhc)
514 {
515           struct vmbus_msghc *mh;
516 
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);
521 
522           mh = vmbus_msghc_get1(mhc, 0);
523           if (mh == NULL)
524                     panic("can't get msghc");
525 
526           vmbus_msghc_free(mh);
527           vmbus_msghc_ctx_free(mhc);
528 }
529 
530 int
vmbus_msghc_exec_noresult(struct vmbus_msghc * mh)531 vmbus_msghc_exec_noresult(struct vmbus_msghc *mh)
532 {
533           int i, wait_ticks = 1;
534 
535           /*
536            * Save the input parameter so that we could restore the input
537            * parameter if the Hypercall failed.
538            *
539            * XXX
540            * Is this really necessary?!  i.e. Will the Hypercall ever
541            * overwrite the input parameter?
542            */
543           memcpy(&mh->mh_inprm_save, mh->mh_inprm, HYPERCALL_POSTMSGIN_SIZE);
544 
545           /*
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.
549            */
550 #define HC_RETRY_MAX          20
551 
552           for (i = 0; i < HC_RETRY_MAX; ++i) {
553                     uint64_t status;
554 
555                     status = hypercall_post_message(mh->mh_inprm_dma.hv_paddr);
556                     if (status == HYPERCALL_STATUS_SUCCESS)
557                               return 0;
558 
559                     tsleep(&status, 0, "hcpmsg", wait_ticks);
560                     if (wait_ticks < hz)
561                               wait_ticks *= 2;
562 
563                     /* Restore input parameter and try again */
564                     memcpy(mh->mh_inprm, &mh->mh_inprm_save,
565                         HYPERCALL_POSTMSGIN_SIZE);
566           }
567 
568 #undef HC_RETRY_MAX
569 
570           return EIO;
571 }
572 
573 int
vmbus_msghc_exec(struct vmbus_softc * sc,struct vmbus_msghc * mh)574 vmbus_msghc_exec(struct vmbus_softc *sc, struct vmbus_msghc *mh)
575 {
576           struct vmbus_msghc_ctx *mhc = sc->vmbus_msg_hc;
577           int error;
578 
579           KASSERT(mh->mh_resp == NULL, ("hypercall msg has pending response"));
580 
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);
585 
586           error = vmbus_msghc_exec_noresult(mh);
587           if (error) {
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);
592           }
593           return error;
594 }
595 
596 const struct vmbus_message *
vmbus_msghc_wait_result(struct vmbus_softc * sc,struct vmbus_msghc * mh)597 vmbus_msghc_wait_result(struct vmbus_softc *sc, struct vmbus_msghc *mh)
598 {
599           struct vmbus_msghc_ctx *mhc = sc->vmbus_msg_hc;
600 
601           lwkt_gettoken(&mhc->mhc_active_token);
602 
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;
607 
608           lwkt_reltoken(&mhc->mhc_active_token);
609 
610           return mh->mh_resp;
611 }
612 
613 void
vmbus_msghc_wakeup(struct vmbus_softc * sc,const struct vmbus_message * msg)614 vmbus_msghc_wakeup(struct vmbus_softc *sc, const struct vmbus_message *msg)
615 {
616           struct vmbus_msghc_ctx *mhc = sc->vmbus_msg_hc;
617           struct vmbus_msghc *mh;
618 
619           lwkt_gettoken(&mhc->mhc_active_token);
620 
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;
625 
626           lwkt_reltoken(&mhc->mhc_active_token);
627           wakeup(&mhc->mhc_active);
628 }
629 
630 static int
vmbus_dma_alloc(struct vmbus_softc * sc)631 vmbus_dma_alloc(struct vmbus_softc *sc)
632 {
633           bus_dma_tag_t parent_dtag;
634           uint8_t *evtflags;
635           int cpu;
636 
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);
640 
641                     /*
642                      * Per-cpu messages and event flags.
643                      */
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)
648                               return ENOMEM;
649 
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)
654                               return ENOMEM;
655           }
656 
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)
660                     return ENOMEM;
661           sc->vmbus_rx_evtflags = (u_long *)evtflags;
662           sc->vmbus_tx_evtflags = (u_long *)(evtflags + (PAGE_SIZE / 2));
663           sc->vmbus_evtflags = evtflags;
664 
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)
668                     return ENOMEM;
669 
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)
673                     return ENOMEM;
674 
675           return 0;
676 }
677 
678 static void
vmbus_dma_free(struct vmbus_softc * sc)679 vmbus_dma_free(struct vmbus_softc *sc)
680 {
681           int cpu;
682 
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;
688           }
689           if (sc->vmbus_mnf1 != NULL) {
690                     hyperv_dmamem_free(&sc->vmbus_mnf1_dma, sc->vmbus_mnf1);
691                     sc->vmbus_mnf1 = NULL;
692           }
693           if (sc->vmbus_mnf2 != NULL) {
694                     hyperv_dmamem_free(&sc->vmbus_mnf2_dma, sc->vmbus_mnf2);
695                     sc->vmbus_mnf2 = NULL;
696           }
697 
698           for (cpu = 0; cpu < ncpus; ++cpu) {
699                     struct vmbus_pcpu_data *psc = VMBUS_PCPU(sc, cpu);
700 
701                     if (psc->message != NULL) {
702                               hyperv_dmamem_free(&psc->message_dma, psc->message);
703                               psc->message = NULL;
704                     }
705                     if (psc->event_flags != NULL) {
706                               hyperv_dmamem_free(&psc->event_flags_dma,
707                                   psc->event_flags);
708                               psc->event_flags = NULL;
709                     }
710           }
711 }
712 
713 static int
vmbus_intr_setup(struct vmbus_softc * sc)714 vmbus_intr_setup(struct vmbus_softc *sc)
715 {
716           device_t dev = sc->vmbus_dev;
717           device_t bus = device_get_parent(device_get_parent(dev));
718           int rid, cpu;
719 
720           rid = 0;
721           for (cpu = 0; cpu < ncpus; ++cpu) {
722                     struct vmbus_pcpu_data *psc = VMBUS_PCPU(sc, cpu);
723                     uint64_t msi_addr;
724                     uint32_t msi_data;
725                     int error;
726 
727                     error = PCIB_ALLOC_MSIX(bus, dev, &psc->intr_irq, cpu);
728                     if (error) {
729                               device_printf(dev, "alloc vector on cpu%d failed: %d\n",
730                                   cpu, error);
731                               return ENXIO;
732                     }
733                     psc->intr_rid = ++rid;
734 
735                     psc->intr_res = BUS_ALLOC_RESOURCE(bus, dev, SYS_RES_IRQ,
736                         &psc->intr_rid, psc->intr_irq, psc->intr_irq, 1,
737                         RF_ACTIVE, cpu);
738                     if (psc->intr_res == NULL) {
739                               device_printf(dev, "alloc irq on cpu%d failed: %d\n",
740                                   cpu, error);
741                               return ENXIO;
742                     }
743 
744                     error = PCIB_MAP_MSI(bus, dev, rman_get_start(psc->intr_res),
745                         &msi_addr, &msi_data, cpu);
746                     if (error) {
747                               device_printf(dev, "map irq on cpu%d failed: %d\n",
748                                   cpu, error);
749                               return ENXIO;
750                     }
751                     psc->intr_vec = hyperv_msi2vector(msi_addr, msi_data);
752 
753                     if (bootverbose) {
754                               device_printf(dev, "vector %d irq %d on cpu%d\n",
755                                   psc->intr_vec, psc->intr_irq, cpu);
756                     }
757 
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);
762                     if (error) {
763                               device_printf(dev, "setup intr on cpu%d failed: %d\n",
764                                   cpu, error);
765                               return ENXIO;
766                     }
767           }
768           return 0;
769 }
770 
771 static void
vmbus_intr_teardown(struct vmbus_softc * sc)772 vmbus_intr_teardown(struct vmbus_softc *sc)
773 {
774           device_t dev = sc->vmbus_dev;
775           device_t bus = device_get_parent(device_get_parent(dev));
776           int cpu;
777 
778           for (cpu = 0; cpu < ncpus; ++cpu) {
779                     struct vmbus_pcpu_data *psc = VMBUS_PCPU(sc, cpu);
780 
781                     if (psc->intr_hand != NULL) {
782                               bus_teardown_intr(dev, psc->intr_res, psc->intr_hand);
783                               psc->intr_hand = NULL;
784                     }
785 
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;
790                     }
791 
792                     if (psc->intr_rid != 0) {
793                               PCIB_RELEASE_MSIX(bus, dev, psc->intr_irq, psc->cpuid);
794                               psc->intr_rid = 0;
795                     }
796           }
797 }
798 
799 static void
vmbus_synic_setup(void * xsc)800 vmbus_synic_setup(void *xsc)
801 {
802           struct vmbus_softc *sc = xsc;
803           struct vmbus_pcpu_data *psc = VMBUS_PCPU(sc, mycpuid);
804           uint64_t val, orig;
805           uint32_t sint;
806 
807           if (hyperv_features & CPUID_HV_MSR_VP_INDEX) {
808                     /*
809                      * Save virtual processor id.
810                      */
811                     psc->vcpuid = rdmsr(MSR_HV_VP_INDEX);
812           } else {
813                     /*
814                      * XXX
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
818                      * moving on.
819                      */
820                     psc->vcpuid = mycpuid;
821           }
822 
823           /*
824            * Setup the SynIC message.
825            */
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);
830 
831           /*
832            * Setup the SynIC event flags.
833            */
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);
839 
840 
841           /*
842            * Configure and unmask SINT for message and event flags.
843            */
844           sint = MSR_HV_SINT0 + VMBUS_SINT_MESSAGE;
845           orig = rdmsr(sint);
846           val = psc->intr_vec | /* MSR_HV_SINT_AUTOEOI | notyet */
847               (orig & MSR_HV_SINT_RSVD_MASK);
848           wrmsr(sint, val);
849 
850           /*
851            * Configure and unmask SINT for timer.
852            */
853           sint = MSR_HV_SINT0 + VMBUS_SINT_TIMER;
854           orig = rdmsr(sint);
855           val = XTIMER_OFFSET | /* MSR_HV_SINT_AUTOEOI | notyet */
856               (orig & MSR_HV_SINT_RSVD_MASK);
857           wrmsr(sint, val);
858 
859           /*
860            * All done; enable SynIC.
861            */
862           orig = rdmsr(MSR_HV_SCONTROL);
863           val = MSR_HV_SCTRL_ENABLE | (orig & MSR_HV_SCTRL_RSVD_MASK);
864           wrmsr(MSR_HV_SCONTROL, val);
865 }
866 
867 static void
vmbus_timer_stop(void * arg __unused)868 vmbus_timer_stop(void *arg __unused)
869 {
870           for (;;) {
871                     uint64_t val;
872 
873                     /* Stop counting, and this also implies disabling STIMER0 */
874                     wrmsr(MSR_HV_STIMER0_COUNT, 0);
875 
876                     val = rdmsr(MSR_HV_STIMER0_CONFIG);
877                     if ((val & MSR_HV_STIMER_CFG_ENABLE) == 0)
878                               break;
879                     cpu_pause();
880           }
881 }
882 
883 static void
vmbus_timer_config(void * arg __unused)884 vmbus_timer_config(void *arg __unused)
885 {
886           /*
887            * Make sure that STIMER0 is really disabled before writing
888            * to STIMER0_CONFIG.
889            *
890            * "Writing to the configuration register of a timer that
891            *  is already enabled may result in undefined behaviour."
892            */
893           vmbus_timer_stop(arg);
894           wrmsr(MSR_HV_STIMER0_CONFIG,
895               MSR_HV_STIMER_CFG_AUTOEN | MSR_HV_STIMER0_CFG_SINT);
896 }
897 
898 static void
vmbus_timer_msgintr(struct vmbus_pcpu_data * psc)899 vmbus_timer_msgintr(struct vmbus_pcpu_data *psc)
900 {
901           volatile struct vmbus_message *msg;
902 
903           msg = psc->message + VMBUS_SINT_TIMER;
904           if (msg->msg_type == HYPERV_MSGTYPE_TIMER_EXPIRED)
905                     vmbus_msg_reset(msg);
906 }
907 
908 static void
vmbus_timer_restart(void * xsc)909 vmbus_timer_restart(void *xsc)
910 {
911           struct vmbus_softc *sc = xsc;
912           struct vmbus_pcpu_data *psc = VMBUS_PCPU(sc, mycpuid);
913 
914           crit_enter();
915           vmbus_timer_msgintr(psc);
916           vmbus_timer_oneshot(psc, hyperv_tc64() + 1);
917           crit_exit();
918 }
919 
920 static void
vmbus_synic_teardown(void * arg __unused)921 vmbus_synic_teardown(void *arg __unused)
922 {
923           uint64_t orig;
924           uint32_t sint;
925 
926           /*
927            * Disable SynIC.
928            */
929           orig = rdmsr(MSR_HV_SCONTROL);
930           wrmsr(MSR_HV_SCONTROL, (orig & MSR_HV_SCTRL_RSVD_MASK));
931 
932           /*
933            * Mask message and event flags SINT.
934            */
935           sint = MSR_HV_SINT0 + VMBUS_SINT_MESSAGE;
936           orig = rdmsr(sint);
937           wrmsr(sint, orig | MSR_HV_SINT_MASKED);
938 
939           /*
940            * Mask timer SINT.
941            */
942           sint = MSR_HV_SINT0 + VMBUS_SINT_TIMER;
943           orig = rdmsr(sint);
944           wrmsr(sint, orig | MSR_HV_SINT_MASKED);
945 
946           /*
947            * Teardown SynIC message.
948            */
949           orig = rdmsr(MSR_HV_SIMP);
950           wrmsr(MSR_HV_SIMP, (orig & MSR_HV_SIMP_RSVD_MASK));
951 
952           /*
953            * Teardown SynIC event flags.
954            */
955           orig = rdmsr(MSR_HV_SIEFP);
956           wrmsr(MSR_HV_SIEFP, (orig & MSR_HV_SIEFP_RSVD_MASK));
957 }
958 
959 static int
vmbus_init_contact(struct vmbus_softc * sc,uint32_t version)960 vmbus_init_contact(struct vmbus_softc *sc, uint32_t version)
961 {
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;
966           int error, supp = 0;
967 
968           mh = vmbus_msghc_get(sc, sizeof(*req));
969           if (mh == NULL)
970                     return ENXIO;
971 
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;
978 
979           error = vmbus_msghc_exec(sc, mh);
980           if (error) {
981                     vmbus_msghc_put(sc, mh);
982                     return error;
983           }
984 
985           msg = vmbus_msghc_wait_result(sc, mh);
986           resp = (const struct vmbus_chanmsg_version_resp *)msg->msg_data;
987           supp = resp->chm_supp;
988 
989           vmbus_msghc_put(sc, mh);
990 
991           return (supp ? 0 : EOPNOTSUPP);
992 }
993 
994 static int
vmbus_init(struct vmbus_softc * sc)995 vmbus_init(struct vmbus_softc *sc)
996 {
997           int i;
998 
999           for (i = 0; i < nitems(vmbus_version); ++i) {
1000                     int error;
1001 
1002                     error = vmbus_init_contact(sc, vmbus_version[i]);
1003                     if (!error) {
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));
1008                               return 0;
1009                     }
1010           }
1011           return ENXIO;
1012 }
1013 
1014 static void
vmbus_chan_msgproc(struct vmbus_softc * sc,const struct vmbus_message * msg)1015 vmbus_chan_msgproc(struct vmbus_softc *sc, const struct vmbus_message *msg)
1016 {
1017           const struct vmbus_chanmsg_hdr *hdr;
1018 
1019           hdr = (const struct vmbus_chanmsg_hdr *)msg->msg_data;
1020 
1021           /* TODO */
1022           if (hdr->chm_type == VMBUS_CHANMSG_TYPE_VERSION_RESP)
1023                     vmbus_msghc_wakeup(sc, msg);
1024 }
1025