Home | History | Annotate | Line # | Download | only in hyperv
      1  1.2     chs /*	$NetBSD: vmbusic.c,v 1.2 2019/10/01 18:00:08 chs Exp $	*/
      2  1.1  nonaka /*-
      3  1.1  nonaka  * Copyright (c) 2014,2016 Microsoft Corp.
      4  1.1  nonaka  * All rights reserved.
      5  1.1  nonaka  *
      6  1.1  nonaka  * Redistribution and use in source and binary forms, with or without
      7  1.1  nonaka  * modification, are permitted provided that the following conditions
      8  1.1  nonaka  * are met:
      9  1.1  nonaka  * 1. Redistributions of source code must retain the above copyright
     10  1.1  nonaka  *    notice unmodified, this list of conditions, and the following
     11  1.1  nonaka  *    disclaimer.
     12  1.1  nonaka  * 2. Redistributions in binary form must reproduce the above copyright
     13  1.1  nonaka  *    notice, this list of conditions and the following disclaimer in the
     14  1.1  nonaka  *    documentation and/or other materials provided with the distribution.
     15  1.1  nonaka  *
     16  1.1  nonaka  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     17  1.1  nonaka  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     18  1.1  nonaka  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     19  1.1  nonaka  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     20  1.1  nonaka  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     21  1.1  nonaka  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     22  1.1  nonaka  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     23  1.1  nonaka  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     24  1.1  nonaka  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     25  1.1  nonaka  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26  1.1  nonaka  */
     27  1.1  nonaka 
     28  1.1  nonaka #include <sys/cdefs.h>
     29  1.1  nonaka #ifdef __KERNEL_RCSID
     30  1.2     chs __KERNEL_RCSID(0, "$NetBSD: vmbusic.c,v 1.2 2019/10/01 18:00:08 chs Exp $");
     31  1.1  nonaka #endif
     32  1.1  nonaka #ifdef __FBSDID
     33  1.1  nonaka __FBSDID("$FreeBSD: head/sys/dev/hyperv/utilities/vmbus_ic.c 310317 2016-12-20 07:14:24Z sephe $");
     34  1.1  nonaka #endif
     35  1.1  nonaka 
     36  1.1  nonaka #include <sys/param.h>
     37  1.1  nonaka #include <sys/systm.h>
     38  1.1  nonaka #include <sys/kernel.h>
     39  1.1  nonaka #include <sys/device.h>
     40  1.1  nonaka #include <sys/kmem.h>
     41  1.1  nonaka #include <sys/reboot.h>
     42  1.1  nonaka 
     43  1.1  nonaka #include <dev/hyperv/vmbusvar.h>
     44  1.1  nonaka #include <dev/hyperv/vmbusicreg.h>
     45  1.1  nonaka #include <dev/hyperv/vmbusicvar.h>
     46  1.1  nonaka 
     47  1.1  nonaka #define VMBUS_IC_BRSIZE		(4 * PAGE_SIZE)
     48  1.1  nonaka 
     49  1.1  nonaka #define VMBUS_IC_VERCNT         2
     50  1.1  nonaka #define VMBUS_IC_NEGOSZ		\
     51  1.1  nonaka     offsetof(struct vmbus_icmsg_negotiate, ic_ver[VMBUS_IC_VERCNT])
     52  1.1  nonaka __CTASSERT(VMBUS_IC_NEGOSZ < VMBUS_IC_BRSIZE);
     53  1.1  nonaka 
     54  1.1  nonaka 
     55  1.1  nonaka int
     56  1.1  nonaka vmbusic_probe(struct vmbus_attach_args *aa, const struct hyperv_guid *guid)
     57  1.1  nonaka {
     58  1.1  nonaka 
     59  1.1  nonaka 	if (memcmp(aa->aa_type, guid, sizeof(*aa->aa_type)) != 0)
     60  1.1  nonaka 		return 0;
     61  1.1  nonaka 	return 1;
     62  1.1  nonaka }
     63  1.1  nonaka 
     64  1.1  nonaka int
     65  1.1  nonaka vmbusic_attach(device_t dv, struct vmbus_attach_args *aa,
     66  1.1  nonaka     vmbus_channel_callback_t cb)
     67  1.1  nonaka {
     68  1.1  nonaka 	struct vmbusic_softc *sc = device_private(dv);
     69  1.1  nonaka 
     70  1.1  nonaka 	sc->sc_dev = dv;
     71  1.1  nonaka 	sc->sc_chan = aa->aa_chan;
     72  1.1  nonaka 
     73  1.1  nonaka 	sc->sc_buflen = VMBUS_IC_BRSIZE;
     74  1.2     chs 	sc->sc_buf = kmem_alloc(sc->sc_buflen, KM_SLEEP);
     75  1.1  nonaka 
     76  1.1  nonaka 	/*
     77  1.1  nonaka 	 * These services are not performance critical and do not need
     78  1.1  nonaka 	 * batched reading. Furthermore, some services such as KVP can
     79  1.1  nonaka 	 * only handle one message from the host at a time.
     80  1.1  nonaka 	 * Turn off batched reading for all util drivers before we open the
     81  1.1  nonaka 	 * channel.
     82  1.1  nonaka 	 */
     83  1.1  nonaka 	sc->sc_chan->ch_flags &= ~CHF_BATCHED;
     84  1.1  nonaka 
     85  1.1  nonaka 	if (vmbus_channel_open(sc->sc_chan, sc->sc_buflen, NULL, 0, cb, sc)) {
     86  1.1  nonaka 		aprint_error_dev(dv, "failed to open channel\n");
     87  1.1  nonaka 		kmem_free(sc->sc_buf, sc->sc_buflen);
     88  1.1  nonaka 		sc->sc_buf = NULL;
     89  1.1  nonaka 		return ENXIO;
     90  1.1  nonaka 	}
     91  1.1  nonaka 
     92  1.1  nonaka 	return 0;
     93  1.1  nonaka }
     94  1.1  nonaka 
     95  1.1  nonaka int
     96  1.1  nonaka vmbusic_detach(device_t dv, int flags)
     97  1.1  nonaka {
     98  1.1  nonaka 	struct vmbusic_softc *sc = device_private(dv);
     99  1.1  nonaka 	int error;
    100  1.1  nonaka 
    101  1.1  nonaka 	error = vmbus_channel_close(sc->sc_chan);
    102  1.1  nonaka 	if (error != 0)
    103  1.1  nonaka 		return error;
    104  1.1  nonaka 
    105  1.1  nonaka 	if (sc->sc_buf != NULL) {
    106  1.1  nonaka 		kmem_free(sc->sc_buf, sc->sc_buflen);
    107  1.1  nonaka 		sc->sc_buf = NULL;
    108  1.1  nonaka 	}
    109  1.1  nonaka 
    110  1.1  nonaka 	if (sc->sc_log != NULL) {
    111  1.1  nonaka 		sysctl_teardown(&sc->sc_log);
    112  1.1  nonaka 		sc->sc_log = NULL;
    113  1.1  nonaka 	}
    114  1.1  nonaka 
    115  1.1  nonaka 	return 0;
    116  1.1  nonaka }
    117  1.1  nonaka 
    118  1.1  nonaka int
    119  1.1  nonaka vmbusic_negotiate(struct vmbusic_softc *sc, void *data, uint32_t *dlen0,
    120  1.1  nonaka     uint32_t fw_ver, uint32_t msg_ver)
    121  1.1  nonaka {
    122  1.1  nonaka 	struct vmbus_icmsg_negotiate *nego;
    123  1.1  nonaka 	uint32_t sel_fw_ver = 0, sel_msg_ver = 0;
    124  1.1  nonaka 	int i, cnt, dlen = *dlen0, error;
    125  1.1  nonaka 	bool has_fw_ver, has_msg_ver = false;
    126  1.1  nonaka 
    127  1.1  nonaka 	/*
    128  1.1  nonaka 	 * Preliminary message verification.
    129  1.1  nonaka 	 */
    130  1.1  nonaka 	if (dlen < sizeof(*nego)) {
    131  1.1  nonaka 		device_printf(sc->sc_dev, "truncated ic negotiate, len %d\n",
    132  1.1  nonaka 		    dlen);
    133  1.1  nonaka 		return EINVAL;
    134  1.1  nonaka 	}
    135  1.1  nonaka 	nego = data;
    136  1.1  nonaka 
    137  1.1  nonaka 	if (nego->ic_fwver_cnt == 0) {
    138  1.1  nonaka 		device_printf(sc->sc_dev, "ic negotiate does not contain "
    139  1.1  nonaka 		    "framework version %u\n", nego->ic_fwver_cnt);
    140  1.1  nonaka 		return EINVAL;
    141  1.1  nonaka 	}
    142  1.1  nonaka 	if (nego->ic_msgver_cnt == 0) {
    143  1.1  nonaka 		device_printf(sc->sc_dev, "ic negotiate does not contain "
    144  1.1  nonaka 		    "message version %u\n", nego->ic_msgver_cnt);
    145  1.1  nonaka 		return EINVAL;
    146  1.1  nonaka 	}
    147  1.1  nonaka 
    148  1.1  nonaka 	cnt = nego->ic_fwver_cnt + nego->ic_msgver_cnt;
    149  1.1  nonaka 	if (dlen < offsetof(struct vmbus_icmsg_negotiate, ic_ver[cnt])) {
    150  1.1  nonaka 		device_printf(sc->sc_dev, "ic negotiate does not contain "
    151  1.1  nonaka 		    "versions %d\n", dlen);
    152  1.1  nonaka 		return EINVAL;
    153  1.1  nonaka 	}
    154  1.1  nonaka 
    155  1.1  nonaka 	error = EOPNOTSUPP;
    156  1.1  nonaka 
    157  1.1  nonaka 	/*
    158  1.1  nonaka 	 * Find the best match framework version.
    159  1.1  nonaka 	 */
    160  1.1  nonaka 	has_fw_ver = false;
    161  1.1  nonaka 	for (i = 0; i < nego->ic_fwver_cnt; ++i) {
    162  1.1  nonaka 		if (VMBUS_ICVER_LE(nego->ic_ver[i], fw_ver)) {
    163  1.1  nonaka 			if (!has_fw_ver) {
    164  1.1  nonaka 				sel_fw_ver = nego->ic_ver[i];
    165  1.1  nonaka 				has_fw_ver = true;
    166  1.1  nonaka 			} else if (VMBUS_ICVER_GT(nego->ic_ver[i],
    167  1.1  nonaka 			    sel_fw_ver)) {
    168  1.1  nonaka 				sel_fw_ver = nego->ic_ver[i];
    169  1.1  nonaka 			}
    170  1.1  nonaka 		}
    171  1.1  nonaka 	}
    172  1.1  nonaka 	if (!has_fw_ver) {
    173  1.1  nonaka 		device_printf(sc->sc_dev, "failed to select framework "
    174  1.1  nonaka 		    "version\n");
    175  1.1  nonaka 		goto done;
    176  1.1  nonaka 	}
    177  1.1  nonaka 
    178  1.1  nonaka 	/*
    179  1.1  nonaka 	 * Fine the best match message version.
    180  1.1  nonaka 	 */
    181  1.1  nonaka 	has_msg_ver = false;
    182  1.1  nonaka 	for (i = nego->ic_fwver_cnt;
    183  1.1  nonaka 	    i < nego->ic_fwver_cnt + nego->ic_msgver_cnt; ++i) {
    184  1.1  nonaka 		if (VMBUS_ICVER_LE(nego->ic_ver[i], msg_ver)) {
    185  1.1  nonaka 			if (!has_msg_ver) {
    186  1.1  nonaka 				sel_msg_ver = nego->ic_ver[i];
    187  1.1  nonaka 				has_msg_ver = true;
    188  1.1  nonaka 			} else if (VMBUS_ICVER_GT(nego->ic_ver[i],
    189  1.1  nonaka 			    sel_msg_ver)) {
    190  1.1  nonaka 				sel_msg_ver = nego->ic_ver[i];
    191  1.1  nonaka 			}
    192  1.1  nonaka 		}
    193  1.1  nonaka 	}
    194  1.1  nonaka 	if (!has_msg_ver) {
    195  1.1  nonaka 		device_printf(sc->sc_dev, "failed to select message version\n");
    196  1.1  nonaka 		goto done;
    197  1.1  nonaka 	}
    198  1.1  nonaka 
    199  1.1  nonaka 	error = 0;
    200  1.1  nonaka done:
    201  1.1  nonaka 	if (bootverbose || !has_fw_ver || !has_msg_ver) {
    202  1.1  nonaka 		if (has_fw_ver) {
    203  1.1  nonaka 			device_printf(sc->sc_dev,
    204  1.1  nonaka 			    "sel framework version: %u.%u\n",
    205  1.1  nonaka 			    VMBUS_ICVER_MAJOR(sel_fw_ver),
    206  1.1  nonaka 			    VMBUS_ICVER_MINOR(sel_fw_ver));
    207  1.1  nonaka 		}
    208  1.1  nonaka 		for (i = 0; i < nego->ic_fwver_cnt; i++) {
    209  1.1  nonaka 			device_printf(sc->sc_dev,
    210  1.1  nonaka 			    "supp framework version: %u.%u\n",
    211  1.1  nonaka 			    VMBUS_ICVER_MAJOR(nego->ic_ver[i]),
    212  1.1  nonaka 			    VMBUS_ICVER_MINOR(nego->ic_ver[i]));
    213  1.1  nonaka 		}
    214  1.1  nonaka 
    215  1.1  nonaka 		if (has_msg_ver) {
    216  1.1  nonaka 			device_printf(sc->sc_dev,
    217  1.1  nonaka 			    "sel message version: %u.%u\n",
    218  1.1  nonaka 			    VMBUS_ICVER_MAJOR(sel_msg_ver),
    219  1.1  nonaka 			    VMBUS_ICVER_MINOR(sel_msg_ver));
    220  1.1  nonaka 		}
    221  1.1  nonaka 		for (i = nego->ic_fwver_cnt;
    222  1.1  nonaka 		    i < nego->ic_fwver_cnt + nego->ic_msgver_cnt; i++) {
    223  1.1  nonaka 			device_printf(sc->sc_dev,
    224  1.1  nonaka 			    "supp message version: %u.%u\n",
    225  1.1  nonaka 			    VMBUS_ICVER_MAJOR(nego->ic_ver[i]),
    226  1.1  nonaka 			    VMBUS_ICVER_MINOR(nego->ic_ver[i]));
    227  1.1  nonaka 		}
    228  1.1  nonaka 	}
    229  1.1  nonaka 	if (error)
    230  1.1  nonaka 		return error;
    231  1.1  nonaka 
    232  1.1  nonaka 	/* Record the selected versions. */
    233  1.1  nonaka 	sc->sc_fwver = sel_fw_ver;
    234  1.1  nonaka 	sc->sc_msgver = sel_msg_ver;
    235  1.1  nonaka 
    236  1.1  nonaka 	/* One framework version. */
    237  1.1  nonaka 	nego->ic_fwver_cnt = 1;
    238  1.1  nonaka 	nego->ic_ver[0] = sel_fw_ver;
    239  1.1  nonaka 
    240  1.1  nonaka 	/* One message version. */
    241  1.1  nonaka 	nego->ic_msgver_cnt = 1;
    242  1.1  nonaka 	nego->ic_ver[1] = sel_msg_ver;
    243  1.1  nonaka 
    244  1.1  nonaka 	/* Update data size. */
    245  1.1  nonaka 	nego->ic_hdr.ic_dsize = VMBUS_IC_NEGOSZ -
    246  1.1  nonaka 	    sizeof(struct vmbus_icmsg_hdr);
    247  1.1  nonaka 
    248  1.1  nonaka 	/* Update total size, if necessary. */
    249  1.1  nonaka 	if (dlen < VMBUS_IC_NEGOSZ)
    250  1.1  nonaka 		*dlen0 = VMBUS_IC_NEGOSZ;
    251  1.1  nonaka 
    252  1.1  nonaka 	return 0;
    253  1.1  nonaka }
    254  1.1  nonaka 
    255  1.1  nonaka int
    256  1.1  nonaka vmbusic_sendresp(struct vmbusic_softc *sc, struct vmbus_channel *chan,
    257  1.1  nonaka     void *data, uint32_t dlen, uint64_t rid)
    258  1.1  nonaka {
    259  1.1  nonaka 	struct vmbus_icmsg_hdr *hdr;
    260  1.1  nonaka 	int error;
    261  1.1  nonaka 
    262  1.1  nonaka 	KASSERTMSG(dlen >= sizeof(*hdr), "invalid data length %d", dlen);
    263  1.1  nonaka 	hdr = data;
    264  1.1  nonaka 
    265  1.1  nonaka 	hdr->ic_flags = VMBUS_ICMSG_FLAG_TRANSACTION|VMBUS_ICMSG_FLAG_RESPONSE;
    266  1.1  nonaka 	error = vmbus_channel_send(chan, data, dlen, rid,
    267  1.1  nonaka 	    VMBUS_CHANPKT_TYPE_INBAND, 0);
    268  1.1  nonaka 	if (error != 0)
    269  1.1  nonaka 		device_printf(sc->sc_dev, "resp send failed: %d\n", error);
    270  1.1  nonaka 	return error;
    271  1.1  nonaka }
    272