Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F153746419
D6878.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
15 KB
Referenced Files
None
Subscribers
None
D6878.diff
View Options
Index: head/sys/dev/hyperv/vmbus/hv_channel.c
===================================================================
--- head/sys/dev/hyperv/vmbus/hv_channel.c
+++ head/sys/dev/hyperv/vmbus/hv_channel.c
@@ -49,14 +49,6 @@
#include <dev/hyperv/vmbus/vmbus_reg.h>
#include <dev/hyperv/vmbus/vmbus_var.h>
-static int vmbus_channel_create_gpadl_header(
- /* must be phys and virt contiguous*/
- void* contig_buffer,
- /* page-size multiple */
- uint32_t size,
- hv_vmbus_channel_msg_info** msg_info,
- uint32_t* message_count);
-
static void vmbus_channel_set_event(hv_vmbus_channel* channel);
static void VmbusProcessChannelEvent(void* channel, int pending);
@@ -309,241 +301,130 @@
}
/**
- * @brief Create a gpadl for the specified buffer
+ * @brief Establish a GPADL for the specified buffer
*/
-static int
-vmbus_channel_create_gpadl_header(
- void* contig_buffer,
- uint32_t size, /* page-size multiple */
- hv_vmbus_channel_msg_info** msg_info,
- uint32_t* message_count)
-{
- int i;
- int page_count;
- unsigned long long pfn;
- uint32_t msg_size;
- hv_vmbus_channel_gpadl_header* gpa_header;
- hv_vmbus_channel_gpadl_body* gpadl_body;
- hv_vmbus_channel_msg_info* msg_header;
- hv_vmbus_channel_msg_info* msg_body;
+int
+hv_vmbus_channel_establish_gpadl(struct hv_vmbus_channel *channel,
+ void *contig_buffer, uint32_t size, uint32_t *gpadl0)
+{
+ struct vmbus_softc *sc = channel->vmbus_sc;
+ struct vmbus_msghc *mh;
+ struct vmbus_chanmsg_gpadl_conn *req;
+ const struct vmbus_message *msg;
+ size_t reqsz;
+ uint32_t gpadl, status;
+ int page_count, range_len, i, cnt, error;
+ uint64_t page_id, paddr;
- int pfnSum, pfnCount, pfnLeft, pfnCurr, pfnSize;
+ /*
+ * Preliminary checks.
+ */
+ KASSERT((size & PAGE_MASK) == 0,
+ ("invalid GPA size %u, not multiple page size", size));
page_count = size >> PAGE_SHIFT;
- pfn = hv_get_phys_addr(contig_buffer) >> PAGE_SHIFT;
-
- /*do we need a gpadl body msg */
- pfnSize = HV_MAX_SIZE_CHANNEL_MESSAGE
- - sizeof(hv_vmbus_channel_gpadl_header)
- - sizeof(hv_gpa_range);
- pfnCount = pfnSize / sizeof(uint64_t);
-
- if (page_count > pfnCount) { /* if(we need a gpadl body) */
- /* fill in the header */
- msg_size = sizeof(hv_vmbus_channel_msg_info)
- + sizeof(hv_vmbus_channel_gpadl_header)
- + sizeof(hv_gpa_range)
- + pfnCount * sizeof(uint64_t);
- msg_header = malloc(msg_size, M_DEVBUF, M_NOWAIT | M_ZERO);
- KASSERT(
- msg_header != NULL,
- ("Error VMBUS: malloc failed to allocate Gpadl Message!"));
- if (msg_header == NULL)
- return (ENOMEM);
-
- TAILQ_INIT(&msg_header->sub_msg_list_anchor);
- msg_header->message_size = msg_size;
-
- gpa_header = (hv_vmbus_channel_gpadl_header*) msg_header->msg;
- gpa_header->range_count = 1;
- gpa_header->range_buf_len = sizeof(hv_gpa_range)
- + page_count * sizeof(uint64_t);
- gpa_header->range[0].byte_offset = 0;
- gpa_header->range[0].byte_count = size;
- for (i = 0; i < pfnCount; i++) {
- gpa_header->range[0].pfn_array[i] = pfn + i;
- }
- *msg_info = msg_header;
- *message_count = 1;
-
- pfnSum = pfnCount;
- pfnLeft = page_count - pfnCount;
-
- /*
- * figure out how many pfns we can fit
- */
- pfnSize = HV_MAX_SIZE_CHANNEL_MESSAGE
- - sizeof(hv_vmbus_channel_gpadl_body);
- pfnCount = pfnSize / sizeof(uint64_t);
-
- /*
- * fill in the body
- */
- while (pfnLeft) {
- if (pfnLeft > pfnCount) {
- pfnCurr = pfnCount;
- } else {
- pfnCurr = pfnLeft;
- }
-
- msg_size = sizeof(hv_vmbus_channel_msg_info) +
- sizeof(hv_vmbus_channel_gpadl_body) +
- pfnCurr * sizeof(uint64_t);
- msg_body = malloc(msg_size, M_DEVBUF, M_NOWAIT | M_ZERO);
- KASSERT(
- msg_body != NULL,
- ("Error VMBUS: malloc failed to allocate Gpadl msg_body!"));
- if (msg_body == NULL)
- return (ENOMEM);
-
- msg_body->message_size = msg_size;
- (*message_count)++;
- gpadl_body =
- (hv_vmbus_channel_gpadl_body*) msg_body->msg;
- /*
- * gpadl_body->gpadl = kbuffer;
- */
- for (i = 0; i < pfnCurr; i++) {
- gpadl_body->pfn[i] = pfn + pfnSum + i;
- }
-
- TAILQ_INSERT_TAIL(
- &msg_header->sub_msg_list_anchor,
- msg_body,
- msg_list_entry);
- pfnSum += pfnCurr;
- pfnLeft -= pfnCurr;
- }
- } else { /* else everything fits in a header */
-
- msg_size = sizeof(hv_vmbus_channel_msg_info) +
- sizeof(hv_vmbus_channel_gpadl_header) +
- sizeof(hv_gpa_range) +
- page_count * sizeof(uint64_t);
- msg_header = malloc(msg_size, M_DEVBUF, M_NOWAIT | M_ZERO);
- KASSERT(
- msg_header != NULL,
- ("Error VMBUS: malloc failed to allocate Gpadl Message!"));
- if (msg_header == NULL)
- return (ENOMEM);
- msg_header->message_size = msg_size;
+ paddr = hv_get_phys_addr(contig_buffer);
+ KASSERT((paddr & PAGE_MASK) == 0,
+ ("GPA is not page aligned %jx", (uintmax_t)paddr));
+ page_id = paddr >> PAGE_SHIFT;
- gpa_header = (hv_vmbus_channel_gpadl_header*) msg_header->msg;
- gpa_header->range_count = 1;
- gpa_header->range_buf_len = sizeof(hv_gpa_range) +
- page_count * sizeof(uint64_t);
- gpa_header->range[0].byte_offset = 0;
- gpa_header->range[0].byte_count = size;
- for (i = 0; i < page_count; i++) {
- gpa_header->range[0].pfn_array[i] = pfn + i;
- }
-
- *msg_info = msg_header;
- *message_count = 1;
+ range_len = __offsetof(struct vmbus_gpa_range, gpa_page[page_count]);
+ /*
+ * We don't support multiple GPA ranges.
+ */
+ if (range_len > UINT16_MAX) {
+ device_printf(sc->vmbus_dev, "GPA too large, %d pages\n",
+ page_count);
+ return EOPNOTSUPP;
}
- return (0);
-}
-
-/**
- * @brief Establish a GPADL for the specified buffer
- */
-int
-hv_vmbus_channel_establish_gpadl(
- hv_vmbus_channel* channel,
- void* contig_buffer,
- uint32_t size, /* page-size multiple */
- uint32_t* gpadl_handle)
-
-{
- int ret = 0;
- hv_vmbus_channel_gpadl_header* gpadl_msg;
- hv_vmbus_channel_gpadl_body* gpadl_body;
- hv_vmbus_channel_msg_info* msg_info;
- hv_vmbus_channel_msg_info* sub_msg_info;
- uint32_t msg_count;
- hv_vmbus_channel_msg_info* curr;
- uint32_t next_gpadl_handle;
-
- next_gpadl_handle = atomic_fetchadd_int(
+ /*
+ * Allocate GPADL id.
+ */
+ gpadl = atomic_fetchadd_int(
&hv_vmbus_g_connection.next_gpadl_handle, 1);
+ *gpadl0 = gpadl;
- ret = vmbus_channel_create_gpadl_header(
- contig_buffer, size, &msg_info, &msg_count);
-
- if(ret != 0) {
- /*
- * XXX
- * We can _not_ even revert the above incremental,
- * if multiple GPADL establishments are running
- * parallelly, decrement the global next_gpadl_handle
- * is calling for _big_ trouble. A better solution
- * is to have a 0-based GPADL id bitmap ...
- */
- return ret;
+ /*
+ * Connect this GPADL to the target channel.
+ *
+ * NOTE:
+ * Since each message can only hold small set of page
+ * addresses, several messages may be required to
+ * complete the connection.
+ */
+ if (page_count > VMBUS_CHANMSG_GPADL_CONN_PGMAX)
+ cnt = VMBUS_CHANMSG_GPADL_CONN_PGMAX;
+ else
+ cnt = page_count;
+ page_count -= cnt;
+
+ reqsz = __offsetof(struct vmbus_chanmsg_gpadl_conn,
+ chm_range.gpa_page[cnt]);
+ mh = vmbus_msghc_get(sc, reqsz);
+ if (mh == NULL) {
+ device_printf(sc->vmbus_dev,
+ "can not get msg hypercall for gpadl->chan%u\n",
+ channel->offer_msg.child_rel_id);
+ return EIO;
}
- sema_init(&msg_info->wait_sema, 0, "Open Info Sema");
- gpadl_msg = (hv_vmbus_channel_gpadl_header*) msg_info->msg;
- gpadl_msg->header.message_type = HV_CHANNEL_MESSAGEL_GPADL_HEADER;
- gpadl_msg->child_rel_id = channel->offer_msg.child_rel_id;
- gpadl_msg->gpadl = next_gpadl_handle;
-
- mtx_lock(&hv_vmbus_g_connection.channel_msg_lock);
- TAILQ_INSERT_TAIL(
- &hv_vmbus_g_connection.channel_msg_anchor,
- msg_info,
- msg_list_entry);
-
- mtx_unlock(&hv_vmbus_g_connection.channel_msg_lock);
+ req = vmbus_msghc_dataptr(mh);
+ req->chm_hdr.chm_type = VMBUS_CHANMSG_TYPE_GPADL_CONN;
+ req->chm_chanid = channel->offer_msg.child_rel_id;
+ req->chm_gpadl = gpadl;
+ req->chm_range_len = range_len;
+ req->chm_range_cnt = 1;
+ req->chm_range.gpa_len = size;
+ req->chm_range.gpa_ofs = 0;
+ for (i = 0; i < cnt; ++i)
+ req->chm_range.gpa_page[i] = page_id++;
- ret = hv_vmbus_post_message(
- gpadl_msg,
- msg_info->message_size -
- (uint32_t) sizeof(hv_vmbus_channel_msg_info));
+ error = vmbus_msghc_exec(sc, mh);
+ if (error) {
+ device_printf(sc->vmbus_dev,
+ "gpadl->chan%u msg hypercall exec failed: %d\n",
+ channel->offer_msg.child_rel_id, error);
+ vmbus_msghc_put(sc, mh);
+ return error;
+ }
- if (ret != 0)
- goto cleanup;
+ while (page_count > 0) {
+ struct vmbus_chanmsg_gpadl_subconn *subreq;
- if (msg_count > 1) {
- TAILQ_FOREACH(curr,
- &msg_info->sub_msg_list_anchor, msg_list_entry) {
- sub_msg_info = curr;
- gpadl_body =
- (hv_vmbus_channel_gpadl_body*) sub_msg_info->msg;
-
- gpadl_body->header.message_type =
- HV_CHANNEL_MESSAGE_GPADL_BODY;
- gpadl_body->gpadl = next_gpadl_handle;
-
- ret = hv_vmbus_post_message(
- gpadl_body,
- sub_msg_info->message_size
- - (uint32_t) sizeof(hv_vmbus_channel_msg_info));
- /* if (the post message failed) give up and clean up */
- if(ret != 0)
- goto cleanup;
- }
- }
+ if (page_count > VMBUS_CHANMSG_GPADL_SUBCONN_PGMAX)
+ cnt = VMBUS_CHANMSG_GPADL_SUBCONN_PGMAX;
+ else
+ cnt = page_count;
+ page_count -= cnt;
- ret = sema_timedwait(&msg_info->wait_sema, 5 * hz); /* KYS 5 seconds*/
- if (ret != 0)
- goto cleanup;
+ reqsz = __offsetof(struct vmbus_chanmsg_gpadl_subconn,
+ chm_gpa_page[cnt]);
+ vmbus_msghc_reset(mh, reqsz);
- *gpadl_handle = gpadl_msg->gpadl;
+ subreq = vmbus_msghc_dataptr(mh);
+ subreq->chm_hdr.chm_type = VMBUS_CHANMSG_TYPE_GPADL_SUBCONN;
+ subreq->chm_gpadl = gpadl;
+ for (i = 0; i < cnt; ++i)
+ subreq->chm_gpa_page[i] = page_id++;
-cleanup:
+ vmbus_msghc_exec_noresult(mh);
+ }
+ KASSERT(page_count == 0, ("invalid page count %d", page_count));
- mtx_lock(&hv_vmbus_g_connection.channel_msg_lock);
- TAILQ_REMOVE(&hv_vmbus_g_connection.channel_msg_anchor,
- msg_info, msg_list_entry);
- mtx_unlock(&hv_vmbus_g_connection.channel_msg_lock);
+ msg = vmbus_msghc_wait_result(sc, mh);
+ status = ((const struct vmbus_chanmsg_gpadl_connresp *)
+ msg->msg_data)->chm_status;
- sema_destroy(&msg_info->wait_sema);
- free(msg_info, M_DEVBUF);
+ vmbus_msghc_put(sc, mh);
- return (ret);
+ if (status != 0) {
+ device_printf(sc->vmbus_dev, "gpadl->chan%u failed: "
+ "status %u\n", channel->offer_msg.child_rel_id, status);
+ return EIO;
+ }
+ return 0;
}
/**
Index: head/sys/dev/hyperv/vmbus/hv_channel_mgmt.c
===================================================================
--- head/sys/dev/hyperv/vmbus/hv_channel_mgmt.c
+++ head/sys/dev/hyperv/vmbus/hv_channel_mgmt.c
@@ -438,39 +438,7 @@
vmbus_channel_on_gpadl_created(struct vmbus_softc *sc,
const struct vmbus_message *msg)
{
- const hv_vmbus_channel_msg_header *hdr =
- (const hv_vmbus_channel_msg_header *)msg->msg_data;
-
- const hv_vmbus_channel_gpadl_created *gpadl_created;
- hv_vmbus_channel_msg_info* msg_info;
- hv_vmbus_channel_msg_header* request_header;
- hv_vmbus_channel_gpadl_header* gpadl_header;
-
- gpadl_created = (const hv_vmbus_channel_gpadl_created *)hdr;
-
- /* Find the establish msg, copy the result and signal/unblock
- * the wait event
- */
- mtx_lock(&hv_vmbus_g_connection.channel_msg_lock);
- TAILQ_FOREACH(msg_info, &hv_vmbus_g_connection.channel_msg_anchor,
- msg_list_entry) {
- request_header = (hv_vmbus_channel_msg_header*) msg_info->msg;
- if (request_header->message_type ==
- HV_CHANNEL_MESSAGEL_GPADL_HEADER) {
- gpadl_header =
- (hv_vmbus_channel_gpadl_header*) request_header;
-
- if ((gpadl_created->child_rel_id == gpadl_header->child_rel_id)
- && (gpadl_created->gpadl == gpadl_header->gpadl)) {
- memcpy(&msg_info->response.gpadl_created,
- gpadl_created,
- sizeof(hv_vmbus_channel_gpadl_created));
- sema_post(&msg_info->wait_sema);
- break;
- }
- }
- }
- mtx_unlock(&hv_vmbus_g_connection.channel_msg_lock);
+ vmbus_msghc_wakeup(sc, msg);
}
/**
Index: head/sys/dev/hyperv/vmbus/vmbus.c
===================================================================
--- head/sys/dev/hyperv/vmbus/vmbus.c
+++ head/sys/dev/hyperv/vmbus/vmbus.c
@@ -205,25 +205,34 @@
return mh;
}
-struct vmbus_msghc *
-vmbus_msghc_get(struct vmbus_softc *sc, size_t dsize)
+void
+vmbus_msghc_reset(struct vmbus_msghc *mh, size_t dsize)
{
struct hypercall_postmsg_in *inprm;
- struct vmbus_msghc *mh;
if (dsize > HYPERCALL_POSTMSGIN_DSIZE_MAX)
- return NULL;
-
- mh = vmbus_msghc_get1(sc->vmbus_msg_hc, VMBUS_MSGHC_CTXF_DESTROY);
- if (mh == NULL)
- return NULL;
+ panic("invalid data size %zu", dsize);
inprm = mh->mh_inprm;
memset(inprm, 0, HYPERCALL_POSTMSGIN_SIZE);
inprm->hc_connid = VMBUS_CONNID_MESSAGE;
inprm->hc_msgtype = HYPERV_MSGTYPE_CHANNEL;
inprm->hc_dsize = dsize;
+}
+
+struct vmbus_msghc *
+vmbus_msghc_get(struct vmbus_softc *sc, size_t dsize)
+{
+ struct vmbus_msghc *mh;
+
+ 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;
+ vmbus_msghc_reset(mh, dsize);
return mh;
}
Index: head/sys/dev/hyperv/vmbus/vmbus_reg.h
===================================================================
--- head/sys/dev/hyperv/vmbus/vmbus_reg.h
+++ head/sys/dev/hyperv/vmbus/vmbus_reg.h
@@ -30,6 +30,7 @@
#define _VMBUS_REG_H_
#include <sys/param.h>
+#include <dev/hyperv/vmbus/hyperv_reg.h>
/*
* Hyper-V SynIC message format.
@@ -78,6 +79,15 @@
#define VMBUS_CHAN_MAX (VMBUS_EVTFLAG_LEN * VMBUS_EVTFLAGS_MAX)
/*
+ * GPA range.
+ */
+struct vmbus_gpa_range {
+ uint32_t gpa_len;
+ uint32_t gpa_ofs;
+ uint64_t gpa_page[];
+} __packed;
+
+/*
* Channel messages
* - Embedded in vmbus_message.msg_data, e.g. response.
* - Embedded in hypercall_postmsg_in.hc_data, e.g. request.
@@ -86,6 +96,9 @@
#define VMBUS_CHANMSG_TYPE_CHANNEL_REQ 3 /* REQ */
#define VMBUS_CHANMSG_TYPE_CHOPEN 5 /* REQ */
#define VMBUS_CHANMSG_TYPE_CHOPEN_RESP 6 /* RESP */
+#define VMBUS_CHANMSG_TYPE_GPADL_CONN 8 /* REQ */
+#define VMBUS_CHANMSG_TYPE_GPADL_SUBCONN 9 /* REQ */
+#define VMBUS_CHANMSG_TYPE_GPADP_CONNRESP 10 /* RESP */
#define VMBUS_CHANMSG_TYPE_INIT_CONTACT 14 /* REQ */
#define VMBUS_CHANMSG_TYPE_VERSION_RESP 15 /* RESP */
#define VMBUS_CHANMSG_TYPE_UNLOAD 16 /* REQ */
@@ -141,4 +154,40 @@
uint32_t chm_status;
} __packed;
+/* VMBUS_CHANMSG_TYPE_GPADL_CONN */
+struct vmbus_chanmsg_gpadl_conn {
+ struct vmbus_chanmsg_hdr chm_hdr;
+ uint32_t chm_chanid;
+ uint32_t chm_gpadl;
+ uint16_t chm_range_len;
+ uint16_t chm_range_cnt;
+ struct vmbus_gpa_range chm_range;
+} __packed;
+
+#define VMBUS_CHANMSG_GPADL_CONN_PGMAX 26
+CTASSERT(__offsetof(struct vmbus_chanmsg_gpadl_conn,
+ chm_range.gpa_page[VMBUS_CHANMSG_GPADL_CONN_PGMAX]) <=
+ HYPERCALL_POSTMSGIN_DSIZE_MAX);
+
+/* VMBUS_CHANMSG_TYPE_GPADL_SUBCONN */
+struct vmbus_chanmsg_gpadl_subconn {
+ struct vmbus_chanmsg_hdr chm_hdr;
+ uint32_t chm_msgno;
+ uint32_t chm_gpadl;
+ uint64_t chm_gpa_page[];
+} __packed;
+
+#define VMBUS_CHANMSG_GPADL_SUBCONN_PGMAX 28
+CTASSERT(__offsetof(struct vmbus_chanmsg_gpadl_subconn,
+ chm_gpa_page[VMBUS_CHANMSG_GPADL_SUBCONN_PGMAX]) <=
+ HYPERCALL_POSTMSGIN_DSIZE_MAX);
+
+/* VMBUS_CHANMSG_TYPE_GPADL_CONNRESP */
+struct vmbus_chanmsg_gpadl_connresp {
+ struct vmbus_chanmsg_hdr chm_hdr;
+ uint32_t chm_chanid;
+ uint32_t chm_gpadl;
+ uint32_t chm_status;
+} __packed;
+
#endif /* !_VMBUS_REG_H_ */
Index: head/sys/dev/hyperv/vmbus/vmbus_var.h
===================================================================
--- head/sys/dev/hyperv/vmbus/vmbus_var.h
+++ head/sys/dev/hyperv/vmbus/vmbus_var.h
@@ -133,6 +133,7 @@
const struct vmbus_message *vmbus_msghc_wait_result(struct vmbus_softc *,
struct vmbus_msghc *);
void vmbus_msghc_wakeup(struct vmbus_softc *, const struct vmbus_message *);
+void vmbus_msghc_reset(struct vmbus_msghc *, size_t);
void vmbus_scan_done(struct vmbus_softc *);
void vmbus_scan_newchan(struct vmbus_softc *);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Apr 24, 9:40 AM (9 h, 42 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
32071246
Default Alt Text
D6878.diff (15 KB)
Attached To
Mode
D6878: hyperv/vmbus: Use post message Hypercall APIs for GPADL connect.
Attached
Detach File
Event Timeline
Log In to Comment