diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c index 73e0affa7732..eccf6648d60c 100644 --- a/drivers/hv/connection.c +++ b/drivers/hv/connection.c @@ -71,22 +71,22 @@ module_param(max_version, uint, S_IRUGO); MODULE_PARM_DESC(max_version, "Maximal VMBus protocol version which can be negotiated"); -/* - * User requested connection id used to connect to the host. Useful for testing - * or when running a vmbus server on a non-standard connection id. - */ -static uint message_connection_id; - -module_param(message_connection_id, uint, 0444); -MODULE_PARM_DESC(message_connection_id, - "The VMBus message connection id used to communicate with the Host"); +/* Array of connection IDs to try in order: standard first, then redirect */ +static const u32 connection_ids[] = { + VMBUS_MESSAGE_CONNECTION_ID_4, + VMBUS_MESSAGE_CONNECTION_ID_REDIRECT +}; -int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version) +int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version, + u32 connection_id) { int ret = 0; struct vmbus_channel_initiate_contact *msg; unsigned long flags; + pr_info("VMBus: Starting negotiation - version 0x%x, connection_id 0x%x\n", + version, connection_id); + init_completion(&msginfo->waitevent); msg = (struct vmbus_channel_initiate_contact *)msginfo->msg; @@ -97,7 +97,7 @@ int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version) /* * VMBus protocol 5.0 (VERSION_WIN10_V5) and higher require that we must - * use VMBUS_MESSAGE_CONNECTION_ID_4 for the Initiate Contact Message, + * use connection_id 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 and higher, we don't use msg->interrupt_page, but we @@ -107,17 +107,18 @@ int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version) * On old hosts, we should always use VMBUS_MESSAGE_CONNECTION_ID (1). */ if (version >= VERSION_WIN10_V5) { + pr_info("VMBus: Using modern protocol (v5+) with connection_id 0x%x\n", + connection_id); msg->msg_sint = VMBUS_MESSAGE_SINT; msg->msg_vtl = ms_hyperv.vtl; - vmbus_connection.msg_conn_id = VMBUS_MESSAGE_CONNECTION_ID_4; + vmbus_connection.msg_conn_id = connection_id; } else { + pr_info("VMBus: Using legacy protocol with connection_id %d\n", + VMBUS_MESSAGE_CONNECTION_ID); msg->interrupt_page = virt_to_phys(vmbus_connection.int_page); vmbus_connection.msg_conn_id = VMBUS_MESSAGE_CONNECTION_ID; } - if (message_connection_id > 0) - vmbus_connection.msg_conn_id = message_connection_id; - /* * shared_gpa_boundary is zero in non-SNP VMs, so it's safe to always * bitwise OR it @@ -144,8 +145,10 @@ int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version) true); trace_vmbus_negotiate_version(msg, ret); + pr_info("VMBus: Posted negotiation message, ret=%d\n", ret); if (ret != 0) { + pr_err("VMBus: Failed to post negotiation message, ret=%d\n", ret); spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); list_del(&msginfo->msglistentry); spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, @@ -162,12 +165,16 @@ int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version) /* Check if successful */ if (msginfo->response.version_response.version_supported) { + pr_info("VMBus: Version 0x%x supported with connection_id 0x%x\n", + version, connection_id); vmbus_connection.conn_state = CONNECTED; if (version >= VERSION_WIN10_V5) vmbus_connection.msg_conn_id = msginfo->response.version_response.msg_conn_id; } else { + pr_info("VMBus: Version 0x%x rejected with connection_id 0x%x\n", + version, connection_id); return -ECONNREFUSED; } @@ -183,6 +190,10 @@ int vmbus_connect(void) int i, ret = 0; __u32 version; + pr_info("VMBus: Starting VMBus connection process\n"); + pr_info("VMBus: Available connection IDs: 0x%x (standard), 0x%x (redirect)\n", + connection_ids[0], connection_ids[1]); + /* Initialize the vmbus connection */ vmbus_connection.conn_state = CONNECTING; vmbus_connection.work_queue = create_workqueue("hv_vmbus_con"); @@ -290,10 +301,16 @@ int vmbus_connect(void) * 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. + * version. For each version, we try standard connection ID first, + * then VMBus redirect if the standard fails. */ + pr_info("VMBus: Starting connection negotiation with %d versions and %d connection IDs\n", + (int)ARRAY_SIZE(vmbus_versions), (int)ARRAY_SIZE(connection_ids)); + for (i = 0; ; i++) { + int conn_id_idx; + if (i == ARRAY_SIZE(vmbus_versions)) { ret = -EDOM; goto cleanup; @@ -303,14 +320,51 @@ int vmbus_connect(void) if (version > max_version) continue; - ret = vmbus_negotiate_version(msginfo, version); - if (ret == -ETIMEDOUT) - goto cleanup; - - if (vmbus_connection.conn_state == CONNECTED) + pr_info("VMBus: Trying version 0x%x (%d.%d)\n", version, + version >> 16, version & 0xFFFF); + + /* Try each connection ID for this version */ + for (conn_id_idx = 0; conn_id_idx < ARRAY_SIZE(connection_ids); conn_id_idx++) { + pr_info("VMBus: Attempting connection_id 0x%x (%s)\n", + connection_ids[conn_id_idx], + conn_id_idx == 0 ? "standard" : "redirect"); + + ret = vmbus_negotiate_version(msginfo, version, + connection_ids[conn_id_idx]); + if (ret == -ETIMEDOUT) { + pr_err("VMBus: Negotiation timed out for connection_id 0x%x\n", + connection_ids[conn_id_idx]); + goto cleanup; + } + + if (vmbus_connection.conn_state == CONNECTED) { + pr_info("VMBus: Successfully connected with version 0x%x, connection_id 0x%x\n", + version, connection_ids[conn_id_idx]); + break; + } + + pr_info("VMBus: Failed to connect with connection_id 0x%x, trying next\n", + connection_ids[conn_id_idx]); + } + + if (vmbus_connection.conn_state == CONNECTED) { + pr_info("VMBus: Connection established successfully!\n"); break; + } + + pr_info("VMBus: All connection IDs failed for version 0x%x, trying next version\n", + version); } + if (vmbus_connection.conn_state != CONNECTED) { + pr_err("VMBus: Failed to establish connection with any version/connection_id combination\n"); + ret = -EDOM; + goto cleanup; + } + + pr_info("VMBus: Final connection established - version: 0x%x, connection_id: 0x%x\n", + version, vmbus_connection.msg_conn_id); + if (hv_is_isolation_supported() && version < VERSION_WIN10_V5_2) { pr_err("Invalid VMBus version %d.%d (expected >= %d.%d) from the host supporting isolation\n", version >> 16, version & 0xFFFF, VERSION_WIN10_V5_2 >> 16, VERSION_WIN10_V5_2 & 0xFFFF); diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index 97c5b57de819..f5e26c358332 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h @@ -108,6 +108,7 @@ struct hv_input_post_message { enum { VMBUS_MESSAGE_CONNECTION_ID = 1, VMBUS_MESSAGE_CONNECTION_ID_4 = 4, + VMBUS_MESSAGE_CONNECTION_ID_REDIRECT = 0x800074, VMBUS_MESSAGE_PORT_ID = 1, VMBUS_EVENT_CONNECTION_ID = 2, VMBUS_EVENT_PORT_ID = 2, @@ -305,7 +306,8 @@ struct vmbus_msginfo { extern struct vmbus_connection vmbus_connection; -int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version); +int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version, + u32 connection_id); static inline void vmbus_send_interrupt(u32 relid) {