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