summaryrefslogtreecommitdiff
path: root/sys/dev/pv/hyperv.c
diff options
context:
space:
mode:
authorMike Belopuhov <mikeb@cvs.openbsd.org>2016-10-11 11:46:50 +0000
committerMike Belopuhov <mikeb@cvs.openbsd.org>2016-10-11 11:46:50 +0000
commit9d5cacf3308b5c7205c8633103a8ce7a8b7f25e6 (patch)
treee06fc596af20f308418aea6047dff0bd17b72b2c /sys/dev/pv/hyperv.c
parent14b61fa386500850d6df6ed4603d4abd2c4f2641 (diff)
Move Hyper-V integration components into a separate source file
Input & OK reyk.
Diffstat (limited to 'sys/dev/pv/hyperv.c')
-rw-r--r--sys/dev/pv/hyperv.c282
1 files changed, 4 insertions, 278 deletions
diff --git a/sys/dev/pv/hyperv.c b/sys/dev/pv/hyperv.c
index 3798440ef90..1c54dd75e17 100644
--- a/sys/dev/pv/hyperv.c
+++ b/sys/dev/pv/hyperv.c
@@ -103,15 +103,7 @@ struct hv_channel *
hv_channel_lookup(struct hv_softc *, uint32_t);
int hv_channel_ring_create(struct hv_channel *, uint32_t, uint32_t);
void hv_channel_ring_destroy(struct hv_channel *);
-void hv_attach_internal(struct hv_softc *);
-void hv_heartbeat(void *);
-void hv_kvp_init(struct hv_channel *);
-void hv_kvp(void *);
-int hv_kvop(void *, int, char *, char *, size_t);
-void hv_shutdown_init(struct hv_channel *);
-void hv_shutdown(void *);
-void hv_timesync_init(struct hv_channel *);
-void hv_timesync(void *);
+extern void hv_attach_icdevs(struct hv_softc *);
int hv_attach_devices(struct hv_softc *);
struct {
@@ -316,8 +308,6 @@ hv_deferred(void *arg)
if (hv_channel_scan(sc))
return;
- hv_attach_internal(sc);
-
if (hv_attach_devices(sc))
return;
}
@@ -1617,273 +1607,6 @@ hv_handle_free(struct hv_channel *ch, uint32_t handle)
sc->sc_dev.dv_xname, rv);
}
-const struct {
- const char *id_name;
- const struct hv_guid *id_type;
- void (*id_init)(struct hv_channel *);
- void (*id_handler)(void *);
-} hv_internal_devs[] = {
- { "heartbeat", &hv_guid_heartbeat, NULL, hv_heartbeat },
- { "kvp", &hv_guid_kvp, hv_kvp_init, hv_kvp },
- { "shutdown", &hv_guid_shutdown, hv_shutdown_init, hv_shutdown },
- { "timesync", &hv_guid_timesync, hv_timesync_init, hv_timesync }
-};
-
-void
-hv_attach_internal(struct hv_softc *sc)
-{
- struct hv_channel *ch;
- int i;
-
- TAILQ_FOREACH(ch, &sc->sc_channels, ch_entry) {
- if (ch->ch_state != HV_CHANSTATE_OFFERED)
- continue;
- if (ch->ch_flags & CHF_MONITOR)
- continue;
- for (i = 0; i < nitems(hv_internal_devs); i++) {
- if (memcmp(hv_internal_devs[i].id_type, &ch->ch_type,
- sizeof(ch->ch_type)) != 0)
- continue;
- /*
- * These services are not performance critical and
- * do not need batched reading. Furthermore, some
- * services such as KVP can only handle one message
- * from the host at a time.
- */
- ch->ch_flags &= ~CHF_BATCHED;
-
- if (hv_internal_devs[i].id_init)
- hv_internal_devs[i].id_init(ch);
-
- ch->ch_buf = km_alloc(PAGE_SIZE, &kv_any, &kp_zero,
- (cold ? &kd_nowait : &kd_waitok));
- if (ch->ch_buf == NULL) {
- hv_channel_ring_destroy(ch);
- printf("%s: failed to allocate channel data "
- "buffer for \"%s\"", sc->sc_dev.dv_xname,
- hv_internal_devs[i].id_name);
- continue;
- }
- ch->ch_buflen = PAGE_SIZE;
-
- if (hv_channel_open(ch, NULL, 0,
- hv_internal_devs[i].id_handler, ch)) {
- km_free(ch->ch_buf, PAGE_SIZE, &kv_any,
- &kp_zero);
- ch->ch_buf = NULL;
- ch->ch_buflen = 0;
- printf("%s: failed to open channel for \"%s\"\n",
- sc->sc_dev.dv_xname,
- hv_internal_devs[i].id_name);
- }
- evcount_attach(&ch->ch_evcnt,
- hv_internal_devs[i].id_name, &sc->sc_idtvec);
- break;
- }
- }
-}
-
-int
-hv_service_common(struct hv_channel *ch, uint32_t *rlen, uint64_t *rid,
- struct hv_icmsg_hdr **hdr)
-{
- struct hv_icmsg_negotiate *msg;
- int rv;
-
- rv = hv_channel_recv(ch, ch->ch_buf, ch->ch_buflen, rlen, rid, 0);
- if (rv || *rlen == 0)
- return (rv);
- *hdr = (struct hv_icmsg_hdr *)&ch->ch_buf[sizeof(struct hv_pipe_hdr)];
- if ((*hdr)->icmsgtype == HV_ICMSGTYPE_NEGOTIATE) {
- msg = (struct hv_icmsg_negotiate *)(*hdr + 1);
- if (msg->icframe_vercnt >= 2 &&
- msg->icversion_data[1].major == 3) {
- msg->icversion_data[0].major = 3;
- msg->icversion_data[0].minor = 0;
- msg->icversion_data[1].major = 3;
- msg->icversion_data[1].minor = 0;
- } else {
- msg->icversion_data[0].major = 1;
- msg->icversion_data[0].minor = 0;
- msg->icversion_data[1].major = 1;
- msg->icversion_data[1].minor = 0;
- }
- msg->icframe_vercnt = 1;
- msg->icmsg_vercnt = 1;
- (*hdr)->icmsgsize = 0x10;
- }
- return (0);
-}
-
-void
-hv_heartbeat(void *arg)
-{
- struct hv_channel *ch = arg;
- struct hv_softc *sc = ch->ch_sc;
- struct hv_icmsg_hdr *hdr;
- struct hv_heartbeat_msg *msg;
- uint64_t rid;
- uint32_t rlen;
- int rv;
-
- rv = hv_service_common(ch, &rlen, &rid, &hdr);
- if (rv || rlen == 0) {
- if (rv != EAGAIN)
- printf("heartbeat: rv=%d rlen=%u\n", rv, rlen);
- return;
- }
- if (hdr->icmsgtype == HV_ICMSGTYPE_HEARTBEAT) {
- msg = (struct hv_heartbeat_msg *)(hdr + 1);
- msg->seq_num += 1;
- } else if (hdr->icmsgtype != HV_ICMSGTYPE_NEGOTIATE) {
- printf("%s: unhandled heartbeat message type %u\n",
- sc->sc_dev.dv_xname, hdr->icmsgtype);
- }
- hdr->icflags = HV_ICMSGHDRFLAG_TRANSACTION | HV_ICMSGHDRFLAG_RESPONSE;
- hv_channel_send(ch, ch->ch_buf, rlen, rid, VMBUS_CHANPKT_TYPE_INBAND, 0);
-}
-
-void
-hv_kvp_init(struct hv_channel *ch)
-{
- struct hv_softc *sc = ch->ch_sc;
-
- sc->sc_pvbus->hv_kvop = hv_kvop;
- sc->sc_pvbus->hv_arg = sc;
-}
-
-void
-hv_kvp(void *arg)
-{
-}
-
-int
-hv_kvop(void *arg, int op, char *key, char *value, size_t valuelen)
-{
- switch (op) {
- case PVBUS_KVWRITE:
- case PVBUS_KVREAD:
- default:
- return (EOPNOTSUPP);
- }
-}
-
-static void
-hv_shutdown_task(void *arg)
-{
- extern int allowpowerdown;
-
- if (allowpowerdown == 0)
- return;
-
- suspend_randomness();
-
- log(LOG_KERN | LOG_NOTICE, "Shutting down in response to "
- "request from Hyper-V host\n");
- prsignal(initprocess, SIGUSR2);
-}
-
-void
-hv_shutdown_init(struct hv_channel *ch)
-{
- struct hv_softc *sc = ch->ch_sc;
-
- task_set(&sc->sc_sdtask, hv_shutdown_task, sc);
-}
-
-void
-hv_shutdown(void *arg)
-{
- struct hv_channel *ch = arg;
- struct hv_softc *sc = ch->ch_sc;
- struct hv_icmsg_hdr *hdr;
- struct hv_shutdown_msg *msg;
- uint64_t rid;
- uint32_t rlen;
- int rv, shutdown = 0;
-
- rv = hv_service_common(ch, &rlen, &rid, &hdr);
- if (rv || rlen == 0) {
- if (rv != EAGAIN)
- printf("shutdown: rv=%d rlen=%u\n", rv, rlen);
- return;
- }
- if (hdr->icmsgtype == HV_ICMSGTYPE_SHUTDOWN) {
- msg = (struct hv_shutdown_msg *)(hdr + 1);
- if (msg->flags == 0 || msg->flags == 1) {
- shutdown = 1;
- hdr->status = HV_ICMSG_STATUS_OK;
- } else
- hdr->status = HV_ICMSG_STATUS_FAIL;
- } else if (hdr->icmsgtype != HV_ICMSGTYPE_NEGOTIATE) {
- printf("%s: unhandled shutdown message type %u\n",
- sc->sc_dev.dv_xname, hdr->icmsgtype);
- }
-
- hdr->icflags = HV_ICMSGHDRFLAG_TRANSACTION | HV_ICMSGHDRFLAG_RESPONSE;
- hv_channel_send(ch, ch->ch_buf, rlen, rid, VMBUS_CHANPKT_TYPE_INBAND, 0);
-
- if (shutdown)
- task_add(systq, &sc->sc_sdtask);
-}
-
-void
-hv_timesync_init(struct hv_channel *ch)
-{
- struct hv_softc *sc = ch->ch_sc;
-
- strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
- sizeof(sc->sc_sensordev.xname));
-
- sc->sc_sensor.type = SENSOR_TIMEDELTA;
- sc->sc_sensor.status = SENSOR_S_UNKNOWN;
-
- sensor_attach(&sc->sc_sensordev, &sc->sc_sensor);
- sensordev_install(&sc->sc_sensordev);
-}
-
-void
-hv_timesync(void *arg)
-{
- struct hv_channel *ch = arg;
- struct hv_softc *sc = ch->ch_sc;
- struct hv_icmsg_hdr *hdr;
- struct hv_timesync_msg *msg;
- struct timespec guest, host, diff;
- uint64_t tns;
- uint64_t rid;
- uint32_t rlen;
- int rv;
-
- rv = hv_service_common(ch, &rlen, &rid, &hdr);
- if (rv || rlen == 0) {
- if (rv != EAGAIN)
- printf("timesync: rv=%d rlen=%u\n", rv, rlen);
- return;
- }
- if (hdr->icmsgtype == HV_ICMSGTYPE_TIMESYNC) {
- msg = (struct hv_timesync_msg *)(hdr + 1);
- if (msg->flags == HV_TIMESYNC_SYNC ||
- msg->flags == HV_TIMESYNC_SAMPLE) {
- microtime(&sc->sc_sensor.tv);
- nanotime(&guest);
- tns = (msg->parent_time - 116444736000000000LL) * 100;
- host.tv_sec = tns / 1000000000LL;
- host.tv_nsec = tns % 1000000000LL;
- timespecsub(&guest, &host, &diff);
- sc->sc_sensor.value = (int64_t)diff.tv_sec *
- 1000000000LL + diff.tv_nsec;
- sc->sc_sensor.status = SENSOR_S_OK;
- }
- } else if (hdr->icmsgtype != HV_ICMSGTYPE_NEGOTIATE) {
- printf("%s: unhandled timesync message type %u\n",
- sc->sc_dev.dv_xname, hdr->icmsgtype);
- }
-
- hdr->icflags = HV_ICMSGHDRFLAG_TRANSACTION | HV_ICMSGHDRFLAG_RESPONSE;
- hv_channel_send(ch, ch->ch_buf, rlen, rid, VMBUS_CHANPKT_TYPE_INBAND, 0);
-}
-
static int
hv_attach_print(void *aux, const char *name)
{
@@ -1904,6 +1627,9 @@ hv_attach_devices(struct hv_softc *sc)
SLIST_INIT(&sc->sc_devs);
mtx_init(&sc->sc_devlck, IPL_NET);
+ /* Attach heartbeat, KVP and other "internal" services */
+ hv_attach_icdevs(sc);
+
TAILQ_FOREACH(ch, &sc->sc_channels, ch_entry) {
if (ch->ch_state != HV_CHANSTATE_OFFERED)
continue;