diff options
Diffstat (limited to 'drivers/hv/channel_mgmt.c')
-rw-r--r-- | drivers/hv/channel_mgmt.c | 58 |
1 files changed, 43 insertions, 15 deletions
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index 38b682bab85a..b6c1211b4df7 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c | |||
@@ -597,27 +597,55 @@ static void init_vp_index(struct vmbus_channel *channel, u16 dev_type) | |||
597 | 597 | ||
598 | static void vmbus_wait_for_unload(void) | 598 | static void vmbus_wait_for_unload(void) |
599 | { | 599 | { |
600 | int cpu = smp_processor_id(); | 600 | int cpu; |
601 | void *page_addr = hv_context.synic_message_page[cpu]; | 601 | void *page_addr; |
602 | struct hv_message *msg = (struct hv_message *)page_addr + | 602 | struct hv_message *msg; |
603 | VMBUS_MESSAGE_SINT; | ||
604 | struct vmbus_channel_message_header *hdr; | 603 | struct vmbus_channel_message_header *hdr; |
605 | bool unloaded = false; | 604 | u32 message_type; |
606 | 605 | ||
606 | /* | ||
607 | * CHANNELMSG_UNLOAD_RESPONSE is always delivered to the CPU which was | ||
608 | * used for initial contact or to CPU0 depending on host version. When | ||
609 | * we're crashing on a different CPU let's hope that IRQ handler on | ||
610 | * the cpu which receives CHANNELMSG_UNLOAD_RESPONSE is still | ||
611 | * functional and vmbus_unload_response() will complete | ||
612 | * vmbus_connection.unload_event. If not, the last thing we can do is | ||
613 | * read message pages for all CPUs directly. | ||
614 | */ | ||
607 | while (1) { | 615 | while (1) { |
608 | if (READ_ONCE(msg->header.message_type) == HVMSG_NONE) { | 616 | if (completion_done(&vmbus_connection.unload_event)) |
609 | mdelay(10); | 617 | break; |
610 | continue; | ||
611 | } | ||
612 | 618 | ||
613 | hdr = (struct vmbus_channel_message_header *)msg->u.payload; | 619 | for_each_online_cpu(cpu) { |
614 | if (hdr->msgtype == CHANNELMSG_UNLOAD_RESPONSE) | 620 | page_addr = hv_context.synic_message_page[cpu]; |
615 | unloaded = true; | 621 | msg = (struct hv_message *)page_addr + |
622 | VMBUS_MESSAGE_SINT; | ||
616 | 623 | ||
617 | vmbus_signal_eom(msg); | 624 | message_type = READ_ONCE(msg->header.message_type); |
625 | if (message_type == HVMSG_NONE) | ||
626 | continue; | ||
618 | 627 | ||
619 | if (unloaded) | 628 | hdr = (struct vmbus_channel_message_header *) |
620 | break; | 629 | msg->u.payload; |
630 | |||
631 | if (hdr->msgtype == CHANNELMSG_UNLOAD_RESPONSE) | ||
632 | complete(&vmbus_connection.unload_event); | ||
633 | |||
634 | vmbus_signal_eom(msg, message_type); | ||
635 | } | ||
636 | |||
637 | mdelay(10); | ||
638 | } | ||
639 | |||
640 | /* | ||
641 | * We're crashing and already got the UNLOAD_RESPONSE, cleanup all | ||
642 | * maybe-pending messages on all CPUs to be able to receive new | ||
643 | * messages after we reconnect. | ||
644 | */ | ||
645 | for_each_online_cpu(cpu) { | ||
646 | page_addr = hv_context.synic_message_page[cpu]; | ||
647 | msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT; | ||
648 | msg->header.message_type = HVMSG_NONE; | ||
621 | } | 649 | } |
622 | } | 650 | } |
623 | 651 | ||