summaryrefslogtreecommitdiffstats
path: root/sys/dev/hyperv/vmbus
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/hyperv/vmbus')
-rw-r--r--sys/dev/hyperv/vmbus/vmbus.c233
-rw-r--r--sys/dev/hyperv/vmbus/vmbus_var.h2
-rw-r--r--sys/dev/hyperv/vmbus/vmbus_xact.c313
3 files changed, 357 insertions, 191 deletions
diff --git a/sys/dev/hyperv/vmbus/vmbus.c b/sys/dev/hyperv/vmbus/vmbus.c
index 27e72fe..d6c47ba 100644
--- a/sys/dev/hyperv/vmbus/vmbus.c
+++ b/sys/dev/hyperv/vmbus/vmbus.c
@@ -52,6 +52,7 @@ __FBSDID("$FreeBSD$");
#include <contrib/dev/acpica/include/acpi.h>
#include <dev/hyperv/include/hyperv.h>
+#include <dev/hyperv/include/vmbus_xact.h>
#include <dev/hyperv/vmbus/hyperv_reg.h>
#include <dev/hyperv/vmbus/hyperv_var.h>
#include <dev/hyperv/vmbus/vmbus_reg.h>
@@ -64,25 +65,10 @@ __FBSDID("$FreeBSD$");
#define VMBUS_GPADL_START 0xe1e10
struct vmbus_msghc {
- struct hypercall_postmsg_in *mh_inprm;
+ struct vmbus_xact *mh_xact;
struct hypercall_postmsg_in mh_inprm_save;
- struct hyperv_dma mh_inprm_dma;
-
- struct vmbus_message *mh_resp;
- struct vmbus_message mh_resp0;
-};
-
-struct vmbus_msghc_ctx {
- struct vmbus_msghc *mhc_free;
- struct mtx mhc_free_lock;
- uint32_t mhc_flags;
-
- struct vmbus_msghc *mhc_active;
- struct mtx mhc_active_lock;
};
-#define VMBUS_MSGHC_CTXF_DESTROY 0x0001
-
static int vmbus_probe(device_t);
static int vmbus_attach(device_t);
static int vmbus_detach(device_t);
@@ -118,15 +104,6 @@ static int vmbus_doattach(struct vmbus_softc *);
static void vmbus_event_proc_dummy(struct vmbus_softc *,
int);
-static struct vmbus_msghc_ctx *vmbus_msghc_ctx_create(bus_dma_tag_t);
-static void vmbus_msghc_ctx_destroy(
- struct vmbus_msghc_ctx *);
-static void vmbus_msghc_ctx_free(struct vmbus_msghc_ctx *);
-static struct vmbus_msghc *vmbus_msghc_alloc(bus_dma_tag_t);
-static void vmbus_msghc_free(struct vmbus_msghc *);
-static struct vmbus_msghc *vmbus_msghc_get1(struct vmbus_msghc_ctx *,
- uint32_t);
-
static struct vmbus_softc *vmbus_sc;
extern inthand_t IDTVEC(rsvd), IDTVEC(vmbus_isr);
@@ -184,85 +161,6 @@ vmbus_get_softc(void)
return vmbus_sc;
}
-static struct vmbus_msghc *
-vmbus_msghc_alloc(bus_dma_tag_t parent_dtag)
-{
- struct vmbus_msghc *mh;
-
- mh = malloc(sizeof(*mh), M_DEVBUF, M_WAITOK | M_ZERO);
-
- mh->mh_inprm = hyperv_dmamem_alloc(parent_dtag,
- HYPERCALL_PARAM_ALIGN, 0, HYPERCALL_POSTMSGIN_SIZE,
- &mh->mh_inprm_dma, BUS_DMA_WAITOK);
- if (mh->mh_inprm == NULL) {
- free(mh, M_DEVBUF);
- return NULL;
- }
- return mh;
-}
-
-static void
-vmbus_msghc_free(struct vmbus_msghc *mh)
-{
- hyperv_dmamem_free(&mh->mh_inprm_dma, mh->mh_inprm);
- free(mh, M_DEVBUF);
-}
-
-static void
-vmbus_msghc_ctx_free(struct vmbus_msghc_ctx *mhc)
-{
- KASSERT(mhc->mhc_active == NULL, ("still have active msg hypercall"));
- KASSERT(mhc->mhc_free == NULL, ("still have hypercall msg"));
-
- mtx_destroy(&mhc->mhc_free_lock);
- mtx_destroy(&mhc->mhc_active_lock);
- free(mhc, M_DEVBUF);
-}
-
-static struct vmbus_msghc_ctx *
-vmbus_msghc_ctx_create(bus_dma_tag_t parent_dtag)
-{
- struct vmbus_msghc_ctx *mhc;
-
- mhc = malloc(sizeof(*mhc), M_DEVBUF, M_WAITOK | M_ZERO);
- mtx_init(&mhc->mhc_free_lock, "vmbus msghc free", NULL, MTX_DEF);
- mtx_init(&mhc->mhc_active_lock, "vmbus msghc act", NULL, MTX_DEF);
-
- mhc->mhc_free = vmbus_msghc_alloc(parent_dtag);
- if (mhc->mhc_free == NULL) {
- vmbus_msghc_ctx_free(mhc);
- return NULL;
- }
- return mhc;
-}
-
-static struct vmbus_msghc *
-vmbus_msghc_get1(struct vmbus_msghc_ctx *mhc, uint32_t dtor_flag)
-{
- struct vmbus_msghc *mh;
-
- mtx_lock(&mhc->mhc_free_lock);
-
- while ((mhc->mhc_flags & dtor_flag) == 0 && mhc->mhc_free == NULL) {
- mtx_sleep(&mhc->mhc_free, &mhc->mhc_free_lock, 0,
- "gmsghc", 0);
- }
- if (mhc->mhc_flags & dtor_flag) {
- /* Being destroyed */
- mh = NULL;
- } else {
- mh = mhc->mhc_free;
- KASSERT(mh != NULL, ("no free hypercall msg"));
- KASSERT(mh->mh_resp == NULL,
- ("hypercall msg has pending response"));
- mhc->mhc_free = NULL;
- }
-
- mtx_unlock(&mhc->mhc_free_lock);
-
- return mh;
-}
-
void
vmbus_msghc_reset(struct vmbus_msghc *mh, size_t dsize)
{
@@ -271,7 +169,7 @@ vmbus_msghc_reset(struct vmbus_msghc *mh, size_t dsize)
if (dsize > HYPERCALL_POSTMSGIN_DSIZE_MAX)
panic("invalid data size %zu", dsize);
- inprm = mh->mh_inprm;
+ inprm = vmbus_xact_req_data(mh->mh_xact);
memset(inprm, 0, HYPERCALL_POSTMSGIN_SIZE);
inprm->hc_connid = VMBUS_CONNID_MESSAGE;
inprm->hc_msgtype = HYPERV_MSGTYPE_CHANNEL;
@@ -282,63 +180,50 @@ struct vmbus_msghc *
vmbus_msghc_get(struct vmbus_softc *sc, size_t dsize)
{
struct vmbus_msghc *mh;
+ struct vmbus_xact *xact;
if (dsize > HYPERCALL_POSTMSGIN_DSIZE_MAX)
panic("invalid data size %zu", dsize);
- mh = vmbus_msghc_get1(sc->vmbus_msg_hc, VMBUS_MSGHC_CTXF_DESTROY);
- if (mh == NULL)
- return NULL;
+ xact = vmbus_xact_get(sc->vmbus_xc,
+ dsize + __offsetof(struct hypercall_postmsg_in, hc_data[0]));
+ if (xact == NULL)
+ return (NULL);
+
+ mh = vmbus_xact_priv(xact, sizeof(*mh));
+ mh->mh_xact = xact;
vmbus_msghc_reset(mh, dsize);
- return mh;
+ return (mh);
}
void
-vmbus_msghc_put(struct vmbus_softc *sc, struct vmbus_msghc *mh)
+vmbus_msghc_put(struct vmbus_softc *sc __unused, struct vmbus_msghc *mh)
{
- struct vmbus_msghc_ctx *mhc = sc->vmbus_msg_hc;
-
- KASSERT(mhc->mhc_active == NULL, ("msg hypercall is active"));
- mh->mh_resp = NULL;
- mtx_lock(&mhc->mhc_free_lock);
- KASSERT(mhc->mhc_free == NULL, ("has free hypercall msg"));
- mhc->mhc_free = mh;
- mtx_unlock(&mhc->mhc_free_lock);
- wakeup(&mhc->mhc_free);
+ vmbus_xact_put(mh->mh_xact);
}
void *
vmbus_msghc_dataptr(struct vmbus_msghc *mh)
{
- return mh->mh_inprm->hc_data;
-}
-
-static void
-vmbus_msghc_ctx_destroy(struct vmbus_msghc_ctx *mhc)
-{
- struct vmbus_msghc *mh;
-
- mtx_lock(&mhc->mhc_free_lock);
- mhc->mhc_flags |= VMBUS_MSGHC_CTXF_DESTROY;
- mtx_unlock(&mhc->mhc_free_lock);
- wakeup(&mhc->mhc_free);
-
- mh = vmbus_msghc_get1(mhc, 0);
- if (mh == NULL)
- panic("can't get msghc");
+ struct hypercall_postmsg_in *inprm;
- vmbus_msghc_free(mh);
- vmbus_msghc_ctx_free(mhc);
+ inprm = vmbus_xact_req_data(mh->mh_xact);
+ return (inprm->hc_data);
}
int
vmbus_msghc_exec_noresult(struct vmbus_msghc *mh)
{
sbintime_t time = SBT_1MS;
+ struct hypercall_postmsg_in *inprm;
+ bus_addr_t inprm_paddr;
int i;
+ inprm = vmbus_xact_req_data(mh->mh_xact);
+ inprm_paddr = vmbus_xact_req_paddr(mh->mh_xact);
+
/*
* Save the input parameter so that we could restore the input
* parameter if the Hypercall failed.
@@ -347,7 +232,7 @@ vmbus_msghc_exec_noresult(struct vmbus_msghc *mh)
* Is this really necessary?! i.e. Will the Hypercall ever
* overwrite the input parameter?
*/
- memcpy(&mh->mh_inprm_save, mh->mh_inprm, HYPERCALL_POSTMSGIN_SIZE);
+ memcpy(&mh->mh_inprm_save, inprm, HYPERCALL_POSTMSGIN_SIZE);
/*
* In order to cope with transient failures, e.g. insufficient
@@ -359,7 +244,7 @@ vmbus_msghc_exec_noresult(struct vmbus_msghc *mh)
for (i = 0; i < HC_RETRY_MAX; ++i) {
uint64_t status;
- status = hypercall_post_message(mh->mh_inprm_dma.hv_paddr);
+ status = hypercall_post_message(inprm_paddr);
if (status == HYPERCALL_STATUS_SUCCESS)
return 0;
@@ -368,8 +253,7 @@ vmbus_msghc_exec_noresult(struct vmbus_msghc *mh)
time *= 2;
/* Restore input parameter and try again */
- memcpy(mh->mh_inprm, &mh->mh_inprm_save,
- HYPERCALL_POSTMSGIN_SIZE);
+ memcpy(inprm, &mh->mh_inprm_save, HYPERCALL_POSTMSGIN_SIZE);
}
#undef HC_RETRY_MAX
@@ -378,62 +262,30 @@ vmbus_msghc_exec_noresult(struct vmbus_msghc *mh)
}
int
-vmbus_msghc_exec(struct vmbus_softc *sc, struct vmbus_msghc *mh)
+vmbus_msghc_exec(struct vmbus_softc *sc __unused, struct vmbus_msghc *mh)
{
- struct vmbus_msghc_ctx *mhc = sc->vmbus_msg_hc;
int error;
- KASSERT(mh->mh_resp == NULL, ("hypercall msg has pending response"));
-
- mtx_lock(&mhc->mhc_active_lock);
- KASSERT(mhc->mhc_active == NULL, ("pending active msg hypercall"));
- mhc->mhc_active = mh;
- mtx_unlock(&mhc->mhc_active_lock);
-
+ vmbus_xact_activate(mh->mh_xact);
error = vmbus_msghc_exec_noresult(mh);
- if (error) {
- mtx_lock(&mhc->mhc_active_lock);
- KASSERT(mhc->mhc_active == mh, ("msghc mismatch"));
- mhc->mhc_active = NULL;
- mtx_unlock(&mhc->mhc_active_lock);
- }
+ if (error)
+ vmbus_xact_deactivate(mh->mh_xact);
return error;
}
const struct vmbus_message *
-vmbus_msghc_wait_result(struct vmbus_softc *sc, struct vmbus_msghc *mh)
+vmbus_msghc_wait_result(struct vmbus_softc *sc __unused, struct vmbus_msghc *mh)
{
- struct vmbus_msghc_ctx *mhc = sc->vmbus_msg_hc;
-
- mtx_lock(&mhc->mhc_active_lock);
-
- KASSERT(mhc->mhc_active == mh, ("msghc mismatch"));
- while (mh->mh_resp == NULL) {
- mtx_sleep(&mhc->mhc_active, &mhc->mhc_active_lock, 0,
- "wmsghc", 0);
- }
- mhc->mhc_active = NULL;
+ size_t resp_len;
- mtx_unlock(&mhc->mhc_active_lock);
-
- return mh->mh_resp;
+ return (vmbus_xact_wait(mh->mh_xact, &resp_len));
}
void
vmbus_msghc_wakeup(struct vmbus_softc *sc, const struct vmbus_message *msg)
{
- struct vmbus_msghc_ctx *mhc = sc->vmbus_msg_hc;
- struct vmbus_msghc *mh;
-
- mtx_lock(&mhc->mhc_active_lock);
-
- mh = mhc->mhc_active;
- KASSERT(mh != NULL, ("no pending msg hypercall"));
- memcpy(&mh->mh_resp0, msg, sizeof(mh->mh_resp0));
- mh->mh_resp = &mh->mh_resp0;
- mtx_unlock(&mhc->mhc_active_lock);
- wakeup(&mhc->mhc_active);
+ vmbus_xact_ctx_wakeup(sc->vmbus_xc, msg, sizeof(*msg));
}
uint32_t
@@ -1269,9 +1121,10 @@ vmbus_doattach(struct vmbus_softc *sc)
/*
* Create context for "post message" Hypercalls
*/
- sc->vmbus_msg_hc = vmbus_msghc_ctx_create(
- bus_get_dma_tag(sc->vmbus_dev));
- if (sc->vmbus_msg_hc == NULL) {
+ sc->vmbus_xc = vmbus_xact_ctx_create(bus_get_dma_tag(sc->vmbus_dev),
+ HYPERCALL_POSTMSGIN_SIZE, VMBUS_MSG_SIZE,
+ sizeof(struct vmbus_msghc));
+ if (sc->vmbus_xc == NULL) {
ret = ENXIO;
goto cleanup;
}
@@ -1326,9 +1179,9 @@ vmbus_doattach(struct vmbus_softc *sc)
cleanup:
vmbus_intr_teardown(sc);
vmbus_dma_free(sc);
- if (sc->vmbus_msg_hc != NULL) {
- vmbus_msghc_ctx_destroy(sc->vmbus_msg_hc);
- sc->vmbus_msg_hc = NULL;
+ if (sc->vmbus_xc != NULL) {
+ vmbus_xact_ctx_destroy(sc->vmbus_xc);
+ sc->vmbus_xc = NULL;
}
free(sc->vmbus_chmap, M_DEVBUF);
mtx_destroy(&sc->vmbus_scan_lock);
@@ -1384,9 +1237,9 @@ vmbus_detach(device_t dev)
vmbus_intr_teardown(sc);
vmbus_dma_free(sc);
- if (sc->vmbus_msg_hc != NULL) {
- vmbus_msghc_ctx_destroy(sc->vmbus_msg_hc);
- sc->vmbus_msg_hc = NULL;
+ if (sc->vmbus_xc != NULL) {
+ vmbus_xact_ctx_destroy(sc->vmbus_xc);
+ sc->vmbus_xc = NULL;
}
free(sc->vmbus_chmap, M_DEVBUF);
diff --git a/sys/dev/hyperv/vmbus/vmbus_var.h b/sys/dev/hyperv/vmbus/vmbus_var.h
index c278c15..47d9004 100644
--- a/sys/dev/hyperv/vmbus/vmbus_var.h
+++ b/sys/dev/hyperv/vmbus/vmbus_var.h
@@ -86,7 +86,7 @@ struct vmbus_softc {
u_long *vmbus_rx_evtflags;
/* compat evtflgs from host */
struct vmbus_channel **vmbus_chmap;
- struct vmbus_msghc_ctx *vmbus_msg_hc;
+ struct vmbus_xact_ctx *vmbus_xc;
struct vmbus_pcpu_data vmbus_pcpu[MAXCPU];
/*
diff --git a/sys/dev/hyperv/vmbus/vmbus_xact.c b/sys/dev/hyperv/vmbus/vmbus_xact.c
new file mode 100644
index 0000000..642c165
--- /dev/null
+++ b/sys/dev/hyperv/vmbus/vmbus_xact.c
@@ -0,0 +1,313 @@
+/*-
+ * Copyright (c) 2016 Microsoft Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/systm.h>
+
+#include <dev/hyperv/include/hyperv_busdma.h>
+#include <dev/hyperv/include/vmbus_xact.h>
+
+struct vmbus_xact {
+ struct vmbus_xact_ctx *x_ctx;
+ void *x_priv;
+
+ void *x_req;
+ struct hyperv_dma x_req_dma;
+
+ const void *x_resp;
+ size_t x_resp_len;
+ void *x_resp0;
+};
+
+struct vmbus_xact_ctx {
+ uint32_t xc_flags;
+ size_t xc_req_size;
+ size_t xc_resp_size;
+ size_t xc_priv_size;
+
+ struct vmbus_xact *xc_free;
+ struct mtx xc_free_lock;
+
+ struct vmbus_xact *xc_active;
+ struct mtx xc_active_lock;
+};
+
+#define VMBUS_XACT_CTXF_DESTROY 0x0001
+
+static struct vmbus_xact *vmbus_xact_alloc(struct vmbus_xact_ctx *,
+ bus_dma_tag_t);
+static void vmbus_xact_free(struct vmbus_xact *);
+static struct vmbus_xact *vmbus_xact_get1(struct vmbus_xact_ctx *,
+ uint32_t);
+
+static struct vmbus_xact *
+vmbus_xact_alloc(struct vmbus_xact_ctx *ctx, bus_dma_tag_t parent_dtag)
+{
+ struct vmbus_xact *xact;
+
+ xact = malloc(sizeof(*xact), M_DEVBUF, M_WAITOK | M_ZERO);
+ xact->x_ctx = ctx;
+
+ /* XXX assume that page aligned is enough */
+ xact->x_req = hyperv_dmamem_alloc(parent_dtag, PAGE_SIZE, 0,
+ ctx->xc_req_size, &xact->x_req_dma, BUS_DMA_WAITOK);
+ if (xact->x_req == NULL) {
+ free(xact, M_DEVBUF);
+ return (NULL);
+ }
+ if (ctx->xc_priv_size != 0)
+ xact->x_priv = malloc(ctx->xc_priv_size, M_DEVBUF, M_WAITOK);
+ xact->x_resp0 = malloc(ctx->xc_resp_size, M_DEVBUF, M_WAITOK);
+
+ return (xact);
+}
+
+static void
+vmbus_xact_free(struct vmbus_xact *xact)
+{
+
+ hyperv_dmamem_free(&xact->x_req_dma, xact->x_req);
+ free(xact->x_resp0, M_DEVBUF);
+ if (xact->x_priv != NULL)
+ free(xact->x_priv, M_DEVBUF);
+ free(xact, M_DEVBUF);
+}
+
+static struct vmbus_xact *
+vmbus_xact_get1(struct vmbus_xact_ctx *ctx, uint32_t dtor_flag)
+{
+ struct vmbus_xact *xact;
+
+ mtx_lock(&ctx->xc_free_lock);
+
+ while ((ctx->xc_flags & dtor_flag) == 0 && ctx->xc_free == NULL)
+ mtx_sleep(&ctx->xc_free, &ctx->xc_free_lock, 0, "gxact", 0);
+ if (ctx->xc_flags & dtor_flag) {
+ /* Being destroyed */
+ xact = NULL;
+ } else {
+ xact = ctx->xc_free;
+ KASSERT(xact != NULL, ("no free xact"));
+ KASSERT(xact->x_resp == NULL, ("xact has pending response"));
+ ctx->xc_free = NULL;
+ }
+
+ mtx_unlock(&ctx->xc_free_lock);
+
+ return (xact);
+}
+
+struct vmbus_xact_ctx *
+vmbus_xact_ctx_create(bus_dma_tag_t dtag, size_t req_size, size_t resp_size,
+ size_t priv_size)
+{
+ struct vmbus_xact_ctx *ctx;
+
+ ctx = malloc(sizeof(*ctx), M_DEVBUF, M_WAITOK | M_ZERO);
+ ctx->xc_req_size = req_size;
+ ctx->xc_resp_size = resp_size;
+ ctx->xc_priv_size = priv_size;
+
+ ctx->xc_free = vmbus_xact_alloc(ctx, dtag);
+ if (ctx->xc_free == NULL) {
+ free(ctx, M_DEVBUF);
+ return (NULL);
+ }
+
+ mtx_init(&ctx->xc_free_lock, "vmbus xact free", NULL, MTX_DEF);
+ mtx_init(&ctx->xc_active_lock, "vmbus xact active", NULL, MTX_DEF);
+
+ return (ctx);
+}
+
+void
+vmbus_xact_ctx_destroy(struct vmbus_xact_ctx *ctx)
+{
+ struct vmbus_xact *xact;
+
+ mtx_lock(&ctx->xc_free_lock);
+ ctx->xc_flags |= VMBUS_XACT_CTXF_DESTROY;
+ mtx_unlock(&ctx->xc_free_lock);
+ wakeup(&ctx->xc_free);
+
+ xact = vmbus_xact_get1(ctx, 0);
+ if (xact == NULL)
+ panic("can't get xact");
+
+ vmbus_xact_free(xact);
+ mtx_destroy(&ctx->xc_free_lock);
+ mtx_destroy(&ctx->xc_active_lock);
+ free(ctx, M_DEVBUF);
+}
+
+struct vmbus_xact *
+vmbus_xact_get(struct vmbus_xact_ctx *ctx, size_t req_len)
+{
+ struct vmbus_xact *xact;
+
+ if (req_len > ctx->xc_req_size)
+ panic("invalid request size %zu", req_len);
+
+ xact = vmbus_xact_get1(ctx, VMBUS_XACT_CTXF_DESTROY);
+ if (xact == NULL)
+ return (NULL);
+
+ memset(xact->x_req, 0, req_len);
+ return (xact);
+}
+
+void
+vmbus_xact_put(struct vmbus_xact *xact)
+{
+ struct vmbus_xact_ctx *ctx = xact->x_ctx;
+
+ KASSERT(ctx->xc_active == NULL, ("pending active xact"));
+ xact->x_resp = NULL;
+
+ mtx_lock(&ctx->xc_free_lock);
+ KASSERT(ctx->xc_free == NULL, ("has free xact"));
+ ctx->xc_free = xact;
+ mtx_unlock(&ctx->xc_free_lock);
+ wakeup(&ctx->xc_free);
+}
+
+void *
+vmbus_xact_req_data(const struct vmbus_xact *xact)
+{
+
+ return (xact->x_req);
+}
+
+bus_addr_t
+vmbus_xact_req_paddr(const struct vmbus_xact *xact)
+{
+
+ return (xact->x_req_dma.hv_paddr);
+}
+
+void *
+vmbus_xact_priv(const struct vmbus_xact *xact, size_t priv_len)
+{
+
+ if (priv_len > xact->x_ctx->xc_priv_size)
+ panic("invalid priv size %zu", priv_len);
+ return (xact->x_priv);
+}
+
+void
+vmbus_xact_activate(struct vmbus_xact *xact)
+{
+ struct vmbus_xact_ctx *ctx = xact->x_ctx;
+
+ KASSERT(xact->x_resp == NULL, ("xact has pending response"));
+
+ mtx_lock(&ctx->xc_active_lock);
+ KASSERT(ctx->xc_active == NULL, ("pending active xact"));
+ ctx->xc_active = xact;
+ mtx_unlock(&ctx->xc_active_lock);
+}
+
+void
+vmbus_xact_deactivate(struct vmbus_xact *xact)
+{
+ struct vmbus_xact_ctx *ctx = xact->x_ctx;
+
+ mtx_lock(&ctx->xc_active_lock);
+ KASSERT(ctx->xc_active == xact, ("xact mismatch"));
+ ctx->xc_active = NULL;
+ mtx_unlock(&ctx->xc_active_lock);
+}
+
+const void *
+vmbus_xact_wait(struct vmbus_xact *xact, size_t *resp_len)
+{
+ struct vmbus_xact_ctx *ctx = xact->x_ctx;
+ const void *resp;
+
+ mtx_lock(&ctx->xc_active_lock);
+
+ KASSERT(ctx->xc_active == xact, ("xact mismatch"));
+ while (xact->x_resp == NULL) {
+ mtx_sleep(&ctx->xc_active, &ctx->xc_active_lock, 0,
+ "wxact", 0);
+ }
+ ctx->xc_active = NULL;
+
+ resp = xact->x_resp;
+ *resp_len = xact->x_resp_len;
+
+ mtx_unlock(&ctx->xc_active_lock);
+
+ return (resp);
+}
+
+static void
+vmbus_xact_save_resp(struct vmbus_xact *xact, const void *data, size_t dlen)
+{
+ struct vmbus_xact_ctx *ctx = xact->x_ctx;
+ size_t cplen = dlen;
+
+ mtx_assert(&ctx->xc_active_lock, MA_OWNED);
+
+ if (cplen > ctx->xc_resp_size) {
+ printf("vmbus: xact response truncated %zu -> %zu\n",
+ cplen, ctx->xc_resp_size);
+ cplen = ctx->xc_resp_size;
+ }
+
+ KASSERT(ctx->xc_active == xact, ("xact mismatch"));
+ memcpy(xact->x_resp0, data, cplen);
+ xact->x_resp_len = cplen;
+ xact->x_resp = xact->x_resp0;
+}
+
+void
+vmbus_xact_wakeup(struct vmbus_xact *xact, const void *data, size_t dlen)
+{
+ struct vmbus_xact_ctx *ctx = xact->x_ctx;
+
+ mtx_lock(&ctx->xc_active_lock);
+ vmbus_xact_save_resp(xact, data, dlen);
+ mtx_unlock(&ctx->xc_active_lock);
+ wakeup(&ctx->xc_active);
+}
+
+void
+vmbus_xact_ctx_wakeup(struct vmbus_xact_ctx *ctx, const void *data, size_t dlen)
+{
+ mtx_lock(&ctx->xc_active_lock);
+ KASSERT(ctx->xc_active != NULL, ("no pending xact"));
+ vmbus_xact_save_resp(ctx->xc_active, data, dlen);
+ mtx_unlock(&ctx->xc_active_lock);
+ wakeup(&ctx->xc_active);
+}
OpenPOWER on IntegriCloud