vmbus.c revision 307466
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/11/sys/dev/hyperv/vmbus/vmbus.c 307466 2016-10-17 03:48:22Z 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/mutex.h>
42#include <sys/smp.h>
43#include <sys/sysctl.h>
44#include <sys/systm.h>
45#include <sys/taskqueue.h>
46
47#include <machine/intr_machdep.h>
48#include <x86/include/apicvar.h>
49
50#include <contrib/dev/acpica/include/acpi.h>
51
52#include <dev/hyperv/include/hyperv.h>
53#include <dev/hyperv/vmbus/hyperv_reg.h>
54#include <dev/hyperv/vmbus/hyperv_var.h>
55#include <dev/hyperv/vmbus/vmbus_reg.h>
56#include <dev/hyperv/vmbus/vmbus_var.h>
57#include <dev/hyperv/vmbus/vmbus_chanvar.h>
58
59#include "acpi_if.h"
60#include "vmbus_if.h"
61
62#define VMBUS_GPADL_START		0xe1e10
63
64struct vmbus_msghc {
65	struct hypercall_postmsg_in	*mh_inprm;
66	struct hypercall_postmsg_in	mh_inprm_save;
67	struct hyperv_dma		mh_inprm_dma;
68
69	struct vmbus_message		*mh_resp;
70	struct vmbus_message		mh_resp0;
71};
72
73struct vmbus_msghc_ctx {
74	struct vmbus_msghc		*mhc_free;
75	struct mtx			mhc_free_lock;
76	uint32_t			mhc_flags;
77
78	struct vmbus_msghc		*mhc_active;
79	struct mtx			mhc_active_lock;
80};
81
82#define VMBUS_MSGHC_CTXF_DESTROY	0x0001
83
84static int			vmbus_probe(device_t);
85static int			vmbus_attach(device_t);
86static int			vmbus_detach(device_t);
87static int			vmbus_read_ivar(device_t, device_t, int,
88				    uintptr_t *);
89static int			vmbus_child_pnpinfo_str(device_t, device_t,
90				    char *, size_t);
91static uint32_t			vmbus_get_version_method(device_t, device_t);
92static int			vmbus_probe_guid_method(device_t, device_t,
93				    const struct hyperv_guid *);
94
95static int			vmbus_init(struct vmbus_softc *);
96static int			vmbus_connect(struct vmbus_softc *, uint32_t);
97static int			vmbus_req_channels(struct vmbus_softc *sc);
98static void			vmbus_disconnect(struct vmbus_softc *);
99static int			vmbus_scan(struct vmbus_softc *);
100static void			vmbus_scan_wait(struct vmbus_softc *);
101static void			vmbus_scan_newchan(struct vmbus_softc *);
102static void			vmbus_scan_newdev(struct vmbus_softc *);
103static void			vmbus_scan_done(struct vmbus_softc *,
104				    const struct vmbus_message *);
105static void			vmbus_chanmsg_handle(struct vmbus_softc *,
106				    const struct vmbus_message *);
107static void			vmbus_msg_task(void *, int);
108static void			vmbus_synic_setup(void *);
109static void			vmbus_synic_teardown(void *);
110static int			vmbus_sysctl_version(SYSCTL_HANDLER_ARGS);
111static int			vmbus_dma_alloc(struct vmbus_softc *);
112static void			vmbus_dma_free(struct vmbus_softc *);
113static int			vmbus_intr_setup(struct vmbus_softc *);
114static void			vmbus_intr_teardown(struct vmbus_softc *);
115static int			vmbus_doattach(struct vmbus_softc *);
116static void			vmbus_event_proc_dummy(struct vmbus_softc *,
117				    int);
118
119static struct vmbus_msghc_ctx	*vmbus_msghc_ctx_create(bus_dma_tag_t);
120static void			vmbus_msghc_ctx_destroy(
121				    struct vmbus_msghc_ctx *);
122static void			vmbus_msghc_ctx_free(struct vmbus_msghc_ctx *);
123static struct vmbus_msghc	*vmbus_msghc_alloc(bus_dma_tag_t);
124static void			vmbus_msghc_free(struct vmbus_msghc *);
125static struct vmbus_msghc	*vmbus_msghc_get1(struct vmbus_msghc_ctx *,
126				    uint32_t);
127
128static struct vmbus_softc	*vmbus_sc;
129
130extern inthand_t IDTVEC(vmbus_isr);
131
132static const uint32_t		vmbus_version[] = {
133	VMBUS_VERSION_WIN8_1,
134	VMBUS_VERSION_WIN8,
135	VMBUS_VERSION_WIN7,
136	VMBUS_VERSION_WS2008
137};
138
139static const vmbus_chanmsg_proc_t
140vmbus_chanmsg_handlers[VMBUS_CHANMSG_TYPE_MAX] = {
141	VMBUS_CHANMSG_PROC(CHOFFER_DONE, vmbus_scan_done),
142	VMBUS_CHANMSG_PROC_WAKEUP(CONNECT_RESP)
143};
144
145static device_method_t vmbus_methods[] = {
146	/* Device interface */
147	DEVMETHOD(device_probe,			vmbus_probe),
148	DEVMETHOD(device_attach,		vmbus_attach),
149	DEVMETHOD(device_detach,		vmbus_detach),
150	DEVMETHOD(device_shutdown,		bus_generic_shutdown),
151	DEVMETHOD(device_suspend,		bus_generic_suspend),
152	DEVMETHOD(device_resume,		bus_generic_resume),
153
154	/* Bus interface */
155	DEVMETHOD(bus_add_child,		bus_generic_add_child),
156	DEVMETHOD(bus_print_child,		bus_generic_print_child),
157	DEVMETHOD(bus_read_ivar,		vmbus_read_ivar),
158	DEVMETHOD(bus_child_pnpinfo_str,	vmbus_child_pnpinfo_str),
159
160	/* Vmbus interface */
161	DEVMETHOD(vmbus_get_version,		vmbus_get_version_method),
162	DEVMETHOD(vmbus_probe_guid,		vmbus_probe_guid_method),
163
164	DEVMETHOD_END
165};
166
167static driver_t vmbus_driver = {
168	"vmbus",
169	vmbus_methods,
170	sizeof(struct vmbus_softc)
171};
172
173static devclass_t vmbus_devclass;
174
175DRIVER_MODULE(vmbus, acpi, vmbus_driver, vmbus_devclass, NULL, NULL);
176MODULE_DEPEND(vmbus, acpi, 1, 1, 1);
177MODULE_VERSION(vmbus, 1);
178
179static __inline struct vmbus_softc *
180vmbus_get_softc(void)
181{
182	return vmbus_sc;
183}
184
185static struct vmbus_msghc *
186vmbus_msghc_alloc(bus_dma_tag_t parent_dtag)
187{
188	struct vmbus_msghc *mh;
189
190	mh = malloc(sizeof(*mh), M_DEVBUF, M_WAITOK | M_ZERO);
191
192	mh->mh_inprm = hyperv_dmamem_alloc(parent_dtag,
193	    HYPERCALL_PARAM_ALIGN, 0, HYPERCALL_POSTMSGIN_SIZE,
194	    &mh->mh_inprm_dma, BUS_DMA_WAITOK);
195	if (mh->mh_inprm == NULL) {
196		free(mh, M_DEVBUF);
197		return NULL;
198	}
199	return mh;
200}
201
202static void
203vmbus_msghc_free(struct vmbus_msghc *mh)
204{
205	hyperv_dmamem_free(&mh->mh_inprm_dma, mh->mh_inprm);
206	free(mh, M_DEVBUF);
207}
208
209static void
210vmbus_msghc_ctx_free(struct vmbus_msghc_ctx *mhc)
211{
212	KASSERT(mhc->mhc_active == NULL, ("still have active msg hypercall"));
213	KASSERT(mhc->mhc_free == NULL, ("still have hypercall msg"));
214
215	mtx_destroy(&mhc->mhc_free_lock);
216	mtx_destroy(&mhc->mhc_active_lock);
217	free(mhc, M_DEVBUF);
218}
219
220static struct vmbus_msghc_ctx *
221vmbus_msghc_ctx_create(bus_dma_tag_t parent_dtag)
222{
223	struct vmbus_msghc_ctx *mhc;
224
225	mhc = malloc(sizeof(*mhc), M_DEVBUF, M_WAITOK | M_ZERO);
226	mtx_init(&mhc->mhc_free_lock, "vmbus msghc free", NULL, MTX_DEF);
227	mtx_init(&mhc->mhc_active_lock, "vmbus msghc act", NULL, MTX_DEF);
228
229	mhc->mhc_free = vmbus_msghc_alloc(parent_dtag);
230	if (mhc->mhc_free == NULL) {
231		vmbus_msghc_ctx_free(mhc);
232		return NULL;
233	}
234	return mhc;
235}
236
237static struct vmbus_msghc *
238vmbus_msghc_get1(struct vmbus_msghc_ctx *mhc, uint32_t dtor_flag)
239{
240	struct vmbus_msghc *mh;
241
242	mtx_lock(&mhc->mhc_free_lock);
243
244	while ((mhc->mhc_flags & dtor_flag) == 0 && mhc->mhc_free == NULL) {
245		mtx_sleep(&mhc->mhc_free, &mhc->mhc_free_lock, 0,
246		    "gmsghc", 0);
247	}
248	if (mhc->mhc_flags & dtor_flag) {
249		/* Being destroyed */
250		mh = NULL;
251	} else {
252		mh = mhc->mhc_free;
253		KASSERT(mh != NULL, ("no free hypercall msg"));
254		KASSERT(mh->mh_resp == NULL,
255		    ("hypercall msg has pending response"));
256		mhc->mhc_free = NULL;
257	}
258
259	mtx_unlock(&mhc->mhc_free_lock);
260
261	return mh;
262}
263
264void
265vmbus_msghc_reset(struct vmbus_msghc *mh, size_t dsize)
266{
267	struct hypercall_postmsg_in *inprm;
268
269	if (dsize > HYPERCALL_POSTMSGIN_DSIZE_MAX)
270		panic("invalid data size %zu", dsize);
271
272	inprm = mh->mh_inprm;
273	memset(inprm, 0, HYPERCALL_POSTMSGIN_SIZE);
274	inprm->hc_connid = VMBUS_CONNID_MESSAGE;
275	inprm->hc_msgtype = HYPERV_MSGTYPE_CHANNEL;
276	inprm->hc_dsize = dsize;
277}
278
279struct vmbus_msghc *
280vmbus_msghc_get(struct vmbus_softc *sc, size_t dsize)
281{
282	struct vmbus_msghc *mh;
283
284	if (dsize > HYPERCALL_POSTMSGIN_DSIZE_MAX)
285		panic("invalid data size %zu", dsize);
286
287	mh = vmbus_msghc_get1(sc->vmbus_msg_hc, VMBUS_MSGHC_CTXF_DESTROY);
288	if (mh == NULL)
289		return NULL;
290
291	vmbus_msghc_reset(mh, dsize);
292	return mh;
293}
294
295void
296vmbus_msghc_put(struct vmbus_softc *sc, struct vmbus_msghc *mh)
297{
298	struct vmbus_msghc_ctx *mhc = sc->vmbus_msg_hc;
299
300	KASSERT(mhc->mhc_active == NULL, ("msg hypercall is active"));
301	mh->mh_resp = NULL;
302
303	mtx_lock(&mhc->mhc_free_lock);
304	KASSERT(mhc->mhc_free == NULL, ("has free hypercall msg"));
305	mhc->mhc_free = mh;
306	mtx_unlock(&mhc->mhc_free_lock);
307	wakeup(&mhc->mhc_free);
308}
309
310void *
311vmbus_msghc_dataptr(struct vmbus_msghc *mh)
312{
313	return mh->mh_inprm->hc_data;
314}
315
316static void
317vmbus_msghc_ctx_destroy(struct vmbus_msghc_ctx *mhc)
318{
319	struct vmbus_msghc *mh;
320
321	mtx_lock(&mhc->mhc_free_lock);
322	mhc->mhc_flags |= VMBUS_MSGHC_CTXF_DESTROY;
323	mtx_unlock(&mhc->mhc_free_lock);
324	wakeup(&mhc->mhc_free);
325
326	mh = vmbus_msghc_get1(mhc, 0);
327	if (mh == NULL)
328		panic("can't get msghc");
329
330	vmbus_msghc_free(mh);
331	vmbus_msghc_ctx_free(mhc);
332}
333
334int
335vmbus_msghc_exec_noresult(struct vmbus_msghc *mh)
336{
337	sbintime_t time = SBT_1MS;
338	int i;
339
340	/*
341	 * Save the input parameter so that we could restore the input
342	 * parameter if the Hypercall failed.
343	 *
344	 * XXX
345	 * Is this really necessary?!  i.e. Will the Hypercall ever
346	 * overwrite the input parameter?
347	 */
348	memcpy(&mh->mh_inprm_save, mh->mh_inprm, HYPERCALL_POSTMSGIN_SIZE);
349
350	/*
351	 * In order to cope with transient failures, e.g. insufficient
352	 * resources on host side, we retry the post message Hypercall
353	 * several times.  20 retries seem sufficient.
354	 */
355#define HC_RETRY_MAX	20
356
357	for (i = 0; i < HC_RETRY_MAX; ++i) {
358		uint64_t status;
359
360		status = hypercall_post_message(mh->mh_inprm_dma.hv_paddr);
361		if (status == HYPERCALL_STATUS_SUCCESS)
362			return 0;
363
364		pause_sbt("hcpmsg", time, 0, C_HARDCLOCK);
365		if (time < SBT_1S * 2)
366			time *= 2;
367
368		/* Restore input parameter and try again */
369		memcpy(mh->mh_inprm, &mh->mh_inprm_save,
370		    HYPERCALL_POSTMSGIN_SIZE);
371	}
372
373#undef HC_RETRY_MAX
374
375	return EIO;
376}
377
378int
379vmbus_msghc_exec(struct vmbus_softc *sc, struct vmbus_msghc *mh)
380{
381	struct vmbus_msghc_ctx *mhc = sc->vmbus_msg_hc;
382	int error;
383
384	KASSERT(mh->mh_resp == NULL, ("hypercall msg has pending response"));
385
386	mtx_lock(&mhc->mhc_active_lock);
387	KASSERT(mhc->mhc_active == NULL, ("pending active msg hypercall"));
388	mhc->mhc_active = mh;
389	mtx_unlock(&mhc->mhc_active_lock);
390
391	error = vmbus_msghc_exec_noresult(mh);
392	if (error) {
393		mtx_lock(&mhc->mhc_active_lock);
394		KASSERT(mhc->mhc_active == mh, ("msghc mismatch"));
395		mhc->mhc_active = NULL;
396		mtx_unlock(&mhc->mhc_active_lock);
397	}
398	return error;
399}
400
401const struct vmbus_message *
402vmbus_msghc_wait_result(struct vmbus_softc *sc, struct vmbus_msghc *mh)
403{
404	struct vmbus_msghc_ctx *mhc = sc->vmbus_msg_hc;
405
406	mtx_lock(&mhc->mhc_active_lock);
407
408	KASSERT(mhc->mhc_active == mh, ("msghc mismatch"));
409	while (mh->mh_resp == NULL) {
410		mtx_sleep(&mhc->mhc_active, &mhc->mhc_active_lock, 0,
411		    "wmsghc", 0);
412	}
413	mhc->mhc_active = NULL;
414
415	mtx_unlock(&mhc->mhc_active_lock);
416
417	return mh->mh_resp;
418}
419
420void
421vmbus_msghc_wakeup(struct vmbus_softc *sc, const struct vmbus_message *msg)
422{
423	struct vmbus_msghc_ctx *mhc = sc->vmbus_msg_hc;
424	struct vmbus_msghc *mh;
425
426	mtx_lock(&mhc->mhc_active_lock);
427
428	mh = mhc->mhc_active;
429	KASSERT(mh != NULL, ("no pending msg hypercall"));
430	memcpy(&mh->mh_resp0, msg, sizeof(mh->mh_resp0));
431	mh->mh_resp = &mh->mh_resp0;
432
433	mtx_unlock(&mhc->mhc_active_lock);
434	wakeup(&mhc->mhc_active);
435}
436
437uint32_t
438vmbus_gpadl_alloc(struct vmbus_softc *sc)
439{
440	return atomic_fetchadd_int(&sc->vmbus_gpadl, 1);
441}
442
443static int
444vmbus_connect(struct vmbus_softc *sc, uint32_t version)
445{
446	struct vmbus_chanmsg_connect *req;
447	const struct vmbus_message *msg;
448	struct vmbus_msghc *mh;
449	int error, done = 0;
450
451	mh = vmbus_msghc_get(sc, sizeof(*req));
452	if (mh == NULL)
453		return ENXIO;
454
455	req = vmbus_msghc_dataptr(mh);
456	req->chm_hdr.chm_type = VMBUS_CHANMSG_TYPE_CONNECT;
457	req->chm_ver = version;
458	req->chm_evtflags = sc->vmbus_evtflags_dma.hv_paddr;
459	req->chm_mnf1 = sc->vmbus_mnf1_dma.hv_paddr;
460	req->chm_mnf2 = sc->vmbus_mnf2_dma.hv_paddr;
461
462	error = vmbus_msghc_exec(sc, mh);
463	if (error) {
464		vmbus_msghc_put(sc, mh);
465		return error;
466	}
467
468	msg = vmbus_msghc_wait_result(sc, mh);
469	done = ((const struct vmbus_chanmsg_connect_resp *)
470	    msg->msg_data)->chm_done;
471
472	vmbus_msghc_put(sc, mh);
473
474	return (done ? 0 : EOPNOTSUPP);
475}
476
477static int
478vmbus_init(struct vmbus_softc *sc)
479{
480	int i;
481
482	for (i = 0; i < nitems(vmbus_version); ++i) {
483		int error;
484
485		error = vmbus_connect(sc, vmbus_version[i]);
486		if (!error) {
487			sc->vmbus_version = vmbus_version[i];
488			device_printf(sc->vmbus_dev, "version %u.%u\n",
489			    VMBUS_VERSION_MAJOR(sc->vmbus_version),
490			    VMBUS_VERSION_MINOR(sc->vmbus_version));
491			return 0;
492		}
493	}
494	return ENXIO;
495}
496
497static void
498vmbus_disconnect(struct vmbus_softc *sc)
499{
500	struct vmbus_chanmsg_disconnect *req;
501	struct vmbus_msghc *mh;
502	int error;
503
504	mh = vmbus_msghc_get(sc, sizeof(*req));
505	if (mh == NULL) {
506		device_printf(sc->vmbus_dev,
507		    "can not get msg hypercall for disconnect\n");
508		return;
509	}
510
511	req = vmbus_msghc_dataptr(mh);
512	req->chm_hdr.chm_type = VMBUS_CHANMSG_TYPE_DISCONNECT;
513
514	error = vmbus_msghc_exec_noresult(mh);
515	vmbus_msghc_put(sc, mh);
516
517	if (error) {
518		device_printf(sc->vmbus_dev,
519		    "disconnect msg hypercall failed\n");
520	}
521}
522
523static int
524vmbus_req_channels(struct vmbus_softc *sc)
525{
526	struct vmbus_chanmsg_chrequest *req;
527	struct vmbus_msghc *mh;
528	int error;
529
530	mh = vmbus_msghc_get(sc, sizeof(*req));
531	if (mh == NULL)
532		return ENXIO;
533
534	req = vmbus_msghc_dataptr(mh);
535	req->chm_hdr.chm_type = VMBUS_CHANMSG_TYPE_CHREQUEST;
536
537	error = vmbus_msghc_exec_noresult(mh);
538	vmbus_msghc_put(sc, mh);
539
540	return error;
541}
542
543static void
544vmbus_scan_newchan(struct vmbus_softc *sc)
545{
546	mtx_lock(&sc->vmbus_scan_lock);
547	if ((sc->vmbus_scan_chcnt & VMBUS_SCAN_CHCNT_DONE) == 0)
548		sc->vmbus_scan_chcnt++;
549	mtx_unlock(&sc->vmbus_scan_lock);
550}
551
552static void
553vmbus_scan_done(struct vmbus_softc *sc,
554    const struct vmbus_message *msg __unused)
555{
556	mtx_lock(&sc->vmbus_scan_lock);
557	sc->vmbus_scan_chcnt |= VMBUS_SCAN_CHCNT_DONE;
558	mtx_unlock(&sc->vmbus_scan_lock);
559	wakeup(&sc->vmbus_scan_chcnt);
560}
561
562static void
563vmbus_scan_newdev(struct vmbus_softc *sc)
564{
565	mtx_lock(&sc->vmbus_scan_lock);
566	sc->vmbus_scan_devcnt++;
567	mtx_unlock(&sc->vmbus_scan_lock);
568	wakeup(&sc->vmbus_scan_devcnt);
569}
570
571static void
572vmbus_scan_wait(struct vmbus_softc *sc)
573{
574	uint32_t chancnt;
575
576	mtx_lock(&sc->vmbus_scan_lock);
577	while ((sc->vmbus_scan_chcnt & VMBUS_SCAN_CHCNT_DONE) == 0) {
578		mtx_sleep(&sc->vmbus_scan_chcnt, &sc->vmbus_scan_lock, 0,
579		    "waitch", 0);
580	}
581	chancnt = sc->vmbus_scan_chcnt & ~VMBUS_SCAN_CHCNT_DONE;
582
583	while (sc->vmbus_scan_devcnt != chancnt) {
584		mtx_sleep(&sc->vmbus_scan_devcnt, &sc->vmbus_scan_lock, 0,
585		    "waitdev", 0);
586	}
587	mtx_unlock(&sc->vmbus_scan_lock);
588}
589
590static int
591vmbus_scan(struct vmbus_softc *sc)
592{
593	int error;
594
595	/*
596	 * Start vmbus scanning.
597	 */
598	error = vmbus_req_channels(sc);
599	if (error) {
600		device_printf(sc->vmbus_dev, "channel request failed: %d\n",
601		    error);
602		return error;
603	}
604
605	/*
606	 * Wait for all devices are added to vmbus.
607	 */
608	vmbus_scan_wait(sc);
609
610	/*
611	 * Identify, probe and attach.
612	 */
613	bus_generic_probe(sc->vmbus_dev);
614	bus_generic_attach(sc->vmbus_dev);
615
616	if (bootverbose) {
617		device_printf(sc->vmbus_dev, "device scan, probe and attach "
618		    "done\n");
619	}
620	return 0;
621}
622
623static void
624vmbus_chanmsg_handle(struct vmbus_softc *sc, const struct vmbus_message *msg)
625{
626	vmbus_chanmsg_proc_t msg_proc;
627	uint32_t msg_type;
628
629	msg_type = ((const struct vmbus_chanmsg_hdr *)msg->msg_data)->chm_type;
630	if (msg_type >= VMBUS_CHANMSG_TYPE_MAX) {
631		device_printf(sc->vmbus_dev, "unknown message type 0x%x\n",
632		    msg_type);
633		return;
634	}
635
636	msg_proc = vmbus_chanmsg_handlers[msg_type];
637	if (msg_proc != NULL)
638		msg_proc(sc, msg);
639
640	/* Channel specific processing */
641	vmbus_chan_msgproc(sc, msg);
642}
643
644static void
645vmbus_msg_task(void *xsc, int pending __unused)
646{
647	struct vmbus_softc *sc = xsc;
648	volatile struct vmbus_message *msg;
649
650	msg = VMBUS_PCPU_GET(sc, message, curcpu) + VMBUS_SINT_MESSAGE;
651	for (;;) {
652		if (msg->msg_type == HYPERV_MSGTYPE_NONE) {
653			/* No message */
654			break;
655		} else if (msg->msg_type == HYPERV_MSGTYPE_CHANNEL) {
656			/* Channel message */
657			vmbus_chanmsg_handle(sc,
658			    __DEVOLATILE(const struct vmbus_message *, msg));
659		}
660
661		msg->msg_type = HYPERV_MSGTYPE_NONE;
662		/*
663		 * Make sure the write to msg_type (i.e. set to
664		 * HYPERV_MSGTYPE_NONE) happens before we read the
665		 * msg_flags and EOMing. Otherwise, the EOMing will
666		 * not deliver any more messages since there is no
667		 * empty slot
668		 *
669		 * NOTE:
670		 * mb() is used here, since atomic_thread_fence_seq_cst()
671		 * will become compiler fence on UP kernel.
672		 */
673		mb();
674		if (msg->msg_flags & VMBUS_MSGFLAG_PENDING) {
675			/*
676			 * This will cause message queue rescan to possibly
677			 * deliver another msg from the hypervisor
678			 */
679			wrmsr(MSR_HV_EOM, 0);
680		}
681	}
682}
683
684static __inline int
685vmbus_handle_intr1(struct vmbus_softc *sc, struct trapframe *frame, int cpu)
686{
687	volatile struct vmbus_message *msg;
688	struct vmbus_message *msg_base;
689
690	msg_base = VMBUS_PCPU_GET(sc, message, cpu);
691
692	/*
693	 * Check event timer.
694	 *
695	 * TODO: move this to independent IDT vector.
696	 */
697	msg = msg_base + VMBUS_SINT_TIMER;
698	if (msg->msg_type == HYPERV_MSGTYPE_TIMER_EXPIRED) {
699		msg->msg_type = HYPERV_MSGTYPE_NONE;
700
701		vmbus_et_intr(frame);
702
703		/*
704		 * Make sure the write to msg_type (i.e. set to
705		 * HYPERV_MSGTYPE_NONE) happens before we read the
706		 * msg_flags and EOMing. Otherwise, the EOMing will
707		 * not deliver any more messages since there is no
708		 * empty slot
709		 *
710		 * NOTE:
711		 * mb() is used here, since atomic_thread_fence_seq_cst()
712		 * will become compiler fence on UP kernel.
713		 */
714		mb();
715		if (msg->msg_flags & VMBUS_MSGFLAG_PENDING) {
716			/*
717			 * This will cause message queue rescan to possibly
718			 * deliver another msg from the hypervisor
719			 */
720			wrmsr(MSR_HV_EOM, 0);
721		}
722	}
723
724	/*
725	 * Check events.  Hot path for network and storage I/O data; high rate.
726	 *
727	 * NOTE:
728	 * As recommended by the Windows guest fellows, we check events before
729	 * checking messages.
730	 */
731	sc->vmbus_event_proc(sc, cpu);
732
733	/*
734	 * Check messages.  Mainly management stuffs; ultra low rate.
735	 */
736	msg = msg_base + VMBUS_SINT_MESSAGE;
737	if (__predict_false(msg->msg_type != HYPERV_MSGTYPE_NONE)) {
738		taskqueue_enqueue(VMBUS_PCPU_GET(sc, message_tq, cpu),
739		    VMBUS_PCPU_PTR(sc, message_task, cpu));
740	}
741
742	return (FILTER_HANDLED);
743}
744
745void
746vmbus_handle_intr(struct trapframe *trap_frame)
747{
748	struct vmbus_softc *sc = vmbus_get_softc();
749	int cpu = curcpu;
750
751	/*
752	 * Disable preemption.
753	 */
754	critical_enter();
755
756	/*
757	 * Do a little interrupt counting.
758	 */
759	(*VMBUS_PCPU_GET(sc, intr_cnt, cpu))++;
760
761	vmbus_handle_intr1(sc, trap_frame, cpu);
762
763	/*
764	 * Enable preemption.
765	 */
766	critical_exit();
767}
768
769static void
770vmbus_synic_setup(void *xsc)
771{
772	struct vmbus_softc *sc = xsc;
773	int cpu = curcpu;
774	uint64_t val, orig;
775	uint32_t sint;
776
777	if (hyperv_features & CPUID_HV_MSR_VP_INDEX) {
778		/* Save virtual processor id. */
779		VMBUS_PCPU_GET(sc, vcpuid, cpu) = rdmsr(MSR_HV_VP_INDEX);
780	} else {
781		/* Set virtual processor id to 0 for compatibility. */
782		VMBUS_PCPU_GET(sc, vcpuid, cpu) = 0;
783	}
784
785	/*
786	 * Setup the SynIC message.
787	 */
788	orig = rdmsr(MSR_HV_SIMP);
789	val = MSR_HV_SIMP_ENABLE | (orig & MSR_HV_SIMP_RSVD_MASK) |
790	    ((VMBUS_PCPU_GET(sc, message_dma.hv_paddr, cpu) >> PAGE_SHIFT) <<
791	     MSR_HV_SIMP_PGSHIFT);
792	wrmsr(MSR_HV_SIMP, val);
793
794	/*
795	 * Setup the SynIC event flags.
796	 */
797	orig = rdmsr(MSR_HV_SIEFP);
798	val = MSR_HV_SIEFP_ENABLE | (orig & MSR_HV_SIEFP_RSVD_MASK) |
799	    ((VMBUS_PCPU_GET(sc, event_flags_dma.hv_paddr, cpu)
800	      >> PAGE_SHIFT) << MSR_HV_SIEFP_PGSHIFT);
801	wrmsr(MSR_HV_SIEFP, val);
802
803
804	/*
805	 * Configure and unmask SINT for message and event flags.
806	 */
807	sint = MSR_HV_SINT0 + VMBUS_SINT_MESSAGE;
808	orig = rdmsr(sint);
809	val = sc->vmbus_idtvec | MSR_HV_SINT_AUTOEOI |
810	    (orig & MSR_HV_SINT_RSVD_MASK);
811	wrmsr(sint, val);
812
813	/*
814	 * Configure and unmask SINT for timer.
815	 */
816	sint = MSR_HV_SINT0 + VMBUS_SINT_TIMER;
817	orig = rdmsr(sint);
818	val = sc->vmbus_idtvec | MSR_HV_SINT_AUTOEOI |
819	    (orig & MSR_HV_SINT_RSVD_MASK);
820	wrmsr(sint, val);
821
822	/*
823	 * All done; enable SynIC.
824	 */
825	orig = rdmsr(MSR_HV_SCONTROL);
826	val = MSR_HV_SCTRL_ENABLE | (orig & MSR_HV_SCTRL_RSVD_MASK);
827	wrmsr(MSR_HV_SCONTROL, val);
828}
829
830static void
831vmbus_synic_teardown(void *arg)
832{
833	uint64_t orig;
834	uint32_t sint;
835
836	/*
837	 * Disable SynIC.
838	 */
839	orig = rdmsr(MSR_HV_SCONTROL);
840	wrmsr(MSR_HV_SCONTROL, (orig & MSR_HV_SCTRL_RSVD_MASK));
841
842	/*
843	 * Mask message and event flags SINT.
844	 */
845	sint = MSR_HV_SINT0 + VMBUS_SINT_MESSAGE;
846	orig = rdmsr(sint);
847	wrmsr(sint, orig | MSR_HV_SINT_MASKED);
848
849	/*
850	 * Mask timer SINT.
851	 */
852	sint = MSR_HV_SINT0 + VMBUS_SINT_TIMER;
853	orig = rdmsr(sint);
854	wrmsr(sint, orig | MSR_HV_SINT_MASKED);
855
856	/*
857	 * Teardown SynIC message.
858	 */
859	orig = rdmsr(MSR_HV_SIMP);
860	wrmsr(MSR_HV_SIMP, (orig & MSR_HV_SIMP_RSVD_MASK));
861
862	/*
863	 * Teardown SynIC event flags.
864	 */
865	orig = rdmsr(MSR_HV_SIEFP);
866	wrmsr(MSR_HV_SIEFP, (orig & MSR_HV_SIEFP_RSVD_MASK));
867}
868
869static int
870vmbus_dma_alloc(struct vmbus_softc *sc)
871{
872	bus_dma_tag_t parent_dtag;
873	uint8_t *evtflags;
874	int cpu;
875
876	parent_dtag = bus_get_dma_tag(sc->vmbus_dev);
877	CPU_FOREACH(cpu) {
878		void *ptr;
879
880		/*
881		 * Per-cpu messages and event flags.
882		 */
883		ptr = hyperv_dmamem_alloc(parent_dtag, PAGE_SIZE, 0,
884		    PAGE_SIZE, VMBUS_PCPU_PTR(sc, message_dma, cpu),
885		    BUS_DMA_WAITOK | BUS_DMA_ZERO);
886		if (ptr == NULL)
887			return ENOMEM;
888		VMBUS_PCPU_GET(sc, message, cpu) = ptr;
889
890		ptr = hyperv_dmamem_alloc(parent_dtag, PAGE_SIZE, 0,
891		    PAGE_SIZE, VMBUS_PCPU_PTR(sc, event_flags_dma, cpu),
892		    BUS_DMA_WAITOK | BUS_DMA_ZERO);
893		if (ptr == NULL)
894			return ENOMEM;
895		VMBUS_PCPU_GET(sc, event_flags, cpu) = ptr;
896	}
897
898	evtflags = hyperv_dmamem_alloc(parent_dtag, PAGE_SIZE, 0,
899	    PAGE_SIZE, &sc->vmbus_evtflags_dma, BUS_DMA_WAITOK | BUS_DMA_ZERO);
900	if (evtflags == NULL)
901		return ENOMEM;
902	sc->vmbus_rx_evtflags = (u_long *)evtflags;
903	sc->vmbus_tx_evtflags = (u_long *)(evtflags + (PAGE_SIZE / 2));
904	sc->vmbus_evtflags = evtflags;
905
906	sc->vmbus_mnf1 = hyperv_dmamem_alloc(parent_dtag, PAGE_SIZE, 0,
907	    PAGE_SIZE, &sc->vmbus_mnf1_dma, BUS_DMA_WAITOK | BUS_DMA_ZERO);
908	if (sc->vmbus_mnf1 == NULL)
909		return ENOMEM;
910
911	sc->vmbus_mnf2 = hyperv_dmamem_alloc(parent_dtag, PAGE_SIZE, 0,
912	    sizeof(struct vmbus_mnf), &sc->vmbus_mnf2_dma,
913	    BUS_DMA_WAITOK | BUS_DMA_ZERO);
914	if (sc->vmbus_mnf2 == NULL)
915		return ENOMEM;
916
917	return 0;
918}
919
920static void
921vmbus_dma_free(struct vmbus_softc *sc)
922{
923	int cpu;
924
925	if (sc->vmbus_evtflags != NULL) {
926		hyperv_dmamem_free(&sc->vmbus_evtflags_dma, sc->vmbus_evtflags);
927		sc->vmbus_evtflags = NULL;
928		sc->vmbus_rx_evtflags = NULL;
929		sc->vmbus_tx_evtflags = NULL;
930	}
931	if (sc->vmbus_mnf1 != NULL) {
932		hyperv_dmamem_free(&sc->vmbus_mnf1_dma, sc->vmbus_mnf1);
933		sc->vmbus_mnf1 = NULL;
934	}
935	if (sc->vmbus_mnf2 != NULL) {
936		hyperv_dmamem_free(&sc->vmbus_mnf2_dma, sc->vmbus_mnf2);
937		sc->vmbus_mnf2 = NULL;
938	}
939
940	CPU_FOREACH(cpu) {
941		if (VMBUS_PCPU_GET(sc, message, cpu) != NULL) {
942			hyperv_dmamem_free(
943			    VMBUS_PCPU_PTR(sc, message_dma, cpu),
944			    VMBUS_PCPU_GET(sc, message, cpu));
945			VMBUS_PCPU_GET(sc, message, cpu) = NULL;
946		}
947		if (VMBUS_PCPU_GET(sc, event_flags, cpu) != NULL) {
948			hyperv_dmamem_free(
949			    VMBUS_PCPU_PTR(sc, event_flags_dma, cpu),
950			    VMBUS_PCPU_GET(sc, event_flags, cpu));
951			VMBUS_PCPU_GET(sc, event_flags, cpu) = NULL;
952		}
953	}
954}
955
956static int
957vmbus_intr_setup(struct vmbus_softc *sc)
958{
959	int cpu;
960
961	CPU_FOREACH(cpu) {
962		char buf[MAXCOMLEN + 1];
963		cpuset_t cpu_mask;
964
965		/* Allocate an interrupt counter for Hyper-V interrupt */
966		snprintf(buf, sizeof(buf), "cpu%d:hyperv", cpu);
967		intrcnt_add(buf, VMBUS_PCPU_PTR(sc, intr_cnt, cpu));
968
969		/*
970		 * Setup taskqueue to handle events.  Task will be per-
971		 * channel.
972		 */
973		VMBUS_PCPU_GET(sc, event_tq, cpu) = taskqueue_create_fast(
974		    "hyperv event", M_WAITOK, taskqueue_thread_enqueue,
975		    VMBUS_PCPU_PTR(sc, event_tq, cpu));
976		CPU_SETOF(cpu, &cpu_mask);
977		taskqueue_start_threads_cpuset(
978		    VMBUS_PCPU_PTR(sc, event_tq, cpu), 1, PI_NET, &cpu_mask,
979		    "hvevent%d", cpu);
980
981		/*
982		 * Setup tasks and taskqueues to handle messages.
983		 */
984		VMBUS_PCPU_GET(sc, message_tq, cpu) = taskqueue_create_fast(
985		    "hyperv msg", M_WAITOK, taskqueue_thread_enqueue,
986		    VMBUS_PCPU_PTR(sc, message_tq, cpu));
987		CPU_SETOF(cpu, &cpu_mask);
988		taskqueue_start_threads_cpuset(
989		    VMBUS_PCPU_PTR(sc, message_tq, cpu), 1, PI_NET, &cpu_mask,
990		    "hvmsg%d", cpu);
991		TASK_INIT(VMBUS_PCPU_PTR(sc, message_task, cpu), 0,
992		    vmbus_msg_task, sc);
993	}
994
995	/*
996	 * All Hyper-V ISR required resources are setup, now let's find a
997	 * free IDT vector for Hyper-V ISR and set it up.
998	 */
999	sc->vmbus_idtvec = lapic_ipi_alloc(IDTVEC(vmbus_isr));
1000	if (sc->vmbus_idtvec < 0) {
1001		device_printf(sc->vmbus_dev, "cannot find free IDT vector\n");
1002		return ENXIO;
1003	}
1004	if(bootverbose) {
1005		device_printf(sc->vmbus_dev, "vmbus IDT vector %d\n",
1006		    sc->vmbus_idtvec);
1007	}
1008	return 0;
1009}
1010
1011static void
1012vmbus_intr_teardown(struct vmbus_softc *sc)
1013{
1014	int cpu;
1015
1016	if (sc->vmbus_idtvec >= 0) {
1017		lapic_ipi_free(sc->vmbus_idtvec);
1018		sc->vmbus_idtvec = -1;
1019	}
1020
1021	CPU_FOREACH(cpu) {
1022		if (VMBUS_PCPU_GET(sc, event_tq, cpu) != NULL) {
1023			taskqueue_free(VMBUS_PCPU_GET(sc, event_tq, cpu));
1024			VMBUS_PCPU_GET(sc, event_tq, cpu) = NULL;
1025		}
1026		if (VMBUS_PCPU_GET(sc, message_tq, cpu) != NULL) {
1027			taskqueue_drain(VMBUS_PCPU_GET(sc, message_tq, cpu),
1028			    VMBUS_PCPU_PTR(sc, message_task, cpu));
1029			taskqueue_free(VMBUS_PCPU_GET(sc, message_tq, cpu));
1030			VMBUS_PCPU_GET(sc, message_tq, cpu) = NULL;
1031		}
1032	}
1033}
1034
1035static int
1036vmbus_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
1037{
1038	return (ENOENT);
1039}
1040
1041static int
1042vmbus_child_pnpinfo_str(device_t dev, device_t child, char *buf, size_t buflen)
1043{
1044	const struct vmbus_channel *chan;
1045	char guidbuf[HYPERV_GUID_STRLEN];
1046
1047	chan = vmbus_get_channel(child);
1048	if (chan == NULL) {
1049		/* Event timer device, which does not belong to a channel */
1050		return (0);
1051	}
1052
1053	strlcat(buf, "classid=", buflen);
1054	hyperv_guid2str(&chan->ch_guid_type, guidbuf, sizeof(guidbuf));
1055	strlcat(buf, guidbuf, buflen);
1056
1057	strlcat(buf, " deviceid=", buflen);
1058	hyperv_guid2str(&chan->ch_guid_inst, guidbuf, sizeof(guidbuf));
1059	strlcat(buf, guidbuf, buflen);
1060
1061	return (0);
1062}
1063
1064int
1065vmbus_add_child(struct vmbus_channel *chan)
1066{
1067	struct vmbus_softc *sc = chan->ch_vmbus;
1068	device_t parent = sc->vmbus_dev;
1069	int error = 0;
1070
1071	/* New channel has been offered */
1072	vmbus_scan_newchan(sc);
1073
1074	chan->ch_dev = device_add_child(parent, NULL, -1);
1075	if (chan->ch_dev == NULL) {
1076		device_printf(parent, "device_add_child for chan%u failed\n",
1077		    chan->ch_id);
1078		error = ENXIO;
1079		goto done;
1080	}
1081	device_set_ivars(chan->ch_dev, chan);
1082
1083done:
1084	/* New device has been/should be added to vmbus. */
1085	vmbus_scan_newdev(sc);
1086	return error;
1087}
1088
1089int
1090vmbus_delete_child(struct vmbus_channel *chan)
1091{
1092	int error;
1093
1094	if (chan->ch_dev == NULL) {
1095		/* Failed to add a device. */
1096		return 0;
1097	}
1098
1099	/*
1100	 * XXXKYS: Ensure that this is the opposite of
1101	 * device_add_child()
1102	 */
1103	mtx_lock(&Giant);
1104	error = device_delete_child(chan->ch_vmbus->vmbus_dev, chan->ch_dev);
1105	mtx_unlock(&Giant);
1106
1107	return error;
1108}
1109
1110static int
1111vmbus_sysctl_version(SYSCTL_HANDLER_ARGS)
1112{
1113	struct vmbus_softc *sc = arg1;
1114	char verstr[16];
1115
1116	snprintf(verstr, sizeof(verstr), "%u.%u",
1117	    VMBUS_VERSION_MAJOR(sc->vmbus_version),
1118	    VMBUS_VERSION_MINOR(sc->vmbus_version));
1119	return sysctl_handle_string(oidp, verstr, sizeof(verstr), req);
1120}
1121
1122static uint32_t
1123vmbus_get_version_method(device_t bus, device_t dev)
1124{
1125	struct vmbus_softc *sc = device_get_softc(bus);
1126
1127	return sc->vmbus_version;
1128}
1129
1130static int
1131vmbus_probe_guid_method(device_t bus, device_t dev,
1132    const struct hyperv_guid *guid)
1133{
1134	const struct vmbus_channel *chan = vmbus_get_channel(dev);
1135
1136	if (memcmp(&chan->ch_guid_type, guid, sizeof(struct hyperv_guid)) == 0)
1137		return 0;
1138	return ENXIO;
1139}
1140
1141static int
1142vmbus_probe(device_t dev)
1143{
1144	char *id[] = { "VMBUS", NULL };
1145
1146	if (ACPI_ID_PROBE(device_get_parent(dev), dev, id) == NULL ||
1147	    device_get_unit(dev) != 0 || vm_guest != VM_GUEST_HV ||
1148	    (hyperv_features & CPUID_HV_MSR_SYNIC) == 0)
1149		return (ENXIO);
1150
1151	device_set_desc(dev, "Hyper-V Vmbus");
1152
1153	return (BUS_PROBE_DEFAULT);
1154}
1155
1156/**
1157 * @brief Main vmbus driver initialization routine.
1158 *
1159 * Here, we
1160 * - initialize the vmbus driver context
1161 * - setup various driver entry points
1162 * - invoke the vmbus hv main init routine
1163 * - get the irq resource
1164 * - invoke the vmbus to add the vmbus root device
1165 * - setup the vmbus root device
1166 * - retrieve the channel offers
1167 */
1168static int
1169vmbus_doattach(struct vmbus_softc *sc)
1170{
1171	struct sysctl_oid_list *child;
1172	struct sysctl_ctx_list *ctx;
1173	int ret;
1174
1175	if (sc->vmbus_flags & VMBUS_FLAG_ATTACHED)
1176		return (0);
1177	sc->vmbus_flags |= VMBUS_FLAG_ATTACHED;
1178
1179	mtx_init(&sc->vmbus_scan_lock, "vmbus scan", NULL, MTX_DEF);
1180	sc->vmbus_gpadl = VMBUS_GPADL_START;
1181	mtx_init(&sc->vmbus_prichan_lock, "vmbus prichan", NULL, MTX_DEF);
1182	TAILQ_INIT(&sc->vmbus_prichans);
1183	sc->vmbus_chmap = malloc(
1184	    sizeof(struct vmbus_channel *) * VMBUS_CHAN_MAX, M_DEVBUF,
1185	    M_WAITOK | M_ZERO);
1186
1187	/*
1188	 * Create context for "post message" Hypercalls
1189	 */
1190	sc->vmbus_msg_hc = vmbus_msghc_ctx_create(
1191	    bus_get_dma_tag(sc->vmbus_dev));
1192	if (sc->vmbus_msg_hc == NULL) {
1193		ret = ENXIO;
1194		goto cleanup;
1195	}
1196
1197	/*
1198	 * Allocate DMA stuffs.
1199	 */
1200	ret = vmbus_dma_alloc(sc);
1201	if (ret != 0)
1202		goto cleanup;
1203
1204	/*
1205	 * Setup interrupt.
1206	 */
1207	ret = vmbus_intr_setup(sc);
1208	if (ret != 0)
1209		goto cleanup;
1210
1211	/*
1212	 * Setup SynIC.
1213	 */
1214	if (bootverbose)
1215		device_printf(sc->vmbus_dev, "smp_started = %d\n", smp_started);
1216	smp_rendezvous(NULL, vmbus_synic_setup, NULL, sc);
1217	sc->vmbus_flags |= VMBUS_FLAG_SYNIC;
1218
1219	/*
1220	 * Initialize vmbus, e.g. connect to Hypervisor.
1221	 */
1222	ret = vmbus_init(sc);
1223	if (ret != 0)
1224		goto cleanup;
1225
1226	if (sc->vmbus_version == VMBUS_VERSION_WS2008 ||
1227	    sc->vmbus_version == VMBUS_VERSION_WIN7)
1228		sc->vmbus_event_proc = vmbus_event_proc_compat;
1229	else
1230		sc->vmbus_event_proc = vmbus_event_proc;
1231
1232	ret = vmbus_scan(sc);
1233	if (ret != 0)
1234		goto cleanup;
1235
1236	ctx = device_get_sysctl_ctx(sc->vmbus_dev);
1237	child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->vmbus_dev));
1238	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "version",
1239	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
1240	    vmbus_sysctl_version, "A", "vmbus version");
1241
1242	return (ret);
1243
1244cleanup:
1245	vmbus_intr_teardown(sc);
1246	vmbus_dma_free(sc);
1247	if (sc->vmbus_msg_hc != NULL) {
1248		vmbus_msghc_ctx_destroy(sc->vmbus_msg_hc);
1249		sc->vmbus_msg_hc = NULL;
1250	}
1251	free(sc->vmbus_chmap, M_DEVBUF);
1252	mtx_destroy(&sc->vmbus_scan_lock);
1253	mtx_destroy(&sc->vmbus_prichan_lock);
1254
1255	return (ret);
1256}
1257
1258static void
1259vmbus_event_proc_dummy(struct vmbus_softc *sc __unused, int cpu __unused)
1260{
1261}
1262
1263static int
1264vmbus_attach(device_t dev)
1265{
1266	vmbus_sc = device_get_softc(dev);
1267	vmbus_sc->vmbus_dev = dev;
1268	vmbus_sc->vmbus_idtvec = -1;
1269
1270	/*
1271	 * Event processing logic will be configured:
1272	 * - After the vmbus protocol version negotiation.
1273	 * - Before we request channel offers.
1274	 */
1275	vmbus_sc->vmbus_event_proc = vmbus_event_proc_dummy;
1276
1277#ifndef EARLY_AP_STARTUP
1278	/*
1279	 * If the system has already booted and thread
1280	 * scheduling is possible indicated by the global
1281	 * cold set to zero, we just call the driver
1282	 * initialization directly.
1283	 */
1284	if (!cold)
1285#endif
1286		vmbus_doattach(vmbus_sc);
1287
1288	return (0);
1289}
1290
1291static int
1292vmbus_detach(device_t dev)
1293{
1294	struct vmbus_softc *sc = device_get_softc(dev);
1295
1296	vmbus_chan_destroy_all(sc);
1297
1298	vmbus_disconnect(sc);
1299
1300	if (sc->vmbus_flags & VMBUS_FLAG_SYNIC) {
1301		sc->vmbus_flags &= ~VMBUS_FLAG_SYNIC;
1302		smp_rendezvous(NULL, vmbus_synic_teardown, NULL, NULL);
1303	}
1304
1305	vmbus_intr_teardown(sc);
1306	vmbus_dma_free(sc);
1307
1308	if (sc->vmbus_msg_hc != NULL) {
1309		vmbus_msghc_ctx_destroy(sc->vmbus_msg_hc);
1310		sc->vmbus_msg_hc = NULL;
1311	}
1312
1313	free(sc->vmbus_chmap, M_DEVBUF);
1314	mtx_destroy(&sc->vmbus_scan_lock);
1315	mtx_destroy(&sc->vmbus_prichan_lock);
1316
1317	return (0);
1318}
1319
1320#ifndef EARLY_AP_STARTUP
1321
1322static void
1323vmbus_sysinit(void *arg __unused)
1324{
1325	struct vmbus_softc *sc = vmbus_get_softc();
1326
1327	if (vm_guest != VM_GUEST_HV || sc == NULL)
1328		return;
1329
1330	/*
1331	 * If the system has already booted and thread
1332	 * scheduling is possible, as indicated by the
1333	 * global cold set to zero, we just call the driver
1334	 * initialization directly.
1335	 */
1336	if (!cold)
1337		vmbus_doattach(sc);
1338}
1339/*
1340 * NOTE:
1341 * We have to start as the last step of SI_SUB_SMP, i.e. after SMP is
1342 * initialized.
1343 */
1344SYSINIT(vmbus_initialize, SI_SUB_SMP, SI_ORDER_ANY, vmbus_sysinit, NULL);
1345
1346#endif	/* !EARLY_AP_STARTUP */
1347