Changeset View
Changeset View
Standalone View
Standalone View
head/sys/dev/hyperv/utilities/hv_heartbeat.c
Show All 16 Lines | |||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
* | |||||
* $FreeBSD$ | |||||
*/ | */ | ||||
#include <sys/cdefs.h> | |||||
__FBSDID("$FreeBSD$"); | |||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/kernel.h> | |||||
#include <sys/bus.h> | #include <sys/bus.h> | ||||
#include <sys/malloc.h> | #include <sys/kernel.h> | ||||
#include <sys/module.h> | #include <sys/module.h> | ||||
#include <sys/timetc.h> | |||||
#include <sys/syscallsubr.h> | |||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <dev/hyperv/include/hyperv.h> | #include <dev/hyperv/include/hyperv.h> | ||||
#include <dev/hyperv/include/vmbus.h> | #include <dev/hyperv/include/vmbus.h> | ||||
#include <dev/hyperv/utilities/hv_utilreg.h> | #include <dev/hyperv/utilities/hv_util.h> | ||||
#include "hv_util.h" | #include <dev/hyperv/utilities/vmbus_icreg.h> | ||||
#include "vmbus_if.h" | #include "vmbus_if.h" | ||||
static const struct vmbus_ic_desc vmbus_heartbeat_descs[] = { | static const struct vmbus_ic_desc vmbus_heartbeat_descs[] = { | ||||
{ | { | ||||
.ic_guid = { .hv_guid = { | .ic_guid = { .hv_guid = { | ||||
0x39, 0x4f, 0x16, 0x57, 0x15, 0x91, 0x78, 0x4e, | 0x39, 0x4f, 0x16, 0x57, 0x15, 0x91, 0x78, 0x4e, | ||||
0xab, 0x55, 0x38, 0x2f, 0x3b, 0xd5, 0x42, 0x2d} }, | 0xab, 0x55, 0x38, 0x2f, 0x3b, 0xd5, 0x42, 0x2d} }, | ||||
.ic_desc = "Hyper-V Heartbeat" | .ic_desc = "Hyper-V Heartbeat" | ||||
}, | }, | ||||
VMBUS_IC_DESC_END | VMBUS_IC_DESC_END | ||||
}; | }; | ||||
/** | |||||
* Process heartbeat message | |||||
*/ | |||||
static void | static void | ||||
hv_heartbeat_cb(struct vmbus_channel *channel, void *context) | vmbus_heartbeat_cb(struct vmbus_channel *chan, void *xsc) | ||||
{ | { | ||||
uint8_t* buf; | struct hv_util_sc *sc = xsc; | ||||
int recvlen; | struct vmbus_icmsg_hdr *hdr; | ||||
uint64_t requestid; | int dlen, error; | ||||
int ret; | uint64_t xactid; | ||||
void *data; | |||||
struct hv_vmbus_heartbeat_msg_data* heartbeat_msg; | /* | ||||
struct hv_vmbus_icmsg_hdr* icmsghdrp; | * Receive request. | ||||
hv_util_sc *softc; | */ | ||||
data = sc->receive_buffer; | |||||
dlen = sc->ic_buflen; | |||||
error = vmbus_chan_recv(chan, data, &dlen, &xactid); | |||||
KASSERT(error != ENOBUFS, ("icbuf is not large enough")); | |||||
if (error) | |||||
return; | |||||
softc = (hv_util_sc*)context; | if (dlen < sizeof(struct vmbus_icmsg_hdr)) { | ||||
buf = softc->receive_buffer; | device_printf(sc->ic_dev, "invalid data len %d\n", dlen); | ||||
return; | |||||
} | |||||
hdr = data; | |||||
recvlen = softc->ic_buflen; | /* | ||||
ret = vmbus_chan_recv(channel, buf, &recvlen, &requestid); | * Update request, which will be echoed back as response. | ||||
KASSERT(ret != ENOBUFS, ("hvheartbeat recvbuf is not large enough")); | */ | ||||
/* XXX check recvlen to make sure that it contains enough data */ | switch (hdr->ic_type) { | ||||
case VMBUS_ICMSG_TYPE_NEGOTIATE: | |||||
if ((ret == 0) && recvlen > 0) { | error = vmbus_ic_negomsg(sc, data, dlen); | ||||
icmsghdrp = (struct hv_vmbus_icmsg_hdr *) | |||||
&buf[sizeof(struct hv_vmbus_pipe_hdr)]; | |||||
if (icmsghdrp->icmsgtype == HV_ICMSGTYPE_NEGOTIATE) { | |||||
int error; | |||||
error = vmbus_ic_negomsg(softc, buf, recvlen); | |||||
if (error) | if (error) | ||||
return; | return; | ||||
} else { | break; | ||||
heartbeat_msg = | |||||
(struct hv_vmbus_heartbeat_msg_data *) | |||||
&buf[sizeof(struct hv_vmbus_pipe_hdr) + | |||||
sizeof(struct hv_vmbus_icmsg_hdr)]; | |||||
heartbeat_msg->seq_num += 1; | case VMBUS_ICMSG_TYPE_HEARTBEAT: | ||||
/* Only ic_seq is a must */ | |||||
if (dlen < VMBUS_ICMSG_HEARTBEAT_SIZE_MIN) { | |||||
device_printf(sc->ic_dev, "invalid heartbeat len %d\n", | |||||
dlen); | |||||
return; | |||||
} | } | ||||
((struct vmbus_icmsg_heartbeat *)data)->ic_seq++; | |||||
break; | |||||
icmsghdrp->icflags = HV_ICMSGHDRFLAG_TRANSACTION | | default: | ||||
HV_ICMSGHDRFLAG_RESPONSE; | device_printf(sc->ic_dev, "got 0x%08x icmsg\n", hdr->ic_type); | ||||
break; | |||||
} | |||||
vmbus_chan_send(channel, VMBUS_CHANPKT_TYPE_INBAND, 0, | /* | ||||
buf, recvlen, requestid); | * Send response by echoing the updated request back. | ||||
*/ | |||||
hdr->ic_flags = VMBUS_ICMSG_FLAG_XACT | VMBUS_ICMSG_FLAG_RESP; | |||||
error = vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_INBAND, 0, | |||||
data, dlen, xactid); | |||||
if (error) | |||||
device_printf(sc->ic_dev, "resp send failed: %d\n", error); | |||||
} | } | ||||
} | |||||
static int | static int | ||||
hv_heartbeat_probe(device_t dev) | hv_heartbeat_probe(device_t dev) | ||||
{ | { | ||||
return (vmbus_ic_probe(dev, vmbus_heartbeat_descs)); | return (vmbus_ic_probe(dev, vmbus_heartbeat_descs)); | ||||
} | } | ||||
static int | static int | ||||
hv_heartbeat_attach(device_t dev) | hv_heartbeat_attach(device_t dev) | ||||
{ | { | ||||
return hv_util_attach(dev, hv_heartbeat_cb); | |||||
return (hv_util_attach(dev, vmbus_heartbeat_cb)); | |||||
} | } | ||||
static device_method_t heartbeat_methods[] = { | static device_method_t heartbeat_methods[] = { | ||||
/* Device interface */ | /* Device interface */ | ||||
DEVMETHOD(device_probe, hv_heartbeat_probe), | DEVMETHOD(device_probe, hv_heartbeat_probe), | ||||
DEVMETHOD(device_attach, hv_heartbeat_attach), | DEVMETHOD(device_attach, hv_heartbeat_attach), | ||||
DEVMETHOD(device_detach, hv_util_detach), | DEVMETHOD(device_detach, hv_util_detach), | ||||
{ 0, 0 } | { 0, 0 } | ||||
Show All 9 Lines |