Commit ae20b254 authored by Dexuan Cui's avatar Dexuan Cui Committed by Greg Kroah-Hartman

Drivers: hv: vmbus: enable VMBus protocol version 5.0

With VMBus protocol 5.0, we're able to better support new features, e.g.
running two or more VMBus drivers simultaneously in a single VM -- note:
we can't simply load the current VMBus driver twice, instead, a secondary
VMBus driver must be implemented.

This patch adds the support for the new VMBus protocol, which is available
on new Windows hosts, by:

1) We still use SINT2 for compatibility;
2) We must use Connection ID 4 for the Initiate Contact Message, and for
subsequent messages, we must use the Message Connection ID field in
the host-returned VersionResponse Message.

Notes for developers of the secondary VMBus driver:
1) Must use VMBus protocol 5.0 as well;
2) Must use a different SINT number that is not in use.
3) Must use Connection ID 4 for the Initiate Contact Message, and for
subsequent messages, must use the Message Connection ID field in
the host-returned VersionResponse Message.
4) It's possible that the primary VMBus driver using protocol version 4.0
can work with a secondary VMBus driver using protocol version 5.0, but it's
recommended that both should use 5.0 for new Hyper-V features in the future.
Signed-off-by: default avatarDexuan Cui <decui@microsoft.com>
Cc: Stephen Hemminger <sthemmin@microsoft.com>
Cc: K. Y. Srinivasan <kys@microsoft.com>
Cc: Michael Kelley <mikelley@microsoft.com>
Signed-off-by: default avatarK. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent e19f70aa
...@@ -63,6 +63,9 @@ static __u32 vmbus_get_next_version(__u32 current_version) ...@@ -63,6 +63,9 @@ static __u32 vmbus_get_next_version(__u32 current_version)
case (VERSION_WIN10): case (VERSION_WIN10):
return VERSION_WIN8_1; return VERSION_WIN8_1;
case (VERSION_WIN10_V5):
return VERSION_WIN10;
case (VERSION_WS2008): case (VERSION_WS2008):
default: default:
return VERSION_INVAL; return VERSION_INVAL;
...@@ -80,9 +83,29 @@ static int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, ...@@ -80,9 +83,29 @@ static int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo,
msg = (struct vmbus_channel_initiate_contact *)msginfo->msg; msg = (struct vmbus_channel_initiate_contact *)msginfo->msg;
memset(msg, 0, sizeof(*msg));
msg->header.msgtype = CHANNELMSG_INITIATE_CONTACT; msg->header.msgtype = CHANNELMSG_INITIATE_CONTACT;
msg->vmbus_version_requested = version; msg->vmbus_version_requested = version;
/*
* VMBus protocol 5.0 (VERSION_WIN10_V5) requires that we must use
* VMBUS_MESSAGE_CONNECTION_ID_4 for the Initiate Contact Message,
* and for subsequent messages, we must use the Message Connection ID
* field in the host-returned Version Response Message. And, with
* VERSION_WIN10_V5, we don't use msg->interrupt_page, but we tell
* the host explicitly that we still use VMBUS_MESSAGE_SINT(2) for
* compatibility.
*
* On old hosts, we should always use VMBUS_MESSAGE_CONNECTION_ID (1).
*/
if (version >= VERSION_WIN10_V5) {
msg->msg_sint = VMBUS_MESSAGE_SINT;
vmbus_connection.msg_conn_id = VMBUS_MESSAGE_CONNECTION_ID_4;
} else {
msg->interrupt_page = virt_to_phys(vmbus_connection.int_page); msg->interrupt_page = virt_to_phys(vmbus_connection.int_page);
vmbus_connection.msg_conn_id = VMBUS_MESSAGE_CONNECTION_ID;
}
msg->monitor_page1 = virt_to_phys(vmbus_connection.monitor_pages[0]); msg->monitor_page1 = virt_to_phys(vmbus_connection.monitor_pages[0]);
msg->monitor_page2 = virt_to_phys(vmbus_connection.monitor_pages[1]); msg->monitor_page2 = virt_to_phys(vmbus_connection.monitor_pages[1]);
/* /*
...@@ -137,6 +160,10 @@ static int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, ...@@ -137,6 +160,10 @@ static int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo,
/* Check if successful */ /* Check if successful */
if (msginfo->response.version_response.version_supported) { if (msginfo->response.version_response.version_supported) {
vmbus_connection.conn_state = CONNECTED; vmbus_connection.conn_state = CONNECTED;
if (version >= VERSION_WIN10_V5)
vmbus_connection.msg_conn_id =
msginfo->response.version_response.msg_conn_id;
} else { } else {
return -ECONNREFUSED; return -ECONNREFUSED;
} }
...@@ -354,13 +381,14 @@ void vmbus_on_event(unsigned long data) ...@@ -354,13 +381,14 @@ void vmbus_on_event(unsigned long data)
*/ */
int vmbus_post_msg(void *buffer, size_t buflen, bool can_sleep) int vmbus_post_msg(void *buffer, size_t buflen, bool can_sleep)
{ {
struct vmbus_channel_message_header *hdr;
union hv_connection_id conn_id; union hv_connection_id conn_id;
int ret = 0; int ret = 0;
int retries = 0; int retries = 0;
u32 usec = 1; u32 usec = 1;
conn_id.asu32 = 0; conn_id.asu32 = 0;
conn_id.u.id = VMBUS_MESSAGE_CONNECTION_ID; conn_id.u.id = vmbus_connection.msg_conn_id;
/* /*
* hv_post_message() can have transient failures because of * hv_post_message() can have transient failures because of
...@@ -372,6 +400,18 @@ int vmbus_post_msg(void *buffer, size_t buflen, bool can_sleep) ...@@ -372,6 +400,18 @@ int vmbus_post_msg(void *buffer, size_t buflen, bool can_sleep)
switch (ret) { switch (ret) {
case HV_STATUS_INVALID_CONNECTION_ID: case HV_STATUS_INVALID_CONNECTION_ID:
/*
* See vmbus_negotiate_version(): VMBus protocol 5.0
* requires that we must use
* VMBUS_MESSAGE_CONNECTION_ID_4 for the Initiate
* Contact message, but on old hosts that only
* support VMBus protocol 4.0 or lower, here we get
* HV_STATUS_INVALID_CONNECTION_ID and we should
* return an error immediately without retrying.
*/
hdr = (struct vmbus_channel_message_header *)buffer;
if (hdr->msgtype == CHANNELMSG_INITIATE_CONTACT)
return -EINVAL;
/* /*
* We could get this if we send messages too * We could get this if we send messages too
* frequently. * frequently.
......
...@@ -187,6 +187,7 @@ struct hv_input_post_message { ...@@ -187,6 +187,7 @@ struct hv_input_post_message {
enum { enum {
VMBUS_MESSAGE_CONNECTION_ID = 1, VMBUS_MESSAGE_CONNECTION_ID = 1,
VMBUS_MESSAGE_CONNECTION_ID_4 = 4,
VMBUS_MESSAGE_PORT_ID = 1, VMBUS_MESSAGE_PORT_ID = 1,
VMBUS_EVENT_CONNECTION_ID = 2, VMBUS_EVENT_CONNECTION_ID = 2,
VMBUS_EVENT_PORT_ID = 2, VMBUS_EVENT_PORT_ID = 2,
...@@ -302,6 +303,8 @@ struct vmbus_connection { ...@@ -302,6 +303,8 @@ struct vmbus_connection {
*/ */
int connect_cpu; int connect_cpu;
u32 msg_conn_id;
atomic_t offer_in_progress; atomic_t offer_in_progress;
enum vmbus_connect_state conn_state; enum vmbus_connect_state conn_state;
......
...@@ -163,6 +163,7 @@ static inline u32 hv_get_bytes_to_write(const struct hv_ring_buffer_info *rbi) ...@@ -163,6 +163,7 @@ static inline u32 hv_get_bytes_to_write(const struct hv_ring_buffer_info *rbi)
* 2 . 4 (Windows 8) * 2 . 4 (Windows 8)
* 3 . 0 (Windows 8 R2) * 3 . 0 (Windows 8 R2)
* 4 . 0 (Windows 10) * 4 . 0 (Windows 10)
* 5 . 0 (Newer Windows 10)
*/ */
#define VERSION_WS2008 ((0 << 16) | (13)) #define VERSION_WS2008 ((0 << 16) | (13))
...@@ -170,10 +171,11 @@ static inline u32 hv_get_bytes_to_write(const struct hv_ring_buffer_info *rbi) ...@@ -170,10 +171,11 @@ static inline u32 hv_get_bytes_to_write(const struct hv_ring_buffer_info *rbi)
#define VERSION_WIN8 ((2 << 16) | (4)) #define VERSION_WIN8 ((2 << 16) | (4))
#define VERSION_WIN8_1 ((3 << 16) | (0)) #define VERSION_WIN8_1 ((3 << 16) | (0))
#define VERSION_WIN10 ((4 << 16) | (0)) #define VERSION_WIN10 ((4 << 16) | (0))
#define VERSION_WIN10_V5 ((5 << 16) | (0))
#define VERSION_INVAL -1 #define VERSION_INVAL -1
#define VERSION_CURRENT VERSION_WIN10 #define VERSION_CURRENT VERSION_WIN10_V5
/* Make maximum size of pipe payload of 16K */ /* Make maximum size of pipe payload of 16K */
#define MAX_PIPE_DATA_PAYLOAD (sizeof(u8) * 16384) #define MAX_PIPE_DATA_PAYLOAD (sizeof(u8) * 16384)
...@@ -570,7 +572,14 @@ struct vmbus_channel_initiate_contact { ...@@ -570,7 +572,14 @@ struct vmbus_channel_initiate_contact {
struct vmbus_channel_message_header header; struct vmbus_channel_message_header header;
u32 vmbus_version_requested; u32 vmbus_version_requested;
u32 target_vcpu; /* The VCPU the host should respond to */ u32 target_vcpu; /* The VCPU the host should respond to */
union {
u64 interrupt_page; u64 interrupt_page;
struct {
u8 msg_sint;
u8 padding1[3];
u32 padding2;
};
};
u64 monitor_page1; u64 monitor_page1;
u64 monitor_page2; u64 monitor_page2;
} __packed; } __packed;
...@@ -585,6 +594,19 @@ struct vmbus_channel_tl_connect_request { ...@@ -585,6 +594,19 @@ struct vmbus_channel_tl_connect_request {
struct vmbus_channel_version_response { struct vmbus_channel_version_response {
struct vmbus_channel_message_header header; struct vmbus_channel_message_header header;
u8 version_supported; u8 version_supported;
u8 connection_state;
u16 padding;
/*
* On new hosts that support VMBus protocol 5.0, we must use
* VMBUS_MESSAGE_CONNECTION_ID_4 for the Initiate Contact Message,
* and for subsequent messages, we must use the Message Connection ID
* field in the host-returned Version Response Message.
*
* On old hosts, we should always use VMBUS_MESSAGE_CONNECTION_ID (1).
*/
u32 msg_conn_id;
} __packed; } __packed;
enum vmbus_channel_state { enum vmbus_channel_state {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment