vmbus.c revision 302170
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 302170 2016-06-24 02:30:14Z 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		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
116static __inline int
117vmbus_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
177void
178vmbus_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
201static void
202vmbus_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
270static void
271vmbus_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
309static int
310vmbus_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
359static void
360vmbus_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 */
398static int
399vmbus_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 */
432static void
433vmbus_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
452static void
453vmbus_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
465static int
466vmbus_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
533static void
534vmbus_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
554static int
555vmbus_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
579static int
580vmbus_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
593static int
594vmbus_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
613struct hv_device *
614hv_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
631int
632hv_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
651int
652hv_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
665static int
666vmbus_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 */
692static int
693vmbus_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
745cleanup:
746	vmbus_intr_teardown(sc);
747	vmbus_dma_free(sc);
748
749	return (ret);
750}
751
752static void
753vmbus_event_proc_dummy(struct vmbus_softc *sc __unused, int cpu __unused)
754{
755}
756
757static int
758vmbus_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
783static void
784vmbus_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
799static int
800vmbus_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
818static 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
837static driver_t vmbus_driver = {
838	"vmbus",
839	vmbus_methods,
840	sizeof(struct vmbus_softc)
841};
842
843static devclass_t vmbus_devclass;
844
845DRIVER_MODULE(vmbus, acpi, vmbus_driver, vmbus_devclass, NULL, NULL);
846MODULE_DEPEND(vmbus, acpi, 1, 1, 1);
847MODULE_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 */
854SYSINIT(vmbus_initialize, SI_SUB_SMP, SI_ORDER_ANY, vmbus_sysinit, NULL);
855
856