]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c
MFC 300565,300567,300568,300570,300571
[FreeBSD/stable/10.git] / sys / dev / hyperv / vmbus / hv_vmbus_drv_freebsd.c
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 /*
30  * VM Bus Driver Implementation
31  */
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34
35 #include <sys/param.h>
36 #include <sys/bus.h>
37 #include <sys/kernel.h>
38 #include <sys/lock.h>
39 #include <sys/malloc.h>
40 #include <sys/module.h>
41 #include <sys/proc.h>
42 #include <sys/sysctl.h>
43 #include <sys/syslog.h>
44 #include <sys/systm.h>
45 #include <sys/rtprio.h>
46 #include <sys/interrupt.h>
47 #include <sys/sx.h>
48 #include <sys/taskqueue.h>
49 #include <sys/mutex.h>
50 #include <sys/smp.h>
51
52 #include <machine/resource.h>
53 #include <sys/rman.h>
54
55 #include <machine/stdarg.h>
56 #include <machine/intr_machdep.h>
57 #include <machine/md_var.h>
58 #include <machine/segments.h>
59 #include <sys/pcpu.h>
60 #include <machine/apicvar.h>
61
62 #include <dev/hyperv/include/hyperv.h>
63 #include <dev/hyperv/vmbus/hv_vmbus_priv.h>
64 #include <dev/hyperv/vmbus/vmbus_var.h>
65
66 #include <contrib/dev/acpica/include/acpi.h>
67 #include "acpi_if.h"
68
69 struct vmbus_softc      *vmbus_sc;
70
71 static int vmbus_inited;
72 static hv_setup_args setup_args; /* only CPU 0 supported at this time */
73
74 static char *vmbus_ids[] = { "VMBUS", NULL };
75
76 static void
77 vmbus_msg_task(void *arg __unused, int pending __unused)
78 {
79         hv_vmbus_message *msg;
80
81         msg = hv_vmbus_g_context.syn_ic_msg_page[curcpu] +
82             HV_VMBUS_MESSAGE_SINT;
83
84         for (;;) {
85                 const hv_vmbus_channel_msg_table_entry *entry;
86                 hv_vmbus_channel_msg_header *hdr;
87                 hv_vmbus_channel_msg_type msg_type;
88
89                 if (msg->header.message_type == HV_MESSAGE_TYPE_NONE)
90                         break; /* no message */
91
92                 hdr = (hv_vmbus_channel_msg_header *)msg->u.payload;
93                 msg_type = hdr->message_type;
94
95                 if (msg_type >= HV_CHANNEL_MESSAGE_COUNT) {
96                         printf("VMBUS: unknown message type = %d\n", msg_type);
97                         goto handled;
98                 }
99
100                 entry = &g_channel_message_table[msg_type];
101                 if (entry->messageHandler)
102                         entry->messageHandler(hdr);
103 handled:
104                 msg->header.message_type = HV_MESSAGE_TYPE_NONE;
105                 /*
106                  * Make sure the write to message_type (ie set to
107                  * HV_MESSAGE_TYPE_NONE) happens before we read the
108                  * message_pending and EOMing. Otherwise, the EOMing will
109                  * not deliver any more messages
110                  * since there is no empty slot
111                  *
112                  * NOTE:
113                  * mb() is used here, since atomic_thread_fence_seq_cst()
114                  * will become compiler fence on UP kernel.
115                  */
116                 mb();
117                 if (msg->header.message_flags.u.message_pending) {
118                         /*
119                          * This will cause message queue rescan to possibly
120                          * deliver another msg from the hypervisor
121                          */
122                         wrmsr(HV_X64_MSR_EOM, 0);
123                 }
124         }
125 }
126
127 /**
128  * @brief Interrupt filter routine for VMBUS.
129  *
130  * The purpose of this routine is to determine the type of VMBUS protocol
131  * message to process - an event or a channel message.
132  */
133 static inline int
134 hv_vmbus_isr(struct vmbus_softc *sc, struct trapframe *frame, int cpu)
135 {
136         hv_vmbus_message *msg, *msg_base;
137
138         /*
139          * The Windows team has advised that we check for events
140          * before checking for messages. This is the way they do it
141          * in Windows when running as a guest in Hyper-V
142          */
143         sc->vmbus_event_proc(sc, cpu);
144
145         /* Check if there are actual msgs to be process */
146         msg_base = hv_vmbus_g_context.syn_ic_msg_page[cpu];
147         msg = msg_base + HV_VMBUS_TIMER_SINT;
148
149         /* we call eventtimer process the message */
150         if (msg->header.message_type == HV_MESSAGE_TIMER_EXPIRED) {
151                 msg->header.message_type = HV_MESSAGE_TYPE_NONE;
152
153                 /* call intrrupt handler of event timer */
154                 hv_et_intr(frame);
155
156                 /*
157                  * Make sure the write to message_type (ie set to
158                  * HV_MESSAGE_TYPE_NONE) happens before we read the
159                  * message_pending and EOMing. Otherwise, the EOMing will
160                  * not deliver any more messages
161                  * since there is no empty slot
162                  *
163                  * NOTE:
164                  * mb() is used here, since atomic_thread_fence_seq_cst()
165                  * will become compiler fence on UP kernel.
166                  */
167                 mb();
168
169                 if (msg->header.message_flags.u.message_pending) {
170                         /*
171                          * This will cause message queue rescan to possibly
172                          * deliver another msg from the hypervisor
173                          */
174                         wrmsr(HV_X64_MSR_EOM, 0);
175                 }
176         }
177
178         msg = msg_base + HV_VMBUS_MESSAGE_SINT;
179         if (msg->header.message_type != HV_MESSAGE_TYPE_NONE) {
180                 taskqueue_enqueue(hv_vmbus_g_context.hv_msg_tq[cpu],
181                     &hv_vmbus_g_context.hv_msg_task[cpu]);
182         }
183
184         return (FILTER_HANDLED);
185 }
186
187 void
188 hv_vector_handler(struct trapframe *trap_frame)
189 {
190         struct vmbus_softc *sc = vmbus_get_softc();
191         int cpu = curcpu;
192
193         /*
194          * Disable preemption.
195          */
196         critical_enter();
197
198         /*
199          * Do a little interrupt counting.
200          */
201         (*VMBUS_SC_PCPU_GET(sc, intr_cnt, cpu))++;
202
203         hv_vmbus_isr(sc, trap_frame, cpu);
204
205         /*
206          * Enable preemption.
207          */
208         critical_exit();
209 }
210
211 static void
212 vmbus_synic_setup(void *arg)
213 {
214         struct vmbus_softc *sc = vmbus_get_softc();
215         int                     cpu;
216         uint64_t                hv_vcpu_index;
217         hv_vmbus_synic_simp     simp;
218         hv_vmbus_synic_siefp    siefp;
219         hv_vmbus_synic_scontrol sctrl;
220         hv_vmbus_synic_sint     shared_sint;
221         uint64_t                version;
222         hv_setup_args*          setup_args = (hv_setup_args *)arg;
223
224         cpu = PCPU_GET(cpuid);
225
226         /*
227          * TODO: Check the version
228          */
229         version = rdmsr(HV_X64_MSR_SVERSION);
230
231         hv_vmbus_g_context.syn_ic_msg_page[cpu] =
232             setup_args->page_buffers[2 * cpu];
233         hv_vmbus_g_context.syn_ic_event_page[cpu] =
234             setup_args->page_buffers[2 * cpu + 1];
235
236         /*
237          * Setup the Synic's message page
238          */
239
240         simp.as_uint64_t = rdmsr(HV_X64_MSR_SIMP);
241         simp.u.simp_enabled = 1;
242         simp.u.base_simp_gpa = ((hv_get_phys_addr(
243             hv_vmbus_g_context.syn_ic_msg_page[cpu])) >> PAGE_SHIFT);
244
245         wrmsr(HV_X64_MSR_SIMP, simp.as_uint64_t);
246
247         /*
248          * Setup the Synic's event page
249          */
250         siefp.as_uint64_t = rdmsr(HV_X64_MSR_SIEFP);
251         siefp.u.siefp_enabled = 1;
252         siefp.u.base_siefp_gpa = ((hv_get_phys_addr(
253             hv_vmbus_g_context.syn_ic_event_page[cpu])) >> PAGE_SHIFT);
254
255         wrmsr(HV_X64_MSR_SIEFP, siefp.as_uint64_t);
256
257         /*HV_SHARED_SINT_IDT_VECTOR + 0x20; */
258         shared_sint.as_uint64_t = 0;
259         shared_sint.u.vector = sc->vmbus_idtvec;
260         shared_sint.u.masked = FALSE;
261         shared_sint.u.auto_eoi = TRUE;
262
263         wrmsr(HV_X64_MSR_SINT0 + HV_VMBUS_MESSAGE_SINT,
264             shared_sint.as_uint64_t);
265
266         wrmsr(HV_X64_MSR_SINT0 + HV_VMBUS_TIMER_SINT,
267             shared_sint.as_uint64_t);
268
269         /* Enable the global synic bit */
270         sctrl.as_uint64_t = rdmsr(HV_X64_MSR_SCONTROL);
271         sctrl.u.enable = 1;
272
273         wrmsr(HV_X64_MSR_SCONTROL, sctrl.as_uint64_t);
274
275         hv_vmbus_g_context.syn_ic_initialized = TRUE;
276
277         /*
278          * Set up the cpuid mapping from Hyper-V to FreeBSD.
279          * The array is indexed using FreeBSD cpuid.
280          */
281         hv_vcpu_index = rdmsr(HV_X64_MSR_VP_INDEX);
282         hv_vmbus_g_context.hv_vcpu_index[cpu] = (uint32_t)hv_vcpu_index;
283 }
284
285 static void
286 vmbus_synic_teardown(void *arg)
287 {
288         hv_vmbus_synic_sint     shared_sint;
289         hv_vmbus_synic_simp     simp;
290         hv_vmbus_synic_siefp    siefp;
291
292         if (!hv_vmbus_g_context.syn_ic_initialized)
293             return;
294
295         shared_sint.as_uint64_t = rdmsr(
296             HV_X64_MSR_SINT0 + HV_VMBUS_MESSAGE_SINT);
297
298         shared_sint.u.masked = 1;
299
300         /*
301          * Disable the interrupt 0
302          */
303         wrmsr(
304             HV_X64_MSR_SINT0 + HV_VMBUS_MESSAGE_SINT,
305             shared_sint.as_uint64_t);
306
307         shared_sint.as_uint64_t = rdmsr(
308             HV_X64_MSR_SINT0 + HV_VMBUS_TIMER_SINT);
309
310         shared_sint.u.masked = 1;
311
312         /*
313          * Disable the interrupt 1
314          */
315         wrmsr(
316             HV_X64_MSR_SINT0 + HV_VMBUS_TIMER_SINT,
317             shared_sint.as_uint64_t);
318         simp.as_uint64_t = rdmsr(HV_X64_MSR_SIMP);
319         simp.u.simp_enabled = 0;
320         simp.u.base_simp_gpa = 0;
321
322         wrmsr(HV_X64_MSR_SIMP, simp.as_uint64_t);
323
324         siefp.as_uint64_t = rdmsr(HV_X64_MSR_SIEFP);
325         siefp.u.siefp_enabled = 0;
326         siefp.u.base_siefp_gpa = 0;
327
328         wrmsr(HV_X64_MSR_SIEFP, siefp.as_uint64_t);
329 }
330
331 static int
332 vmbus_read_ivar(
333         device_t        dev,
334         device_t        child,
335         int             index,
336         uintptr_t*      result)
337 {
338         struct hv_device *child_dev_ctx = device_get_ivars(child);
339
340         switch (index) {
341
342         case HV_VMBUS_IVAR_TYPE:
343                 *result = (uintptr_t) &child_dev_ctx->class_id;
344                 return (0);
345         case HV_VMBUS_IVAR_INSTANCE:
346                 *result = (uintptr_t) &child_dev_ctx->device_id;
347                 return (0);
348         case HV_VMBUS_IVAR_DEVCTX:
349                 *result = (uintptr_t) child_dev_ctx;
350                 return (0);
351         case HV_VMBUS_IVAR_NODE:
352                 *result = (uintptr_t) child_dev_ctx->device;
353                 return (0);
354         }
355         return (ENOENT);
356 }
357
358 static int
359 vmbus_write_ivar(
360         device_t        dev,
361         device_t        child,
362         int             index,
363         uintptr_t       value)
364 {
365         switch (index) {
366
367         case HV_VMBUS_IVAR_TYPE:
368         case HV_VMBUS_IVAR_INSTANCE:
369         case HV_VMBUS_IVAR_DEVCTX:
370         case HV_VMBUS_IVAR_NODE:
371                 /* read-only */
372                 return (EINVAL);
373         }
374         return (ENOENT);
375 }
376
377 static int
378 vmbus_child_pnpinfo_str(device_t dev, device_t child, char *buf, size_t buflen)
379 {
380         char guidbuf[40];
381         struct hv_device *dev_ctx = device_get_ivars(child);
382
383         if (dev_ctx == NULL)
384                 return (0);
385
386         strlcat(buf, "classid=", buflen);
387         snprintf_hv_guid(guidbuf, sizeof(guidbuf), &dev_ctx->class_id);
388         strlcat(buf, guidbuf, buflen);
389
390         strlcat(buf, " deviceid=", buflen);
391         snprintf_hv_guid(guidbuf, sizeof(guidbuf), &dev_ctx->device_id);
392         strlcat(buf, guidbuf, buflen);
393
394         return (0);
395 }
396
397 struct hv_device*
398 hv_vmbus_child_device_create(
399         hv_guid         type,
400         hv_guid         instance,
401         hv_vmbus_channel*       channel)
402 {
403         hv_device* child_dev;
404
405         /*
406          * Allocate the new child device
407          */
408         child_dev = malloc(sizeof(hv_device), M_DEVBUF,
409                         M_WAITOK |  M_ZERO);
410
411         child_dev->channel = channel;
412         memcpy(&child_dev->class_id, &type, sizeof(hv_guid));
413         memcpy(&child_dev->device_id, &instance, sizeof(hv_guid));
414
415         return (child_dev);
416 }
417
418 int
419 snprintf_hv_guid(char *buf, size_t sz, const hv_guid *guid)
420 {
421         int cnt;
422         const unsigned char *d = guid->data;
423
424         cnt = snprintf(buf, sz,
425                 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
426                 d[3], d[2], d[1], d[0], d[5], d[4], d[7], d[6],
427                 d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
428         return (cnt);
429 }
430
431 int
432 hv_vmbus_child_device_register(struct hv_device *child_dev)
433 {
434         device_t child;
435
436         if (bootverbose) {
437                 char name[40];
438                 snprintf_hv_guid(name, sizeof(name), &child_dev->class_id);
439                 printf("VMBUS: Class ID: %s\n", name);
440         }
441
442         child = device_add_child(vmbus_get_device(), NULL, -1);
443         child_dev->device = child;
444         device_set_ivars(child, child_dev);
445
446         return (0);
447 }
448
449 int
450 hv_vmbus_child_device_unregister(struct hv_device *child_dev)
451 {
452         int ret = 0;
453         /*
454          * XXXKYS: Ensure that this is the opposite of
455          * device_add_child()
456          */
457         mtx_lock(&Giant);
458         ret = device_delete_child(vmbus_get_device(), child_dev->device);
459         mtx_unlock(&Giant);
460         return(ret);
461 }
462
463 static int
464 vmbus_probe(device_t dev)
465 {
466         if (ACPI_ID_PROBE(device_get_parent(dev), dev, vmbus_ids) == NULL ||
467             device_get_unit(dev) != 0 || vm_guest != VM_GUEST_HV)
468                 return (ENXIO);
469
470         device_set_desc(dev, "Hyper-V Vmbus");
471
472         return (BUS_PROBE_DEFAULT);
473 }
474
475 extern inthand_t IDTVEC(rsvd), IDTVEC(hv_vmbus_callback);
476
477 /**
478  * @brief Find a free IDT slot and setup the interrupt handler.
479  */
480 static int
481 vmbus_vector_alloc(void)
482 {
483         int vector;
484         uintptr_t func;
485         struct gate_descriptor *ip;
486
487         /*
488          * Search backwards form the highest IDT vector available for use
489          * as vmbus channel callback vector. We install 'hv_vmbus_callback'
490          * handler at that vector and use it to interrupt vcpus.
491          */
492         vector = APIC_SPURIOUS_INT;
493         while (--vector >= APIC_IPI_INTS) {
494                 ip = &idt[vector];
495                 func = ((long)ip->gd_hioffset << 16 | ip->gd_looffset);
496                 if (func == (uintptr_t)&IDTVEC(rsvd)) {
497 #ifdef __i386__
498                         setidt(vector , IDTVEC(hv_vmbus_callback), SDT_SYS386IGT,
499                             SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
500 #else
501                         setidt(vector , IDTVEC(hv_vmbus_callback), SDT_SYSIGT,
502                             SEL_KPL, 0);
503 #endif
504
505                         return (vector);
506                 }
507         }
508         return (0);
509 }
510
511 /**
512  * @brief Restore the IDT slot to rsvd.
513  */
514 static void
515 vmbus_vector_free(int vector)
516 {
517         uintptr_t func;
518         struct gate_descriptor *ip;
519
520         if (vector == 0)
521                 return;
522
523         KASSERT(vector >= APIC_IPI_INTS && vector < APIC_SPURIOUS_INT,
524             ("invalid vector %d", vector));
525
526         ip = &idt[vector];
527         func = ((long)ip->gd_hioffset << 16 | ip->gd_looffset);
528         KASSERT(func == (uintptr_t)&IDTVEC(hv_vmbus_callback),
529             ("invalid vector %d", vector));
530
531         setidt(vector, IDTVEC(rsvd), SDT_SYSIGT, SEL_KPL, 0);
532 }
533
534 static void
535 vmbus_cpuset_setthread_task(void *xmask, int pending __unused)
536 {
537         cpuset_t *mask = xmask;
538         int error;
539
540         error = cpuset_setthread(curthread->td_tid, mask);
541         if (error) {
542                 panic("curthread=%ju: can't pin; error=%d",
543                     (uintmax_t)curthread->td_tid, error);
544         }
545 }
546
547 /**
548  * @brief Main vmbus driver initialization routine.
549  *
550  * Here, we
551  * - initialize the vmbus driver context
552  * - setup various driver entry points
553  * - invoke the vmbus hv main init routine
554  * - get the irq resource
555  * - invoke the vmbus to add the vmbus root device
556  * - setup the vmbus root device
557  * - retrieve the channel offers
558  */
559 static int
560 vmbus_bus_init(void)
561 {
562         struct vmbus_softc *sc;
563         int i, n, ret, cpu;
564         char buf[MAXCOMLEN + 1];
565         cpuset_t cpu_mask;
566
567         if (vmbus_inited)
568                 return (0);
569
570         vmbus_inited = 1;
571         sc = vmbus_get_softc();
572
573         /*
574          * Find a free IDT vector for vmbus messages/events.
575          */
576         sc->vmbus_idtvec = vmbus_vector_alloc();
577         if (sc->vmbus_idtvec == 0) {
578                 device_printf(sc->vmbus_dev, "cannot find free IDT vector\n");
579                 ret = ENXIO;
580                 goto cleanup;
581         }
582         if(bootverbose) {
583                 device_printf(sc->vmbus_dev, "vmbus IDT vector %d\n",
584                     sc->vmbus_idtvec);
585         }
586
587         CPU_FOREACH(cpu) {
588                 snprintf(buf, sizeof(buf), "cpu%d:hyperv", cpu);
589                 intrcnt_add(buf, VMBUS_SC_PCPU_PTR(sc, intr_cnt, cpu));
590
591                 for (i = 0; i < 2; i++)
592                         setup_args.page_buffers[2 * cpu + i] = NULL;
593         }
594
595         /*
596          * Per cpu setup.
597          */
598         CPU_FOREACH(cpu) {
599                 struct task cpuset_task;
600
601                 /*
602                  * Setup taskqueue to handle events
603                  */
604                 hv_vmbus_g_context.hv_event_queue[cpu] =
605                     taskqueue_create_fast("hyperv event", M_WAITOK,
606                     taskqueue_thread_enqueue,
607                     &hv_vmbus_g_context.hv_event_queue[cpu]);
608                 taskqueue_start_threads(&hv_vmbus_g_context.hv_event_queue[cpu],
609                     1, PI_NET, "hvevent%d", cpu);
610
611                 CPU_SETOF(cpu, &cpu_mask);
612                 TASK_INIT(&cpuset_task, 0, vmbus_cpuset_setthread_task,
613                     &cpu_mask);
614                 taskqueue_enqueue(hv_vmbus_g_context.hv_event_queue[cpu],
615                     &cpuset_task);
616                 taskqueue_drain(hv_vmbus_g_context.hv_event_queue[cpu],
617                     &cpuset_task);
618
619                 /*
620                  * Setup per-cpu tasks and taskqueues to handle msg.
621                  */
622                 hv_vmbus_g_context.hv_msg_tq[cpu] = taskqueue_create_fast(
623                     "hyperv msg", M_WAITOK, taskqueue_thread_enqueue,
624                     &hv_vmbus_g_context.hv_msg_tq[cpu]);
625                 taskqueue_start_threads(&hv_vmbus_g_context.hv_msg_tq[cpu], 1,
626                      PI_NET, "hvmsg%d", cpu);
627                 TASK_INIT(&hv_vmbus_g_context.hv_msg_task[cpu], 0,
628                     vmbus_msg_task, NULL);
629
630                 CPU_SETOF(cpu, &cpu_mask);
631                 TASK_INIT(&cpuset_task, 0, vmbus_cpuset_setthread_task,
632                     &cpu_mask);
633                 taskqueue_enqueue(hv_vmbus_g_context.hv_msg_tq[cpu],
634                     &cpuset_task);
635                 taskqueue_drain(hv_vmbus_g_context.hv_msg_tq[cpu],
636                     &cpuset_task);
637
638                 /*
639                  * Prepare the per cpu msg and event pages to be called on
640                  * each cpu.
641                  */
642                 for(i = 0; i < 2; i++) {
643                         setup_args.page_buffers[2 * cpu + i] =
644                                 malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK | M_ZERO);
645                 }
646         }
647
648         if (bootverbose)
649                 printf("VMBUS: Calling smp_rendezvous, smp_started = %d\n",
650                     smp_started);
651
652         smp_rendezvous(NULL, vmbus_synic_setup, NULL, &setup_args);
653
654         /*
655          * Connect to VMBus in the root partition
656          */
657         ret = hv_vmbus_connect();
658
659         if (ret != 0)
660                 goto cleanup1;
661
662         if (hv_vmbus_protocal_version == HV_VMBUS_VERSION_WS2008 ||
663             hv_vmbus_protocal_version == HV_VMBUS_VERSION_WIN7)
664                 sc->vmbus_event_proc = vmbus_event_proc_compat;
665         else
666                 sc->vmbus_event_proc = vmbus_event_proc;
667
668         hv_vmbus_request_channel_offers();
669
670         vmbus_scan();
671         bus_generic_attach(sc->vmbus_dev);
672         device_printf(sc->vmbus_dev, "device scan, probe and attach done\n");
673
674         return (ret);
675
676         cleanup1:
677         /*
678          * Free pages alloc'ed
679          */
680         for (n = 0; n < 2 * MAXCPU; n++)
681                 if (setup_args.page_buffers[n] != NULL)
682                         free(setup_args.page_buffers[n], M_DEVBUF);
683
684         /*
685          * remove swi and vmbus callback vector;
686          */
687         CPU_FOREACH(cpu) {
688                 if (hv_vmbus_g_context.hv_event_queue[cpu] != NULL) {
689                         taskqueue_free(hv_vmbus_g_context.hv_event_queue[cpu]);
690                         hv_vmbus_g_context.hv_event_queue[cpu] = NULL;
691                 }
692         }
693
694         vmbus_vector_free(sc->vmbus_idtvec);
695
696         cleanup:
697         return (ret);
698 }
699
700 static void
701 vmbus_event_proc_dummy(struct vmbus_softc *sc __unused, int cpu __unused)
702 {
703 }
704
705 static int
706 vmbus_attach(device_t dev)
707 {
708         vmbus_sc = device_get_softc(dev);
709         vmbus_sc->vmbus_dev = dev;
710
711         /*
712          * Event processing logic will be configured:
713          * - After the vmbus protocol version negotiation.
714          * - Before we request channel offers.
715          */
716         vmbus_sc->vmbus_event_proc = vmbus_event_proc_dummy;
717
718         /* 
719          * If the system has already booted and thread
720          * scheduling is possible indicated by the global
721          * cold set to zero, we just call the driver
722          * initialization directly.
723          */
724         if (!cold)
725                 vmbus_bus_init();
726
727         bus_generic_probe(dev);
728         return (0);
729 }
730
731 static void
732 vmbus_sysinit(void *arg __unused)
733 {
734         if (vm_guest != VM_GUEST_HV || vmbus_get_softc() == NULL)
735                 return;
736
737         /* 
738          * If the system has already booted and thread
739          * scheduling is possible, as indicated by the
740          * global cold set to zero, we just call the driver
741          * initialization directly.
742          */
743         if (!cold) 
744                 vmbus_bus_init();
745 }
746
747 static int
748 vmbus_detach(device_t dev)
749 {
750         struct vmbus_softc *sc = device_get_softc(dev);
751         int i;
752
753         hv_vmbus_release_unattached_channels();
754         hv_vmbus_disconnect();
755
756         smp_rendezvous(NULL, vmbus_synic_teardown, NULL, NULL);
757
758         for(i = 0; i < 2 * MAXCPU; i++) {
759                 if (setup_args.page_buffers[i] != NULL)
760                         free(setup_args.page_buffers[i], M_DEVBUF);
761         }
762
763         /* remove swi */
764         CPU_FOREACH(i) {
765                 if (hv_vmbus_g_context.hv_event_queue[i] != NULL) {
766                         taskqueue_free(hv_vmbus_g_context.hv_event_queue[i]);
767                         hv_vmbus_g_context.hv_event_queue[i] = NULL;
768                 }
769         }
770
771         vmbus_vector_free(sc->vmbus_idtvec);
772
773         return (0);
774 }
775
776 static device_method_t vmbus_methods[] = {
777         /* Device interface */
778         DEVMETHOD(device_probe,                 vmbus_probe),
779         DEVMETHOD(device_attach,                vmbus_attach),
780         DEVMETHOD(device_detach,                vmbus_detach),
781         DEVMETHOD(device_shutdown,              bus_generic_shutdown),
782         DEVMETHOD(device_suspend,               bus_generic_suspend),
783         DEVMETHOD(device_resume,                bus_generic_resume),
784
785         /* Bus interface */
786         DEVMETHOD(bus_add_child,                bus_generic_add_child),
787         DEVMETHOD(bus_print_child,              bus_generic_print_child),
788         DEVMETHOD(bus_read_ivar,                vmbus_read_ivar),
789         DEVMETHOD(bus_write_ivar,               vmbus_write_ivar),
790         DEVMETHOD(bus_child_pnpinfo_str,        vmbus_child_pnpinfo_str),
791
792         DEVMETHOD_END
793 };
794
795 static driver_t vmbus_driver = {
796         "vmbus",
797         vmbus_methods,
798         sizeof(struct vmbus_softc)
799 };
800
801 static devclass_t vmbus_devclass;
802
803 DRIVER_MODULE(vmbus, acpi, vmbus_driver, vmbus_devclass, NULL, NULL);
804 MODULE_DEPEND(vmbus, acpi, 1, 1, 1);
805 MODULE_VERSION(vmbus, 1);
806
807 /*
808  * NOTE:
809  * We have to start as the last step of SI_SUB_SMP, i.e. after SMP is
810  * initialized.
811  */
812 SYSINIT(vmbus_initialize, SI_SUB_SMP, SI_ORDER_ANY, vmbus_sysinit, NULL);
813