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