summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/dev/pv/hyperv.c120
-rw-r--r--sys/dev/pv/hypervvar.h2
2 files changed, 72 insertions, 50 deletions
diff --git a/sys/dev/pv/hyperv.c b/sys/dev/pv/hyperv.c
index bd9a1c3a6d1..985b5949d14 100644
--- a/sys/dev/pv/hyperv.c
+++ b/sys/dev/pv/hyperv.c
@@ -89,6 +89,8 @@ int hv_init_synic(struct hv_softc *);
int hv_cmd(struct hv_softc *, void *, size_t, void *, size_t, int);
int hv_start(struct hv_softc *, struct hv_msg *);
int hv_reply(struct hv_softc *, struct hv_msg *);
+void hv_wait(struct hv_softc *, int (*done)(struct hv_softc *,
+ struct hv_msg *), struct hv_msg *, void *, const char *);
uint16_t hv_intr_signal(struct hv_softc *, void *);
void hv_intr(void);
void hv_event_intr(struct hv_softc *);
@@ -285,7 +287,7 @@ hv_attach(struct device *parent, struct device *self, void *aux)
return;
}
- printf("\n");
+ DPRINTF("\n");
hv_set_version(sc);
@@ -301,6 +303,21 @@ hv_attach(struct device *parent, struct device *self, void *aux)
if (hv_init_interrupts(sc))
return;
+ if (hv_vmbus_connect(sc))
+ return;
+
+ DPRINTF("%s", sc->sc_dev.dv_xname);
+ printf(": protocol %d.%d, features %#x\n",
+ VMBUS_VERSION_MAJOR(sc->sc_proto),
+ VMBUS_VERSION_MINOR(sc->sc_proto),
+ hv->hv_features);
+
+ if (hv_channel_scan(sc))
+ return;
+
+ /* Attach heartbeat, KVP and other "internal" services */
+ hv_attach_icdevs(sc);
+
startuphook_establish(hv_deferred, sc);
}
@@ -309,12 +326,6 @@ hv_deferred(void *arg)
{
struct hv_softc *sc = arg;
- if (hv_vmbus_connect(sc))
- return;
-
- if (hv_channel_scan(sc))
- return;
-
if (hv_attach_devices(sc))
return;
}
@@ -571,47 +582,54 @@ hv_start(struct hv_softc *sc, struct hv_msg *msg)
return (0);
}
+static int
+hv_reply_done(struct hv_softc *sc, struct hv_msg *msg)
+{
+ struct hv_msg *m;
+
+ mtx_enter(&sc->sc_rsplck);
+ TAILQ_FOREACH(m, &sc->sc_rsps, msg_entry) {
+ if (m == msg) {
+ mtx_leave(&sc->sc_rsplck);
+ return (1);
+ }
+ }
+ mtx_leave(&sc->sc_rsplck);
+ return (0);
+}
+
int
hv_reply(struct hv_softc *sc, struct hv_msg *msg)
{
- const char *wchan = "hvreply";
- struct hv_msg *m, *tmp;
- int i, s;
-
if (msg->msg_flags & MSGF_NOQUEUE)
return (0);
- for (i = 0; i < 1000; i++) {
- mtx_enter(&sc->sc_rsplck);
- TAILQ_FOREACH_SAFE(m, &sc->sc_rsps, msg_entry, tmp) {
- if (m == msg) {
- TAILQ_REMOVE(&sc->sc_rsps, m, msg_entry);
- break;
- }
- }
- mtx_leave(&sc->sc_rsplck);
- if (m != NULL)
- return (0);
+ hv_wait(sc, hv_reply_done, msg, msg, "hvreply");
+
+ mtx_enter(&sc->sc_rsplck);
+ TAILQ_REMOVE(&sc->sc_rsps, msg, msg_entry);
+ mtx_leave(&sc->sc_rsplck);
+
+ return (0);
+}
+
+void
+hv_wait(struct hv_softc *sc, int (*cond)(struct hv_softc *, struct hv_msg *),
+ struct hv_msg *msg, void *wchan, const char *wmsg)
+{
+ int s;
+
+ KASSERT(cold ? msg->msg_flags & MSGF_NOSLEEP : 1);
+
+ while (!cond(sc, msg)) {
if (msg->msg_flags & MSGF_NOSLEEP) {
- delay(100000);
+ delay(1000);
s = splnet();
hv_intr();
splx(s);
- } else {
- s = tsleep(&msg, PRIBIO | PCATCH, wchan, 1);
- if (s != EWOULDBLOCK)
- return (EINTR);
- }
- }
- mtx_enter(&sc->sc_rsplck);
- TAILQ_FOREACH_SAFE(m, &sc->sc_reqs, msg_entry, tmp) {
- if (m == msg) {
- TAILQ_REMOVE(&sc->sc_reqs, m, msg_entry);
- break;
- }
+ } else
+ tsleep(wchan, PRIBIO, wmsg ? wmsg : "hvwait", 1);
}
- mtx_leave(&sc->sc_rsplck);
- return (ETIMEDOUT);
}
uint16_t
@@ -730,13 +748,13 @@ hv_message_intr(struct hv_softc *sc)
void
hv_channel_response(struct hv_softc *sc, struct vmbus_chanmsg_hdr *rsphdr)
{
- struct hv_msg *msg, *tmp;
+ struct hv_msg *msg;
struct vmbus_chanmsg_hdr *reqhdr;
int req;
req = hv_msg_dispatch[rsphdr->chm_type].hmd_request;
mtx_enter(&sc->sc_reqlck);
- TAILQ_FOREACH_SAFE(msg, &sc->sc_reqs, msg_entry, tmp) {
+ TAILQ_FOREACH(msg, &sc->sc_reqs, msg_entry) {
reqhdr = (struct vmbus_chanmsg_hdr *)&msg->msg_req.hc_data;
if (reqhdr->chm_type == req) {
TAILQ_REMOVE(&sc->sc_reqs, msg, msg_entry);
@@ -844,8 +862,6 @@ hv_vmbus_connect(struct hv_softc *sc)
sc->sc_flags |= HSF_CONNECTED;
sc->sc_proto = versions[i];
sc->sc_handle = VMBUS_GPADL_START;
- DPRINTF("%s: protocol version %#x\n",
- sc->sc_dev.dv_xname, versions[i]);
break;
}
}
@@ -946,6 +962,12 @@ hv_guid_sprint(struct hv_guid *guid, char *str, size_t size)
#endif
}
+static int
+hv_channel_scan_done(struct hv_softc *sc, struct hv_msg *msg __unused)
+{
+ return (sc->sc_flags & HSF_OFFERS_DELIVERED);
+}
+
int
hv_channel_scan(struct hv_softc *sc)
{
@@ -959,13 +981,14 @@ hv_channel_scan(struct hv_softc *sc)
memset(&hdr, 0, sizeof(hdr));
hdr.chm_type = VMBUS_CHANMSG_CHREQUEST;
- if (hv_cmd(sc, &hdr, sizeof(hdr), &rsp, sizeof(rsp), HCF_NOREPLY)) {
+ if (hv_cmd(sc, &hdr, sizeof(hdr), &rsp, sizeof(rsp),
+ HCF_NOSLEEP | HCF_NOREPLY)) {
DPRINTF("%s: CHREQUEST failed\n", sc->sc_dev.dv_xname);
return (-1);
}
- while ((sc->sc_flags & HSF_OFFERS_DELIVERED) == 0)
- tsleep(&sc->sc_offers, PRIBIO, "hvoffers", 1);
+ hv_wait(sc, hv_channel_scan_done, (struct hv_msg *)&hdr,
+ &sc->sc_offers, "hvscan");
TAILQ_INIT(&sc->sc_channels);
mtx_init(&sc->sc_channelck, IPL_NET);
@@ -1136,7 +1159,8 @@ hv_channel_open(struct hv_channel *ch, size_t buflen, void *udata,
if (ch->ch_ring == NULL &&
hv_channel_ring_create(ch, buflen)) {
- DPRINTF(": failed to create channel ring\n");
+ DPRINTF("%s: failed to create channel ring\n",
+ sc->sc_dev.dv_xname);
return (-1);
}
@@ -1158,7 +1182,8 @@ hv_channel_open(struct hv_channel *ch, size_t buflen, void *udata,
ch->ch_state = HV_CHANSTATE_OPENED;
- rv = hv_cmd(sc, &cmd, sizeof(cmd), &rsp, sizeof(rsp), 0);
+ rv = hv_cmd(sc, &cmd, sizeof(cmd), &rsp, sizeof(rsp),
+ cold ? HCF_NOSLEEP : HCF_SLEEPOK);
if (rv) {
hv_channel_ring_destroy(ch);
DPRINTF("%s: CHOPEN failed with %d\n",
@@ -1632,9 +1657,6 @@ 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;
diff --git a/sys/dev/pv/hypervvar.h b/sys/dev/pv/hypervvar.h
index 2f754677555..425431bb406 100644
--- a/sys/dev/pv/hypervvar.h
+++ b/sys/dev/pv/hypervvar.h
@@ -32,7 +32,7 @@ struct hv_msg {
#define MSGF_NOSLEEP 0x0001
#define MSGF_NOQUEUE 0x0002
#define MSGF_ORPHANED 0x0004
- struct hypercall_postmsg_in msg_req;
+ struct hypercall_postmsg_in msg_req; /* must be 8 byte aligned */
void *msg_rsp;
size_t msg_rsplen;
TAILQ_ENTRY(hv_msg) msg_entry;