diff options
Diffstat (limited to 'drivers/hv/connection.c')
-rw-r--r-- | drivers/hv/connection.c | 44 |
1 files changed, 42 insertions, 2 deletions
diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c index 72855182b191..ced041899456 100644 --- a/drivers/hv/connection.c +++ b/drivers/hv/connection.c | |||
@@ -63,6 +63,9 @@ static __u32 vmbus_get_next_version(__u32 current_version) | |||
63 | case (VERSION_WIN10): | 63 | case (VERSION_WIN10): |
64 | return VERSION_WIN8_1; | 64 | return VERSION_WIN8_1; |
65 | 65 | ||
66 | case (VERSION_WIN10_V5): | ||
67 | return VERSION_WIN10; | ||
68 | |||
66 | case (VERSION_WS2008): | 69 | case (VERSION_WS2008): |
67 | default: | 70 | default: |
68 | return VERSION_INVAL; | 71 | return VERSION_INVAL; |
@@ -80,9 +83,29 @@ static int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, | |||
80 | 83 | ||
81 | msg = (struct vmbus_channel_initiate_contact *)msginfo->msg; | 84 | msg = (struct vmbus_channel_initiate_contact *)msginfo->msg; |
82 | 85 | ||
86 | memset(msg, 0, sizeof(*msg)); | ||
83 | msg->header.msgtype = CHANNELMSG_INITIATE_CONTACT; | 87 | msg->header.msgtype = CHANNELMSG_INITIATE_CONTACT; |
84 | msg->vmbus_version_requested = version; | 88 | msg->vmbus_version_requested = version; |
85 | msg->interrupt_page = virt_to_phys(vmbus_connection.int_page); | 89 | |
90 | /* | ||
91 | * VMBus protocol 5.0 (VERSION_WIN10_V5) requires that we must use | ||
92 | * VMBUS_MESSAGE_CONNECTION_ID_4 for the Initiate Contact Message, | ||
93 | * and for subsequent messages, we must use the Message Connection ID | ||
94 | * field in the host-returned Version Response Message. And, with | ||
95 | * VERSION_WIN10_V5, we don't use msg->interrupt_page, but we tell | ||
96 | * the host explicitly that we still use VMBUS_MESSAGE_SINT(2) for | ||
97 | * compatibility. | ||
98 | * | ||
99 | * On old hosts, we should always use VMBUS_MESSAGE_CONNECTION_ID (1). | ||
100 | */ | ||
101 | if (version >= VERSION_WIN10_V5) { | ||
102 | msg->msg_sint = VMBUS_MESSAGE_SINT; | ||
103 | vmbus_connection.msg_conn_id = VMBUS_MESSAGE_CONNECTION_ID_4; | ||
104 | } else { | ||
105 | msg->interrupt_page = virt_to_phys(vmbus_connection.int_page); | ||
106 | vmbus_connection.msg_conn_id = VMBUS_MESSAGE_CONNECTION_ID; | ||
107 | } | ||
108 | |||
86 | msg->monitor_page1 = virt_to_phys(vmbus_connection.monitor_pages[0]); | 109 | msg->monitor_page1 = virt_to_phys(vmbus_connection.monitor_pages[0]); |
87 | msg->monitor_page2 = virt_to_phys(vmbus_connection.monitor_pages[1]); | 110 | msg->monitor_page2 = virt_to_phys(vmbus_connection.monitor_pages[1]); |
88 | /* | 111 | /* |
@@ -137,6 +160,10 @@ static int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, | |||
137 | /* Check if successful */ | 160 | /* Check if successful */ |
138 | if (msginfo->response.version_response.version_supported) { | 161 | if (msginfo->response.version_response.version_supported) { |
139 | vmbus_connection.conn_state = CONNECTED; | 162 | vmbus_connection.conn_state = CONNECTED; |
163 | |||
164 | if (version >= VERSION_WIN10_V5) | ||
165 | vmbus_connection.msg_conn_id = | ||
166 | msginfo->response.version_response.msg_conn_id; | ||
140 | } else { | 167 | } else { |
141 | return -ECONNREFUSED; | 168 | return -ECONNREFUSED; |
142 | } | 169 | } |
@@ -354,13 +381,14 @@ void vmbus_on_event(unsigned long data) | |||
354 | */ | 381 | */ |
355 | int vmbus_post_msg(void *buffer, size_t buflen, bool can_sleep) | 382 | int vmbus_post_msg(void *buffer, size_t buflen, bool can_sleep) |
356 | { | 383 | { |
384 | struct vmbus_channel_message_header *hdr; | ||
357 | union hv_connection_id conn_id; | 385 | union hv_connection_id conn_id; |
358 | int ret = 0; | 386 | int ret = 0; |
359 | int retries = 0; | 387 | int retries = 0; |
360 | u32 usec = 1; | 388 | u32 usec = 1; |
361 | 389 | ||
362 | conn_id.asu32 = 0; | 390 | conn_id.asu32 = 0; |
363 | conn_id.u.id = VMBUS_MESSAGE_CONNECTION_ID; | 391 | conn_id.u.id = vmbus_connection.msg_conn_id; |
364 | 392 | ||
365 | /* | 393 | /* |
366 | * hv_post_message() can have transient failures because of | 394 | * hv_post_message() can have transient failures because of |
@@ -373,6 +401,18 @@ int vmbus_post_msg(void *buffer, size_t buflen, bool can_sleep) | |||
373 | switch (ret) { | 401 | switch (ret) { |
374 | case HV_STATUS_INVALID_CONNECTION_ID: | 402 | case HV_STATUS_INVALID_CONNECTION_ID: |
375 | /* | 403 | /* |
404 | * See vmbus_negotiate_version(): VMBus protocol 5.0 | ||
405 | * requires that we must use | ||
406 | * VMBUS_MESSAGE_CONNECTION_ID_4 for the Initiate | ||
407 | * Contact message, but on old hosts that only | ||
408 | * support VMBus protocol 4.0 or lower, here we get | ||
409 | * HV_STATUS_INVALID_CONNECTION_ID and we should | ||
410 | * return an error immediately without retrying. | ||
411 | */ | ||
412 | hdr = buffer; | ||
413 | if (hdr->msgtype == CHANNELMSG_INITIATE_CONTACT) | ||
414 | return -EINVAL; | ||
415 | /* | ||
376 | * We could get this if we send messages too | 416 | * We could get this if we send messages too |
377 | * frequently. | 417 | * frequently. |
378 | */ | 418 | */ |