vmbus_ic.c revision 304788
1/*- 2 * Copyright (c) 2014,2016 Microsoft Corp. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice unmodified, this list of conditions, and the following 10 * disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * 26 * $FreeBSD: head/sys/dev/hyperv/utilities/hv_util.c 304788 2016-08-25 05:24:57Z sephe $ 27 */ 28 29/* 30 * A common driver for all hyper-V util services. 31 */ 32 33#include <sys/param.h> 34#include <sys/kernel.h> 35#include <sys/bus.h> 36#include <sys/malloc.h> 37#include <sys/module.h> 38#include <sys/reboot.h> 39#include <sys/systm.h> 40#include <sys/timetc.h> 41 42#include <dev/hyperv/include/hyperv.h> 43#include <dev/hyperv/include/vmbus.h> 44#include <dev/hyperv/utilities/hv_util.h> 45#include <dev/hyperv/utilities/vmbus_icreg.h> 46 47#include "vmbus_if.h" 48 49#define VMBUS_IC_BRSIZE (4 * PAGE_SIZE) 50 51#define VMBUS_IC_VERCNT 2 52#define VMBUS_IC_NEGOSZ \ 53 __offsetof(struct vmbus_icmsg_negotiate, ic_ver[VMBUS_IC_VERCNT]) 54CTASSERT(VMBUS_IC_NEGOSZ < VMBUS_IC_BRSIZE); 55 56int 57vmbus_ic_negomsg(struct hv_util_sc *sc, void *data, int *dlen0) 58{ 59 struct vmbus_icmsg_negotiate *nego; 60 int cnt, major, dlen = *dlen0; 61 62 /* 63 * Preliminary message size verification 64 */ 65 if (dlen < sizeof(*nego)) { 66 device_printf(sc->ic_dev, "truncated ic negotiate, len %d\n", 67 dlen); 68 return EINVAL; 69 } 70 nego = data; 71 72 cnt = nego->ic_fwver_cnt + nego->ic_msgver_cnt; 73 if (dlen < __offsetof(struct vmbus_icmsg_negotiate, ic_ver[cnt])) { 74 device_printf(sc->ic_dev, "ic negotiate does not contain " 75 "versions %d\n", dlen); 76 return EINVAL; 77 } 78 79 /* Select major version; XXX looks wrong. */ 80 if (nego->ic_fwver_cnt >= 2 && VMBUS_ICVER_MAJOR(nego->ic_ver[1]) == 3) 81 major = 3; 82 else 83 major = 1; 84 85 /* One framework version */ 86 nego->ic_fwver_cnt = 1; 87 nego->ic_ver[0] = VMBUS_IC_VERSION(major, 0); 88 89 /* One message version */ 90 nego->ic_msgver_cnt = 1; 91 nego->ic_ver[1] = VMBUS_IC_VERSION(major, 0); 92 93 /* Update data size */ 94 nego->ic_hdr.ic_dsize = VMBUS_IC_NEGOSZ - 95 sizeof(struct vmbus_icmsg_hdr); 96 97 /* Update total size, if necessary */ 98 if (dlen < VMBUS_IC_NEGOSZ) 99 *dlen0 = VMBUS_IC_NEGOSZ; 100 101 return 0; 102} 103 104int 105vmbus_ic_probe(device_t dev, const struct vmbus_ic_desc descs[]) 106{ 107 device_t bus = device_get_parent(dev); 108 const struct vmbus_ic_desc *d; 109 110 if (resource_disabled(device_get_name(dev), 0)) 111 return (ENXIO); 112 113 for (d = descs; d->ic_desc != NULL; ++d) { 114 if (VMBUS_PROBE_GUID(bus, dev, &d->ic_guid) == 0) { 115 device_set_desc(dev, d->ic_desc); 116 return (BUS_PROBE_DEFAULT); 117 } 118 } 119 return (ENXIO); 120} 121 122int 123hv_util_attach(device_t dev, vmbus_chan_callback_t cb) 124{ 125 struct hv_util_sc *sc = device_get_softc(dev); 126 struct vmbus_channel *chan = vmbus_get_channel(dev); 127 int error; 128 129 sc->ic_dev = dev; 130 sc->ic_buflen = VMBUS_IC_BRSIZE; 131 sc->receive_buffer = malloc(VMBUS_IC_BRSIZE, M_DEVBUF, 132 M_WAITOK | M_ZERO); 133 134 /* 135 * These services are not performance critical and do not need 136 * batched reading. Furthermore, some services such as KVP can 137 * only handle one message from the host at a time. 138 * Turn off batched reading for all util drivers before we open the 139 * channel. 140 */ 141 vmbus_chan_set_readbatch(chan, false); 142 143 error = vmbus_chan_open(chan, VMBUS_IC_BRSIZE, VMBUS_IC_BRSIZE, NULL, 0, 144 cb, sc); 145 if (error) { 146 free(sc->receive_buffer, M_DEVBUF); 147 return (error); 148 } 149 return (0); 150} 151 152int 153hv_util_detach(device_t dev) 154{ 155 struct hv_util_sc *sc = device_get_softc(dev); 156 157 vmbus_chan_close(vmbus_get_channel(dev)); 158 free(sc->receive_buffer, M_DEVBUF); 159 160 return (0); 161} 162