19ff08654SSepherosa Ziehau /*-
29ff08654SSepherosa Ziehau * Copyright (c) 2014,2016 Microsoft Corp.
39ff08654SSepherosa Ziehau * All rights reserved.
49ff08654SSepherosa Ziehau *
59ff08654SSepherosa Ziehau * Redistribution and use in source and binary forms, with or without
69ff08654SSepherosa Ziehau * modification, are permitted provided that the following conditions
79ff08654SSepherosa Ziehau * are met:
89ff08654SSepherosa Ziehau * 1. Redistributions of source code must retain the above copyright
99ff08654SSepherosa Ziehau * notice unmodified, this list of conditions, and the following
109ff08654SSepherosa Ziehau * disclaimer.
119ff08654SSepherosa Ziehau * 2. Redistributions in binary form must reproduce the above copyright
129ff08654SSepherosa Ziehau * notice, this list of conditions and the following disclaimer in the
139ff08654SSepherosa Ziehau * documentation and/or other materials provided with the distribution.
149ff08654SSepherosa Ziehau *
159ff08654SSepherosa Ziehau * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
169ff08654SSepherosa Ziehau * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
179ff08654SSepherosa Ziehau * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
189ff08654SSepherosa Ziehau * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
199ff08654SSepherosa Ziehau * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
209ff08654SSepherosa Ziehau * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
219ff08654SSepherosa Ziehau * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
229ff08654SSepherosa Ziehau * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
239ff08654SSepherosa Ziehau * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
249ff08654SSepherosa Ziehau * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
259ff08654SSepherosa Ziehau */
269ff08654SSepherosa Ziehau
279ff08654SSepherosa Ziehau #include <sys/param.h>
289ff08654SSepherosa Ziehau #include <sys/bus.h>
299ff08654SSepherosa Ziehau #include <sys/malloc.h>
309ff08654SSepherosa Ziehau #include <sys/systm.h>
319ff08654SSepherosa Ziehau #include <sys/sysctl.h>
329ff08654SSepherosa Ziehau
339ff08654SSepherosa Ziehau #include <dev/hyperv/include/hyperv.h>
349ff08654SSepherosa Ziehau #include <dev/hyperv/include/vmbus.h>
359ff08654SSepherosa Ziehau #include <dev/hyperv/utilities/vmbus_icreg.h>
369ff08654SSepherosa Ziehau #include <dev/hyperv/utilities/vmbus_icvar.h>
379ff08654SSepherosa Ziehau
389ff08654SSepherosa Ziehau #include "vmbus_if.h"
399ff08654SSepherosa Ziehau
409ff08654SSepherosa Ziehau #define VMBUS_IC_BRSIZE (4 * PAGE_SIZE)
419ff08654SSepherosa Ziehau
429ff08654SSepherosa Ziehau #define VMBUS_IC_VERCNT 2
439ff08654SSepherosa Ziehau #define VMBUS_IC_NEGOSZ \
449ff08654SSepherosa Ziehau __offsetof(struct vmbus_icmsg_negotiate, ic_ver[VMBUS_IC_VERCNT])
459ff08654SSepherosa Ziehau CTASSERT(VMBUS_IC_NEGOSZ < VMBUS_IC_BRSIZE);
469ff08654SSepherosa Ziehau
479ff08654SSepherosa Ziehau static int vmbus_ic_fwver_sysctl(SYSCTL_HANDLER_ARGS);
489ff08654SSepherosa Ziehau static int vmbus_ic_msgver_sysctl(SYSCTL_HANDLER_ARGS);
499ff08654SSepherosa Ziehau
509ff08654SSepherosa Ziehau int
vmbus_ic_negomsg(struct vmbus_ic_softc * sc,void * data,int * dlen0,uint32_t fw_ver,uint32_t msg_ver)519ff08654SSepherosa Ziehau vmbus_ic_negomsg(struct vmbus_ic_softc *sc, void *data, int *dlen0,
529ff08654SSepherosa Ziehau uint32_t fw_ver, uint32_t msg_ver)
539ff08654SSepherosa Ziehau {
549ff08654SSepherosa Ziehau struct vmbus_icmsg_negotiate *nego;
559ff08654SSepherosa Ziehau int i, cnt, dlen = *dlen0, error;
569ff08654SSepherosa Ziehau uint32_t sel_fw_ver, sel_msg_ver;
579ff08654SSepherosa Ziehau bool has_fw_ver, has_msg_ver;
589ff08654SSepherosa Ziehau
59*b086426bSRobert Herndon has_fw_ver = false;
60*b086426bSRobert Herndon has_msg_ver = false;
61*b086426bSRobert Herndon
629ff08654SSepherosa Ziehau /*
639ff08654SSepherosa Ziehau * Preliminary message verification.
649ff08654SSepherosa Ziehau */
659ff08654SSepherosa Ziehau if (dlen < sizeof(*nego)) {
669ff08654SSepherosa Ziehau device_printf(sc->ic_dev, "truncated ic negotiate, len %d\n",
679ff08654SSepherosa Ziehau dlen);
689ff08654SSepherosa Ziehau return (EINVAL);
699ff08654SSepherosa Ziehau }
709ff08654SSepherosa Ziehau nego = data;
719ff08654SSepherosa Ziehau
729ff08654SSepherosa Ziehau if (nego->ic_fwver_cnt == 0) {
739ff08654SSepherosa Ziehau device_printf(sc->ic_dev, "ic negotiate does not contain "
749ff08654SSepherosa Ziehau "framework version %u\n", nego->ic_fwver_cnt);
759ff08654SSepherosa Ziehau return (EINVAL);
769ff08654SSepherosa Ziehau }
779ff08654SSepherosa Ziehau if (nego->ic_msgver_cnt == 0) {
789ff08654SSepherosa Ziehau device_printf(sc->ic_dev, "ic negotiate does not contain "
799ff08654SSepherosa Ziehau "message version %u\n", nego->ic_msgver_cnt);
809ff08654SSepherosa Ziehau return (EINVAL);
819ff08654SSepherosa Ziehau }
829ff08654SSepherosa Ziehau
839ff08654SSepherosa Ziehau cnt = nego->ic_fwver_cnt + nego->ic_msgver_cnt;
849ff08654SSepherosa Ziehau if (dlen < __offsetof(struct vmbus_icmsg_negotiate, ic_ver[cnt])) {
859ff08654SSepherosa Ziehau device_printf(sc->ic_dev, "ic negotiate does not contain "
869ff08654SSepherosa Ziehau "versions %d\n", dlen);
879ff08654SSepherosa Ziehau return (EINVAL);
889ff08654SSepherosa Ziehau }
899ff08654SSepherosa Ziehau
909ff08654SSepherosa Ziehau error = EOPNOTSUPP;
919ff08654SSepherosa Ziehau
929ff08654SSepherosa Ziehau /*
939ff08654SSepherosa Ziehau * Find the best match framework version.
949ff08654SSepherosa Ziehau */
959ff08654SSepherosa Ziehau for (i = 0; i < nego->ic_fwver_cnt; ++i) {
969ff08654SSepherosa Ziehau if (VMBUS_ICVER_LE(nego->ic_ver[i], fw_ver)) {
979ff08654SSepherosa Ziehau if (!has_fw_ver) {
989ff08654SSepherosa Ziehau sel_fw_ver = nego->ic_ver[i];
999ff08654SSepherosa Ziehau has_fw_ver = true;
1009ff08654SSepherosa Ziehau } else if (VMBUS_ICVER_GT(nego->ic_ver[i],
1019ff08654SSepherosa Ziehau sel_fw_ver)) {
1029ff08654SSepherosa Ziehau sel_fw_ver = nego->ic_ver[i];
1039ff08654SSepherosa Ziehau }
1049ff08654SSepherosa Ziehau }
1059ff08654SSepherosa Ziehau }
1069ff08654SSepherosa Ziehau if (!has_fw_ver) {
1079ff08654SSepherosa Ziehau device_printf(sc->ic_dev, "failed to select framework "
1089ff08654SSepherosa Ziehau "version\n");
1099ff08654SSepherosa Ziehau goto done;
1109ff08654SSepherosa Ziehau }
1119ff08654SSepherosa Ziehau
1129ff08654SSepherosa Ziehau /*
113*b086426bSRobert Herndon * Find the best match message version.
1149ff08654SSepherosa Ziehau */
1159ff08654SSepherosa Ziehau for (i = nego->ic_fwver_cnt;
1169ff08654SSepherosa Ziehau i < nego->ic_fwver_cnt + nego->ic_msgver_cnt; ++i) {
1179ff08654SSepherosa Ziehau if (VMBUS_ICVER_LE(nego->ic_ver[i], msg_ver)) {
1189ff08654SSepherosa Ziehau if (!has_msg_ver) {
1199ff08654SSepherosa Ziehau sel_msg_ver = nego->ic_ver[i];
1209ff08654SSepherosa Ziehau has_msg_ver = true;
1219ff08654SSepherosa Ziehau } else if (VMBUS_ICVER_GT(nego->ic_ver[i],
1229ff08654SSepherosa Ziehau sel_msg_ver)) {
1239ff08654SSepherosa Ziehau sel_msg_ver = nego->ic_ver[i];
1249ff08654SSepherosa Ziehau }
1259ff08654SSepherosa Ziehau }
1269ff08654SSepherosa Ziehau }
1279ff08654SSepherosa Ziehau if (!has_msg_ver) {
1289ff08654SSepherosa Ziehau device_printf(sc->ic_dev, "failed to select message "
1299ff08654SSepherosa Ziehau "version\n");
1309ff08654SSepherosa Ziehau goto done;
1319ff08654SSepherosa Ziehau }
1329ff08654SSepherosa Ziehau
1339ff08654SSepherosa Ziehau error = 0;
1349ff08654SSepherosa Ziehau done:
1359ff08654SSepherosa Ziehau if (bootverbose || !has_fw_ver || !has_msg_ver) {
1369ff08654SSepherosa Ziehau if (has_fw_ver) {
1379ff08654SSepherosa Ziehau device_printf(sc->ic_dev, "sel framework version: "
1389ff08654SSepherosa Ziehau "%u.%u\n",
1399ff08654SSepherosa Ziehau VMBUS_ICVER_MAJOR(sel_fw_ver),
1409ff08654SSepherosa Ziehau VMBUS_ICVER_MINOR(sel_fw_ver));
1419ff08654SSepherosa Ziehau }
1429ff08654SSepherosa Ziehau for (i = 0; i < nego->ic_fwver_cnt; i++) {
1439ff08654SSepherosa Ziehau device_printf(sc->ic_dev, "supp framework version: "
1449ff08654SSepherosa Ziehau "%u.%u\n",
1459ff08654SSepherosa Ziehau VMBUS_ICVER_MAJOR(nego->ic_ver[i]),
1469ff08654SSepherosa Ziehau VMBUS_ICVER_MINOR(nego->ic_ver[i]));
1479ff08654SSepherosa Ziehau }
1489ff08654SSepherosa Ziehau
1499ff08654SSepherosa Ziehau if (has_msg_ver) {
1509ff08654SSepherosa Ziehau device_printf(sc->ic_dev, "sel message version: "
1519ff08654SSepherosa Ziehau "%u.%u\n",
1529ff08654SSepherosa Ziehau VMBUS_ICVER_MAJOR(sel_msg_ver),
1539ff08654SSepherosa Ziehau VMBUS_ICVER_MINOR(sel_msg_ver));
1549ff08654SSepherosa Ziehau }
1559ff08654SSepherosa Ziehau for (i = nego->ic_fwver_cnt;
1569ff08654SSepherosa Ziehau i < nego->ic_fwver_cnt + nego->ic_msgver_cnt; i++) {
1579ff08654SSepherosa Ziehau device_printf(sc->ic_dev, "supp message version: "
1589ff08654SSepherosa Ziehau "%u.%u\n",
1599ff08654SSepherosa Ziehau VMBUS_ICVER_MAJOR(nego->ic_ver[i]),
1609ff08654SSepherosa Ziehau VMBUS_ICVER_MINOR(nego->ic_ver[i]));
1619ff08654SSepherosa Ziehau }
1629ff08654SSepherosa Ziehau }
1639ff08654SSepherosa Ziehau if (error)
1649ff08654SSepherosa Ziehau return (error);
1659ff08654SSepherosa Ziehau
1669ff08654SSepherosa Ziehau /* Record the selected versions. */
1679ff08654SSepherosa Ziehau sc->ic_fwver = sel_fw_ver;
1689ff08654SSepherosa Ziehau sc->ic_msgver = sel_msg_ver;
1699ff08654SSepherosa Ziehau
1709ff08654SSepherosa Ziehau /* One framework version. */
1719ff08654SSepherosa Ziehau nego->ic_fwver_cnt = 1;
1729ff08654SSepherosa Ziehau nego->ic_ver[0] = sel_fw_ver;
1739ff08654SSepherosa Ziehau
1749ff08654SSepherosa Ziehau /* One message version. */
1759ff08654SSepherosa Ziehau nego->ic_msgver_cnt = 1;
1769ff08654SSepherosa Ziehau nego->ic_ver[1] = sel_msg_ver;
1779ff08654SSepherosa Ziehau
1789ff08654SSepherosa Ziehau /* Update data size. */
1799ff08654SSepherosa Ziehau nego->ic_hdr.ic_dsize = VMBUS_IC_NEGOSZ -
1809ff08654SSepherosa Ziehau sizeof(struct vmbus_icmsg_hdr);
1819ff08654SSepherosa Ziehau
1829ff08654SSepherosa Ziehau /* Update total size, if necessary. */
1839ff08654SSepherosa Ziehau if (dlen < VMBUS_IC_NEGOSZ)
1849ff08654SSepherosa Ziehau *dlen0 = VMBUS_IC_NEGOSZ;
1859ff08654SSepherosa Ziehau
1869ff08654SSepherosa Ziehau return (0);
1879ff08654SSepherosa Ziehau }
1889ff08654SSepherosa Ziehau
1899ff08654SSepherosa Ziehau int
vmbus_ic_probe(device_t dev,const struct vmbus_ic_desc descs[])1909ff08654SSepherosa Ziehau vmbus_ic_probe(device_t dev, const struct vmbus_ic_desc descs[])
1919ff08654SSepherosa Ziehau {
1929ff08654SSepherosa Ziehau device_t bus = device_get_parent(dev);
1939ff08654SSepherosa Ziehau const struct vmbus_ic_desc *d;
1949ff08654SSepherosa Ziehau
1959ff08654SSepherosa Ziehau if (resource_disabled(device_get_name(dev), 0))
1969ff08654SSepherosa Ziehau return (ENXIO);
1979ff08654SSepherosa Ziehau
1989ff08654SSepherosa Ziehau for (d = descs; d->ic_desc != NULL; ++d) {
1999ff08654SSepherosa Ziehau if (VMBUS_PROBE_GUID(bus, dev, &d->ic_guid) == 0) {
2009ff08654SSepherosa Ziehau device_set_desc(dev, d->ic_desc);
2019ff08654SSepherosa Ziehau return (BUS_PROBE_DEFAULT);
2029ff08654SSepherosa Ziehau }
2039ff08654SSepherosa Ziehau }
2049ff08654SSepherosa Ziehau return (ENXIO);
2059ff08654SSepherosa Ziehau }
2069ff08654SSepherosa Ziehau
2079ff08654SSepherosa Ziehau int
vmbus_ic_attach(device_t dev,vmbus_chan_callback_t cb)2089ff08654SSepherosa Ziehau vmbus_ic_attach(device_t dev, vmbus_chan_callback_t cb)
2099ff08654SSepherosa Ziehau {
2109ff08654SSepherosa Ziehau struct vmbus_ic_softc *sc = device_get_softc(dev);
2119ff08654SSepherosa Ziehau struct vmbus_channel *chan = vmbus_get_channel(dev);
2129ff08654SSepherosa Ziehau struct sysctl_oid_list *child;
2139ff08654SSepherosa Ziehau struct sysctl_ctx_list *ctx;
2149ff08654SSepherosa Ziehau int error;
2159ff08654SSepherosa Ziehau
2169ff08654SSepherosa Ziehau sc->ic_dev = dev;
2179ff08654SSepherosa Ziehau sc->ic_buflen = VMBUS_IC_BRSIZE;
2189ff08654SSepherosa Ziehau sc->ic_buf = malloc(VMBUS_IC_BRSIZE, M_DEVBUF, M_WAITOK | M_ZERO);
2199ff08654SSepherosa Ziehau
2209ff08654SSepherosa Ziehau /*
2219ff08654SSepherosa Ziehau * These services are not performance critical and do not need
2229ff08654SSepherosa Ziehau * batched reading. Furthermore, some services such as KVP can
2239ff08654SSepherosa Ziehau * only handle one message from the host at a time.
2249ff08654SSepherosa Ziehau * Turn off batched reading for all util drivers before we open the
2259ff08654SSepherosa Ziehau * channel.
2269ff08654SSepherosa Ziehau */
2279ff08654SSepherosa Ziehau vmbus_chan_set_readbatch(chan, false);
2289ff08654SSepherosa Ziehau
2299ff08654SSepherosa Ziehau error = vmbus_chan_open(chan, VMBUS_IC_BRSIZE, VMBUS_IC_BRSIZE, NULL, 0,
2309ff08654SSepherosa Ziehau cb, sc);
2319ff08654SSepherosa Ziehau if (error) {
2329ff08654SSepherosa Ziehau free(sc->ic_buf, M_DEVBUF);
2339ff08654SSepherosa Ziehau return (error);
2349ff08654SSepherosa Ziehau }
2359ff08654SSepherosa Ziehau
2369ff08654SSepherosa Ziehau ctx = device_get_sysctl_ctx(dev);
2379ff08654SSepherosa Ziehau child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
2389ff08654SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "fw_version",
2399ff08654SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
2409ff08654SSepherosa Ziehau vmbus_ic_fwver_sysctl, "A", "framework version");
2419ff08654SSepherosa Ziehau SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "msg_version",
2429ff08654SSepherosa Ziehau CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
2439ff08654SSepherosa Ziehau vmbus_ic_msgver_sysctl, "A", "message version");
2449ff08654SSepherosa Ziehau
2459ff08654SSepherosa Ziehau return (0);
2469ff08654SSepherosa Ziehau }
2479ff08654SSepherosa Ziehau
2489ff08654SSepherosa Ziehau static int
vmbus_ic_fwver_sysctl(SYSCTL_HANDLER_ARGS)2499ff08654SSepherosa Ziehau vmbus_ic_fwver_sysctl(SYSCTL_HANDLER_ARGS)
2509ff08654SSepherosa Ziehau {
2519ff08654SSepherosa Ziehau struct vmbus_ic_softc *sc = arg1;
2529ff08654SSepherosa Ziehau char verstr[16];
2539ff08654SSepherosa Ziehau
2549ff08654SSepherosa Ziehau snprintf(verstr, sizeof(verstr), "%u.%u",
2559ff08654SSepherosa Ziehau VMBUS_ICVER_MAJOR(sc->ic_fwver), VMBUS_ICVER_MINOR(sc->ic_fwver));
2569ff08654SSepherosa Ziehau return sysctl_handle_string(oidp, verstr, sizeof(verstr), req);
2579ff08654SSepherosa Ziehau }
2589ff08654SSepherosa Ziehau
2599ff08654SSepherosa Ziehau static int
vmbus_ic_msgver_sysctl(SYSCTL_HANDLER_ARGS)2609ff08654SSepherosa Ziehau vmbus_ic_msgver_sysctl(SYSCTL_HANDLER_ARGS)
2619ff08654SSepherosa Ziehau {
2629ff08654SSepherosa Ziehau struct vmbus_ic_softc *sc = arg1;
2639ff08654SSepherosa Ziehau char verstr[16];
2649ff08654SSepherosa Ziehau
2659ff08654SSepherosa Ziehau snprintf(verstr, sizeof(verstr), "%u.%u",
2669ff08654SSepherosa Ziehau VMBUS_ICVER_MAJOR(sc->ic_msgver), VMBUS_ICVER_MINOR(sc->ic_msgver));
2679ff08654SSepherosa Ziehau return sysctl_handle_string(oidp, verstr, sizeof(verstr), req);
2689ff08654SSepherosa Ziehau }
2699ff08654SSepherosa Ziehau
2709ff08654SSepherosa Ziehau int
vmbus_ic_detach(device_t dev)2719ff08654SSepherosa Ziehau vmbus_ic_detach(device_t dev)
2729ff08654SSepherosa Ziehau {
2739ff08654SSepherosa Ziehau struct vmbus_ic_softc *sc = device_get_softc(dev);
2749ff08654SSepherosa Ziehau
2759ff08654SSepherosa Ziehau vmbus_chan_close(vmbus_get_channel(dev));
2769ff08654SSepherosa Ziehau free(sc->ic_buf, M_DEVBUF);
2779ff08654SSepherosa Ziehau
2789ff08654SSepherosa Ziehau return (0);
2799ff08654SSepherosa Ziehau }
2809ff08654SSepherosa Ziehau
2819ff08654SSepherosa Ziehau int
vmbus_ic_sendresp(struct vmbus_ic_softc * sc,struct vmbus_channel * chan,void * data,int dlen,uint64_t xactid)2829ff08654SSepherosa Ziehau vmbus_ic_sendresp(struct vmbus_ic_softc *sc, struct vmbus_channel *chan,
2839ff08654SSepherosa Ziehau void *data, int dlen, uint64_t xactid)
2849ff08654SSepherosa Ziehau {
2859ff08654SSepherosa Ziehau struct vmbus_icmsg_hdr *hdr;
2869ff08654SSepherosa Ziehau int error;
2879ff08654SSepherosa Ziehau
2889ff08654SSepherosa Ziehau KASSERT(dlen >= sizeof(*hdr), ("invalid data length %d", dlen));
2899ff08654SSepherosa Ziehau hdr = data;
2909ff08654SSepherosa Ziehau
2919ff08654SSepherosa Ziehau hdr->ic_flags = VMBUS_ICMSG_FLAG_XACT | VMBUS_ICMSG_FLAG_RESP;
2929ff08654SSepherosa Ziehau error = vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_INBAND, 0,
2939ff08654SSepherosa Ziehau data, dlen, xactid);
2949ff08654SSepherosa Ziehau if (error)
2959ff08654SSepherosa Ziehau device_printf(sc->ic_dev, "resp send failed: %d\n", error);
2969ff08654SSepherosa Ziehau return (error);
2979ff08654SSepherosa Ziehau }
298