Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 354981
b: refs/heads/master
c: 610071c
h: refs/heads/master
i:
  354979: 8295857
v: v3
  • Loading branch information
K. Y. Srinivasan authored and Greg Kroah-Hartman committed Jan 17, 2013
1 parent 26980cb commit d89688b
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 61 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 4fa152ce24724a4a6b2edd26ca2eb7757ff5b2b8
refs/heads/master: 610071c38463998d5a66388ff9956aaeb24b49a8
165 changes: 111 additions & 54 deletions trunk/drivers/hv/connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,112 @@ struct vmbus_connection vmbus_connection = {
.next_gpadl_handle = ATOMIC_INIT(0xE1E10),
};

/*
* VMBUS version is 32 bit entity broken up into
* two 16 bit quantities: major_number. minor_number.
*
* 0 . 13 (Windows Server 2008)
* 1 . 1 (Windows 7)
* 2 . 4 (Windows 8)
*/

#define VERSION_WS2008 ((0 << 16) | (13))
#define VERSION_WIN7 ((1 << 16) | (1))
#define VERSION_WIN8 ((2 << 16) | (4))

#define VERSION_INVAL -1

static __u32 vmbus_get_next_version(__u32 current_version)
{
switch (current_version) {
case (VERSION_WIN7):
return VERSION_WS2008;

case (VERSION_WIN8):
return VERSION_WIN7;

case (VERSION_WS2008):
default:
return VERSION_INVAL;
}
}

static int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo,
__u32 version)
{
int ret = 0;
struct vmbus_channel_initiate_contact *msg;
unsigned long flags;
int t;

init_completion(&msginfo->waitevent);

msg = (struct vmbus_channel_initiate_contact *)msginfo->msg;

msg->header.msgtype = CHANNELMSG_INITIATE_CONTACT;
msg->vmbus_version_requested = version;
msg->interrupt_page = virt_to_phys(vmbus_connection.int_page);
msg->monitor_page1 = virt_to_phys(vmbus_connection.monitor_pages);
msg->monitor_page2 = virt_to_phys(
(void *)((unsigned long)vmbus_connection.monitor_pages +
PAGE_SIZE));

/*
* Add to list before we send the request since we may
* receive the response before returning from this routine
*/
spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
list_add_tail(&msginfo->msglistentry,
&vmbus_connection.chn_msg_list);

spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);

ret = vmbus_post_msg(msg,
sizeof(struct vmbus_channel_initiate_contact));
if (ret != 0) {
spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
list_del(&msginfo->msglistentry);
spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock,
flags);
return ret;
}

/* Wait for the connection response */
t = wait_for_completion_timeout(&msginfo->waitevent, 5*HZ);
if (t == 0) {
spin_lock_irqsave(&vmbus_connection.channelmsg_lock,
flags);
list_del(&msginfo->msglistentry);
spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock,
flags);
return -ETIMEDOUT;
}

spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
list_del(&msginfo->msglistentry);
spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);

/* Check if successful */
if (msginfo->response.version_response.version_supported) {
vmbus_connection.conn_state = CONNECTED;
} else {
pr_err("Unable to connect, "
"Version %d not supported by Hyper-V\n",
version);
return -ECONNREFUSED;
}

return ret;
}

/*
* vmbus_connect - Sends a connect request on the partition service connection
*/
int vmbus_connect(void)
{
int ret = 0;
int t;
struct vmbus_channel_msginfo *msginfo = NULL;
struct vmbus_channel_initiate_contact *msg;
unsigned long flags;
__u32 version;

/* Initialize the vmbus connection */
vmbus_connection.conn_state = CONNECTING;
Expand Down Expand Up @@ -99,64 +195,25 @@ int vmbus_connect(void)
goto cleanup;
}

init_completion(&msginfo->waitevent);

msg = (struct vmbus_channel_initiate_contact *)msginfo->msg;

msg->header.msgtype = CHANNELMSG_INITIATE_CONTACT;
msg->vmbus_version_requested = VMBUS_REVISION_NUMBER;
msg->interrupt_page = virt_to_phys(vmbus_connection.int_page);
msg->monitor_page1 = virt_to_phys(vmbus_connection.monitor_pages);
msg->monitor_page2 = virt_to_phys(
(void *)((unsigned long)vmbus_connection.monitor_pages +
PAGE_SIZE));

/*
* Add to list before we send the request since we may
* receive the response before returning from this routine
* Negotiate a compatible VMBUS version number with the
* host. We start with the highest number we can support
* and work our way down until we negotiate a compatible
* version.
*/
spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
list_add_tail(&msginfo->msglistentry,
&vmbus_connection.chn_msg_list);

spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);

ret = vmbus_post_msg(msg,
sizeof(struct vmbus_channel_initiate_contact));
if (ret != 0) {
spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
list_del(&msginfo->msglistentry);
spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock,
flags);
goto cleanup;
}
version = VERSION_WS2008;

/* Wait for the connection response */
t = wait_for_completion_timeout(&msginfo->waitevent, 5*HZ);
if (t == 0) {
spin_lock_irqsave(&vmbus_connection.channelmsg_lock,
flags);
list_del(&msginfo->msglistentry);
spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock,
flags);
ret = -ETIMEDOUT;
goto cleanup;
}
do {
ret = vmbus_negotiate_version(msginfo, version);
if (ret == 0)
break;

spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
list_del(&msginfo->msglistentry);
spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
version = vmbus_get_next_version(version);
} while (version != VERSION_INVAL);

/* Check if successful */
if (msginfo->response.version_response.version_supported) {
vmbus_connection.conn_state = CONNECTED;
} else {
pr_err("Unable to connect, "
"Version %d not supported by Hyper-V\n",
VMBUS_REVISION_NUMBER);
ret = -ECONNREFUSED;
if (version == VERSION_INVAL)
goto cleanup;
}

kfree(msginfo);
return 0;
Expand Down
6 changes: 0 additions & 6 deletions trunk/include/linux/hyperv.h
Original file line number Diff line number Diff line change
Expand Up @@ -406,12 +406,6 @@ hv_get_ringbuffer_availbytes(struct hv_ring_buffer_info *rbi,
#define HV_DRV_VERSION "3.1"


/*
* A revision number of vmbus that is used for ensuring both ends on a
* partition are using compatible versions.
*/
#define VMBUS_REVISION_NUMBER 13

/* Make maximum size of pipe payload of 16K */
#define MAX_PIPE_DATA_PAYLOAD (sizeof(u8) * 16384)

Expand Down

0 comments on commit d89688b

Please sign in to comment.