xref: /freebsd/sys/dev/hyperv/vmbus/vmbus.c (revision 62f9bcf2b4271d58ccf0bd8a81c540bb99a53ef7)
1b7bb4816SSepherosa Ziehau /*-
293b4e111SSepherosa Ziehau  * Copyright (c) 2009-2012,2016-2017 Microsoft Corp.
3b7bb4816SSepherosa Ziehau  * Copyright (c) 2012 NetApp Inc.
4b7bb4816SSepherosa Ziehau  * Copyright (c) 2012 Citrix Inc.
5b7bb4816SSepherosa Ziehau  * All rights reserved.
6b7bb4816SSepherosa Ziehau  *
7b7bb4816SSepherosa Ziehau  * Redistribution and use in source and binary forms, with or without
8b7bb4816SSepherosa Ziehau  * modification, are permitted provided that the following conditions
9b7bb4816SSepherosa Ziehau  * are met:
10b7bb4816SSepherosa Ziehau  * 1. Redistributions of source code must retain the above copyright
11b7bb4816SSepherosa Ziehau  *    notice unmodified, this list of conditions, and the following
12b7bb4816SSepherosa Ziehau  *    disclaimer.
13b7bb4816SSepherosa Ziehau  * 2. Redistributions in binary form must reproduce the above copyright
14b7bb4816SSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer in the
15b7bb4816SSepherosa Ziehau  *    documentation and/or other materials provided with the distribution.
16b7bb4816SSepherosa Ziehau  *
17b7bb4816SSepherosa Ziehau  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18b7bb4816SSepherosa Ziehau  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19b7bb4816SSepherosa Ziehau  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20b7bb4816SSepherosa Ziehau  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21b7bb4816SSepherosa Ziehau  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22b7bb4816SSepherosa Ziehau  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23b7bb4816SSepherosa Ziehau  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24b7bb4816SSepherosa Ziehau  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25b7bb4816SSepherosa Ziehau  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26b7bb4816SSepherosa Ziehau  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27b7bb4816SSepherosa Ziehau  */
28b7bb4816SSepherosa Ziehau 
29b7bb4816SSepherosa Ziehau /*
30b7bb4816SSepherosa Ziehau  * VM Bus Driver Implementation
31b7bb4816SSepherosa Ziehau  */
32b7bb4816SSepherosa Ziehau #include <sys/cdefs.h>
33b7bb4816SSepherosa Ziehau __FBSDID("$FreeBSD$");
34b7bb4816SSepherosa Ziehau 
35b7bb4816SSepherosa Ziehau #include <sys/param.h>
36b7bb4816SSepherosa Ziehau #include <sys/bus.h>
37b7bb4816SSepherosa Ziehau #include <sys/kernel.h>
38c5657761SWei Hu #include <sys/linker.h>
39b7bb4816SSepherosa Ziehau #include <sys/lock.h>
40b7bb4816SSepherosa Ziehau #include <sys/malloc.h>
41b7bb4816SSepherosa Ziehau #include <sys/module.h>
42b7bb4816SSepherosa Ziehau #include <sys/mutex.h>
43ddfc9c4cSWarner Losh #include <sys/sbuf.h>
44b7bb4816SSepherosa Ziehau #include <sys/smp.h>
457d8ee480SSepherosa Ziehau #include <sys/sysctl.h>
467d8ee480SSepherosa Ziehau #include <sys/systm.h>
477d8ee480SSepherosa Ziehau #include <sys/taskqueue.h>
48b7bb4816SSepherosa Ziehau 
49fe7d7ac4SKonstantin Belousov #include <vm/vm.h>
50*62f9bcf2SAndrew Turner #include <vm/vm_extern.h>
51fe7d7ac4SKonstantin Belousov #include <vm/vm_param.h>
52fe7d7ac4SKonstantin Belousov #include <vm/pmap.h>
53fe7d7ac4SKonstantin Belousov 
54522c192dSDexuan Cui #include <machine/bus.h>
559729f076SSouradeep Chakrabarti #if defined(__aarch64__)
569729f076SSouradeep Chakrabarti #include <dev/psci/smccc.h>
579729f076SSouradeep Chakrabarti #include <dev/hyperv/vmbus/aarch64/hyperv_machdep.h>
589729f076SSouradeep Chakrabarti #include <dev/hyperv/vmbus/aarch64/hyperv_reg.h>
599729f076SSouradeep Chakrabarti #else
609729f076SSouradeep Chakrabarti #include <dev/hyperv/vmbus/x86/hyperv_machdep.h>
619729f076SSouradeep Chakrabarti #include <dev/hyperv/vmbus/x86/hyperv_reg.h>
62b7bb4816SSepherosa Ziehau #include <machine/intr_machdep.h>
639729f076SSouradeep Chakrabarti #include <x86/include/apicvar.h>
649729f076SSouradeep Chakrabarti #endif
65c5657761SWei Hu #include <machine/metadata.h>
66bd50262fSKonstantin Belousov #include <machine/md_var.h>
67522c192dSDexuan Cui #include <machine/resource.h>
687d8ee480SSepherosa Ziehau #include <contrib/dev/acpica/include/acpi.h>
69522c192dSDexuan Cui #include <dev/acpica/acpivar.h>
70b7bb4816SSepherosa Ziehau 
71b7bb4816SSepherosa Ziehau #include <dev/hyperv/include/hyperv.h>
723dba61ddSSepherosa Ziehau #include <dev/hyperv/include/vmbus_xact.h>
73b7bb4816SSepherosa Ziehau #include <dev/hyperv/vmbus/hyperv_var.h>
74b7bb4816SSepherosa Ziehau #include <dev/hyperv/vmbus/vmbus_reg.h>
75b7bb4816SSepherosa Ziehau #include <dev/hyperv/vmbus/vmbus_var.h>
767dd8881cSSepherosa Ziehau #include <dev/hyperv/vmbus/vmbus_chanvar.h>
779729f076SSouradeep Chakrabarti #include <dev/hyperv/vmbus/hyperv_common_reg.h>
78b7bb4816SSepherosa Ziehau #include "acpi_if.h"
79522c192dSDexuan Cui #include "pcib_if.h"
8038d19df6SSepherosa Ziehau #include "vmbus_if.h"
81b7bb4816SSepherosa Ziehau 
82ee7e313fSSepherosa Ziehau #define VMBUS_GPADL_START		0xe1e10
83ee7e313fSSepherosa Ziehau 
84236764b1SSepherosa Ziehau struct vmbus_msghc {
853dba61ddSSepherosa Ziehau 	struct vmbus_xact		*mh_xact;
86236764b1SSepherosa Ziehau 	struct hypercall_postmsg_in	mh_inprm_save;
87236764b1SSepherosa Ziehau };
88236764b1SSepherosa Ziehau 
89554e6778SSepherosa Ziehau static void			vmbus_identify(driver_t *, device_t);
905b444edaSSepherosa Ziehau static int			vmbus_probe(device_t);
915b444edaSSepherosa Ziehau static int			vmbus_attach(device_t);
925b444edaSSepherosa Ziehau static int			vmbus_detach(device_t);
935b444edaSSepherosa Ziehau static int			vmbus_read_ivar(device_t, device_t, int,
945b444edaSSepherosa Ziehau 				    uintptr_t *);
95ddfc9c4cSWarner Losh static int			vmbus_child_pnpinfo(device_t, device_t, struct sbuf *);
96522c192dSDexuan Cui static struct resource		*vmbus_alloc_resource(device_t dev,
97522c192dSDexuan Cui 				    device_t child, int type, int *rid,
98522c192dSDexuan Cui 				    rman_res_t start, rman_res_t end,
99522c192dSDexuan Cui 				    rman_res_t count, u_int flags);
100522c192dSDexuan Cui static int			vmbus_alloc_msi(device_t bus, device_t dev,
101522c192dSDexuan Cui 				    int count, int maxcount, int *irqs);
102522c192dSDexuan Cui static int			vmbus_release_msi(device_t bus, device_t dev,
103522c192dSDexuan Cui 				    int count, int *irqs);
104522c192dSDexuan Cui static int			vmbus_alloc_msix(device_t bus, device_t dev,
105522c192dSDexuan Cui 				    int *irq);
106522c192dSDexuan Cui static int			vmbus_release_msix(device_t bus, device_t dev,
107522c192dSDexuan Cui 				    int irq);
108522c192dSDexuan Cui static int			vmbus_map_msi(device_t bus, device_t dev,
109522c192dSDexuan Cui 				    int irq, uint64_t *addr, uint32_t *data);
1105b444edaSSepherosa Ziehau static uint32_t			vmbus_get_version_method(device_t, device_t);
1115b444edaSSepherosa Ziehau static int			vmbus_probe_guid_method(device_t, device_t,
1125b444edaSSepherosa Ziehau 				    const struct hyperv_guid *);
113c8b32f71SDexuan Cui static uint32_t			vmbus_get_vcpu_id_method(device_t bus,
114c8b32f71SDexuan Cui 				    device_t dev, int cpu);
115b5c7e241SSepherosa Ziehau static struct taskqueue		*vmbus_get_eventtq_method(device_t, device_t,
116b5c7e241SSepherosa Ziehau 				    int);
1179729f076SSouradeep Chakrabarti #if defined(EARLY_AP_STARTUP) || defined(__aarch64__)
118be53a2faSSepherosa Ziehau static void			vmbus_intrhook(void *);
119be53a2faSSepherosa Ziehau #endif
1205b444edaSSepherosa Ziehau 
121236764b1SSepherosa Ziehau static int			vmbus_init(struct vmbus_softc *);
122f24517f0SSepherosa Ziehau static int			vmbus_connect(struct vmbus_softc *, uint32_t);
123c1cc5bdfSSepherosa Ziehau static int			vmbus_req_channels(struct vmbus_softc *sc);
124f24517f0SSepherosa Ziehau static void			vmbus_disconnect(struct vmbus_softc *);
125796a90bfSSepherosa Ziehau static int			vmbus_scan(struct vmbus_softc *);
1269f06037bSSepherosa Ziehau static void			vmbus_scan_teardown(struct vmbus_softc *);
127e11f3043SSepherosa Ziehau static void			vmbus_scan_done(struct vmbus_softc *,
128e11f3043SSepherosa Ziehau 				    const struct vmbus_message *);
129e11f3043SSepherosa Ziehau static void			vmbus_chanmsg_handle(struct vmbus_softc *,
130e11f3043SSepherosa Ziehau 				    const struct vmbus_message *);
1315b444edaSSepherosa Ziehau static void			vmbus_msg_task(void *, int);
1325b444edaSSepherosa Ziehau static void			vmbus_synic_setup(void *);
1335b444edaSSepherosa Ziehau static void			vmbus_synic_teardown(void *);
13447a3ee5cSSepherosa Ziehau static int			vmbus_sysctl_version(SYSCTL_HANDLER_ARGS);
1355b444edaSSepherosa Ziehau static int			vmbus_dma_alloc(struct vmbus_softc *);
1365b444edaSSepherosa Ziehau static void			vmbus_dma_free(struct vmbus_softc *);
1375b444edaSSepherosa Ziehau static int			vmbus_intr_setup(struct vmbus_softc *);
1385b444edaSSepherosa Ziehau static void			vmbus_intr_teardown(struct vmbus_softc *);
1395b444edaSSepherosa Ziehau static int			vmbus_doattach(struct vmbus_softc *);
1405b444edaSSepherosa Ziehau static void			vmbus_event_proc_dummy(struct vmbus_softc *,
1415b444edaSSepherosa Ziehau 				    int);
142c0c90897SSepherosa Ziehau static struct vmbus_softc	*vmbus_sc;
143b7bb4816SSepherosa Ziehau 
1448dc07838SSepherosa Ziehau SYSCTL_NODE(_hw, OID_AUTO, vmbus, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
1458dc07838SSepherosa Ziehau     "Hyper-V vmbus");
1468dc07838SSepherosa Ziehau 
1478dc07838SSepherosa Ziehau static int			vmbus_pin_evttask = 1;
1488dc07838SSepherosa Ziehau SYSCTL_INT(_hw_vmbus, OID_AUTO, pin_evttask, CTLFLAG_RDTUN,
1498dc07838SSepherosa Ziehau     &vmbus_pin_evttask, 0, "Pin event tasks to their respective CPU");
150ace5ce7eSWei Hu uint32_t			vmbus_current_version;
151ace5ce7eSWei Hu 
152236764b1SSepherosa Ziehau static const uint32_t		vmbus_version[] = {
153ace5ce7eSWei Hu 	VMBUS_VERSION_WIN10,
15438d19df6SSepherosa Ziehau 	VMBUS_VERSION_WIN8_1,
15538d19df6SSepherosa Ziehau 	VMBUS_VERSION_WIN8,
15638d19df6SSepherosa Ziehau 	VMBUS_VERSION_WIN7,
15738d19df6SSepherosa Ziehau 	VMBUS_VERSION_WS2008
158236764b1SSepherosa Ziehau };
159236764b1SSepherosa Ziehau 
160e11f3043SSepherosa Ziehau static const vmbus_chanmsg_proc_t
161e11f3043SSepherosa Ziehau vmbus_chanmsg_handlers[VMBUS_CHANMSG_TYPE_MAX] = {
162e11f3043SSepherosa Ziehau 	VMBUS_CHANMSG_PROC(CHOFFER_DONE, vmbus_scan_done),
163e11f3043SSepherosa Ziehau 	VMBUS_CHANMSG_PROC_WAKEUP(CONNECT_RESP)
164e11f3043SSepherosa Ziehau };
165e11f3043SSepherosa Ziehau 
166fd42dfc5SSepherosa Ziehau static device_method_t vmbus_methods[] = {
167fd42dfc5SSepherosa Ziehau 	/* Device interface */
168554e6778SSepherosa Ziehau 	DEVMETHOD(device_identify,		vmbus_identify),
169fd42dfc5SSepherosa Ziehau 	DEVMETHOD(device_probe,			vmbus_probe),
170fd42dfc5SSepherosa Ziehau 	DEVMETHOD(device_attach,		vmbus_attach),
171fd42dfc5SSepherosa Ziehau 	DEVMETHOD(device_detach,		vmbus_detach),
172fd42dfc5SSepherosa Ziehau 	DEVMETHOD(device_shutdown,		bus_generic_shutdown),
173fd42dfc5SSepherosa Ziehau 	DEVMETHOD(device_suspend,		bus_generic_suspend),
174fd42dfc5SSepherosa Ziehau 	DEVMETHOD(device_resume,		bus_generic_resume),
175fd42dfc5SSepherosa Ziehau 
176fd42dfc5SSepherosa Ziehau 	/* Bus interface */
177fd42dfc5SSepherosa Ziehau 	DEVMETHOD(bus_add_child,		bus_generic_add_child),
178fd42dfc5SSepherosa Ziehau 	DEVMETHOD(bus_print_child,		bus_generic_print_child),
179fd42dfc5SSepherosa Ziehau 	DEVMETHOD(bus_read_ivar,		vmbus_read_ivar),
180ddfc9c4cSWarner Losh 	DEVMETHOD(bus_child_pnpinfo,		vmbus_child_pnpinfo),
181522c192dSDexuan Cui 	DEVMETHOD(bus_alloc_resource,		vmbus_alloc_resource),
182522c192dSDexuan Cui 	DEVMETHOD(bus_release_resource,		bus_generic_release_resource),
183522c192dSDexuan Cui 	DEVMETHOD(bus_activate_resource,	bus_generic_activate_resource),
184522c192dSDexuan Cui 	DEVMETHOD(bus_deactivate_resource,	bus_generic_deactivate_resource),
185522c192dSDexuan Cui 	DEVMETHOD(bus_setup_intr,		bus_generic_setup_intr),
186522c192dSDexuan Cui 	DEVMETHOD(bus_teardown_intr,		bus_generic_teardown_intr),
187522c192dSDexuan Cui 	DEVMETHOD(bus_get_cpus,			bus_generic_get_cpus),
188522c192dSDexuan Cui 
189522c192dSDexuan Cui 	/* pcib interface */
190522c192dSDexuan Cui 	DEVMETHOD(pcib_alloc_msi,		vmbus_alloc_msi),
191522c192dSDexuan Cui 	DEVMETHOD(pcib_release_msi,		vmbus_release_msi),
192522c192dSDexuan Cui 	DEVMETHOD(pcib_alloc_msix,		vmbus_alloc_msix),
193522c192dSDexuan Cui 	DEVMETHOD(pcib_release_msix,		vmbus_release_msix),
194522c192dSDexuan Cui 	DEVMETHOD(pcib_map_msi,			vmbus_map_msi),
195fd42dfc5SSepherosa Ziehau 
196fd42dfc5SSepherosa Ziehau 	/* Vmbus interface */
197fd42dfc5SSepherosa Ziehau 	DEVMETHOD(vmbus_get_version,		vmbus_get_version_method),
198fd42dfc5SSepherosa Ziehau 	DEVMETHOD(vmbus_probe_guid,		vmbus_probe_guid_method),
199c8b32f71SDexuan Cui 	DEVMETHOD(vmbus_get_vcpu_id,		vmbus_get_vcpu_id_method),
200b5c7e241SSepherosa Ziehau 	DEVMETHOD(vmbus_get_event_taskq,	vmbus_get_eventtq_method),
201fd42dfc5SSepherosa Ziehau 
202fd42dfc5SSepherosa Ziehau 	DEVMETHOD_END
203fd42dfc5SSepherosa Ziehau };
204fd42dfc5SSepherosa Ziehau 
205fd42dfc5SSepherosa Ziehau static driver_t vmbus_driver = {
206fd42dfc5SSepherosa Ziehau 	"vmbus",
207fd42dfc5SSepherosa Ziehau 	vmbus_methods,
208fd42dfc5SSepherosa Ziehau 	sizeof(struct vmbus_softc)
209fd42dfc5SSepherosa Ziehau };
210fd42dfc5SSepherosa Ziehau 
211c1cef544SJohn Baldwin DRIVER_MODULE(vmbus, pcib, vmbus_driver, NULL, NULL);
212c1cef544SJohn Baldwin DRIVER_MODULE(vmbus, acpi_syscontainer, vmbus_driver, NULL, NULL);
213554e6778SSepherosa Ziehau 
214fd42dfc5SSepherosa Ziehau MODULE_DEPEND(vmbus, acpi, 1, 1, 1);
21550182f13SDexuan Cui MODULE_DEPEND(vmbus, pci, 1, 1, 1);
216fd42dfc5SSepherosa Ziehau MODULE_VERSION(vmbus, 1);
217fd42dfc5SSepherosa Ziehau 
218c0c90897SSepherosa Ziehau static __inline struct vmbus_softc *
219c0c90897SSepherosa Ziehau vmbus_get_softc(void)
220c0c90897SSepherosa Ziehau {
221c0c90897SSepherosa Ziehau 	return vmbus_sc;
222c0c90897SSepherosa Ziehau }
223c0c90897SSepherosa Ziehau 
2242bf62f9aSSepherosa Ziehau void
2252bf62f9aSSepherosa Ziehau vmbus_msghc_reset(struct vmbus_msghc *mh, size_t dsize)
226236764b1SSepherosa Ziehau {
227236764b1SSepherosa Ziehau 	struct hypercall_postmsg_in *inprm;
228236764b1SSepherosa Ziehau 
229236764b1SSepherosa Ziehau 	if (dsize > HYPERCALL_POSTMSGIN_DSIZE_MAX)
2302bf62f9aSSepherosa Ziehau 		panic("invalid data size %zu", dsize);
231236764b1SSepherosa Ziehau 
2323dba61ddSSepherosa Ziehau 	inprm = vmbus_xact_req_data(mh->mh_xact);
233236764b1SSepherosa Ziehau 	memset(inprm, 0, HYPERCALL_POSTMSGIN_SIZE);
234236764b1SSepherosa Ziehau 	inprm->hc_connid = VMBUS_CONNID_MESSAGE;
235236764b1SSepherosa Ziehau 	inprm->hc_msgtype = HYPERV_MSGTYPE_CHANNEL;
236236764b1SSepherosa Ziehau 	inprm->hc_dsize = dsize;
2372bf62f9aSSepherosa Ziehau }
238236764b1SSepherosa Ziehau 
2392bf62f9aSSepherosa Ziehau struct vmbus_msghc *
2402bf62f9aSSepherosa Ziehau vmbus_msghc_get(struct vmbus_softc *sc, size_t dsize)
2412bf62f9aSSepherosa Ziehau {
2422bf62f9aSSepherosa Ziehau 	struct vmbus_msghc *mh;
2433dba61ddSSepherosa Ziehau 	struct vmbus_xact *xact;
2442bf62f9aSSepherosa Ziehau 
2452bf62f9aSSepherosa Ziehau 	if (dsize > HYPERCALL_POSTMSGIN_DSIZE_MAX)
2462bf62f9aSSepherosa Ziehau 		panic("invalid data size %zu", dsize);
2472bf62f9aSSepherosa Ziehau 
2483dba61ddSSepherosa Ziehau 	xact = vmbus_xact_get(sc->vmbus_xc,
2493dba61ddSSepherosa Ziehau 	    dsize + __offsetof(struct hypercall_postmsg_in, hc_data[0]));
2503dba61ddSSepherosa Ziehau 	if (xact == NULL)
2513dba61ddSSepherosa Ziehau 		return (NULL);
2523dba61ddSSepherosa Ziehau 
2533dba61ddSSepherosa Ziehau 	mh = vmbus_xact_priv(xact, sizeof(*mh));
2543dba61ddSSepherosa Ziehau 	mh->mh_xact = xact;
2552bf62f9aSSepherosa Ziehau 
2562bf62f9aSSepherosa Ziehau 	vmbus_msghc_reset(mh, dsize);
2573dba61ddSSepherosa Ziehau 	return (mh);
258236764b1SSepherosa Ziehau }
259236764b1SSepherosa Ziehau 
260236764b1SSepherosa Ziehau void
2613dba61ddSSepherosa Ziehau vmbus_msghc_put(struct vmbus_softc *sc __unused, struct vmbus_msghc *mh)
262236764b1SSepherosa Ziehau {
263236764b1SSepherosa Ziehau 
2643dba61ddSSepherosa Ziehau 	vmbus_xact_put(mh->mh_xact);
265236764b1SSepherosa Ziehau }
266236764b1SSepherosa Ziehau 
267236764b1SSepherosa Ziehau void *
268236764b1SSepherosa Ziehau vmbus_msghc_dataptr(struct vmbus_msghc *mh)
269236764b1SSepherosa Ziehau {
2703dba61ddSSepherosa Ziehau 	struct hypercall_postmsg_in *inprm;
271236764b1SSepherosa Ziehau 
2723dba61ddSSepherosa Ziehau 	inprm = vmbus_xact_req_data(mh->mh_xact);
2733dba61ddSSepherosa Ziehau 	return (inprm->hc_data);
274236764b1SSepherosa Ziehau }
275236764b1SSepherosa Ziehau 
276236764b1SSepherosa Ziehau int
277236764b1SSepherosa Ziehau vmbus_msghc_exec_noresult(struct vmbus_msghc *mh)
278236764b1SSepherosa Ziehau {
279236764b1SSepherosa Ziehau 	sbintime_t time = SBT_1MS;
2803dba61ddSSepherosa Ziehau 	struct hypercall_postmsg_in *inprm;
2813dba61ddSSepherosa Ziehau 	bus_addr_t inprm_paddr;
282236764b1SSepherosa Ziehau 	int i;
283236764b1SSepherosa Ziehau 
2843dba61ddSSepherosa Ziehau 	inprm = vmbus_xact_req_data(mh->mh_xact);
2853dba61ddSSepherosa Ziehau 	inprm_paddr = vmbus_xact_req_paddr(mh->mh_xact);
2863dba61ddSSepherosa Ziehau 
287236764b1SSepherosa Ziehau 	/*
288236764b1SSepherosa Ziehau 	 * Save the input parameter so that we could restore the input
289236764b1SSepherosa Ziehau 	 * parameter if the Hypercall failed.
290236764b1SSepherosa Ziehau 	 *
291236764b1SSepherosa Ziehau 	 * XXX
292236764b1SSepherosa Ziehau 	 * Is this really necessary?!  i.e. Will the Hypercall ever
293236764b1SSepherosa Ziehau 	 * overwrite the input parameter?
294236764b1SSepherosa Ziehau 	 */
2953dba61ddSSepherosa Ziehau 	memcpy(&mh->mh_inprm_save, inprm, HYPERCALL_POSTMSGIN_SIZE);
296236764b1SSepherosa Ziehau 
297236764b1SSepherosa Ziehau 	/*
298236764b1SSepherosa Ziehau 	 * In order to cope with transient failures, e.g. insufficient
299236764b1SSepherosa Ziehau 	 * resources on host side, we retry the post message Hypercall
300236764b1SSepherosa Ziehau 	 * several times.  20 retries seem sufficient.
301236764b1SSepherosa Ziehau 	 */
302236764b1SSepherosa Ziehau #define HC_RETRY_MAX	20
303236764b1SSepherosa Ziehau 
304236764b1SSepherosa Ziehau 	for (i = 0; i < HC_RETRY_MAX; ++i) {
305236764b1SSepherosa Ziehau 		uint64_t status;
306236764b1SSepherosa Ziehau 
3073dba61ddSSepherosa Ziehau 		status = hypercall_post_message(inprm_paddr);
308236764b1SSepherosa Ziehau 		if (status == HYPERCALL_STATUS_SUCCESS)
309236764b1SSepherosa Ziehau 			return 0;
310236764b1SSepherosa Ziehau 
311236764b1SSepherosa Ziehau 		pause_sbt("hcpmsg", time, 0, C_HARDCLOCK);
312236764b1SSepherosa Ziehau 		if (time < SBT_1S * 2)
313236764b1SSepherosa Ziehau 			time *= 2;
314236764b1SSepherosa Ziehau 
315236764b1SSepherosa Ziehau 		/* Restore input parameter and try again */
3163dba61ddSSepherosa Ziehau 		memcpy(inprm, &mh->mh_inprm_save, HYPERCALL_POSTMSGIN_SIZE);
317236764b1SSepherosa Ziehau 	}
318236764b1SSepherosa Ziehau 
319236764b1SSepherosa Ziehau #undef HC_RETRY_MAX
320236764b1SSepherosa Ziehau 
321236764b1SSepherosa Ziehau 	return EIO;
322236764b1SSepherosa Ziehau }
323236764b1SSepherosa Ziehau 
324236764b1SSepherosa Ziehau int
3253dba61ddSSepherosa Ziehau vmbus_msghc_exec(struct vmbus_softc *sc __unused, struct vmbus_msghc *mh)
326236764b1SSepherosa Ziehau {
327236764b1SSepherosa Ziehau 	int error;
328236764b1SSepherosa Ziehau 
3293dba61ddSSepherosa Ziehau 	vmbus_xact_activate(mh->mh_xact);
330236764b1SSepherosa Ziehau 	error = vmbus_msghc_exec_noresult(mh);
3313dba61ddSSepherosa Ziehau 	if (error)
3323dba61ddSSepherosa Ziehau 		vmbus_xact_deactivate(mh->mh_xact);
333236764b1SSepherosa Ziehau 	return error;
334236764b1SSepherosa Ziehau }
335236764b1SSepherosa Ziehau 
3362ee4e46fSSepherosa Ziehau void
3372ee4e46fSSepherosa Ziehau vmbus_msghc_exec_cancel(struct vmbus_softc *sc __unused, struct vmbus_msghc *mh)
3382ee4e46fSSepherosa Ziehau {
3392ee4e46fSSepherosa Ziehau 
3402ee4e46fSSepherosa Ziehau 	vmbus_xact_deactivate(mh->mh_xact);
3412ee4e46fSSepherosa Ziehau }
3422ee4e46fSSepherosa Ziehau 
343236764b1SSepherosa Ziehau const struct vmbus_message *
3443dba61ddSSepherosa Ziehau vmbus_msghc_wait_result(struct vmbus_softc *sc __unused, struct vmbus_msghc *mh)
345236764b1SSepherosa Ziehau {
3463dba61ddSSepherosa Ziehau 	size_t resp_len;
347236764b1SSepherosa Ziehau 
3483dba61ddSSepherosa Ziehau 	return (vmbus_xact_wait(mh->mh_xact, &resp_len));
349236764b1SSepherosa Ziehau }
350236764b1SSepherosa Ziehau 
3512fb45c54SSepherosa Ziehau const struct vmbus_message *
3522fb45c54SSepherosa Ziehau vmbus_msghc_poll_result(struct vmbus_softc *sc __unused, struct vmbus_msghc *mh)
3532fb45c54SSepherosa Ziehau {
3542fb45c54SSepherosa Ziehau 	size_t resp_len;
3552fb45c54SSepherosa Ziehau 
3562fb45c54SSepherosa Ziehau 	return (vmbus_xact_poll(mh->mh_xact, &resp_len));
3572fb45c54SSepherosa Ziehau }
3582fb45c54SSepherosa Ziehau 
359236764b1SSepherosa Ziehau void
360236764b1SSepherosa Ziehau vmbus_msghc_wakeup(struct vmbus_softc *sc, const struct vmbus_message *msg)
361236764b1SSepherosa Ziehau {
362236764b1SSepherosa Ziehau 
3633dba61ddSSepherosa Ziehau 	vmbus_xact_ctx_wakeup(sc->vmbus_xc, msg, sizeof(*msg));
364236764b1SSepherosa Ziehau }
365236764b1SSepherosa Ziehau 
366ee7e313fSSepherosa Ziehau uint32_t
367ee7e313fSSepherosa Ziehau vmbus_gpadl_alloc(struct vmbus_softc *sc)
368ee7e313fSSepherosa Ziehau {
369fa643a5dSSepherosa Ziehau 	uint32_t gpadl;
370fa643a5dSSepherosa Ziehau 
371fa643a5dSSepherosa Ziehau again:
372fa643a5dSSepherosa Ziehau 	gpadl = atomic_fetchadd_int(&sc->vmbus_gpadl, 1);
373fa643a5dSSepherosa Ziehau 	if (gpadl == 0)
374fa643a5dSSepherosa Ziehau 		goto again;
375fa643a5dSSepherosa Ziehau 	return (gpadl);
376a560f3ebSWei Hu }
377a560f3ebSWei Hu 
378a560f3ebSWei Hu /* Used for Hyper-V socket when guest client connects to host */
379a560f3ebSWei Hu int
380a560f3ebSWei Hu vmbus_req_tl_connect(struct hyperv_guid *guest_srv_id,
381a560f3ebSWei Hu     struct hyperv_guid *host_srv_id)
382a560f3ebSWei Hu {
383a560f3ebSWei Hu 	struct vmbus_softc *sc = vmbus_get_softc();
384a560f3ebSWei Hu 	struct vmbus_chanmsg_tl_connect *req;
385a560f3ebSWei Hu 	struct vmbus_msghc *mh;
386a560f3ebSWei Hu 	int error;
387a560f3ebSWei Hu 
388a560f3ebSWei Hu 	if (!sc)
389a560f3ebSWei Hu 		return ENXIO;
390a560f3ebSWei Hu 
391a560f3ebSWei Hu 	mh = vmbus_msghc_get(sc, sizeof(*req));
392a560f3ebSWei Hu 	if (mh == NULL) {
393a560f3ebSWei Hu 		device_printf(sc->vmbus_dev,
394a560f3ebSWei Hu 		    "can not get msg hypercall for tl connect\n");
395a560f3ebSWei Hu 		return ENXIO;
396a560f3ebSWei Hu 	}
397a560f3ebSWei Hu 
398a560f3ebSWei Hu 	req = vmbus_msghc_dataptr(mh);
399a560f3ebSWei Hu 	req->chm_hdr.chm_type = VMBUS_CHANMSG_TYPE_TL_CONN;
400a560f3ebSWei Hu 	req->guest_endpoint_id = *guest_srv_id;
401a560f3ebSWei Hu 	req->host_service_id = *host_srv_id;
402a560f3ebSWei Hu 
403a560f3ebSWei Hu 	error = vmbus_msghc_exec_noresult(mh);
404a560f3ebSWei Hu 	vmbus_msghc_put(sc, mh);
405a560f3ebSWei Hu 
406a560f3ebSWei Hu 	if (error) {
407a560f3ebSWei Hu 		device_printf(sc->vmbus_dev,
408a560f3ebSWei Hu 		    "tl connect msg hypercall failed\n");
409a560f3ebSWei Hu 	}
410a560f3ebSWei Hu 
411a560f3ebSWei Hu 	return error;
412ee7e313fSSepherosa Ziehau }
413ee7e313fSSepherosa Ziehau 
414236764b1SSepherosa Ziehau static int
415f24517f0SSepherosa Ziehau vmbus_connect(struct vmbus_softc *sc, uint32_t version)
416236764b1SSepherosa Ziehau {
417f24517f0SSepherosa Ziehau 	struct vmbus_chanmsg_connect *req;
418236764b1SSepherosa Ziehau 	const struct vmbus_message *msg;
419236764b1SSepherosa Ziehau 	struct vmbus_msghc *mh;
420f24517f0SSepherosa Ziehau 	int error, done = 0;
421236764b1SSepherosa Ziehau 
422236764b1SSepherosa Ziehau 	mh = vmbus_msghc_get(sc, sizeof(*req));
423236764b1SSepherosa Ziehau 	if (mh == NULL)
424236764b1SSepherosa Ziehau 		return ENXIO;
425236764b1SSepherosa Ziehau 
426236764b1SSepherosa Ziehau 	req = vmbus_msghc_dataptr(mh);
427f24517f0SSepherosa Ziehau 	req->chm_hdr.chm_type = VMBUS_CHANMSG_TYPE_CONNECT;
428236764b1SSepherosa Ziehau 	req->chm_ver = version;
429*62f9bcf2SAndrew Turner 	req->chm_evtflags = pmap_kextract((vm_offset_t)sc->vmbus_evtflags);
430*62f9bcf2SAndrew Turner 	req->chm_mnf1 = pmap_kextract((vm_offset_t)sc->vmbus_mnf1);
431*62f9bcf2SAndrew Turner 	req->chm_mnf2 = pmap_kextract((vm_offset_t)sc->vmbus_mnf2);
432236764b1SSepherosa Ziehau 
433236764b1SSepherosa Ziehau 	error = vmbus_msghc_exec(sc, mh);
434236764b1SSepherosa Ziehau 	if (error) {
435236764b1SSepherosa Ziehau 		vmbus_msghc_put(sc, mh);
436236764b1SSepherosa Ziehau 		return error;
437236764b1SSepherosa Ziehau 	}
438236764b1SSepherosa Ziehau 
439236764b1SSepherosa Ziehau 	msg = vmbus_msghc_wait_result(sc, mh);
440f24517f0SSepherosa Ziehau 	done = ((const struct vmbus_chanmsg_connect_resp *)
441f24517f0SSepherosa Ziehau 	    msg->msg_data)->chm_done;
442236764b1SSepherosa Ziehau 
443236764b1SSepherosa Ziehau 	vmbus_msghc_put(sc, mh);
444236764b1SSepherosa Ziehau 
445f24517f0SSepherosa Ziehau 	return (done ? 0 : EOPNOTSUPP);
446236764b1SSepherosa Ziehau }
447236764b1SSepherosa Ziehau 
448236764b1SSepherosa Ziehau static int
449236764b1SSepherosa Ziehau vmbus_init(struct vmbus_softc *sc)
450236764b1SSepherosa Ziehau {
451236764b1SSepherosa Ziehau 	int i;
452236764b1SSepherosa Ziehau 
453236764b1SSepherosa Ziehau 	for (i = 0; i < nitems(vmbus_version); ++i) {
454236764b1SSepherosa Ziehau 		int error;
455236764b1SSepherosa Ziehau 
456f24517f0SSepherosa Ziehau 		error = vmbus_connect(sc, vmbus_version[i]);
457236764b1SSepherosa Ziehau 		if (!error) {
458ace5ce7eSWei Hu 			vmbus_current_version = vmbus_version[i];
45938d19df6SSepherosa Ziehau 			sc->vmbus_version = vmbus_version[i];
460236764b1SSepherosa Ziehau 			device_printf(sc->vmbus_dev, "version %u.%u\n",
46138d19df6SSepherosa Ziehau 			    VMBUS_VERSION_MAJOR(sc->vmbus_version),
46238d19df6SSepherosa Ziehau 			    VMBUS_VERSION_MINOR(sc->vmbus_version));
463236764b1SSepherosa Ziehau 			return 0;
464236764b1SSepherosa Ziehau 		}
465236764b1SSepherosa Ziehau 	}
466236764b1SSepherosa Ziehau 	return ENXIO;
467236764b1SSepherosa Ziehau }
468236764b1SSepherosa Ziehau 
4691ecb2466SSepherosa Ziehau static void
470f24517f0SSepherosa Ziehau vmbus_disconnect(struct vmbus_softc *sc)
4711ecb2466SSepherosa Ziehau {
472f24517f0SSepherosa Ziehau 	struct vmbus_chanmsg_disconnect *req;
4731ecb2466SSepherosa Ziehau 	struct vmbus_msghc *mh;
4741ecb2466SSepherosa Ziehau 	int error;
4751ecb2466SSepherosa Ziehau 
4761ecb2466SSepherosa Ziehau 	mh = vmbus_msghc_get(sc, sizeof(*req));
4771ecb2466SSepherosa Ziehau 	if (mh == NULL) {
4781ecb2466SSepherosa Ziehau 		device_printf(sc->vmbus_dev,
479f24517f0SSepherosa Ziehau 		    "can not get msg hypercall for disconnect\n");
4801ecb2466SSepherosa Ziehau 		return;
4811ecb2466SSepherosa Ziehau 	}
4821ecb2466SSepherosa Ziehau 
4831ecb2466SSepherosa Ziehau 	req = vmbus_msghc_dataptr(mh);
484f24517f0SSepherosa Ziehau 	req->chm_hdr.chm_type = VMBUS_CHANMSG_TYPE_DISCONNECT;
4851ecb2466SSepherosa Ziehau 
4861ecb2466SSepherosa Ziehau 	error = vmbus_msghc_exec_noresult(mh);
4871ecb2466SSepherosa Ziehau 	vmbus_msghc_put(sc, mh);
4881ecb2466SSepherosa Ziehau 
4891ecb2466SSepherosa Ziehau 	if (error) {
4901ecb2466SSepherosa Ziehau 		device_printf(sc->vmbus_dev,
491f24517f0SSepherosa Ziehau 		    "disconnect msg hypercall failed\n");
4921ecb2466SSepherosa Ziehau 	}
4931ecb2466SSepherosa Ziehau }
4941ecb2466SSepherosa Ziehau 
495c1cc5bdfSSepherosa Ziehau static int
496c1cc5bdfSSepherosa Ziehau vmbus_req_channels(struct vmbus_softc *sc)
497c1cc5bdfSSepherosa Ziehau {
498f24517f0SSepherosa Ziehau 	struct vmbus_chanmsg_chrequest *req;
499c1cc5bdfSSepherosa Ziehau 	struct vmbus_msghc *mh;
500c1cc5bdfSSepherosa Ziehau 	int error;
501c1cc5bdfSSepherosa Ziehau 
502c1cc5bdfSSepherosa Ziehau 	mh = vmbus_msghc_get(sc, sizeof(*req));
503c1cc5bdfSSepherosa Ziehau 	if (mh == NULL)
504c1cc5bdfSSepherosa Ziehau 		return ENXIO;
505c1cc5bdfSSepherosa Ziehau 
506c1cc5bdfSSepherosa Ziehau 	req = vmbus_msghc_dataptr(mh);
507f24517f0SSepherosa Ziehau 	req->chm_hdr.chm_type = VMBUS_CHANMSG_TYPE_CHREQUEST;
508c1cc5bdfSSepherosa Ziehau 
509c1cc5bdfSSepherosa Ziehau 	error = vmbus_msghc_exec_noresult(mh);
510c1cc5bdfSSepherosa Ziehau 	vmbus_msghc_put(sc, mh);
511c1cc5bdfSSepherosa Ziehau 
512c1cc5bdfSSepherosa Ziehau 	return error;
513c1cc5bdfSSepherosa Ziehau }
514c1cc5bdfSSepherosa Ziehau 
515e11f3043SSepherosa Ziehau static void
5169f06037bSSepherosa Ziehau vmbus_scan_done_task(void *xsc, int pending __unused)
517796a90bfSSepherosa Ziehau {
5189f06037bSSepherosa Ziehau 	struct vmbus_softc *sc = xsc;
5199f06037bSSepherosa Ziehau 
520f581847aSWarner Losh 	bus_topo_lock();
5219f06037bSSepherosa Ziehau 	sc->vmbus_scandone = true;
522f581847aSWarner Losh 	bus_topo_unlock();
5239f06037bSSepherosa Ziehau 	wakeup(&sc->vmbus_scandone);
524796a90bfSSepherosa Ziehau }
525796a90bfSSepherosa Ziehau 
526e11f3043SSepherosa Ziehau static void
527e11f3043SSepherosa Ziehau vmbus_scan_done(struct vmbus_softc *sc,
528e11f3043SSepherosa Ziehau     const struct vmbus_message *msg __unused)
529796a90bfSSepherosa Ziehau {
530796a90bfSSepherosa Ziehau 
5319f06037bSSepherosa Ziehau 	taskqueue_enqueue(sc->vmbus_devtq, &sc->vmbus_scandone_task);
532796a90bfSSepherosa Ziehau }
533796a90bfSSepherosa Ziehau 
534796a90bfSSepherosa Ziehau static int
535796a90bfSSepherosa Ziehau vmbus_scan(struct vmbus_softc *sc)
536796a90bfSSepherosa Ziehau {
537796a90bfSSepherosa Ziehau 	int error;
538796a90bfSSepherosa Ziehau 
539796a90bfSSepherosa Ziehau 	/*
5409f06037bSSepherosa Ziehau 	 * Identify, probe and attach for non-channel devices.
5419f06037bSSepherosa Ziehau 	 */
5429f06037bSSepherosa Ziehau 	bus_generic_probe(sc->vmbus_dev);
5439f06037bSSepherosa Ziehau 	bus_generic_attach(sc->vmbus_dev);
5449f06037bSSepherosa Ziehau 
5459f06037bSSepherosa Ziehau 	/*
5469f06037bSSepherosa Ziehau 	 * This taskqueue serializes vmbus devices' attach and detach
5479f06037bSSepherosa Ziehau 	 * for channel offer and rescind messages.
5489f06037bSSepherosa Ziehau 	 */
5499f06037bSSepherosa Ziehau 	sc->vmbus_devtq = taskqueue_create("vmbus dev", M_WAITOK,
5509f06037bSSepherosa Ziehau 	    taskqueue_thread_enqueue, &sc->vmbus_devtq);
5519f06037bSSepherosa Ziehau 	taskqueue_start_threads(&sc->vmbus_devtq, 1, PI_NET, "vmbusdev");
5529f06037bSSepherosa Ziehau 	TASK_INIT(&sc->vmbus_scandone_task, 0, vmbus_scan_done_task, sc);
5539f06037bSSepherosa Ziehau 
5549f06037bSSepherosa Ziehau 	/*
5559f06037bSSepherosa Ziehau 	 * This taskqueue handles sub-channel detach, so that vmbus
5569f06037bSSepherosa Ziehau 	 * device's detach running in vmbus_devtq can drain its sub-
5579f06037bSSepherosa Ziehau 	 * channels.
5589f06037bSSepherosa Ziehau 	 */
5599f06037bSSepherosa Ziehau 	sc->vmbus_subchtq = taskqueue_create("vmbus subch", M_WAITOK,
5609f06037bSSepherosa Ziehau 	    taskqueue_thread_enqueue, &sc->vmbus_subchtq);
5619f06037bSSepherosa Ziehau 	taskqueue_start_threads(&sc->vmbus_subchtq, 1, PI_NET, "vmbussch");
5629f06037bSSepherosa Ziehau 
5639f06037bSSepherosa Ziehau 	/*
564796a90bfSSepherosa Ziehau 	 * Start vmbus scanning.
565796a90bfSSepherosa Ziehau 	 */
566796a90bfSSepherosa Ziehau 	error = vmbus_req_channels(sc);
567796a90bfSSepherosa Ziehau 	if (error) {
568796a90bfSSepherosa Ziehau 		device_printf(sc->vmbus_dev, "channel request failed: %d\n",
569796a90bfSSepherosa Ziehau 		    error);
5709f06037bSSepherosa Ziehau 		return (error);
571796a90bfSSepherosa Ziehau 	}
572796a90bfSSepherosa Ziehau 
573796a90bfSSepherosa Ziehau 	/*
5749f06037bSSepherosa Ziehau 	 * Wait for all vmbus devices from the initial channel offers to be
5759f06037bSSepherosa Ziehau 	 * attached.
576796a90bfSSepherosa Ziehau 	 */
577f581847aSWarner Losh 	bus_topo_assert();
5789f06037bSSepherosa Ziehau 	while (!sc->vmbus_scandone)
579f581847aSWarner Losh 		mtx_sleep(&sc->vmbus_scandone, bus_topo_mtx(), 0, "vmbusdev", 0);
580796a90bfSSepherosa Ziehau 
581796a90bfSSepherosa Ziehau 	if (bootverbose) {
582796a90bfSSepherosa Ziehau 		device_printf(sc->vmbus_dev, "device scan, probe and attach "
583796a90bfSSepherosa Ziehau 		    "done\n");
584796a90bfSSepherosa Ziehau 	}
5859f06037bSSepherosa Ziehau 	return (0);
5869f06037bSSepherosa Ziehau }
5879f06037bSSepherosa Ziehau 
5889f06037bSSepherosa Ziehau static void
5899f06037bSSepherosa Ziehau vmbus_scan_teardown(struct vmbus_softc *sc)
5909f06037bSSepherosa Ziehau {
5919f06037bSSepherosa Ziehau 
592f581847aSWarner Losh 	bus_topo_assert();
5939f06037bSSepherosa Ziehau 	if (sc->vmbus_devtq != NULL) {
594f581847aSWarner Losh 		bus_topo_unlock();
5959f06037bSSepherosa Ziehau 		taskqueue_free(sc->vmbus_devtq);
596f581847aSWarner Losh 		bus_topo_lock();
5979f06037bSSepherosa Ziehau 		sc->vmbus_devtq = NULL;
5989f06037bSSepherosa Ziehau 	}
5999f06037bSSepherosa Ziehau 	if (sc->vmbus_subchtq != NULL) {
600f581847aSWarner Losh 		bus_topo_unlock();
6019f06037bSSepherosa Ziehau 		taskqueue_free(sc->vmbus_subchtq);
602f581847aSWarner Losh 		bus_topo_lock();
6039f06037bSSepherosa Ziehau 		sc->vmbus_subchtq = NULL;
6049f06037bSSepherosa Ziehau 	}
605796a90bfSSepherosa Ziehau }
606796a90bfSSepherosa Ziehau 
607b7bb4816SSepherosa Ziehau static void
608e11f3043SSepherosa Ziehau vmbus_chanmsg_handle(struct vmbus_softc *sc, const struct vmbus_message *msg)
609e11f3043SSepherosa Ziehau {
610e11f3043SSepherosa Ziehau 	vmbus_chanmsg_proc_t msg_proc;
611e11f3043SSepherosa Ziehau 	uint32_t msg_type;
612e11f3043SSepherosa Ziehau 
613e11f3043SSepherosa Ziehau 	msg_type = ((const struct vmbus_chanmsg_hdr *)msg->msg_data)->chm_type;
614e11f3043SSepherosa Ziehau 	if (msg_type >= VMBUS_CHANMSG_TYPE_MAX) {
615e11f3043SSepherosa Ziehau 		device_printf(sc->vmbus_dev, "unknown message type 0x%x\n",
616e11f3043SSepherosa Ziehau 		    msg_type);
617e11f3043SSepherosa Ziehau 		return;
618e11f3043SSepherosa Ziehau 	}
619e11f3043SSepherosa Ziehau 
620e11f3043SSepherosa Ziehau 	msg_proc = vmbus_chanmsg_handlers[msg_type];
621e11f3043SSepherosa Ziehau 	if (msg_proc != NULL)
622e11f3043SSepherosa Ziehau 		msg_proc(sc, msg);
623e11f3043SSepherosa Ziehau 
624e11f3043SSepherosa Ziehau 	/* Channel specific processing */
625e11f3043SSepherosa Ziehau 	vmbus_chan_msgproc(sc, msg);
626e11f3043SSepherosa Ziehau }
627e11f3043SSepherosa Ziehau 
628e11f3043SSepherosa Ziehau static void
629b7bb4816SSepherosa Ziehau vmbus_msg_task(void *xsc, int pending __unused)
630b7bb4816SSepherosa Ziehau {
631b7bb4816SSepherosa Ziehau 	struct vmbus_softc *sc = xsc;
632b7bb4816SSepherosa Ziehau 	volatile struct vmbus_message *msg;
633b7bb4816SSepherosa Ziehau 
634b7bb4816SSepherosa Ziehau 	msg = VMBUS_PCPU_GET(sc, message, curcpu) + VMBUS_SINT_MESSAGE;
635b7bb4816SSepherosa Ziehau 	for (;;) {
636236764b1SSepherosa Ziehau 		if (msg->msg_type == HYPERV_MSGTYPE_NONE) {
637fa4828b0SSepherosa Ziehau 			/* No message */
638fa4828b0SSepherosa Ziehau 			break;
639236764b1SSepherosa Ziehau 		} else if (msg->msg_type == HYPERV_MSGTYPE_CHANNEL) {
64012ea25aeSSepherosa Ziehau 			/* Channel message */
641e11f3043SSepherosa Ziehau 			vmbus_chanmsg_handle(sc,
64243926ba1SSepherosa Ziehau 			    __DEVOLATILE(const struct vmbus_message *, msg));
643fa4828b0SSepherosa Ziehau 		}
644b7bb4816SSepherosa Ziehau 
645236764b1SSepherosa Ziehau 		msg->msg_type = HYPERV_MSGTYPE_NONE;
646b7bb4816SSepherosa Ziehau 		/*
647b7bb4816SSepherosa Ziehau 		 * Make sure the write to msg_type (i.e. set to
648236764b1SSepherosa Ziehau 		 * HYPERV_MSGTYPE_NONE) happens before we read the
649b7bb4816SSepherosa Ziehau 		 * msg_flags and EOMing. Otherwise, the EOMing will
650b7bb4816SSepherosa Ziehau 		 * not deliver any more messages since there is no
651b7bb4816SSepherosa Ziehau 		 * empty slot
652b7bb4816SSepherosa Ziehau 		 *
653b7bb4816SSepherosa Ziehau 		 * NOTE:
654b7bb4816SSepherosa Ziehau 		 * mb() is used here, since atomic_thread_fence_seq_cst()
655b7bb4816SSepherosa Ziehau 		 * will become compiler fence on UP kernel.
656b7bb4816SSepherosa Ziehau 		 */
657b7bb4816SSepherosa Ziehau 		mb();
658b7bb4816SSepherosa Ziehau 		if (msg->msg_flags & VMBUS_MSGFLAG_PENDING) {
659b7bb4816SSepherosa Ziehau 			/*
660b7bb4816SSepherosa Ziehau 			 * This will cause message queue rescan to possibly
661b7bb4816SSepherosa Ziehau 			 * deliver another msg from the hypervisor
662b7bb4816SSepherosa Ziehau 			 */
6639729f076SSouradeep Chakrabarti 			WRMSR(MSR_HV_EOM, 0);
664b7bb4816SSepherosa Ziehau 		}
665b7bb4816SSepherosa Ziehau 	}
666b7bb4816SSepherosa Ziehau }
667b7bb4816SSepherosa Ziehau static __inline int
668b7bb4816SSepherosa Ziehau vmbus_handle_intr1(struct vmbus_softc *sc, struct trapframe *frame, int cpu)
669b7bb4816SSepherosa Ziehau {
670b7bb4816SSepherosa Ziehau 	volatile struct vmbus_message *msg;
671b7bb4816SSepherosa Ziehau 	struct vmbus_message *msg_base;
672b7bb4816SSepherosa Ziehau 
673b7bb4816SSepherosa Ziehau 	msg_base = VMBUS_PCPU_GET(sc, message, cpu);
674b7bb4816SSepherosa Ziehau 
675b7bb4816SSepherosa Ziehau 	/*
676b7bb4816SSepherosa Ziehau 	 * Check event timer.
677b7bb4816SSepherosa Ziehau 	 *
678b7bb4816SSepherosa Ziehau 	 * TODO: move this to independent IDT vector.
679b7bb4816SSepherosa Ziehau 	 */
6809729f076SSouradeep Chakrabarti 	vmbus_handle_timer_intr1(msg_base, frame);
681b7bb4816SSepherosa Ziehau 	/*
682b7bb4816SSepherosa Ziehau 	 * Check events.  Hot path for network and storage I/O data; high rate.
683b7bb4816SSepherosa Ziehau 	 *
684b7bb4816SSepherosa Ziehau 	 * NOTE:
685b7bb4816SSepherosa Ziehau 	 * As recommended by the Windows guest fellows, we check events before
686b7bb4816SSepherosa Ziehau 	 * checking messages.
687b7bb4816SSepherosa Ziehau 	 */
688b7bb4816SSepherosa Ziehau 	sc->vmbus_event_proc(sc, cpu);
689b7bb4816SSepherosa Ziehau 
690b7bb4816SSepherosa Ziehau 	/*
691b7bb4816SSepherosa Ziehau 	 * Check messages.  Mainly management stuffs; ultra low rate.
692b7bb4816SSepherosa Ziehau 	 */
693b7bb4816SSepherosa Ziehau 	msg = msg_base + VMBUS_SINT_MESSAGE;
694236764b1SSepherosa Ziehau 	if (__predict_false(msg->msg_type != HYPERV_MSGTYPE_NONE)) {
695b7bb4816SSepherosa Ziehau 		taskqueue_enqueue(VMBUS_PCPU_GET(sc, message_tq, cpu),
696b7bb4816SSepherosa Ziehau 		    VMBUS_PCPU_PTR(sc, message_task, cpu));
697b7bb4816SSepherosa Ziehau 	}
698b7bb4816SSepherosa Ziehau 
699b7bb4816SSepherosa Ziehau 	return (FILTER_HANDLED);
700b7bb4816SSepherosa Ziehau }
701b7bb4816SSepherosa Ziehau 
702b7bb4816SSepherosa Ziehau void
703b7bb4816SSepherosa Ziehau vmbus_handle_intr(struct trapframe *trap_frame)
704b7bb4816SSepherosa Ziehau {
705b7bb4816SSepherosa Ziehau 	struct vmbus_softc *sc = vmbus_get_softc();
706b7bb4816SSepherosa Ziehau 	int cpu = curcpu;
707b7bb4816SSepherosa Ziehau 
708b7bb4816SSepherosa Ziehau 	/*
709b7bb4816SSepherosa Ziehau 	 * Disable preemption.
710b7bb4816SSepherosa Ziehau 	 */
711b7bb4816SSepherosa Ziehau 	critical_enter();
712b7bb4816SSepherosa Ziehau 
713b7bb4816SSepherosa Ziehau 	/*
7149729f076SSouradeep Chakrabarti 	 * Do a little interrupt counting. This used x86 specific
7159729f076SSouradeep Chakrabarti 	 * intrcnt_add function
716b7bb4816SSepherosa Ziehau 	 */
7179729f076SSouradeep Chakrabarti #if !defined(__aarch64__)
718b7bb4816SSepherosa Ziehau 	(*VMBUS_PCPU_GET(sc, intr_cnt, cpu))++;
7199729f076SSouradeep Chakrabarti #endif /* not for aarch64 */
720b7bb4816SSepherosa Ziehau 	vmbus_handle_intr1(sc, trap_frame, cpu);
721b7bb4816SSepherosa Ziehau 
722b7bb4816SSepherosa Ziehau 	/*
723b7bb4816SSepherosa Ziehau 	 * Enable preemption.
724b7bb4816SSepherosa Ziehau 	 */
725b7bb4816SSepherosa Ziehau 	critical_exit();
726b7bb4816SSepherosa Ziehau }
727b7bb4816SSepherosa Ziehau 
728b7bb4816SSepherosa Ziehau static void
729b7bb4816SSepherosa Ziehau vmbus_synic_setup(void *xsc)
730b7bb4816SSepherosa Ziehau {
731b7bb4816SSepherosa Ziehau 	struct vmbus_softc *sc = xsc;
732b7bb4816SSepherosa Ziehau 	int cpu = curcpu;
733b7bb4816SSepherosa Ziehau 	uint64_t val, orig;
734b7bb4816SSepherosa Ziehau 	uint32_t sint;
735b7bb4816SSepherosa Ziehau 
736b7bb4816SSepherosa Ziehau 	if (hyperv_features & CPUID_HV_MSR_VP_INDEX) {
73723eaa43cSSepherosa Ziehau 		/* Save virtual processor id. */
7389729f076SSouradeep Chakrabarti 		VMBUS_PCPU_GET(sc, vcpuid, cpu) = RDMSR(MSR_HV_VP_INDEX);
739b7bb4816SSepherosa Ziehau 	} else {
74023eaa43cSSepherosa Ziehau 		/* Set virtual processor id to 0 for compatibility. */
74123eaa43cSSepherosa Ziehau 		VMBUS_PCPU_GET(sc, vcpuid, cpu) = 0;
742b7bb4816SSepherosa Ziehau 	}
743b7bb4816SSepherosa Ziehau 
744b7bb4816SSepherosa Ziehau 	/*
745b7bb4816SSepherosa Ziehau 	 * Setup the SynIC message.
746b7bb4816SSepherosa Ziehau 	 */
7479729f076SSouradeep Chakrabarti 	orig = RDMSR(MSR_HV_SIMP);
748*62f9bcf2SAndrew Turner 	val = pmap_kextract((vm_offset_t)VMBUS_PCPU_GET(sc, message, cpu)) &
749*62f9bcf2SAndrew Turner 	    MSR_HV_SIMP_PGMASK;
750*62f9bcf2SAndrew Turner 	val |= MSR_HV_SIMP_ENABLE | (orig & MSR_HV_SIMP_RSVD_MASK);
7519729f076SSouradeep Chakrabarti 	WRMSR(MSR_HV_SIMP, val);
752b7bb4816SSepherosa Ziehau 	/*
753b7bb4816SSepherosa Ziehau 	 * Setup the SynIC event flags.
754b7bb4816SSepherosa Ziehau 	 */
7559729f076SSouradeep Chakrabarti 	orig = RDMSR(MSR_HV_SIEFP);
756*62f9bcf2SAndrew Turner 	val = pmap_kextract((vm_offset_t)VMBUS_PCPU_GET(sc, event_flags, cpu)) &
757*62f9bcf2SAndrew Turner 	    MSR_HV_SIMP_PGMASK;
758*62f9bcf2SAndrew Turner 	val |= MSR_HV_SIEFP_ENABLE | (orig & MSR_HV_SIEFP_RSVD_MASK);
7599729f076SSouradeep Chakrabarti 	WRMSR(MSR_HV_SIEFP, val);
760b7bb4816SSepherosa Ziehau 
761b7bb4816SSepherosa Ziehau 	/*
762b7bb4816SSepherosa Ziehau 	 * Configure and unmask SINT for message and event flags.
763b7bb4816SSepherosa Ziehau 	 */
764b7bb4816SSepherosa Ziehau 	sint = MSR_HV_SINT0 + VMBUS_SINT_MESSAGE;
7659729f076SSouradeep Chakrabarti 	orig = RDMSR(sint);
766b7bb4816SSepherosa Ziehau 	val = sc->vmbus_idtvec | MSR_HV_SINT_AUTOEOI |
767b7bb4816SSepherosa Ziehau 	    (orig & MSR_HV_SINT_RSVD_MASK);
7689729f076SSouradeep Chakrabarti 	WRMSR(sint, val);
769b7bb4816SSepherosa Ziehau 
770b7bb4816SSepherosa Ziehau 	/*
771b7bb4816SSepherosa Ziehau 	 * Configure and unmask SINT for timer.
772b7bb4816SSepherosa Ziehau 	 */
7739729f076SSouradeep Chakrabarti 	vmbus_synic_setup1(sc);
774b7bb4816SSepherosa Ziehau 	/*
775b7bb4816SSepherosa Ziehau 	 * All done; enable SynIC.
776b7bb4816SSepherosa Ziehau 	 */
7779729f076SSouradeep Chakrabarti 	orig = RDMSR(MSR_HV_SCONTROL);
778b7bb4816SSepherosa Ziehau 	val = MSR_HV_SCTRL_ENABLE | (orig & MSR_HV_SCTRL_RSVD_MASK);
7799729f076SSouradeep Chakrabarti 	WRMSR(MSR_HV_SCONTROL, val);
780b7bb4816SSepherosa Ziehau }
781b7bb4816SSepherosa Ziehau 
782b7bb4816SSepherosa Ziehau static void
783b7bb4816SSepherosa Ziehau vmbus_synic_teardown(void *arg)
784b7bb4816SSepherosa Ziehau {
785b7bb4816SSepherosa Ziehau 	uint64_t orig;
786b7bb4816SSepherosa Ziehau 	uint32_t sint;
787b7bb4816SSepherosa Ziehau 
788b7bb4816SSepherosa Ziehau 	/*
789b7bb4816SSepherosa Ziehau 	 * Disable SynIC.
790b7bb4816SSepherosa Ziehau 	 */
7919729f076SSouradeep Chakrabarti 	orig = RDMSR(MSR_HV_SCONTROL);
7929729f076SSouradeep Chakrabarti 	WRMSR(MSR_HV_SCONTROL, (orig & MSR_HV_SCTRL_RSVD_MASK));
793b7bb4816SSepherosa Ziehau 
794b7bb4816SSepherosa Ziehau 	/*
795b7bb4816SSepherosa Ziehau 	 * Mask message and event flags SINT.
796b7bb4816SSepherosa Ziehau 	 */
797b7bb4816SSepherosa Ziehau 	sint = MSR_HV_SINT0 + VMBUS_SINT_MESSAGE;
7989729f076SSouradeep Chakrabarti 	orig = RDMSR(sint);
7999729f076SSouradeep Chakrabarti 	WRMSR(sint, orig | MSR_HV_SINT_MASKED);
800b7bb4816SSepherosa Ziehau 
801b7bb4816SSepherosa Ziehau 	/*
802b7bb4816SSepherosa Ziehau 	 * Mask timer SINT.
803b7bb4816SSepherosa Ziehau 	 */
8049729f076SSouradeep Chakrabarti 	vmbus_synic_teardown1();
805b7bb4816SSepherosa Ziehau 	/*
806b7bb4816SSepherosa Ziehau 	 * Teardown SynIC message.
807b7bb4816SSepherosa Ziehau 	 */
8089729f076SSouradeep Chakrabarti 	orig = RDMSR(MSR_HV_SIMP);
8099729f076SSouradeep Chakrabarti 	WRMSR(MSR_HV_SIMP, (orig & MSR_HV_SIMP_RSVD_MASK));
810b7bb4816SSepherosa Ziehau 
811b7bb4816SSepherosa Ziehau 	/*
812b7bb4816SSepherosa Ziehau 	 * Teardown SynIC event flags.
813b7bb4816SSepherosa Ziehau 	 */
8149729f076SSouradeep Chakrabarti 	orig = RDMSR(MSR_HV_SIEFP);
8159729f076SSouradeep Chakrabarti 	WRMSR(MSR_HV_SIEFP, (orig & MSR_HV_SIEFP_RSVD_MASK));
816b7bb4816SSepherosa Ziehau }
817b7bb4816SSepherosa Ziehau 
818b7bb4816SSepherosa Ziehau static int
819b7bb4816SSepherosa Ziehau vmbus_dma_alloc(struct vmbus_softc *sc)
820b7bb4816SSepherosa Ziehau {
8216523ab7eSSepherosa Ziehau 	uint8_t *evtflags;
822b7bb4816SSepherosa Ziehau 	int cpu;
823b7bb4816SSepherosa Ziehau 
824b7bb4816SSepherosa Ziehau 	CPU_FOREACH(cpu) {
825b7bb4816SSepherosa Ziehau 		void *ptr;
826b7bb4816SSepherosa Ziehau 
827b7bb4816SSepherosa Ziehau 		/*
828b7bb4816SSepherosa Ziehau 		 * Per-cpu messages and event flags.
829b7bb4816SSepherosa Ziehau 		 */
830*62f9bcf2SAndrew Turner 		ptr = contigmalloc(PAGE_SIZE, M_DEVBUF, M_WAITOK | M_ZERO,
831*62f9bcf2SAndrew Turner 		    0ul, ~0ul, PAGE_SIZE, 0);
832b7bb4816SSepherosa Ziehau 		if (ptr == NULL)
833b7bb4816SSepherosa Ziehau 			return ENOMEM;
834b7bb4816SSepherosa Ziehau 		VMBUS_PCPU_GET(sc, message, cpu) = ptr;
835b7bb4816SSepherosa Ziehau 
836*62f9bcf2SAndrew Turner 		ptr = contigmalloc(PAGE_SIZE, M_DEVBUF, M_WAITOK | M_ZERO,
837*62f9bcf2SAndrew Turner 		    0ul, ~0ul, PAGE_SIZE, 0);
838b7bb4816SSepherosa Ziehau 		if (ptr == NULL)
839b7bb4816SSepherosa Ziehau 			return ENOMEM;
840b7bb4816SSepherosa Ziehau 		VMBUS_PCPU_GET(sc, event_flags, cpu) = ptr;
841b7bb4816SSepherosa Ziehau 	}
8426523ab7eSSepherosa Ziehau 
843*62f9bcf2SAndrew Turner 	evtflags = contigmalloc(PAGE_SIZE, M_DEVBUF, M_WAITOK | M_ZERO,
844*62f9bcf2SAndrew Turner 	    0ul, ~0ul, PAGE_SIZE, 0);
8456523ab7eSSepherosa Ziehau 	if (evtflags == NULL)
8466523ab7eSSepherosa Ziehau 		return ENOMEM;
8476523ab7eSSepherosa Ziehau 	sc->vmbus_rx_evtflags = (u_long *)evtflags;
84851a9a000SSepherosa Ziehau 	sc->vmbus_tx_evtflags = (u_long *)(evtflags + (PAGE_SIZE / 2));
8496523ab7eSSepherosa Ziehau 	sc->vmbus_evtflags = evtflags;
8506523ab7eSSepherosa Ziehau 
851*62f9bcf2SAndrew Turner 	sc->vmbus_mnf1 = contigmalloc(PAGE_SIZE, M_DEVBUF, M_WAITOK | M_ZERO,
852*62f9bcf2SAndrew Turner 	    0ul, ~0ul, PAGE_SIZE, 0);
8536523ab7eSSepherosa Ziehau 	if (sc->vmbus_mnf1 == NULL)
8546523ab7eSSepherosa Ziehau 		return ENOMEM;
8556523ab7eSSepherosa Ziehau 
856*62f9bcf2SAndrew Turner 	sc->vmbus_mnf2 = contigmalloc(sizeof(struct vmbus_mnf), M_DEVBUF,
857*62f9bcf2SAndrew Turner 	    M_WAITOK | M_ZERO, 0ul, ~0ul, PAGE_SIZE, 0);
8586523ab7eSSepherosa Ziehau 	if (sc->vmbus_mnf2 == NULL)
8596523ab7eSSepherosa Ziehau 		return ENOMEM;
8606523ab7eSSepherosa Ziehau 
861b7bb4816SSepherosa Ziehau 	return 0;
862b7bb4816SSepherosa Ziehau }
863b7bb4816SSepherosa Ziehau 
864b7bb4816SSepherosa Ziehau static void
865b7bb4816SSepherosa Ziehau vmbus_dma_free(struct vmbus_softc *sc)
866b7bb4816SSepherosa Ziehau {
867b7bb4816SSepherosa Ziehau 	int cpu;
868b7bb4816SSepherosa Ziehau 
8696523ab7eSSepherosa Ziehau 	if (sc->vmbus_evtflags != NULL) {
870*62f9bcf2SAndrew Turner 		contigfree(sc->vmbus_evtflags, PAGE_SIZE, M_DEVBUF);
8716523ab7eSSepherosa Ziehau 		sc->vmbus_evtflags = NULL;
8726523ab7eSSepherosa Ziehau 		sc->vmbus_rx_evtflags = NULL;
8736523ab7eSSepherosa Ziehau 		sc->vmbus_tx_evtflags = NULL;
8746523ab7eSSepherosa Ziehau 	}
8756523ab7eSSepherosa Ziehau 	if (sc->vmbus_mnf1 != NULL) {
876*62f9bcf2SAndrew Turner 		contigfree(sc->vmbus_mnf1, PAGE_SIZE, M_DEVBUF);
8776523ab7eSSepherosa Ziehau 		sc->vmbus_mnf1 = NULL;
8786523ab7eSSepherosa Ziehau 	}
8796523ab7eSSepherosa Ziehau 	if (sc->vmbus_mnf2 != NULL) {
880*62f9bcf2SAndrew Turner 		contigfree(sc->vmbus_mnf2, sizeof(struct vmbus_mnf), M_DEVBUF);
8816523ab7eSSepherosa Ziehau 		sc->vmbus_mnf2 = NULL;
8826523ab7eSSepherosa Ziehau 	}
8836523ab7eSSepherosa Ziehau 
884b7bb4816SSepherosa Ziehau 	CPU_FOREACH(cpu) {
885b7bb4816SSepherosa Ziehau 		if (VMBUS_PCPU_GET(sc, message, cpu) != NULL) {
886*62f9bcf2SAndrew Turner 			contigfree(VMBUS_PCPU_GET(sc, message, cpu), PAGE_SIZE,
887*62f9bcf2SAndrew Turner 			    M_DEVBUF);
888b7bb4816SSepherosa Ziehau 			VMBUS_PCPU_GET(sc, message, cpu) = NULL;
889b7bb4816SSepherosa Ziehau 		}
890b7bb4816SSepherosa Ziehau 		if (VMBUS_PCPU_GET(sc, event_flags, cpu) != NULL) {
891*62f9bcf2SAndrew Turner 			contigfree(VMBUS_PCPU_GET(sc, event_flags, cpu),
892*62f9bcf2SAndrew Turner 			    PAGE_SIZE, M_DEVBUF);
893b7bb4816SSepherosa Ziehau 			VMBUS_PCPU_GET(sc, event_flags, cpu) = NULL;
894b7bb4816SSepherosa Ziehau 		}
895b7bb4816SSepherosa Ziehau 	}
896b7bb4816SSepherosa Ziehau }
897b7bb4816SSepherosa Ziehau 
898b7bb4816SSepherosa Ziehau static int
899b7bb4816SSepherosa Ziehau vmbus_intr_setup(struct vmbus_softc *sc)
900b7bb4816SSepherosa Ziehau {
901b7bb4816SSepherosa Ziehau 	int cpu;
902b7bb4816SSepherosa Ziehau 
903b7bb4816SSepherosa Ziehau 	CPU_FOREACH(cpu) {
904b7bb4816SSepherosa Ziehau 		char buf[MAXCOMLEN + 1];
905b7bb4816SSepherosa Ziehau 		cpuset_t cpu_mask;
906b7bb4816SSepherosa Ziehau 
907b7bb4816SSepherosa Ziehau 		/* Allocate an interrupt counter for Hyper-V interrupt */
908b7bb4816SSepherosa Ziehau 		snprintf(buf, sizeof(buf), "cpu%d:hyperv", cpu);
9099729f076SSouradeep Chakrabarti #if !defined(__aarch64__)
910b7bb4816SSepherosa Ziehau 		intrcnt_add(buf, VMBUS_PCPU_PTR(sc, intr_cnt, cpu));
9119729f076SSouradeep Chakrabarti #endif /* not for aarch64 */
912b7bb4816SSepherosa Ziehau 		/*
913b7bb4816SSepherosa Ziehau 		 * Setup taskqueue to handle events.  Task will be per-
914b7bb4816SSepherosa Ziehau 		 * channel.
915b7bb4816SSepherosa Ziehau 		 */
916b7bb4816SSepherosa Ziehau 		VMBUS_PCPU_GET(sc, event_tq, cpu) = taskqueue_create_fast(
917b7bb4816SSepherosa Ziehau 		    "hyperv event", M_WAITOK, taskqueue_thread_enqueue,
918b7bb4816SSepherosa Ziehau 		    VMBUS_PCPU_PTR(sc, event_tq, cpu));
9198dc07838SSepherosa Ziehau 		if (vmbus_pin_evttask) {
920b7bb4816SSepherosa Ziehau 			CPU_SETOF(cpu, &cpu_mask);
921b7bb4816SSepherosa Ziehau 			taskqueue_start_threads_cpuset(
9228dc07838SSepherosa Ziehau 			    VMBUS_PCPU_PTR(sc, event_tq, cpu), 1, PI_NET,
9238dc07838SSepherosa Ziehau 			    &cpu_mask, "hvevent%d", cpu);
9248dc07838SSepherosa Ziehau 		} else {
9258dc07838SSepherosa Ziehau 			taskqueue_start_threads(
9268dc07838SSepherosa Ziehau 			    VMBUS_PCPU_PTR(sc, event_tq, cpu), 1, PI_NET,
927b7bb4816SSepherosa Ziehau 			    "hvevent%d", cpu);
9288dc07838SSepherosa Ziehau 		}
929b7bb4816SSepherosa Ziehau 
930b7bb4816SSepherosa Ziehau 		/*
931b7bb4816SSepherosa Ziehau 		 * Setup tasks and taskqueues to handle messages.
932b7bb4816SSepherosa Ziehau 		 */
933b7bb4816SSepherosa Ziehau 		VMBUS_PCPU_GET(sc, message_tq, cpu) = taskqueue_create_fast(
934b7bb4816SSepherosa Ziehau 		    "hyperv msg", M_WAITOK, taskqueue_thread_enqueue,
935b7bb4816SSepherosa Ziehau 		    VMBUS_PCPU_PTR(sc, message_tq, cpu));
936b7bb4816SSepherosa Ziehau 		CPU_SETOF(cpu, &cpu_mask);
937b7bb4816SSepherosa Ziehau 		taskqueue_start_threads_cpuset(
938b7bb4816SSepherosa Ziehau 		    VMBUS_PCPU_PTR(sc, message_tq, cpu), 1, PI_NET, &cpu_mask,
939b7bb4816SSepherosa Ziehau 		    "hvmsg%d", cpu);
940b7bb4816SSepherosa Ziehau 		TASK_INIT(VMBUS_PCPU_PTR(sc, message_task, cpu), 0,
941b7bb4816SSepherosa Ziehau 		    vmbus_msg_task, sc);
942b7bb4816SSepherosa Ziehau 	}
9439729f076SSouradeep Chakrabarti 	return (vmbus_setup_intr1(sc));
944b7bb4816SSepherosa Ziehau }
945b7bb4816SSepherosa Ziehau static void
946b7bb4816SSepherosa Ziehau vmbus_intr_teardown(struct vmbus_softc *sc)
947b7bb4816SSepherosa Ziehau {
9489729f076SSouradeep Chakrabarti 	vmbus_intr_teardown1(sc);
949b7bb4816SSepherosa Ziehau }
950b7bb4816SSepherosa Ziehau 
951b7bb4816SSepherosa Ziehau static int
952b7bb4816SSepherosa Ziehau vmbus_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
953b7bb4816SSepherosa Ziehau {
954b7bb4816SSepherosa Ziehau 	return (ENOENT);
955b7bb4816SSepherosa Ziehau }
956b7bb4816SSepherosa Ziehau 
957b7bb4816SSepherosa Ziehau static int
958ddfc9c4cSWarner Losh vmbus_child_pnpinfo(device_t dev, device_t child, struct sbuf *sb)
959b7bb4816SSepherosa Ziehau {
96082b8a879SSepherosa Ziehau 	const struct vmbus_channel *chan;
961b7bb4816SSepherosa Ziehau 	char guidbuf[HYPERV_GUID_STRLEN];
962b7bb4816SSepherosa Ziehau 
9633b50b13bSSepherosa Ziehau 	chan = vmbus_get_channel(child);
9643b50b13bSSepherosa Ziehau 	if (chan == NULL) {
96547575345SSepherosa Ziehau 		/* Event timer device, which does not belong to a channel */
966b7bb4816SSepherosa Ziehau 		return (0);
96747575345SSepherosa Ziehau 	}
968b7bb4816SSepherosa Ziehau 
96947575345SSepherosa Ziehau 	hyperv_guid2str(&chan->ch_guid_type, guidbuf, sizeof(guidbuf));
970ddfc9c4cSWarner Losh 	sbuf_printf(sb, "classid=%s", guidbuf);
971b7bb4816SSepherosa Ziehau 
97247575345SSepherosa Ziehau 	hyperv_guid2str(&chan->ch_guid_inst, guidbuf, sizeof(guidbuf));
973ddfc9c4cSWarner Losh 	sbuf_printf(sb, " deviceid=%s", guidbuf);
974b7bb4816SSepherosa Ziehau 
975b7bb4816SSepherosa Ziehau 	return (0);
976b7bb4816SSepherosa Ziehau }
977b7bb4816SSepherosa Ziehau 
97847575345SSepherosa Ziehau int
97982b8a879SSepherosa Ziehau vmbus_add_child(struct vmbus_channel *chan)
980b7bb4816SSepherosa Ziehau {
9819129ad2dSSepherosa Ziehau 	struct vmbus_softc *sc = chan->ch_vmbus;
98247575345SSepherosa Ziehau 	device_t parent = sc->vmbus_dev;
983b7bb4816SSepherosa Ziehau 
984f581847aSWarner Losh 	bus_topo_lock();
98547575345SSepherosa Ziehau 	chan->ch_dev = device_add_child(parent, NULL, -1);
98647575345SSepherosa Ziehau 	if (chan->ch_dev == NULL) {
987f581847aSWarner Losh 		bus_topo_unlock();
98847575345SSepherosa Ziehau 		device_printf(parent, "device_add_child for chan%u failed\n",
98947575345SSepherosa Ziehau 		    chan->ch_id);
9909f06037bSSepherosa Ziehau 		return (ENXIO);
991b7bb4816SSepherosa Ziehau 	}
9923b50b13bSSepherosa Ziehau 	device_set_ivars(chan->ch_dev, chan);
9939f06037bSSepherosa Ziehau 	device_probe_and_attach(chan->ch_dev);
994f581847aSWarner Losh 	bus_topo_unlock();
995b7bb4816SSepherosa Ziehau 
9969f06037bSSepherosa Ziehau 	return (0);
997b7bb4816SSepherosa Ziehau }
998b7bb4816SSepherosa Ziehau 
999b7bb4816SSepherosa Ziehau int
100082b8a879SSepherosa Ziehau vmbus_delete_child(struct vmbus_channel *chan)
1001b7bb4816SSepherosa Ziehau {
10029f06037bSSepherosa Ziehau 	int error = 0;
100347575345SSepherosa Ziehau 
1004f581847aSWarner Losh 	bus_topo_lock();
10059f06037bSSepherosa Ziehau 	if (chan->ch_dev != NULL) {
10069f06037bSSepherosa Ziehau 		error = device_delete_child(chan->ch_vmbus->vmbus_dev,
10079f06037bSSepherosa Ziehau 		    chan->ch_dev);
1008afe30aa9SSepherosa Ziehau 		chan->ch_dev = NULL;
10099f06037bSSepherosa Ziehau 	}
1010f581847aSWarner Losh 	bus_topo_unlock();
10119f06037bSSepherosa Ziehau 	return (error);
1012b7bb4816SSepherosa Ziehau }
1013b7bb4816SSepherosa Ziehau 
1014b7bb4816SSepherosa Ziehau static int
101547a3ee5cSSepherosa Ziehau vmbus_sysctl_version(SYSCTL_HANDLER_ARGS)
101647a3ee5cSSepherosa Ziehau {
101738d19df6SSepherosa Ziehau 	struct vmbus_softc *sc = arg1;
101847a3ee5cSSepherosa Ziehau 	char verstr[16];
101947a3ee5cSSepherosa Ziehau 
102047a3ee5cSSepherosa Ziehau 	snprintf(verstr, sizeof(verstr), "%u.%u",
102138d19df6SSepherosa Ziehau 	    VMBUS_VERSION_MAJOR(sc->vmbus_version),
102238d19df6SSepherosa Ziehau 	    VMBUS_VERSION_MINOR(sc->vmbus_version));
102347a3ee5cSSepherosa Ziehau 	return sysctl_handle_string(oidp, verstr, sizeof(verstr), req);
102447a3ee5cSSepherosa Ziehau }
102547a3ee5cSSepherosa Ziehau 
1026522c192dSDexuan Cui /*
1027522c192dSDexuan Cui  * We need the function to make sure the MMIO resource is allocated from the
1028522c192dSDexuan Cui  * ranges found in _CRS.
1029522c192dSDexuan Cui  *
1030522c192dSDexuan Cui  * For the release function, we can use bus_generic_release_resource().
1031522c192dSDexuan Cui  */
1032522c192dSDexuan Cui static struct resource *
1033522c192dSDexuan Cui vmbus_alloc_resource(device_t dev, device_t child, int type, int *rid,
1034522c192dSDexuan Cui     rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
1035522c192dSDexuan Cui {
1036522c192dSDexuan Cui 	device_t parent = device_get_parent(dev);
1037522c192dSDexuan Cui 	struct resource *res;
1038522c192dSDexuan Cui 
1039cdb316eeSDexuan Cui #ifdef NEW_PCIB
1040cdb316eeSDexuan Cui 	if (type == SYS_RES_MEMORY) {
1041cdb316eeSDexuan Cui 		struct vmbus_softc *sc = device_get_softc(dev);
1042cdb316eeSDexuan Cui 
1043522c192dSDexuan Cui 		res = pcib_host_res_alloc(&sc->vmbus_mmio_res, child, type,
1044522c192dSDexuan Cui 		    rid, start, end, count, flags);
1045cdb316eeSDexuan Cui 	} else
1046cdb316eeSDexuan Cui #endif
1047cdb316eeSDexuan Cui 	{
1048cdb316eeSDexuan Cui 		res = BUS_ALLOC_RESOURCE(parent, child, type, rid, start,
1049cdb316eeSDexuan Cui 		    end, count, flags);
1050cdb316eeSDexuan Cui 	}
1051522c192dSDexuan Cui 
1052522c192dSDexuan Cui 	return (res);
1053522c192dSDexuan Cui }
1054522c192dSDexuan Cui 
1055522c192dSDexuan Cui static int
1056522c192dSDexuan Cui vmbus_alloc_msi(device_t bus, device_t dev, int count, int maxcount, int *irqs)
1057522c192dSDexuan Cui {
1058554e6778SSepherosa Ziehau 
1059554e6778SSepherosa Ziehau 	return (PCIB_ALLOC_MSI(device_get_parent(bus), dev, count, maxcount,
1060554e6778SSepherosa Ziehau 	    irqs));
1061522c192dSDexuan Cui }
1062522c192dSDexuan Cui 
1063522c192dSDexuan Cui static int
1064522c192dSDexuan Cui vmbus_release_msi(device_t bus, device_t dev, int count, int *irqs)
1065522c192dSDexuan Cui {
1066554e6778SSepherosa Ziehau 
1067554e6778SSepherosa Ziehau 	return (PCIB_RELEASE_MSI(device_get_parent(bus), dev, count, irqs));
1068522c192dSDexuan Cui }
1069522c192dSDexuan Cui 
1070522c192dSDexuan Cui static int
1071522c192dSDexuan Cui vmbus_alloc_msix(device_t bus, device_t dev, int *irq)
1072522c192dSDexuan Cui {
1073554e6778SSepherosa Ziehau 
1074554e6778SSepherosa Ziehau 	return (PCIB_ALLOC_MSIX(device_get_parent(bus), dev, irq));
1075522c192dSDexuan Cui }
1076522c192dSDexuan Cui 
1077522c192dSDexuan Cui static int
1078522c192dSDexuan Cui vmbus_release_msix(device_t bus, device_t dev, int irq)
1079522c192dSDexuan Cui {
1080554e6778SSepherosa Ziehau 
1081554e6778SSepherosa Ziehau 	return (PCIB_RELEASE_MSIX(device_get_parent(bus), dev, irq));
1082522c192dSDexuan Cui }
1083522c192dSDexuan Cui 
1084522c192dSDexuan Cui static int
1085522c192dSDexuan Cui vmbus_map_msi(device_t bus, device_t dev, int irq, uint64_t *addr,
1086522c192dSDexuan Cui 	uint32_t *data)
1087522c192dSDexuan Cui {
1088554e6778SSepherosa Ziehau 
1089554e6778SSepherosa Ziehau 	return (PCIB_MAP_MSI(device_get_parent(bus), dev, irq, addr, data));
1090522c192dSDexuan Cui }
1091522c192dSDexuan Cui 
109238d19df6SSepherosa Ziehau static uint32_t
109338d19df6SSepherosa Ziehau vmbus_get_version_method(device_t bus, device_t dev)
109438d19df6SSepherosa Ziehau {
109538d19df6SSepherosa Ziehau 	struct vmbus_softc *sc = device_get_softc(bus);
109638d19df6SSepherosa Ziehau 
109738d19df6SSepherosa Ziehau 	return sc->vmbus_version;
109838d19df6SSepherosa Ziehau }
109938d19df6SSepherosa Ziehau 
110047a3ee5cSSepherosa Ziehau static int
110171ac1309SSepherosa Ziehau vmbus_probe_guid_method(device_t bus, device_t dev,
110271ac1309SSepherosa Ziehau     const struct hyperv_guid *guid)
1103884d26c8SSepherosa Ziehau {
110482b8a879SSepherosa Ziehau 	const struct vmbus_channel *chan = vmbus_get_channel(dev);
1105884d26c8SSepherosa Ziehau 
110671ac1309SSepherosa Ziehau 	if (memcmp(&chan->ch_guid_type, guid, sizeof(struct hyperv_guid)) == 0)
1107884d26c8SSepherosa Ziehau 		return 0;
1108884d26c8SSepherosa Ziehau 	return ENXIO;
1109884d26c8SSepherosa Ziehau }
1110884d26c8SSepherosa Ziehau 
1111c8b32f71SDexuan Cui static uint32_t
1112c8b32f71SDexuan Cui vmbus_get_vcpu_id_method(device_t bus, device_t dev, int cpu)
1113c8b32f71SDexuan Cui {
1114c8b32f71SDexuan Cui 	const struct vmbus_softc *sc = device_get_softc(bus);
1115c8b32f71SDexuan Cui 
1116c8b32f71SDexuan Cui 	return (VMBUS_PCPU_GET(sc, vcpuid, cpu));
1117c8b32f71SDexuan Cui }
1118c8b32f71SDexuan Cui 
1119b5c7e241SSepherosa Ziehau static struct taskqueue *
1120b5c7e241SSepherosa Ziehau vmbus_get_eventtq_method(device_t bus, device_t dev __unused, int cpu)
1121b5c7e241SSepherosa Ziehau {
1122b5c7e241SSepherosa Ziehau 	const struct vmbus_softc *sc = device_get_softc(bus);
1123b5c7e241SSepherosa Ziehau 
1124b5c7e241SSepherosa Ziehau 	KASSERT(cpu >= 0 && cpu < mp_ncpus, ("invalid cpu%d", cpu));
1125b5c7e241SSepherosa Ziehau 	return (VMBUS_PCPU_GET(sc, event_tq, cpu));
1126b5c7e241SSepherosa Ziehau }
1127b5c7e241SSepherosa Ziehau 
1128cdb316eeSDexuan Cui #ifdef NEW_PCIB
1129522c192dSDexuan Cui #define VTPM_BASE_ADDR 0xfed40000
1130522c192dSDexuan Cui #define FOUR_GB (1ULL << 32)
1131522c192dSDexuan Cui 
1132522c192dSDexuan Cui enum parse_pass { parse_64, parse_32 };
1133522c192dSDexuan Cui 
1134522c192dSDexuan Cui struct parse_context {
1135522c192dSDexuan Cui 	device_t vmbus_dev;
1136522c192dSDexuan Cui 	enum parse_pass pass;
1137522c192dSDexuan Cui };
1138522c192dSDexuan Cui 
1139522c192dSDexuan Cui static ACPI_STATUS
1140522c192dSDexuan Cui parse_crs(ACPI_RESOURCE *res, void *ctx)
1141522c192dSDexuan Cui {
1142522c192dSDexuan Cui 	const struct parse_context *pc = ctx;
1143522c192dSDexuan Cui 	device_t vmbus_dev = pc->vmbus_dev;
1144522c192dSDexuan Cui 
1145522c192dSDexuan Cui 	struct vmbus_softc *sc = device_get_softc(vmbus_dev);
1146522c192dSDexuan Cui 	UINT64 start, end;
1147522c192dSDexuan Cui 
1148522c192dSDexuan Cui 	switch (res->Type) {
1149522c192dSDexuan Cui 	case ACPI_RESOURCE_TYPE_ADDRESS32:
1150522c192dSDexuan Cui 		start = res->Data.Address32.Address.Minimum;
1151522c192dSDexuan Cui 		end = res->Data.Address32.Address.Maximum;
1152522c192dSDexuan Cui 		break;
1153522c192dSDexuan Cui 
1154522c192dSDexuan Cui 	case ACPI_RESOURCE_TYPE_ADDRESS64:
1155522c192dSDexuan Cui 		start = res->Data.Address64.Address.Minimum;
1156522c192dSDexuan Cui 		end = res->Data.Address64.Address.Maximum;
1157522c192dSDexuan Cui 		break;
1158522c192dSDexuan Cui 
1159522c192dSDexuan Cui 	default:
1160522c192dSDexuan Cui 		/* Unused types. */
1161522c192dSDexuan Cui 		return (AE_OK);
1162522c192dSDexuan Cui 	}
1163522c192dSDexuan Cui 
1164522c192dSDexuan Cui 	/*
1165522c192dSDexuan Cui 	 * We don't use <1MB addresses.
1166522c192dSDexuan Cui 	 */
1167522c192dSDexuan Cui 	if (end < 0x100000)
1168522c192dSDexuan Cui 		return (AE_OK);
1169522c192dSDexuan Cui 
1170522c192dSDexuan Cui 	/* Don't conflict with vTPM. */
1171522c192dSDexuan Cui 	if (end >= VTPM_BASE_ADDR && start < VTPM_BASE_ADDR)
1172522c192dSDexuan Cui 		end = VTPM_BASE_ADDR - 1;
1173522c192dSDexuan Cui 
1174522c192dSDexuan Cui 	if ((pc->pass == parse_32 && start < FOUR_GB) ||
1175522c192dSDexuan Cui 	    (pc->pass == parse_64 && start >= FOUR_GB))
1176522c192dSDexuan Cui 		pcib_host_res_decodes(&sc->vmbus_mmio_res, SYS_RES_MEMORY,
1177522c192dSDexuan Cui 		    start, end, 0);
1178522c192dSDexuan Cui 
1179522c192dSDexuan Cui 	return (AE_OK);
1180522c192dSDexuan Cui }
1181522c192dSDexuan Cui 
1182522c192dSDexuan Cui static void
1183522c192dSDexuan Cui vmbus_get_crs(device_t dev, device_t vmbus_dev, enum parse_pass pass)
1184522c192dSDexuan Cui {
1185522c192dSDexuan Cui 	struct parse_context pc;
1186522c192dSDexuan Cui 	ACPI_STATUS status;
1187522c192dSDexuan Cui 
1188522c192dSDexuan Cui 	if (bootverbose)
1189522c192dSDexuan Cui 		device_printf(dev, "walking _CRS, pass=%d\n", pass);
1190522c192dSDexuan Cui 
1191522c192dSDexuan Cui 	pc.vmbus_dev = vmbus_dev;
1192522c192dSDexuan Cui 	pc.pass = pass;
1193522c192dSDexuan Cui 	status = AcpiWalkResources(acpi_get_handle(dev), "_CRS",
1194522c192dSDexuan Cui 			parse_crs, &pc);
1195522c192dSDexuan Cui 
1196522c192dSDexuan Cui 	if (bootverbose && ACPI_FAILURE(status))
1197522c192dSDexuan Cui 		device_printf(dev, "_CRS: not found, pass=%d\n", pass);
1198522c192dSDexuan Cui }
1199522c192dSDexuan Cui 
1200522c192dSDexuan Cui static void
1201522c192dSDexuan Cui vmbus_get_mmio_res_pass(device_t dev, enum parse_pass pass)
1202522c192dSDexuan Cui {
1203554e6778SSepherosa Ziehau 	device_t acpi0, parent;
1204554e6778SSepherosa Ziehau 
1205554e6778SSepherosa Ziehau 	parent = device_get_parent(dev);
1206554e6778SSepherosa Ziehau 
1207554e6778SSepherosa Ziehau 	acpi0 = device_get_parent(parent);
1208554e6778SSepherosa Ziehau 	if (strcmp("acpi0", device_get_nameunit(acpi0)) == 0) {
1209522c192dSDexuan Cui 		device_t *children;
1210554e6778SSepherosa Ziehau 		int count;
1211522c192dSDexuan Cui 
1212554e6778SSepherosa Ziehau 		/*
1213554e6778SSepherosa Ziehau 		 * Try to locate VMBUS resources and find _CRS on them.
1214554e6778SSepherosa Ziehau 		 */
1215554e6778SSepherosa Ziehau 		if (device_get_children(acpi0, &children, &count) == 0) {
1216554e6778SSepherosa Ziehau 			int i;
1217522c192dSDexuan Cui 
1218554e6778SSepherosa Ziehau 			for (i = 0; i < count; ++i) {
1219522c192dSDexuan Cui 				if (!device_is_attached(children[i]))
1220522c192dSDexuan Cui 					continue;
1221522c192dSDexuan Cui 
1222554e6778SSepherosa Ziehau 				if (strcmp("vmbus_res",
1223554e6778SSepherosa Ziehau 				    device_get_name(children[i])) == 0)
1224554e6778SSepherosa Ziehau 					vmbus_get_crs(children[i], dev, pass);
1225554e6778SSepherosa Ziehau 			}
1226554e6778SSepherosa Ziehau 			free(children, M_TEMP);
1227522c192dSDexuan Cui 		}
1228522c192dSDexuan Cui 
1229554e6778SSepherosa Ziehau 		/*
1230554e6778SSepherosa Ziehau 		 * Try to find _CRS on acpi.
1231554e6778SSepherosa Ziehau 		 */
1232554e6778SSepherosa Ziehau 		vmbus_get_crs(acpi0, dev, pass);
1233554e6778SSepherosa Ziehau 	} else {
1234554e6778SSepherosa Ziehau 		device_printf(dev, "not grandchild of acpi\n");
1235554e6778SSepherosa Ziehau 	}
1236522c192dSDexuan Cui 
1237554e6778SSepherosa Ziehau 	/*
1238554e6778SSepherosa Ziehau 	 * Try to find _CRS on parent.
1239554e6778SSepherosa Ziehau 	 */
1240554e6778SSepherosa Ziehau 	vmbus_get_crs(parent, dev, pass);
1241522c192dSDexuan Cui }
1242522c192dSDexuan Cui 
1243522c192dSDexuan Cui static void
1244522c192dSDexuan Cui vmbus_get_mmio_res(device_t dev)
1245522c192dSDexuan Cui {
1246522c192dSDexuan Cui 	struct vmbus_softc *sc = device_get_softc(dev);
1247522c192dSDexuan Cui 	/*
1248522c192dSDexuan Cui 	 * We walk the resources twice to make sure that: in the resource
1249522c192dSDexuan Cui 	 * list, the 32-bit resources appear behind the 64-bit resources.
1250522c192dSDexuan Cui 	 * NB: resource_list_add() uses INSERT_TAIL. This way, when we
1251522c192dSDexuan Cui 	 * iterate through the list to find a range for a 64-bit BAR in
1252522c192dSDexuan Cui 	 * vmbus_alloc_resource(), we can make sure we try to use >4GB
1253522c192dSDexuan Cui 	 * ranges first.
1254522c192dSDexuan Cui 	 */
1255522c192dSDexuan Cui 	pcib_host_res_init(dev, &sc->vmbus_mmio_res);
1256522c192dSDexuan Cui 
1257522c192dSDexuan Cui 	vmbus_get_mmio_res_pass(dev, parse_64);
1258522c192dSDexuan Cui 	vmbus_get_mmio_res_pass(dev, parse_32);
1259522c192dSDexuan Cui }
1260522c192dSDexuan Cui 
1261c5657761SWei Hu /*
1262c5657761SWei Hu  * On Gen2 VMs, Hyper-V provides mmio space for framebuffer.
1263c5657761SWei Hu  * This mmio address range is not useable for other PCI devices.
1264a4a10b37SToomas Soome  * Currently only efifb and vbefb drivers are using this range without
1265a4a10b37SToomas Soome  * reserving it from system.
1266c5657761SWei Hu  * Therefore, vmbus driver reserves it before any other PCI device
1267c5657761SWei Hu  * drivers start to request mmio addresses.
1268c5657761SWei Hu  */
1269c5657761SWei Hu static struct resource *hv_fb_res;
1270c5657761SWei Hu 
1271c5657761SWei Hu static void
1272c5657761SWei Hu vmbus_fb_mmio_res(device_t dev)
1273c5657761SWei Hu {
1274c5657761SWei Hu 	struct efi_fb *efifb;
12759729f076SSouradeep Chakrabarti #if !defined(__aarch64__)
1276a4a10b37SToomas Soome 	struct vbe_fb *vbefb;
12779729f076SSouradeep Chakrabarti #endif /* aarch64 */
1278a4a10b37SToomas Soome 	rman_res_t fb_start, fb_end, fb_count;
1279a4a10b37SToomas Soome 	int fb_height, fb_width;
1280c5657761SWei Hu 	caddr_t kmdp;
1281c5657761SWei Hu 
1282c5657761SWei Hu 	struct vmbus_softc *sc = device_get_softc(dev);
1283c5657761SWei Hu 	int rid = 0;
1284c5657761SWei Hu 
1285c5657761SWei Hu 	kmdp = preload_search_by_type("elf kernel");
1286c5657761SWei Hu 	if (kmdp == NULL)
1287c5657761SWei Hu 		kmdp = preload_search_by_type("elf64 kernel");
1288c5657761SWei Hu 	efifb = (struct efi_fb *)preload_search_info(kmdp,
1289c5657761SWei Hu 	    MODINFO_METADATA | MODINFOMD_EFI_FB);
12909729f076SSouradeep Chakrabarti #if !defined(__aarch64__)
1291a4a10b37SToomas Soome 	vbefb = (struct vbe_fb *)preload_search_info(kmdp,
1292a4a10b37SToomas Soome 	    MODINFO_METADATA | MODINFOMD_VBE_FB);
12939729f076SSouradeep Chakrabarti #endif /* aarch64 */
1294c05b5848SBradley T. Hughes 	if (efifb != NULL) {
1295c05b5848SBradley T. Hughes 		fb_start = efifb->fb_addr;
1296c05b5848SBradley T. Hughes 		fb_end = efifb->fb_addr + efifb->fb_size;
1297c05b5848SBradley T. Hughes 		fb_count = efifb->fb_size;
1298c05b5848SBradley T. Hughes 		fb_height = efifb->fb_height;
1299c05b5848SBradley T. Hughes 		fb_width = efifb->fb_width;
13009729f076SSouradeep Chakrabarti 	}
13019729f076SSouradeep Chakrabarti #if !defined(__aarch64__)
13029729f076SSouradeep Chakrabarti 	else if (vbefb != NULL) {
1303a4a10b37SToomas Soome 		fb_start = vbefb->fb_addr;
1304a4a10b37SToomas Soome 		fb_end = vbefb->fb_addr + vbefb->fb_size;
1305a4a10b37SToomas Soome 		fb_count = vbefb->fb_size;
1306cb794182SToomas Soome 		fb_height = vbefb->fb_height;
1307cb794182SToomas Soome 		fb_width = vbefb->fb_width;
13089729f076SSouradeep Chakrabarti 	}
13099729f076SSouradeep Chakrabarti #endif /* aarch64 */
13109729f076SSouradeep Chakrabarti 	else {
1311c5657761SWei Hu 		if (bootverbose)
1312c5657761SWei Hu 			device_printf(dev,
1313a4a10b37SToomas Soome 			    "no preloaded kernel fb information\n");
1314c5657761SWei Hu 		/* We are on Gen1 VM, just return. */
1315c5657761SWei Hu 		return;
1316c05b5848SBradley T. Hughes 	}
1317c05b5848SBradley T. Hughes 
1318c5657761SWei Hu 	if (bootverbose)
1319c5657761SWei Hu 		device_printf(dev,
1320a4a10b37SToomas Soome 		    "fb: fb_addr: %#jx, size: %#jx, "
1321c5657761SWei Hu 		    "actual size needed: 0x%x\n",
1322a4a10b37SToomas Soome 		    fb_start, fb_count, fb_height * fb_width);
1323c5657761SWei Hu 
1324c5657761SWei Hu 	hv_fb_res = pcib_host_res_alloc(&sc->vmbus_mmio_res, dev,
1325a4a10b37SToomas Soome 	    SYS_RES_MEMORY, &rid, fb_start, fb_end, fb_count,
1326c5657761SWei Hu 	    RF_ACTIVE | rman_make_alignment_flags(PAGE_SIZE));
1327c5657761SWei Hu 
1328c5657761SWei Hu 	if (hv_fb_res && bootverbose)
1329c5657761SWei Hu 		device_printf(dev,
1330c5657761SWei Hu 		    "successfully reserved memory for framebuffer "
1331c5657761SWei Hu 		    "starting at %#jx, size %#jx\n",
1332a4a10b37SToomas Soome 		    fb_start, fb_count);
1333c5657761SWei Hu }
1334c5657761SWei Hu 
1335522c192dSDexuan Cui static void
1336522c192dSDexuan Cui vmbus_free_mmio_res(device_t dev)
1337522c192dSDexuan Cui {
1338522c192dSDexuan Cui 	struct vmbus_softc *sc = device_get_softc(dev);
1339522c192dSDexuan Cui 
1340522c192dSDexuan Cui 	pcib_host_res_free(dev, &sc->vmbus_mmio_res);
1341c5657761SWei Hu 
1342c5657761SWei Hu 	if (hv_fb_res)
1343c5657761SWei Hu 		hv_fb_res = NULL;
1344522c192dSDexuan Cui }
1345cdb316eeSDexuan Cui #endif	/* NEW_PCIB */
1346522c192dSDexuan Cui 
1347554e6778SSepherosa Ziehau static void
1348554e6778SSepherosa Ziehau vmbus_identify(driver_t *driver, device_t parent)
1349554e6778SSepherosa Ziehau {
1350554e6778SSepherosa Ziehau 
1351554e6778SSepherosa Ziehau 	if (device_get_unit(parent) != 0 || vm_guest != VM_GUEST_HV ||
1352554e6778SSepherosa Ziehau 	    (hyperv_features & CPUID_HV_MSR_SYNIC) == 0)
1353554e6778SSepherosa Ziehau 		return;
1354554e6778SSepherosa Ziehau 	device_add_child(parent, "vmbus", -1);
1355554e6778SSepherosa Ziehau }
1356554e6778SSepherosa Ziehau 
1357884d26c8SSepherosa Ziehau static int
1358b7bb4816SSepherosa Ziehau vmbus_probe(device_t dev)
1359b7bb4816SSepherosa Ziehau {
1360b7bb4816SSepherosa Ziehau 
1361554e6778SSepherosa Ziehau 	if (device_get_unit(dev) != 0 || vm_guest != VM_GUEST_HV ||
1362b7bb4816SSepherosa Ziehau 	    (hyperv_features & CPUID_HV_MSR_SYNIC) == 0)
1363b7bb4816SSepherosa Ziehau 		return (ENXIO);
1364b7bb4816SSepherosa Ziehau 
1365b7bb4816SSepherosa Ziehau 	device_set_desc(dev, "Hyper-V Vmbus");
1366b7bb4816SSepherosa Ziehau 	return (BUS_PROBE_DEFAULT);
1367b7bb4816SSepherosa Ziehau }
1368b7bb4816SSepherosa Ziehau 
1369b7bb4816SSepherosa Ziehau /**
1370b7bb4816SSepherosa Ziehau  * @brief Main vmbus driver initialization routine.
1371b7bb4816SSepherosa Ziehau  *
1372b7bb4816SSepherosa Ziehau  * Here, we
1373b7bb4816SSepherosa Ziehau  * - initialize the vmbus driver context
1374b7bb4816SSepherosa Ziehau  * - setup various driver entry points
1375b7bb4816SSepherosa Ziehau  * - invoke the vmbus hv main init routine
1376b7bb4816SSepherosa Ziehau  * - get the irq resource
1377b7bb4816SSepherosa Ziehau  * - invoke the vmbus to add the vmbus root device
1378b7bb4816SSepherosa Ziehau  * - setup the vmbus root device
1379b7bb4816SSepherosa Ziehau  * - retrieve the channel offers
1380b7bb4816SSepherosa Ziehau  */
1381b7bb4816SSepherosa Ziehau static int
1382dd012a57SSepherosa Ziehau vmbus_doattach(struct vmbus_softc *sc)
1383b7bb4816SSepherosa Ziehau {
138447a3ee5cSSepherosa Ziehau 	struct sysctl_oid_list *child;
138547a3ee5cSSepherosa Ziehau 	struct sysctl_ctx_list *ctx;
1386b7bb4816SSepherosa Ziehau 	int ret;
1387b7bb4816SSepherosa Ziehau 
1388b7bb4816SSepherosa Ziehau 	if (sc->vmbus_flags & VMBUS_FLAG_ATTACHED)
1389b7bb4816SSepherosa Ziehau 		return (0);
1390522c192dSDexuan Cui 
1391cdb316eeSDexuan Cui #ifdef NEW_PCIB
1392522c192dSDexuan Cui 	vmbus_get_mmio_res(sc->vmbus_dev);
1393c5657761SWei Hu 	vmbus_fb_mmio_res(sc->vmbus_dev);
1394cdb316eeSDexuan Cui #endif
1395522c192dSDexuan Cui 
1396b7bb4816SSepherosa Ziehau 	sc->vmbus_flags |= VMBUS_FLAG_ATTACHED;
1397b7bb4816SSepherosa Ziehau 
1398ee7e313fSSepherosa Ziehau 	sc->vmbus_gpadl = VMBUS_GPADL_START;
1399c1bea00eSSepherosa Ziehau 	mtx_init(&sc->vmbus_prichan_lock, "vmbus prichan", NULL, MTX_DEF);
1400c1bea00eSSepherosa Ziehau 	TAILQ_INIT(&sc->vmbus_prichans);
14019f06037bSSepherosa Ziehau 	mtx_init(&sc->vmbus_chan_lock, "vmbus channel", NULL, MTX_DEF);
14029f06037bSSepherosa Ziehau 	TAILQ_INIT(&sc->vmbus_chans);
1403af3be0bfSSepherosa Ziehau 	sc->vmbus_chmap = malloc(
140482b8a879SSepherosa Ziehau 	    sizeof(struct vmbus_channel *) * VMBUS_CHAN_MAX, M_DEVBUF,
1405af3be0bfSSepherosa Ziehau 	    M_WAITOK | M_ZERO);
1406796a90bfSSepherosa Ziehau 
1407b7bb4816SSepherosa Ziehau 	/*
1408236764b1SSepherosa Ziehau 	 * Create context for "post message" Hypercalls
1409236764b1SSepherosa Ziehau 	 */
14103dba61ddSSepherosa Ziehau 	sc->vmbus_xc = vmbus_xact_ctx_create(bus_get_dma_tag(sc->vmbus_dev),
14113dba61ddSSepherosa Ziehau 	    HYPERCALL_POSTMSGIN_SIZE, VMBUS_MSG_SIZE,
14123dba61ddSSepherosa Ziehau 	    sizeof(struct vmbus_msghc));
14133dba61ddSSepherosa Ziehau 	if (sc->vmbus_xc == NULL) {
1414236764b1SSepherosa Ziehau 		ret = ENXIO;
1415236764b1SSepherosa Ziehau 		goto cleanup;
1416236764b1SSepherosa Ziehau 	}
1417236764b1SSepherosa Ziehau 
1418236764b1SSepherosa Ziehau 	/*
1419b7bb4816SSepherosa Ziehau 	 * Allocate DMA stuffs.
1420b7bb4816SSepherosa Ziehau 	 */
1421b7bb4816SSepherosa Ziehau 	ret = vmbus_dma_alloc(sc);
1422b7bb4816SSepherosa Ziehau 	if (ret != 0)
1423b7bb4816SSepherosa Ziehau 		goto cleanup;
1424b7bb4816SSepherosa Ziehau 
1425b7bb4816SSepherosa Ziehau 	/*
1426b7bb4816SSepherosa Ziehau 	 * Setup interrupt.
1427b7bb4816SSepherosa Ziehau 	 */
1428b7bb4816SSepherosa Ziehau 	ret = vmbus_intr_setup(sc);
1429b7bb4816SSepherosa Ziehau 	if (ret != 0)
1430b7bb4816SSepherosa Ziehau 		goto cleanup;
1431b7bb4816SSepherosa Ziehau 
1432b7bb4816SSepherosa Ziehau 	/*
1433b7bb4816SSepherosa Ziehau 	 * Setup SynIC.
1434b7bb4816SSepherosa Ziehau 	 */
1435b7bb4816SSepherosa Ziehau 	if (bootverbose)
1436b7bb4816SSepherosa Ziehau 		device_printf(sc->vmbus_dev, "smp_started = %d\n", smp_started);
1437b7bb4816SSepherosa Ziehau 	smp_rendezvous(NULL, vmbus_synic_setup, NULL, sc);
1438b7bb4816SSepherosa Ziehau 	sc->vmbus_flags |= VMBUS_FLAG_SYNIC;
1439b7bb4816SSepherosa Ziehau 
1440b7bb4816SSepherosa Ziehau 	/*
1441250ca4caSSepherosa Ziehau 	 * Initialize vmbus, e.g. connect to Hypervisor.
1442b7bb4816SSepherosa Ziehau 	 */
1443236764b1SSepherosa Ziehau 	ret = vmbus_init(sc);
1444236764b1SSepherosa Ziehau 	if (ret != 0)
1445236764b1SSepherosa Ziehau 		goto cleanup;
1446236764b1SSepherosa Ziehau 
144738d19df6SSepherosa Ziehau 	if (sc->vmbus_version == VMBUS_VERSION_WS2008 ||
144838d19df6SSepherosa Ziehau 	    sc->vmbus_version == VMBUS_VERSION_WIN7)
1449b7bb4816SSepherosa Ziehau 		sc->vmbus_event_proc = vmbus_event_proc_compat;
1450b7bb4816SSepherosa Ziehau 	else
1451b7bb4816SSepherosa Ziehau 		sc->vmbus_event_proc = vmbus_event_proc;
1452b7bb4816SSepherosa Ziehau 
1453796a90bfSSepherosa Ziehau 	ret = vmbus_scan(sc);
1454c1cc5bdfSSepherosa Ziehau 	if (ret != 0)
1455c1cc5bdfSSepherosa Ziehau 		goto cleanup;
1456b7bb4816SSepherosa Ziehau 
145747a3ee5cSSepherosa Ziehau 	ctx = device_get_sysctl_ctx(sc->vmbus_dev);
145847a3ee5cSSepherosa Ziehau 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->vmbus_dev));
145947a3ee5cSSepherosa Ziehau 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "version",
146038d19df6SSepherosa Ziehau 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
146147a3ee5cSSepherosa Ziehau 	    vmbus_sysctl_version, "A", "vmbus version");
146247a3ee5cSSepherosa Ziehau 
1463b7bb4816SSepherosa Ziehau 	return (ret);
1464b7bb4816SSepherosa Ziehau 
1465b7bb4816SSepherosa Ziehau cleanup:
14669f06037bSSepherosa Ziehau 	vmbus_scan_teardown(sc);
1467b7bb4816SSepherosa Ziehau 	vmbus_intr_teardown(sc);
1468b7bb4816SSepherosa Ziehau 	vmbus_dma_free(sc);
14693dba61ddSSepherosa Ziehau 	if (sc->vmbus_xc != NULL) {
14703dba61ddSSepherosa Ziehau 		vmbus_xact_ctx_destroy(sc->vmbus_xc);
14713dba61ddSSepherosa Ziehau 		sc->vmbus_xc = NULL;
1472236764b1SSepherosa Ziehau 	}
147369d2eb82SSepherosa Ziehau 	free(__DEVOLATILE(void *, sc->vmbus_chmap), M_DEVBUF);
1474c1bea00eSSepherosa Ziehau 	mtx_destroy(&sc->vmbus_prichan_lock);
14759f06037bSSepherosa Ziehau 	mtx_destroy(&sc->vmbus_chan_lock);
1476b7bb4816SSepherosa Ziehau 
1477b7bb4816SSepherosa Ziehau 	return (ret);
1478b7bb4816SSepherosa Ziehau }
1479b7bb4816SSepherosa Ziehau 
1480b7bb4816SSepherosa Ziehau static void
1481b7bb4816SSepherosa Ziehau vmbus_event_proc_dummy(struct vmbus_softc *sc __unused, int cpu __unused)
1482b7bb4816SSepherosa Ziehau {
1483b7bb4816SSepherosa Ziehau }
1484b7bb4816SSepherosa Ziehau 
14859729f076SSouradeep Chakrabarti #if defined(EARLY_AP_STARTUP) || defined(__aarch64__)
1486be53a2faSSepherosa Ziehau 
1487be53a2faSSepherosa Ziehau static void
1488be53a2faSSepherosa Ziehau vmbus_intrhook(void *xsc)
1489be53a2faSSepherosa Ziehau {
1490be53a2faSSepherosa Ziehau 	struct vmbus_softc *sc = xsc;
1491be53a2faSSepherosa Ziehau 
1492be53a2faSSepherosa Ziehau 	if (bootverbose)
1493be53a2faSSepherosa Ziehau 		device_printf(sc->vmbus_dev, "intrhook\n");
1494be53a2faSSepherosa Ziehau 	vmbus_doattach(sc);
1495be53a2faSSepherosa Ziehau 	config_intrhook_disestablish(&sc->vmbus_intrhook);
1496be53a2faSSepherosa Ziehau }
1497be53a2faSSepherosa Ziehau 
14989729f076SSouradeep Chakrabarti #endif /* EARLY_AP_STARTUP  aarch64 */
1499be53a2faSSepherosa Ziehau 
1500b7bb4816SSepherosa Ziehau static int
1501b7bb4816SSepherosa Ziehau vmbus_attach(device_t dev)
1502b7bb4816SSepherosa Ziehau {
1503b7bb4816SSepherosa Ziehau 	vmbus_sc = device_get_softc(dev);
1504b7bb4816SSepherosa Ziehau 	vmbus_sc->vmbus_dev = dev;
1505b7bb4816SSepherosa Ziehau 	vmbus_sc->vmbus_idtvec = -1;
1506b7bb4816SSepherosa Ziehau 
1507b7bb4816SSepherosa Ziehau 	/*
1508b7bb4816SSepherosa Ziehau 	 * Event processing logic will be configured:
1509b7bb4816SSepherosa Ziehau 	 * - After the vmbus protocol version negotiation.
1510b7bb4816SSepherosa Ziehau 	 * - Before we request channel offers.
1511b7bb4816SSepherosa Ziehau 	 */
1512b7bb4816SSepherosa Ziehau 	vmbus_sc->vmbus_event_proc = vmbus_event_proc_dummy;
1513b7bb4816SSepherosa Ziehau 
15149729f076SSouradeep Chakrabarti #if defined(EARLY_AP_STARTUP) || defined(__aarch64__)
1515be53a2faSSepherosa Ziehau 	/*
1516be53a2faSSepherosa Ziehau 	 * Defer the real attach until the pause(9) works as expected.
1517be53a2faSSepherosa Ziehau 	 */
1518be53a2faSSepherosa Ziehau 	vmbus_sc->vmbus_intrhook.ich_func = vmbus_intrhook;
1519be53a2faSSepherosa Ziehau 	vmbus_sc->vmbus_intrhook.ich_arg = vmbus_sc;
1520be53a2faSSepherosa Ziehau 	config_intrhook_establish(&vmbus_sc->vmbus_intrhook);
1521be53a2faSSepherosa Ziehau #else	/* !EARLY_AP_STARTUP */
1522b7bb4816SSepherosa Ziehau 	/*
1523b7bb4816SSepherosa Ziehau 	 * If the system has already booted and thread
1524b7bb4816SSepherosa Ziehau 	 * scheduling is possible indicated by the global
1525b7bb4816SSepherosa Ziehau 	 * cold set to zero, we just call the driver
1526b7bb4816SSepherosa Ziehau 	 * initialization directly.
1527b7bb4816SSepherosa Ziehau 	 */
1528b7bb4816SSepherosa Ziehau 	if (!cold)
1529dd012a57SSepherosa Ziehau 		vmbus_doattach(vmbus_sc);
15309729f076SSouradeep Chakrabarti #endif /* EARLY_AP_STARTUP  and aarch64 */
1531b7bb4816SSepherosa Ziehau 
1532b7bb4816SSepherosa Ziehau 	return (0);
1533b7bb4816SSepherosa Ziehau }
1534b7bb4816SSepherosa Ziehau 
1535b7bb4816SSepherosa Ziehau static int
1536b7bb4816SSepherosa Ziehau vmbus_detach(device_t dev)
1537b7bb4816SSepherosa Ziehau {
1538b7bb4816SSepherosa Ziehau 	struct vmbus_softc *sc = device_get_softc(dev);
1539b7bb4816SSepherosa Ziehau 
15409f06037bSSepherosa Ziehau 	bus_generic_detach(dev);
154177321df6SSepherosa Ziehau 	vmbus_chan_destroy_all(sc);
15421ecb2466SSepherosa Ziehau 
15439f06037bSSepherosa Ziehau 	vmbus_scan_teardown(sc);
15449f06037bSSepherosa Ziehau 
1545f24517f0SSepherosa Ziehau 	vmbus_disconnect(sc);
1546b7bb4816SSepherosa Ziehau 
1547b7bb4816SSepherosa Ziehau 	if (sc->vmbus_flags & VMBUS_FLAG_SYNIC) {
1548b7bb4816SSepherosa Ziehau 		sc->vmbus_flags &= ~VMBUS_FLAG_SYNIC;
1549b7bb4816SSepherosa Ziehau 		smp_rendezvous(NULL, vmbus_synic_teardown, NULL, NULL);
1550b7bb4816SSepherosa Ziehau 	}
1551b7bb4816SSepherosa Ziehau 
1552b7bb4816SSepherosa Ziehau 	vmbus_intr_teardown(sc);
1553b7bb4816SSepherosa Ziehau 	vmbus_dma_free(sc);
1554b7bb4816SSepherosa Ziehau 
15553dba61ddSSepherosa Ziehau 	if (sc->vmbus_xc != NULL) {
15563dba61ddSSepherosa Ziehau 		vmbus_xact_ctx_destroy(sc->vmbus_xc);
15573dba61ddSSepherosa Ziehau 		sc->vmbus_xc = NULL;
1558236764b1SSepherosa Ziehau 	}
1559236764b1SSepherosa Ziehau 
156069d2eb82SSepherosa Ziehau 	free(__DEVOLATILE(void *, sc->vmbus_chmap), M_DEVBUF);
1561c1bea00eSSepherosa Ziehau 	mtx_destroy(&sc->vmbus_prichan_lock);
15629f06037bSSepherosa Ziehau 	mtx_destroy(&sc->vmbus_chan_lock);
1563283ec9dfSSepherosa Ziehau 
1564cdb316eeSDexuan Cui #ifdef NEW_PCIB
1565522c192dSDexuan Cui 	vmbus_free_mmio_res(dev);
1566cdb316eeSDexuan Cui #endif
1567522c192dSDexuan Cui 
15689729f076SSouradeep Chakrabarti #if defined(__aarch64__)
15699729f076SSouradeep Chakrabarti 	bus_release_resource(device_get_parent(dev), SYS_RES_IRQ, sc->vector,
15709729f076SSouradeep Chakrabarti 	    sc->ires);
15719729f076SSouradeep Chakrabarti #endif
1572b7bb4816SSepherosa Ziehau 	return (0);
1573b7bb4816SSepherosa Ziehau }
1574b7bb4816SSepherosa Ziehau 
15759729f076SSouradeep Chakrabarti #if !defined(EARLY_AP_STARTUP) && !defined(__aarch64__)
1576fd42dfc5SSepherosa Ziehau 
1577fd42dfc5SSepherosa Ziehau static void
1578fd42dfc5SSepherosa Ziehau vmbus_sysinit(void *arg __unused)
1579fd42dfc5SSepherosa Ziehau {
1580fd42dfc5SSepherosa Ziehau 	struct vmbus_softc *sc = vmbus_get_softc();
1581fd42dfc5SSepherosa Ziehau 
1582fd42dfc5SSepherosa Ziehau 	if (vm_guest != VM_GUEST_HV || sc == NULL)
1583fd42dfc5SSepherosa Ziehau 		return;
1584fd42dfc5SSepherosa Ziehau 
1585fd42dfc5SSepherosa Ziehau 	/*
1586fd42dfc5SSepherosa Ziehau 	 * If the system has already booted and thread
1587fd42dfc5SSepherosa Ziehau 	 * scheduling is possible, as indicated by the
1588fd42dfc5SSepherosa Ziehau 	 * global cold set to zero, we just call the driver
1589fd42dfc5SSepherosa Ziehau 	 * initialization directly.
1590fd42dfc5SSepherosa Ziehau 	 */
1591fd42dfc5SSepherosa Ziehau 	if (!cold)
1592fd42dfc5SSepherosa Ziehau 		vmbus_doattach(sc);
1593fd42dfc5SSepherosa Ziehau }
1594b7bb4816SSepherosa Ziehau /*
1595b7bb4816SSepherosa Ziehau  * NOTE:
1596b7bb4816SSepherosa Ziehau  * We have to start as the last step of SI_SUB_SMP, i.e. after SMP is
1597b7bb4816SSepherosa Ziehau  * initialized.
1598b7bb4816SSepherosa Ziehau  */
1599b7bb4816SSepherosa Ziehau SYSINIT(vmbus_initialize, SI_SUB_SMP, SI_ORDER_ANY, vmbus_sysinit, NULL);
1600fd42dfc5SSepherosa Ziehau #endif	/* !EARLY_AP_STARTUP */
1601