vmbus_ic.c revision 304730
1250199Sgrehan/*-
2298446Ssephe * Copyright (c) 2014,2016 Microsoft Corp.
3250199Sgrehan * All rights reserved.
4250199Sgrehan *
5250199Sgrehan * Redistribution and use in source and binary forms, with or without
6250199Sgrehan * modification, are permitted provided that the following conditions
7250199Sgrehan * are met:
8250199Sgrehan * 1. Redistributions of source code must retain the above copyright
9250199Sgrehan *    notice unmodified, this list of conditions, and the following
10250199Sgrehan *    disclaimer.
11250199Sgrehan * 2. Redistributions in binary form must reproduce the above copyright
12250199Sgrehan *    notice, this list of conditions and the following disclaimer in the
13250199Sgrehan *    documentation and/or other materials provided with the distribution.
14250199Sgrehan *
15250199Sgrehan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16250199Sgrehan * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17250199Sgrehan * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18250199Sgrehan * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19250199Sgrehan * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20250199Sgrehan * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21250199Sgrehan * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22250199Sgrehan * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23250199Sgrehan * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24250199Sgrehan * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25271493Sdelphij *
26271493Sdelphij * $FreeBSD: head/sys/dev/hyperv/utilities/hv_util.c 304730 2016-08-24 04:36:04Z sephe $
27250199Sgrehan */
28250199Sgrehan
29271493Sdelphij/*
30250199Sgrehan * A common driver for all hyper-V util services.
31250199Sgrehan */
32250199Sgrehan
33250199Sgrehan#include <sys/param.h>
34250199Sgrehan#include <sys/kernel.h>
35250199Sgrehan#include <sys/bus.h>
36250199Sgrehan#include <sys/malloc.h>
37250199Sgrehan#include <sys/module.h>
38250199Sgrehan#include <sys/reboot.h>
39304730Ssephe#include <sys/systm.h>
40250199Sgrehan#include <sys/timetc.h>
41250199Sgrehan
42250199Sgrehan#include <dev/hyperv/include/hyperv.h>
43303021Ssephe#include <dev/hyperv/include/vmbus.h>
44304273Ssephe#include <dev/hyperv/utilities/hv_util.h>
45304730Ssephe#include <dev/hyperv/utilities/vmbus_icreg.h>
46250199Sgrehan
47304273Ssephe#include "vmbus_if.h"
48304273Ssephe
49303823Ssephe#define VMBUS_IC_BRSIZE		(4 * PAGE_SIZE)
50303823Ssephe
51304730SsepheCTASSERT(sizeof(struct vmbus_icmsg_negotiate) < VMBUS_IC_BRSIZE);
52304730Ssephe
53304730Ssepheint
54304730Ssephevmbus_ic_negomsg(struct hv_util_sc *sc, void *data, int dlen)
55255414Sgrehan{
56304730Ssephe	struct vmbus_icmsg_negotiate *nego;
57304730Ssephe	int cnt, major;
58303822Ssephe
59304730Ssephe	/*
60304730Ssephe	 * Preliminary message size verification
61304730Ssephe	 */
62304730Ssephe	if (dlen < sizeof(*nego)) {
63304730Ssephe		device_printf(sc->ic_dev, "truncated ic negotiate, len %d\n",
64304730Ssephe		    dlen);
65304730Ssephe		return EINVAL;
66304730Ssephe	}
67304730Ssephe	nego = data;
68250199Sgrehan
69304730Ssephe	cnt = nego->ic_fwver_cnt + nego->ic_msgver_cnt;
70304730Ssephe	if (dlen < __offsetof(struct vmbus_icmsg_negotiate, ic_ver[cnt])) {
71304730Ssephe		device_printf(sc->ic_dev, "ic negotiate does not contain "
72304730Ssephe		    "versions %d\n", dlen);
73304730Ssephe		return EINVAL;
74250199Sgrehan	}
75250199Sgrehan
76304730Ssephe	/* Select major version; XXX looks wrong. */
77304730Ssephe	if (nego->ic_fwver_cnt >= 2 && VMBUS_ICVER_MAJOR(nego->ic_ver[1]) == 3)
78304730Ssephe		major = 3;
79304730Ssephe	else
80304730Ssephe		major = 1;
81304730Ssephe
82304730Ssephe	/* One framework version */
83304730Ssephe	nego->ic_fwver_cnt = 1;
84304730Ssephe	nego->ic_ver[0] = VMBUS_IC_VERSION(major, 0);
85304730Ssephe
86304730Ssephe	/* One message version */
87304730Ssephe	nego->ic_msgver_cnt = 1;
88304730Ssephe	nego->ic_ver[1] = VMBUS_IC_VERSION(major, 0);
89304730Ssephe
90304730Ssephe	/* Data contains two versions */
91304730Ssephe	nego->ic_hdr.ic_dsize = __offsetof(struct vmbus_icmsg_negotiate,
92304730Ssephe	    ic_ver[2]) - sizeof(struct vmbus_icmsg_hdr);
93304730Ssephe
94304730Ssephe	return 0;
95250199Sgrehan}
96250199Sgrehan
97295958Ssepheint
98304273Ssephevmbus_ic_probe(device_t dev, const struct vmbus_ic_desc descs[])
99304273Ssephe{
100304273Ssephe	device_t bus = device_get_parent(dev);
101304273Ssephe	const struct vmbus_ic_desc *d;
102304273Ssephe
103304273Ssephe	if (resource_disabled(device_get_name(dev), 0))
104304273Ssephe		return (ENXIO);
105304273Ssephe
106304273Ssephe	for (d = descs; d->ic_desc != NULL; ++d) {
107304273Ssephe		if (VMBUS_PROBE_GUID(bus, dev, &d->ic_guid) == 0) {
108304273Ssephe			device_set_desc(dev, d->ic_desc);
109304273Ssephe			return (BUS_PROBE_DEFAULT);
110304273Ssephe		}
111304273Ssephe	}
112304273Ssephe	return (ENXIO);
113304273Ssephe}
114304273Ssephe
115304273Ssepheint
116303824Ssephehv_util_attach(device_t dev, vmbus_chan_callback_t cb)
117250199Sgrehan{
118303823Ssephe	struct hv_util_sc *sc = device_get_softc(dev);
119303823Ssephe	struct vmbus_channel *chan = vmbus_get_channel(dev);
120303823Ssephe	int error;
121250199Sgrehan
122304730Ssephe	sc->ic_dev = dev;
123303823Ssephe	sc->ic_buflen = VMBUS_IC_BRSIZE;
124303823Ssephe	sc->receive_buffer = malloc(VMBUS_IC_BRSIZE, M_DEVBUF,
125303823Ssephe	    M_WAITOK | M_ZERO);
126250199Sgrehan
127282212Swhu	/*
128282212Swhu	 * These services are not performance critical and do not need
129282212Swhu	 * batched reading. Furthermore, some services such as KVP can
130282212Swhu	 * only handle one message from the host at a time.
131282212Swhu	 * Turn off batched reading for all util drivers before we open the
132282212Swhu	 * channel.
133282212Swhu	 */
134303069Ssephe	vmbus_chan_set_readbatch(chan, false);
135282212Swhu
136303823Ssephe	error = vmbus_chan_open(chan, VMBUS_IC_BRSIZE, VMBUS_IC_BRSIZE, NULL, 0,
137303824Ssephe	    cb, sc);
138303823Ssephe	if (error) {
139303823Ssephe		free(sc->receive_buffer, M_DEVBUF);
140303823Ssephe		return (error);
141303823Ssephe	}
142250199Sgrehan	return (0);
143250199Sgrehan}
144250199Sgrehan
145295958Ssepheint
146250199Sgrehanhv_util_detach(device_t dev)
147250199Sgrehan{
148302702Ssephe	struct hv_util_sc *sc = device_get_softc(dev);
149250199Sgrehan
150303069Ssephe	vmbus_chan_close(vmbus_get_channel(dev));
151302702Ssephe	free(sc->receive_buffer, M_DEVBUF);
152250199Sgrehan
153250199Sgrehan	return (0);
154250199Sgrehan}
155