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