]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c
MFC 301015
[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/hyperv_reg.h>
65 #include <dev/hyperv/vmbus/hyperv_var.h>
66 #include <dev/hyperv/vmbus/vmbus_var.h>
67
68 #include <contrib/dev/acpica/include/acpi.h>
69 #include "acpi_if.h"
70
71 struct vmbus_softc      *vmbus_sc;
72
73 static char *vmbus_ids[] = { "VMBUS", NULL };
74
75 extern inthand_t IDTVEC(rsvd), IDTVEC(vmbus_isr);
76
77 static void
78 vmbus_msg_task(void *xsc, int pending __unused)
79 {
80         struct vmbus_softc *sc = xsc;
81         hv_vmbus_message *msg;
82
83         msg = VMBUS_PCPU_GET(sc, message, curcpu) + VMBUS_SINT_MESSAGE;
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(MSR_HV_EOM, 0);
123                 }
124         }
125 }
126
127 static __inline int
128 vmbus_handle_intr1(struct vmbus_softc *sc, struct trapframe *frame, int cpu)
129 {
130         hv_vmbus_message *msg, *msg_base;
131
132         msg_base = VMBUS_PCPU_GET(sc, message, cpu);
133
134         /*
135          * Check event timer.
136          *
137          * TODO: move this to independent IDT vector.
138          */
139         msg = msg_base + VMBUS_SINT_TIMER;
140         if (msg->header.message_type == HV_MESSAGE_TIMER_EXPIRED) {
141                 msg->header.message_type = HV_MESSAGE_TYPE_NONE;
142
143                 vmbus_et_intr(frame);
144
145                 /*
146                  * Make sure the write to message_type (ie set to
147                  * HV_MESSAGE_TYPE_NONE) happens before we read the
148                  * message_pending and EOMing. Otherwise, the EOMing will
149                  * not deliver any more messages
150                  * since there is no empty slot
151                  *
152                  * NOTE:
153                  * mb() is used here, since atomic_thread_fence_seq_cst()
154                  * will become compiler fence on UP kernel.
155                  */
156                 mb();
157
158                 if (msg->header.message_flags.u.message_pending) {
159                         /*
160                          * This will cause message queue rescan to possibly
161                          * deliver another msg from the hypervisor
162                          */
163                         wrmsr(MSR_HV_EOM, 0);
164                 }
165         }
166
167         /*
168          * Check events.  Hot path for network and storage I/O data; high rate.
169          *
170          * NOTE:
171          * As recommended by the Windows guest fellows, we check events before
172          * checking messages.
173          */
174         sc->vmbus_event_proc(sc, cpu);
175
176         /*
177          * Check messages.  Mainly management stuffs; ultra low rate.
178          */
179         msg = msg_base + VMBUS_SINT_MESSAGE;
180         if (__predict_false(msg->header.message_type != HV_MESSAGE_TYPE_NONE)) {
181                 taskqueue_enqueue(VMBUS_PCPU_GET(sc, message_tq, cpu),
182                     VMBUS_PCPU_PTR(sc, message_task, cpu));
183         }
184
185         return (FILTER_HANDLED);
186 }
187
188 void
189 vmbus_handle_intr(struct trapframe *trap_frame)
190 {
191         struct vmbus_softc *sc = vmbus_get_softc();
192         int cpu = curcpu;
193
194         /*
195          * Disable preemption.
196          */
197         critical_enter();
198
199         /*
200          * Do a little interrupt counting.
201          */
202         (*VMBUS_PCPU_GET(sc, intr_cnt, cpu))++;
203
204         vmbus_handle_intr1(sc, trap_frame, cpu);
205
206         /*
207          * Enable preemption.
208          */
209         critical_exit();
210 }
211
212 static void
213 vmbus_synic_setup(void *xsc)
214 {
215         struct vmbus_softc *sc = xsc;
216         int cpu = curcpu;
217         uint64_t val, orig;
218         uint32_t sint;
219
220         if (hyperv_features & CPUID_HV_MSR_VP_INDEX) {
221                 /*
222                  * Save virtual processor id.
223                  */
224                 VMBUS_PCPU_GET(sc, vcpuid, cpu) = rdmsr(MSR_HV_VP_INDEX);
225         } else {
226                 /*
227                  * XXX
228                  * Virtual processoor id is only used by a pretty broken
229                  * channel selection code from storvsc.  It's nothing
230                  * critical even if CPUID_HV_MSR_VP_INDEX is not set; keep
231                  * moving on.
232                  */
233                 VMBUS_PCPU_GET(sc, vcpuid, cpu) = cpu;
234         }
235
236         /*
237          * Setup the SynIC message.
238          */
239         orig = rdmsr(MSR_HV_SIMP);
240         val = MSR_HV_SIMP_ENABLE | (orig & MSR_HV_SIMP_RSVD_MASK) |
241             ((VMBUS_PCPU_GET(sc, message_dma.hv_paddr, cpu) >> PAGE_SHIFT) <<
242              MSR_HV_SIMP_PGSHIFT);
243         wrmsr(MSR_HV_SIMP, val);
244
245         /*
246          * Setup the SynIC event flags.
247          */
248         orig = rdmsr(MSR_HV_SIEFP);
249         val = MSR_HV_SIEFP_ENABLE | (orig & MSR_HV_SIEFP_RSVD_MASK) |
250             ((VMBUS_PCPU_GET(sc, event_flag_dma.hv_paddr, cpu) >> PAGE_SHIFT) <<
251              MSR_HV_SIEFP_PGSHIFT);
252         wrmsr(MSR_HV_SIEFP, val);
253
254
255         /*
256          * Configure and unmask SINT for message and event flags.
257          */
258         sint = MSR_HV_SINT0 + VMBUS_SINT_MESSAGE;
259         orig = rdmsr(sint);
260         val = sc->vmbus_idtvec | MSR_HV_SINT_AUTOEOI |
261             (orig & MSR_HV_SINT_RSVD_MASK);
262         wrmsr(sint, val);
263
264         /*
265          * Configure and unmask SINT for timer.
266          */
267         sint = MSR_HV_SINT0 + VMBUS_SINT_TIMER;
268         orig = rdmsr(sint);
269         val = sc->vmbus_idtvec | MSR_HV_SINT_AUTOEOI |
270             (orig & MSR_HV_SINT_RSVD_MASK);
271         wrmsr(sint, val);
272
273         /*
274          * All done; enable SynIC.
275          */
276         orig = rdmsr(MSR_HV_SCONTROL);
277         val = MSR_HV_SCTRL_ENABLE | (orig & MSR_HV_SCTRL_RSVD_MASK);
278         wrmsr(MSR_HV_SCONTROL, val);
279 }
280
281 static void
282 vmbus_synic_teardown(void *arg)
283 {
284         uint64_t orig;
285         uint32_t sint;
286
287         /*
288          * Disable SynIC.
289          */
290         orig = rdmsr(MSR_HV_SCONTROL);
291         wrmsr(MSR_HV_SCONTROL, (orig & MSR_HV_SCTRL_RSVD_MASK));
292
293         /*
294          * Mask message and event flags SINT.
295          */
296         sint = MSR_HV_SINT0 + VMBUS_SINT_MESSAGE;
297         orig = rdmsr(sint);
298         wrmsr(sint, orig | MSR_HV_SINT_MASKED);
299
300         /*
301          * Mask timer SINT.
302          */
303         sint = MSR_HV_SINT0 + VMBUS_SINT_TIMER;
304         orig = rdmsr(sint);
305         wrmsr(sint, orig | MSR_HV_SINT_MASKED);
306
307         /*
308          * Teardown SynIC message.
309          */
310         orig = rdmsr(MSR_HV_SIMP);
311         wrmsr(MSR_HV_SIMP, (orig & MSR_HV_SIMP_RSVD_MASK));
312
313         /*
314          * Teardown SynIC event flags.
315          */
316         orig = rdmsr(MSR_HV_SIEFP);
317         wrmsr(MSR_HV_SIEFP, (orig & MSR_HV_SIEFP_RSVD_MASK));
318 }
319
320 static int
321 vmbus_dma_alloc(struct vmbus_softc *sc)
322 {
323         int cpu;
324
325         CPU_FOREACH(cpu) {
326                 void *ptr;
327
328                 /*
329                  * Per-cpu messages and event flags.
330                  */
331                 ptr = hyperv_dmamem_alloc(bus_get_dma_tag(sc->vmbus_dev),
332                     PAGE_SIZE, 0, PAGE_SIZE,
333                     VMBUS_PCPU_PTR(sc, message_dma, cpu),
334                     BUS_DMA_WAITOK | BUS_DMA_ZERO);
335                 if (ptr == NULL)
336                         return ENOMEM;
337                 VMBUS_PCPU_GET(sc, message, cpu) = ptr;
338
339                 ptr = hyperv_dmamem_alloc(bus_get_dma_tag(sc->vmbus_dev),
340                     PAGE_SIZE, 0, PAGE_SIZE,
341                     VMBUS_PCPU_PTR(sc, event_flag_dma, cpu),
342                     BUS_DMA_WAITOK | BUS_DMA_ZERO);
343                 if (ptr == NULL)
344                         return ENOMEM;
345                 VMBUS_PCPU_GET(sc, event_flag, cpu) = ptr;
346         }
347         return 0;
348 }
349
350 static void
351 vmbus_dma_free(struct vmbus_softc *sc)
352 {
353         int cpu;
354
355         CPU_FOREACH(cpu) {
356                 if (VMBUS_PCPU_GET(sc, message, cpu) != NULL) {
357                         hyperv_dmamem_free(
358                             VMBUS_PCPU_PTR(sc, message_dma, cpu),
359                             VMBUS_PCPU_GET(sc, message, cpu));
360                         VMBUS_PCPU_GET(sc, message, cpu) = NULL;
361                 }
362                 if (VMBUS_PCPU_GET(sc, event_flag, cpu) != NULL) {
363                         hyperv_dmamem_free(
364                             VMBUS_PCPU_PTR(sc, event_flag_dma, cpu),
365                             VMBUS_PCPU_GET(sc, event_flag, cpu));
366                         VMBUS_PCPU_GET(sc, event_flag, cpu) = NULL;
367                 }
368         }
369 }
370
371 /**
372  * @brief Find a free IDT slot and setup the interrupt handler.
373  */
374 static int
375 vmbus_vector_alloc(void)
376 {
377         int vector;
378         uintptr_t func;
379         struct gate_descriptor *ip;
380
381         /*
382          * Search backwards form the highest IDT vector available for use
383          * as vmbus channel callback vector. We install 'hv_vmbus_callback'
384          * handler at that vector and use it to interrupt vcpus.
385          */
386         vector = APIC_SPURIOUS_INT;
387         while (--vector >= APIC_IPI_INTS) {
388                 ip = &idt[vector];
389                 func = ((long)ip->gd_hioffset << 16 | ip->gd_looffset);
390                 if (func == (uintptr_t)&IDTVEC(rsvd)) {
391 #ifdef __i386__
392                         setidt(vector , IDTVEC(vmbus_isr), SDT_SYS386IGT,
393                             SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
394 #else
395                         setidt(vector , IDTVEC(vmbus_isr), SDT_SYSIGT,
396                             SEL_KPL, 0);
397 #endif
398
399                         return (vector);
400                 }
401         }
402         return (0);
403 }
404
405 /**
406  * @brief Restore the IDT slot to rsvd.
407  */
408 static void
409 vmbus_vector_free(int vector)
410 {
411         uintptr_t func;
412         struct gate_descriptor *ip;
413
414         if (vector == 0)
415                 return;
416
417         KASSERT(vector >= APIC_IPI_INTS && vector < APIC_SPURIOUS_INT,
418             ("invalid vector %d", vector));
419
420         ip = &idt[vector];
421         func = ((long)ip->gd_hioffset << 16 | ip->gd_looffset);
422         KASSERT(func == (uintptr_t)&IDTVEC(hv_vmbus_callback),
423             ("invalid vector %d", vector));
424
425         setidt(vector, IDTVEC(rsvd), SDT_SYSIGT, SEL_KPL, 0);
426 }
427
428 static void
429 vmbus_cpuset_setthread_task(void *xmask, int pending __unused)
430 {
431         cpuset_t *mask = xmask;
432         int error;
433
434         error = cpuset_setthread(curthread->td_tid, mask);
435         if (error) {
436                 panic("curthread=%ju: can't pin; error=%d",
437                     (uintmax_t)curthread->td_tid, error);
438         }
439 }
440
441 static int
442 vmbus_intr_setup(struct vmbus_softc *sc)
443 {
444         int cpu;
445
446         CPU_FOREACH(cpu) {
447                 struct task cpuset_task;
448                 char buf[MAXCOMLEN + 1];
449                 cpuset_t cpu_mask;
450
451                 /* Allocate an interrupt counter for Hyper-V interrupt */
452                 snprintf(buf, sizeof(buf), "cpu%d:hyperv", cpu);
453                 intrcnt_add(buf, VMBUS_PCPU_PTR(sc, intr_cnt, cpu));
454
455                 /*
456                  * Setup taskqueue to handle events.  Task will be per-
457                  * channel.
458                  */
459                 VMBUS_PCPU_GET(sc, event_tq, cpu) = taskqueue_create_fast(
460                     "hyperv event", M_WAITOK, taskqueue_thread_enqueue,
461                     VMBUS_PCPU_PTR(sc, event_tq, cpu));
462                 taskqueue_start_threads(VMBUS_PCPU_PTR(sc, event_tq, cpu),
463                     1, PI_NET, "hvevent%d", cpu);
464
465                 CPU_SETOF(cpu, &cpu_mask);
466                 TASK_INIT(&cpuset_task, 0, vmbus_cpuset_setthread_task,
467                     &cpu_mask);
468                 taskqueue_enqueue(VMBUS_PCPU_GET(sc, event_tq, cpu),
469                     &cpuset_task);
470                 taskqueue_drain(VMBUS_PCPU_GET(sc, event_tq, cpu),
471                     &cpuset_task);
472
473                 /*
474                  * Setup tasks and taskqueues to handle messages.
475                  */
476                 VMBUS_PCPU_GET(sc, message_tq, cpu) = taskqueue_create_fast(
477                     "hyperv msg", M_WAITOK, taskqueue_thread_enqueue,
478                     VMBUS_PCPU_PTR(sc, message_tq, cpu));
479                 taskqueue_start_threads(VMBUS_PCPU_PTR(sc, message_tq, cpu), 1,
480                     PI_NET, "hvmsg%d", cpu);
481                 TASK_INIT(VMBUS_PCPU_PTR(sc, message_task, cpu), 0,
482                     vmbus_msg_task, sc);
483
484                 CPU_SETOF(cpu, &cpu_mask);
485                 TASK_INIT(&cpuset_task, 0, vmbus_cpuset_setthread_task,
486                     &cpu_mask);
487                 taskqueue_enqueue(VMBUS_PCPU_GET(sc, message_tq, cpu),
488                     &cpuset_task);
489                 taskqueue_drain(VMBUS_PCPU_GET(sc, message_tq, cpu),
490                     &cpuset_task);
491         }
492
493         /*
494          * All Hyper-V ISR required resources are setup, now let's find a
495          * free IDT vector for Hyper-V ISR and set it up.
496          */
497         sc->vmbus_idtvec = vmbus_vector_alloc();
498         if (sc->vmbus_idtvec == 0) {
499                 device_printf(sc->vmbus_dev, "cannot find free IDT vector\n");
500                 return ENXIO;
501         }
502         if(bootverbose) {
503                 device_printf(sc->vmbus_dev, "vmbus IDT vector %d\n",
504                     sc->vmbus_idtvec);
505         }
506         return 0;
507 }
508
509 static void
510 vmbus_intr_teardown(struct vmbus_softc *sc)
511 {
512         int cpu;
513
514         vmbus_vector_free(sc->vmbus_idtvec);
515
516         CPU_FOREACH(cpu) {
517                 if (VMBUS_PCPU_GET(sc, event_tq, cpu) != NULL) {
518                         taskqueue_free(VMBUS_PCPU_GET(sc, event_tq, cpu));
519                         VMBUS_PCPU_GET(sc, event_tq, cpu) = NULL;
520                 }
521                 if (VMBUS_PCPU_GET(sc, message_tq, cpu) != NULL) {
522                         taskqueue_drain(VMBUS_PCPU_GET(sc, message_tq, cpu),
523                             VMBUS_PCPU_PTR(sc, message_task, cpu));
524                         taskqueue_free(VMBUS_PCPU_GET(sc, message_tq, cpu));
525                         VMBUS_PCPU_GET(sc, message_tq, cpu) = NULL;
526                 }
527         }
528 }
529
530 static int
531 vmbus_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
532 {
533         struct hv_device *child_dev_ctx = device_get_ivars(child);
534
535         switch (index) {
536         case HV_VMBUS_IVAR_TYPE:
537                 *result = (uintptr_t) &child_dev_ctx->class_id;
538                 return (0);
539         case HV_VMBUS_IVAR_INSTANCE:
540                 *result = (uintptr_t) &child_dev_ctx->device_id;
541                 return (0);
542         case HV_VMBUS_IVAR_DEVCTX:
543                 *result = (uintptr_t) child_dev_ctx;
544                 return (0);
545         case HV_VMBUS_IVAR_NODE:
546                 *result = (uintptr_t) child_dev_ctx->device;
547                 return (0);
548         }
549         return (ENOENT);
550 }
551
552 static int
553 vmbus_write_ivar(device_t dev, device_t child, int index, uintptr_t value)
554 {
555         switch (index) {
556         case HV_VMBUS_IVAR_TYPE:
557         case HV_VMBUS_IVAR_INSTANCE:
558         case HV_VMBUS_IVAR_DEVCTX:
559         case HV_VMBUS_IVAR_NODE:
560                 /* read-only */
561                 return (EINVAL);
562         }
563         return (ENOENT);
564 }
565
566 static int
567 vmbus_child_pnpinfo_str(device_t dev, device_t child, char *buf, size_t buflen)
568 {
569         char guidbuf[40];
570         struct hv_device *dev_ctx = device_get_ivars(child);
571
572         if (dev_ctx == NULL)
573                 return (0);
574
575         strlcat(buf, "classid=", buflen);
576         snprintf_hv_guid(guidbuf, sizeof(guidbuf), &dev_ctx->class_id);
577         strlcat(buf, guidbuf, buflen);
578
579         strlcat(buf, " deviceid=", buflen);
580         snprintf_hv_guid(guidbuf, sizeof(guidbuf), &dev_ctx->device_id);
581         strlcat(buf, guidbuf, buflen);
582
583         return (0);
584 }
585
586 struct hv_device *
587 hv_vmbus_child_device_create(hv_guid type, hv_guid instance,
588     hv_vmbus_channel *channel)
589 {
590         hv_device *child_dev;
591
592         /*
593          * Allocate the new child device
594          */
595         child_dev = malloc(sizeof(hv_device), M_DEVBUF, M_WAITOK | M_ZERO);
596
597         child_dev->channel = channel;
598         memcpy(&child_dev->class_id, &type, sizeof(hv_guid));
599         memcpy(&child_dev->device_id, &instance, sizeof(hv_guid));
600
601         return (child_dev);
602 }
603
604 int
605 snprintf_hv_guid(char *buf, size_t sz, const hv_guid *guid)
606 {
607         int cnt;
608         const unsigned char *d = guid->data;
609
610         cnt = snprintf(buf, sz,
611                 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
612                 d[3], d[2], d[1], d[0], d[5], d[4], d[7], d[6],
613                 d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
614         return (cnt);
615 }
616
617 int
618 hv_vmbus_child_device_register(struct hv_device *child_dev)
619 {
620         device_t child;
621
622         if (bootverbose) {
623                 char name[40];
624                 snprintf_hv_guid(name, sizeof(name), &child_dev->class_id);
625                 printf("VMBUS: Class ID: %s\n", name);
626         }
627
628         child = device_add_child(vmbus_get_device(), NULL, -1);
629         child_dev->device = child;
630         device_set_ivars(child, child_dev);
631
632         return (0);
633 }
634
635 int
636 hv_vmbus_child_device_unregister(struct hv_device *child_dev)
637 {
638         int ret = 0;
639         /*
640          * XXXKYS: Ensure that this is the opposite of
641          * device_add_child()
642          */
643         mtx_lock(&Giant);
644         ret = device_delete_child(vmbus_get_device(), child_dev->device);
645         mtx_unlock(&Giant);
646         return(ret);
647 }
648
649 static int
650 vmbus_probe(device_t dev)
651 {
652         if (ACPI_ID_PROBE(device_get_parent(dev), dev, vmbus_ids) == NULL ||
653             device_get_unit(dev) != 0 || vm_guest != VM_GUEST_HV ||
654             (hyperv_features & CPUID_HV_MSR_SYNIC) == 0)
655                 return (ENXIO);
656
657         device_set_desc(dev, "Hyper-V Vmbus");
658
659         return (BUS_PROBE_DEFAULT);
660 }
661
662 /**
663  * @brief Main vmbus driver initialization routine.
664  *
665  * Here, we
666  * - initialize the vmbus driver context
667  * - setup various driver entry points
668  * - invoke the vmbus hv main init routine
669  * - get the irq resource
670  * - invoke the vmbus to add the vmbus root device
671  * - setup the vmbus root device
672  * - retrieve the channel offers
673  */
674 static int
675 vmbus_bus_init(void)
676 {
677         struct vmbus_softc *sc = vmbus_get_softc();
678         int ret;
679
680         if (sc->vmbus_flags & VMBUS_FLAG_ATTACHED)
681                 return (0);
682         sc->vmbus_flags |= VMBUS_FLAG_ATTACHED;
683
684         /*
685          * Allocate DMA stuffs.
686          */
687         ret = vmbus_dma_alloc(sc);
688         if (ret != 0)
689                 goto cleanup;
690
691         /*
692          * Setup interrupt.
693          */
694         ret = vmbus_intr_setup(sc);
695         if (ret != 0)
696                 goto cleanup;
697
698         /*
699          * Setup SynIC.
700          */
701         if (bootverbose)
702                 device_printf(sc->vmbus_dev, "smp_started = %d\n", smp_started);
703         smp_rendezvous(NULL, vmbus_synic_setup, NULL, sc);
704         sc->vmbus_flags |= VMBUS_FLAG_SYNIC;
705
706         /*
707          * Connect to VMBus in the root partition
708          */
709         ret = hv_vmbus_connect();
710
711         if (ret != 0)
712                 goto cleanup;
713
714         if (hv_vmbus_protocal_version == HV_VMBUS_VERSION_WS2008 ||
715             hv_vmbus_protocal_version == HV_VMBUS_VERSION_WIN7)
716                 sc->vmbus_event_proc = vmbus_event_proc_compat;
717         else
718                 sc->vmbus_event_proc = vmbus_event_proc;
719
720         hv_vmbus_request_channel_offers();
721
722         vmbus_scan();
723         bus_generic_attach(sc->vmbus_dev);
724         device_printf(sc->vmbus_dev, "device scan, probe and attach done\n");
725
726         return (ret);
727
728 cleanup:
729         vmbus_intr_teardown(sc);
730         vmbus_dma_free(sc);
731
732         return (ret);
733 }
734
735 static void
736 vmbus_event_proc_dummy(struct vmbus_softc *sc __unused, int cpu __unused)
737 {
738 }
739
740 static int
741 vmbus_attach(device_t dev)
742 {
743         vmbus_sc = device_get_softc(dev);
744         vmbus_sc->vmbus_dev = dev;
745
746         /*
747          * Event processing logic will be configured:
748          * - After the vmbus protocol version negotiation.
749          * - Before we request channel offers.
750          */
751         vmbus_sc->vmbus_event_proc = vmbus_event_proc_dummy;
752
753         /* 
754          * If the system has already booted and thread
755          * scheduling is possible indicated by the global
756          * cold set to zero, we just call the driver
757          * initialization directly.
758          */
759         if (!cold)
760                 vmbus_bus_init();
761
762         bus_generic_probe(dev);
763         return (0);
764 }
765
766 static void
767 vmbus_sysinit(void *arg __unused)
768 {
769         if (vm_guest != VM_GUEST_HV || vmbus_get_softc() == NULL)
770                 return;
771
772         /* 
773          * If the system has already booted and thread
774          * scheduling is possible, as indicated by the
775          * global cold set to zero, we just call the driver
776          * initialization directly.
777          */
778         if (!cold) 
779                 vmbus_bus_init();
780 }
781
782 static int
783 vmbus_detach(device_t dev)
784 {
785         struct vmbus_softc *sc = device_get_softc(dev);
786
787         hv_vmbus_release_unattached_channels();
788         hv_vmbus_disconnect();
789
790         if (sc->vmbus_flags & VMBUS_FLAG_SYNIC) {
791                 sc->vmbus_flags &= ~VMBUS_FLAG_SYNIC;
792                 smp_rendezvous(NULL, vmbus_synic_teardown, NULL, NULL);
793         }
794
795         vmbus_intr_teardown(sc);
796         vmbus_dma_free(sc);
797
798         return (0);
799 }
800
801 static device_method_t vmbus_methods[] = {
802         /* Device interface */
803         DEVMETHOD(device_probe,                 vmbus_probe),
804         DEVMETHOD(device_attach,                vmbus_attach),
805         DEVMETHOD(device_detach,                vmbus_detach),
806         DEVMETHOD(device_shutdown,              bus_generic_shutdown),
807         DEVMETHOD(device_suspend,               bus_generic_suspend),
808         DEVMETHOD(device_resume,                bus_generic_resume),
809
810         /* Bus interface */
811         DEVMETHOD(bus_add_child,                bus_generic_add_child),
812         DEVMETHOD(bus_print_child,              bus_generic_print_child),
813         DEVMETHOD(bus_read_ivar,                vmbus_read_ivar),
814         DEVMETHOD(bus_write_ivar,               vmbus_write_ivar),
815         DEVMETHOD(bus_child_pnpinfo_str,        vmbus_child_pnpinfo_str),
816
817         DEVMETHOD_END
818 };
819
820 static driver_t vmbus_driver = {
821         "vmbus",
822         vmbus_methods,
823         sizeof(struct vmbus_softc)
824 };
825
826 static devclass_t vmbus_devclass;
827
828 DRIVER_MODULE(vmbus, acpi, vmbus_driver, vmbus_devclass, NULL, NULL);
829 MODULE_DEPEND(vmbus, acpi, 1, 1, 1);
830 MODULE_VERSION(vmbus, 1);
831
832 /*
833  * NOTE:
834  * We have to start as the last step of SI_SUB_SMP, i.e. after SMP is
835  * initialized.
836  */
837 SYSINIT(vmbus_initialize, SI_SUB_SMP, SI_ORDER_ANY, vmbus_sysinit, NULL);
838