| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright (c) 2009, Microsoft Corporation. |
|---|
| 3 | | - * |
|---|
| 4 | | - * This program is free software; you can redistribute it and/or modify it |
|---|
| 5 | | - * under the terms and conditions of the GNU General Public License, |
|---|
| 6 | | - * version 2, as published by the Free Software Foundation. |
|---|
| 7 | | - * |
|---|
| 8 | | - * This program is distributed in the hope it will be useful, but WITHOUT |
|---|
| 9 | | - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|---|
| 10 | | - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
|---|
| 11 | | - * more details. |
|---|
| 12 | | - * |
|---|
| 13 | | - * You should have received a copy of the GNU General Public License along with |
|---|
| 14 | | - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple |
|---|
| 15 | | - * Place - Suite 330, Boston, MA 02111-1307 USA. |
|---|
| 16 | 4 | * |
|---|
| 17 | 5 | * Authors: |
|---|
| 18 | 6 | * Haiyang Zhang <haiyangz@microsoft.com> |
|---|
| 19 | 7 | * Hank Janssen <hjanssen@microsoft.com> |
|---|
| 20 | 8 | * K. Y. Srinivasan <kys@microsoft.com> |
|---|
| 21 | | - * |
|---|
| 22 | 9 | */ |
|---|
| 23 | 10 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
|---|
| 24 | 11 | |
|---|
| .. | .. |
|---|
| 36 | 23 | #include <linux/cpu.h> |
|---|
| 37 | 24 | #include <linux/sched/task_stack.h> |
|---|
| 38 | 25 | |
|---|
| 39 | | -#include <asm/mshyperv.h> |
|---|
| 26 | +#include <linux/delay.h> |
|---|
| 40 | 27 | #include <linux/notifier.h> |
|---|
| 41 | 28 | #include <linux/ptrace.h> |
|---|
| 42 | 29 | #include <linux/screen_info.h> |
|---|
| .. | .. |
|---|
| 44 | 31 | #include <linux/efi.h> |
|---|
| 45 | 32 | #include <linux/random.h> |
|---|
| 46 | 33 | #include <linux/kernel.h> |
|---|
| 34 | +#include <linux/syscore_ops.h> |
|---|
| 35 | +#include <clocksource/hyperv_timer.h> |
|---|
| 47 | 36 | #include "hyperv_vmbus.h" |
|---|
| 48 | 37 | |
|---|
| 49 | 38 | struct vmbus_dynid { |
|---|
| .. | .. |
|---|
| 58 | 47 | static int hyperv_cpuhp_online; |
|---|
| 59 | 48 | |
|---|
| 60 | 49 | static void *hv_panic_page; |
|---|
| 50 | + |
|---|
| 51 | +/* Values parsed from ACPI DSDT */ |
|---|
| 52 | +static int vmbus_irq; |
|---|
| 53 | +int vmbus_interrupt; |
|---|
| 61 | 54 | |
|---|
| 62 | 55 | /* |
|---|
| 63 | 56 | * Boolean to control whether to report panic messages over Hyper-V. |
|---|
| .. | .. |
|---|
| 94 | 87 | static int hyperv_die_event(struct notifier_block *nb, unsigned long val, |
|---|
| 95 | 88 | void *args) |
|---|
| 96 | 89 | { |
|---|
| 97 | | - struct die_args *die = (struct die_args *)args; |
|---|
| 90 | + struct die_args *die = args; |
|---|
| 98 | 91 | struct pt_regs *regs = die->regs; |
|---|
| 92 | + |
|---|
| 93 | + /* Don't notify Hyper-V if the die event is other than oops */ |
|---|
| 94 | + if (val != DIE_OOPS) |
|---|
| 95 | + return NOTIFY_DONE; |
|---|
| 99 | 96 | |
|---|
| 100 | 97 | /* |
|---|
| 101 | 98 | * Hyper-V should be notified only once about a panic. If we will be |
|---|
| .. | .. |
|---|
| 117 | 114 | static const char *fb_mmio_name = "fb_range"; |
|---|
| 118 | 115 | static struct resource *fb_mmio; |
|---|
| 119 | 116 | static struct resource *hyperv_mmio; |
|---|
| 120 | | -static DEFINE_SEMAPHORE(hyperv_mmio_lock); |
|---|
| 117 | +static DEFINE_MUTEX(hyperv_mmio_lock); |
|---|
| 121 | 118 | |
|---|
| 122 | 119 | static int vmbus_exists(void) |
|---|
| 123 | 120 | { |
|---|
| .. | .. |
|---|
| 125 | 122 | return -ENODEV; |
|---|
| 126 | 123 | |
|---|
| 127 | 124 | return 0; |
|---|
| 128 | | -} |
|---|
| 129 | | - |
|---|
| 130 | | -#define VMBUS_ALIAS_LEN ((sizeof((struct hv_vmbus_device_id *)0)->guid) * 2) |
|---|
| 131 | | -static void print_alias_name(struct hv_device *hv_dev, char *alias_name) |
|---|
| 132 | | -{ |
|---|
| 133 | | - int i; |
|---|
| 134 | | - for (i = 0; i < VMBUS_ALIAS_LEN; i += 2) |
|---|
| 135 | | - sprintf(&alias_name[i], "%02x", hv_dev->dev_type.b[i/2]); |
|---|
| 136 | 125 | } |
|---|
| 137 | 126 | |
|---|
| 138 | 127 | static u8 channel_monitor_group(const struct vmbus_channel *channel) |
|---|
| .. | .. |
|---|
| 211 | 200 | if (!hv_dev->channel) |
|---|
| 212 | 201 | return -ENODEV; |
|---|
| 213 | 202 | return sprintf(buf, "{%pUl}\n", |
|---|
| 214 | | - hv_dev->channel->offermsg.offer.if_type.b); |
|---|
| 203 | + &hv_dev->channel->offermsg.offer.if_type); |
|---|
| 215 | 204 | } |
|---|
| 216 | 205 | static DEVICE_ATTR_RO(class_id); |
|---|
| 217 | 206 | |
|---|
| .. | .. |
|---|
| 223 | 212 | if (!hv_dev->channel) |
|---|
| 224 | 213 | return -ENODEV; |
|---|
| 225 | 214 | return sprintf(buf, "{%pUl}\n", |
|---|
| 226 | | - hv_dev->channel->offermsg.offer.if_instance.b); |
|---|
| 215 | + &hv_dev->channel->offermsg.offer.if_instance); |
|---|
| 227 | 216 | } |
|---|
| 228 | 217 | static DEVICE_ATTR_RO(device_id); |
|---|
| 229 | 218 | |
|---|
| .. | .. |
|---|
| 231 | 220 | struct device_attribute *dev_attr, char *buf) |
|---|
| 232 | 221 | { |
|---|
| 233 | 222 | struct hv_device *hv_dev = device_to_hv_device(dev); |
|---|
| 234 | | - char alias_name[VMBUS_ALIAS_LEN + 1]; |
|---|
| 235 | 223 | |
|---|
| 236 | | - print_alias_name(hv_dev, alias_name); |
|---|
| 237 | | - return sprintf(buf, "vmbus:%s\n", alias_name); |
|---|
| 224 | + return sprintf(buf, "vmbus:%*phN\n", UUID_SIZE, &hv_dev->dev_type); |
|---|
| 238 | 225 | } |
|---|
| 239 | 226 | static DEVICE_ATTR_RO(modalias); |
|---|
| 240 | 227 | |
|---|
| .. | .. |
|---|
| 247 | 234 | if (!hv_dev->channel) |
|---|
| 248 | 235 | return -ENODEV; |
|---|
| 249 | 236 | |
|---|
| 250 | | - return sprintf(buf, "%d\n", hv_dev->channel->numa_node); |
|---|
| 237 | + return sprintf(buf, "%d\n", cpu_to_node(hv_dev->channel->target_cpu)); |
|---|
| 251 | 238 | } |
|---|
| 252 | 239 | static DEVICE_ATTR_RO(numa_node); |
|---|
| 253 | 240 | #endif |
|---|
| .. | .. |
|---|
| 262 | 249 | return -ENODEV; |
|---|
| 263 | 250 | return sprintf(buf, "%d\n", |
|---|
| 264 | 251 | channel_pending(hv_dev->channel, |
|---|
| 265 | | - vmbus_connection.monitor_pages[1])); |
|---|
| 252 | + vmbus_connection.monitor_pages[0])); |
|---|
| 266 | 253 | } |
|---|
| 267 | 254 | static DEVICE_ATTR_RO(server_monitor_pending); |
|---|
| 268 | 255 | |
|---|
| .. | .. |
|---|
| 528 | 515 | { |
|---|
| 529 | 516 | struct hv_device *hv_dev = device_to_hv_device(dev); |
|---|
| 530 | 517 | struct vmbus_channel *channel = hv_dev->channel, *cur_sc; |
|---|
| 531 | | - unsigned long flags; |
|---|
| 532 | 518 | int buf_size = PAGE_SIZE, n_written, tot_written; |
|---|
| 533 | 519 | struct list_head *cur; |
|---|
| 534 | 520 | |
|---|
| 535 | 521 | if (!channel) |
|---|
| 536 | 522 | return -ENODEV; |
|---|
| 537 | 523 | |
|---|
| 524 | + mutex_lock(&vmbus_connection.channel_mutex); |
|---|
| 525 | + |
|---|
| 538 | 526 | tot_written = snprintf(buf, buf_size, "%u:%u\n", |
|---|
| 539 | 527 | channel->offermsg.child_relid, channel->target_cpu); |
|---|
| 540 | | - |
|---|
| 541 | | - spin_lock_irqsave(&channel->lock, flags); |
|---|
| 542 | 528 | |
|---|
| 543 | 529 | list_for_each(cur, &channel->sc_list) { |
|---|
| 544 | 530 | if (tot_written >= buf_size - 1) |
|---|
| .. | .. |
|---|
| 553 | 539 | tot_written += n_written; |
|---|
| 554 | 540 | } |
|---|
| 555 | 541 | |
|---|
| 556 | | - spin_unlock_irqrestore(&channel->lock, flags); |
|---|
| 542 | + mutex_unlock(&vmbus_connection.channel_mutex); |
|---|
| 557 | 543 | |
|---|
| 558 | 544 | return tot_written; |
|---|
| 559 | 545 | } |
|---|
| .. | .. |
|---|
| 576 | 562 | return sprintf(buf, "0x%x\n", hv_dev->device_id); |
|---|
| 577 | 563 | } |
|---|
| 578 | 564 | static DEVICE_ATTR_RO(device); |
|---|
| 565 | + |
|---|
| 566 | +static ssize_t driver_override_store(struct device *dev, |
|---|
| 567 | + struct device_attribute *attr, |
|---|
| 568 | + const char *buf, size_t count) |
|---|
| 569 | +{ |
|---|
| 570 | + struct hv_device *hv_dev = device_to_hv_device(dev); |
|---|
| 571 | + char *driver_override, *old, *cp; |
|---|
| 572 | + |
|---|
| 573 | + /* We need to keep extra room for a newline */ |
|---|
| 574 | + if (count >= (PAGE_SIZE - 1)) |
|---|
| 575 | + return -EINVAL; |
|---|
| 576 | + |
|---|
| 577 | + driver_override = kstrndup(buf, count, GFP_KERNEL); |
|---|
| 578 | + if (!driver_override) |
|---|
| 579 | + return -ENOMEM; |
|---|
| 580 | + |
|---|
| 581 | + cp = strchr(driver_override, '\n'); |
|---|
| 582 | + if (cp) |
|---|
| 583 | + *cp = '\0'; |
|---|
| 584 | + |
|---|
| 585 | + device_lock(dev); |
|---|
| 586 | + old = hv_dev->driver_override; |
|---|
| 587 | + if (strlen(driver_override)) { |
|---|
| 588 | + hv_dev->driver_override = driver_override; |
|---|
| 589 | + } else { |
|---|
| 590 | + kfree(driver_override); |
|---|
| 591 | + hv_dev->driver_override = NULL; |
|---|
| 592 | + } |
|---|
| 593 | + device_unlock(dev); |
|---|
| 594 | + |
|---|
| 595 | + kfree(old); |
|---|
| 596 | + |
|---|
| 597 | + return count; |
|---|
| 598 | +} |
|---|
| 599 | + |
|---|
| 600 | +static ssize_t driver_override_show(struct device *dev, |
|---|
| 601 | + struct device_attribute *attr, char *buf) |
|---|
| 602 | +{ |
|---|
| 603 | + struct hv_device *hv_dev = device_to_hv_device(dev); |
|---|
| 604 | + ssize_t len; |
|---|
| 605 | + |
|---|
| 606 | + device_lock(dev); |
|---|
| 607 | + len = snprintf(buf, PAGE_SIZE, "%s\n", hv_dev->driver_override); |
|---|
| 608 | + device_unlock(dev); |
|---|
| 609 | + |
|---|
| 610 | + return len; |
|---|
| 611 | +} |
|---|
| 612 | +static DEVICE_ATTR_RW(driver_override); |
|---|
| 579 | 613 | |
|---|
| 580 | 614 | /* Set up per device attributes in /sys/bus/vmbus/devices/<bus device> */ |
|---|
| 581 | 615 | static struct attribute *vmbus_dev_attrs[] = { |
|---|
| .. | .. |
|---|
| 607 | 641 | &dev_attr_channel_vp_mapping.attr, |
|---|
| 608 | 642 | &dev_attr_vendor.attr, |
|---|
| 609 | 643 | &dev_attr_device.attr, |
|---|
| 644 | + &dev_attr_driver_override.attr, |
|---|
| 610 | 645 | NULL, |
|---|
| 611 | 646 | }; |
|---|
| 612 | 647 | |
|---|
| .. | .. |
|---|
| 654 | 689 | static int vmbus_uevent(struct device *device, struct kobj_uevent_env *env) |
|---|
| 655 | 690 | { |
|---|
| 656 | 691 | struct hv_device *dev = device_to_hv_device(device); |
|---|
| 657 | | - int ret; |
|---|
| 658 | | - char alias_name[VMBUS_ALIAS_LEN + 1]; |
|---|
| 692 | + const char *format = "MODALIAS=vmbus:%*phN"; |
|---|
| 659 | 693 | |
|---|
| 660 | | - print_alias_name(dev, alias_name); |
|---|
| 661 | | - ret = add_uevent_var(env, "MODALIAS=vmbus:%s", alias_name); |
|---|
| 662 | | - return ret; |
|---|
| 694 | + return add_uevent_var(env, format, UUID_SIZE, &dev->dev_type); |
|---|
| 663 | 695 | } |
|---|
| 664 | 696 | |
|---|
| 665 | | -static const uuid_le null_guid; |
|---|
| 666 | | - |
|---|
| 667 | | -static inline bool is_null_guid(const uuid_le *guid) |
|---|
| 697 | +static const struct hv_vmbus_device_id * |
|---|
| 698 | +hv_vmbus_dev_match(const struct hv_vmbus_device_id *id, const guid_t *guid) |
|---|
| 668 | 699 | { |
|---|
| 669 | | - if (uuid_le_cmp(*guid, null_guid)) |
|---|
| 670 | | - return false; |
|---|
| 671 | | - return true; |
|---|
| 700 | + if (id == NULL) |
|---|
| 701 | + return NULL; /* empty device table */ |
|---|
| 702 | + |
|---|
| 703 | + for (; !guid_is_null(&id->guid); id++) |
|---|
| 704 | + if (guid_equal(&id->guid, guid)) |
|---|
| 705 | + return id; |
|---|
| 706 | + |
|---|
| 707 | + return NULL; |
|---|
| 672 | 708 | } |
|---|
| 673 | 709 | |
|---|
| 674 | | -/* |
|---|
| 675 | | - * Return a matching hv_vmbus_device_id pointer. |
|---|
| 676 | | - * If there is no match, return NULL. |
|---|
| 677 | | - */ |
|---|
| 678 | | -static const struct hv_vmbus_device_id *hv_vmbus_get_id(struct hv_driver *drv, |
|---|
| 679 | | - const uuid_le *guid) |
|---|
| 710 | +static const struct hv_vmbus_device_id * |
|---|
| 711 | +hv_vmbus_dynid_match(struct hv_driver *drv, const guid_t *guid) |
|---|
| 680 | 712 | { |
|---|
| 681 | 713 | const struct hv_vmbus_device_id *id = NULL; |
|---|
| 682 | 714 | struct vmbus_dynid *dynid; |
|---|
| 683 | 715 | |
|---|
| 684 | | - /* Look at the dynamic ids first, before the static ones */ |
|---|
| 685 | 716 | spin_lock(&drv->dynids.lock); |
|---|
| 686 | 717 | list_for_each_entry(dynid, &drv->dynids.list, node) { |
|---|
| 687 | | - if (!uuid_le_cmp(dynid->id.guid, *guid)) { |
|---|
| 718 | + if (guid_equal(&dynid->id.guid, guid)) { |
|---|
| 688 | 719 | id = &dynid->id; |
|---|
| 689 | 720 | break; |
|---|
| 690 | 721 | } |
|---|
| 691 | 722 | } |
|---|
| 692 | 723 | spin_unlock(&drv->dynids.lock); |
|---|
| 693 | 724 | |
|---|
| 694 | | - if (id) |
|---|
| 695 | | - return id; |
|---|
| 725 | + return id; |
|---|
| 726 | +} |
|---|
| 696 | 727 | |
|---|
| 697 | | - id = drv->id_table; |
|---|
| 698 | | - if (id == NULL) |
|---|
| 699 | | - return NULL; /* empty device table */ |
|---|
| 728 | +static const struct hv_vmbus_device_id vmbus_device_null; |
|---|
| 700 | 729 | |
|---|
| 701 | | - for (; !is_null_guid(&id->guid); id++) |
|---|
| 702 | | - if (!uuid_le_cmp(id->guid, *guid)) |
|---|
| 703 | | - return id; |
|---|
| 730 | +/* |
|---|
| 731 | + * Return a matching hv_vmbus_device_id pointer. |
|---|
| 732 | + * If there is no match, return NULL. |
|---|
| 733 | + */ |
|---|
| 734 | +static const struct hv_vmbus_device_id *hv_vmbus_get_id(struct hv_driver *drv, |
|---|
| 735 | + struct hv_device *dev) |
|---|
| 736 | +{ |
|---|
| 737 | + const guid_t *guid = &dev->dev_type; |
|---|
| 738 | + const struct hv_vmbus_device_id *id; |
|---|
| 704 | 739 | |
|---|
| 705 | | - return NULL; |
|---|
| 740 | + /* When driver_override is set, only bind to the matching driver */ |
|---|
| 741 | + if (dev->driver_override && strcmp(dev->driver_override, drv->name)) |
|---|
| 742 | + return NULL; |
|---|
| 743 | + |
|---|
| 744 | + /* Look at the dynamic ids first, before the static ones */ |
|---|
| 745 | + id = hv_vmbus_dynid_match(drv, guid); |
|---|
| 746 | + if (!id) |
|---|
| 747 | + id = hv_vmbus_dev_match(drv->id_table, guid); |
|---|
| 748 | + |
|---|
| 749 | + /* driver_override will always match, send a dummy id */ |
|---|
| 750 | + if (!id && dev->driver_override) |
|---|
| 751 | + id = &vmbus_device_null; |
|---|
| 752 | + |
|---|
| 753 | + return id; |
|---|
| 706 | 754 | } |
|---|
| 707 | 755 | |
|---|
| 708 | 756 | /* vmbus_add_dynid - add a new device ID to this driver and re-probe devices */ |
|---|
| 709 | | -static int vmbus_add_dynid(struct hv_driver *drv, uuid_le *guid) |
|---|
| 757 | +static int vmbus_add_dynid(struct hv_driver *drv, guid_t *guid) |
|---|
| 710 | 758 | { |
|---|
| 711 | 759 | struct vmbus_dynid *dynid; |
|---|
| 712 | 760 | |
|---|
| .. | .. |
|---|
| 744 | 792 | size_t count) |
|---|
| 745 | 793 | { |
|---|
| 746 | 794 | struct hv_driver *drv = drv_to_hv_drv(driver); |
|---|
| 747 | | - uuid_le guid; |
|---|
| 795 | + guid_t guid; |
|---|
| 748 | 796 | ssize_t retval; |
|---|
| 749 | 797 | |
|---|
| 750 | | - retval = uuid_le_to_bin(buf, &guid); |
|---|
| 798 | + retval = guid_parse(buf, &guid); |
|---|
| 751 | 799 | if (retval) |
|---|
| 752 | 800 | return retval; |
|---|
| 753 | 801 | |
|---|
| 754 | | - if (hv_vmbus_get_id(drv, &guid)) |
|---|
| 802 | + if (hv_vmbus_dynid_match(drv, &guid)) |
|---|
| 755 | 803 | return -EEXIST; |
|---|
| 756 | 804 | |
|---|
| 757 | 805 | retval = vmbus_add_dynid(drv, &guid); |
|---|
| .. | .. |
|---|
| 771 | 819 | { |
|---|
| 772 | 820 | struct hv_driver *drv = drv_to_hv_drv(driver); |
|---|
| 773 | 821 | struct vmbus_dynid *dynid, *n; |
|---|
| 774 | | - uuid_le guid; |
|---|
| 822 | + guid_t guid; |
|---|
| 775 | 823 | ssize_t retval; |
|---|
| 776 | 824 | |
|---|
| 777 | | - retval = uuid_le_to_bin(buf, &guid); |
|---|
| 825 | + retval = guid_parse(buf, &guid); |
|---|
| 778 | 826 | if (retval) |
|---|
| 779 | 827 | return retval; |
|---|
| 780 | 828 | |
|---|
| .. | .. |
|---|
| 783 | 831 | list_for_each_entry_safe(dynid, n, &drv->dynids.list, node) { |
|---|
| 784 | 832 | struct hv_vmbus_device_id *id = &dynid->id; |
|---|
| 785 | 833 | |
|---|
| 786 | | - if (!uuid_le_cmp(id->guid, guid)) { |
|---|
| 834 | + if (guid_equal(&id->guid, &guid)) { |
|---|
| 787 | 835 | list_del(&dynid->node); |
|---|
| 788 | 836 | kfree(dynid); |
|---|
| 789 | 837 | retval = count; |
|---|
| .. | .. |
|---|
| 816 | 864 | if (is_hvsock_channel(hv_dev->channel)) |
|---|
| 817 | 865 | return drv->hvsock; |
|---|
| 818 | 866 | |
|---|
| 819 | | - if (hv_vmbus_get_id(drv, &hv_dev->dev_type)) |
|---|
| 867 | + if (hv_vmbus_get_id(drv, hv_dev)) |
|---|
| 820 | 868 | return 1; |
|---|
| 821 | 869 | |
|---|
| 822 | 870 | return 0; |
|---|
| .. | .. |
|---|
| 833 | 881 | struct hv_device *dev = device_to_hv_device(child_device); |
|---|
| 834 | 882 | const struct hv_vmbus_device_id *dev_id; |
|---|
| 835 | 883 | |
|---|
| 836 | | - dev_id = hv_vmbus_get_id(drv, &dev->dev_type); |
|---|
| 884 | + dev_id = hv_vmbus_get_id(drv, dev); |
|---|
| 837 | 885 | if (drv->probe) { |
|---|
| 838 | 886 | ret = drv->probe(dev, dev_id); |
|---|
| 839 | 887 | if (ret != 0) |
|---|
| .. | .. |
|---|
| 885 | 933 | drv->shutdown(dev); |
|---|
| 886 | 934 | } |
|---|
| 887 | 935 | |
|---|
| 936 | +#ifdef CONFIG_PM_SLEEP |
|---|
| 937 | +/* |
|---|
| 938 | + * vmbus_suspend - Suspend a vmbus device |
|---|
| 939 | + */ |
|---|
| 940 | +static int vmbus_suspend(struct device *child_device) |
|---|
| 941 | +{ |
|---|
| 942 | + struct hv_driver *drv; |
|---|
| 943 | + struct hv_device *dev = device_to_hv_device(child_device); |
|---|
| 944 | + |
|---|
| 945 | + /* The device may not be attached yet */ |
|---|
| 946 | + if (!child_device->driver) |
|---|
| 947 | + return 0; |
|---|
| 948 | + |
|---|
| 949 | + drv = drv_to_hv_drv(child_device->driver); |
|---|
| 950 | + if (!drv->suspend) |
|---|
| 951 | + return -EOPNOTSUPP; |
|---|
| 952 | + |
|---|
| 953 | + return drv->suspend(dev); |
|---|
| 954 | +} |
|---|
| 955 | + |
|---|
| 956 | +/* |
|---|
| 957 | + * vmbus_resume - Resume a vmbus device |
|---|
| 958 | + */ |
|---|
| 959 | +static int vmbus_resume(struct device *child_device) |
|---|
| 960 | +{ |
|---|
| 961 | + struct hv_driver *drv; |
|---|
| 962 | + struct hv_device *dev = device_to_hv_device(child_device); |
|---|
| 963 | + |
|---|
| 964 | + /* The device may not be attached yet */ |
|---|
| 965 | + if (!child_device->driver) |
|---|
| 966 | + return 0; |
|---|
| 967 | + |
|---|
| 968 | + drv = drv_to_hv_drv(child_device->driver); |
|---|
| 969 | + if (!drv->resume) |
|---|
| 970 | + return -EOPNOTSUPP; |
|---|
| 971 | + |
|---|
| 972 | + return drv->resume(dev); |
|---|
| 973 | +} |
|---|
| 974 | +#else |
|---|
| 975 | +#define vmbus_suspend NULL |
|---|
| 976 | +#define vmbus_resume NULL |
|---|
| 977 | +#endif /* CONFIG_PM_SLEEP */ |
|---|
| 888 | 978 | |
|---|
| 889 | 979 | /* |
|---|
| 890 | 980 | * vmbus_device_release - Final callback release of the vmbus child device |
|---|
| .. | .. |
|---|
| 894 | 984 | struct hv_device *hv_dev = device_to_hv_device(device); |
|---|
| 895 | 985 | struct vmbus_channel *channel = hv_dev->channel; |
|---|
| 896 | 986 | |
|---|
| 987 | + hv_debug_rm_dev_dir(hv_dev); |
|---|
| 988 | + |
|---|
| 897 | 989 | mutex_lock(&vmbus_connection.channel_mutex); |
|---|
| 898 | | - hv_process_channel_removal(channel->offermsg.child_relid); |
|---|
| 990 | + hv_process_channel_removal(channel); |
|---|
| 899 | 991 | mutex_unlock(&vmbus_connection.channel_mutex); |
|---|
| 900 | 992 | kfree(hv_dev); |
|---|
| 901 | | - |
|---|
| 902 | 993 | } |
|---|
| 994 | + |
|---|
| 995 | +/* |
|---|
| 996 | + * Note: we must use the "noirq" ops: see the comment before vmbus_bus_pm. |
|---|
| 997 | + * |
|---|
| 998 | + * suspend_noirq/resume_noirq are set to NULL to support Suspend-to-Idle: we |
|---|
| 999 | + * shouldn't suspend the vmbus devices upon Suspend-to-Idle, otherwise there |
|---|
| 1000 | + * is no way to wake up a Generation-2 VM. |
|---|
| 1001 | + * |
|---|
| 1002 | + * The other 4 ops are for hibernation. |
|---|
| 1003 | + */ |
|---|
| 1004 | + |
|---|
| 1005 | +static const struct dev_pm_ops vmbus_pm = { |
|---|
| 1006 | + .suspend_noirq = NULL, |
|---|
| 1007 | + .resume_noirq = NULL, |
|---|
| 1008 | + .freeze_noirq = vmbus_suspend, |
|---|
| 1009 | + .thaw_noirq = vmbus_resume, |
|---|
| 1010 | + .poweroff_noirq = vmbus_suspend, |
|---|
| 1011 | + .restore_noirq = vmbus_resume, |
|---|
| 1012 | +}; |
|---|
| 903 | 1013 | |
|---|
| 904 | 1014 | /* The one and only one */ |
|---|
| 905 | 1015 | static struct bus_type hv_bus = { |
|---|
| .. | .. |
|---|
| 911 | 1021 | .uevent = vmbus_uevent, |
|---|
| 912 | 1022 | .dev_groups = vmbus_dev_groups, |
|---|
| 913 | 1023 | .drv_groups = vmbus_drv_groups, |
|---|
| 1024 | + .pm = &vmbus_pm, |
|---|
| 914 | 1025 | }; |
|---|
| 915 | 1026 | |
|---|
| 916 | 1027 | struct onmessage_work_context { |
|---|
| 917 | 1028 | struct work_struct work; |
|---|
| 918 | | - struct hv_message msg; |
|---|
| 1029 | + struct { |
|---|
| 1030 | + struct hv_message_header header; |
|---|
| 1031 | + u8 payload[]; |
|---|
| 1032 | + } msg; |
|---|
| 919 | 1033 | }; |
|---|
| 920 | 1034 | |
|---|
| 921 | 1035 | static void vmbus_onmessage_work(struct work_struct *work) |
|---|
| .. | .. |
|---|
| 928 | 1042 | |
|---|
| 929 | 1043 | ctx = container_of(work, struct onmessage_work_context, |
|---|
| 930 | 1044 | work); |
|---|
| 931 | | - vmbus_onmessage(&ctx->msg); |
|---|
| 1045 | + vmbus_onmessage((struct vmbus_channel_message_header *) |
|---|
| 1046 | + &ctx->msg.payload); |
|---|
| 932 | 1047 | kfree(ctx); |
|---|
| 933 | | -} |
|---|
| 934 | | - |
|---|
| 935 | | -static void hv_process_timer_expiration(struct hv_message *msg, |
|---|
| 936 | | - struct hv_per_cpu_context *hv_cpu) |
|---|
| 937 | | -{ |
|---|
| 938 | | - struct clock_event_device *dev = hv_cpu->clk_evt; |
|---|
| 939 | | - |
|---|
| 940 | | - if (dev->event_handler) |
|---|
| 941 | | - dev->event_handler(dev); |
|---|
| 942 | | - |
|---|
| 943 | | - vmbus_signal_eom(msg, HVMSG_TIMER_EXPIRED); |
|---|
| 944 | 1048 | } |
|---|
| 945 | 1049 | |
|---|
| 946 | 1050 | void vmbus_on_msg_dpc(unsigned long data) |
|---|
| .. | .. |
|---|
| 953 | 1057 | const struct vmbus_channel_message_table_entry *entry; |
|---|
| 954 | 1058 | struct onmessage_work_context *ctx; |
|---|
| 955 | 1059 | u32 message_type = msg->header.message_type; |
|---|
| 1060 | + |
|---|
| 1061 | + /* |
|---|
| 1062 | + * 'enum vmbus_channel_message_type' is supposed to always be 'u32' as |
|---|
| 1063 | + * it is being used in 'struct vmbus_channel_message_header' definition |
|---|
| 1064 | + * which is supposed to match hypervisor ABI. |
|---|
| 1065 | + */ |
|---|
| 1066 | + BUILD_BUG_ON(sizeof(enum vmbus_channel_message_type) != sizeof(u32)); |
|---|
| 956 | 1067 | |
|---|
| 957 | 1068 | if (message_type == HVMSG_NONE) |
|---|
| 958 | 1069 | /* no msg */ |
|---|
| .. | .. |
|---|
| 967 | 1078 | goto msg_handled; |
|---|
| 968 | 1079 | } |
|---|
| 969 | 1080 | |
|---|
| 1081 | + if (msg->header.payload_size > HV_MESSAGE_PAYLOAD_BYTE_COUNT) { |
|---|
| 1082 | + WARN_ONCE(1, "payload size is too large (%d)\n", |
|---|
| 1083 | + msg->header.payload_size); |
|---|
| 1084 | + goto msg_handled; |
|---|
| 1085 | + } |
|---|
| 1086 | + |
|---|
| 970 | 1087 | entry = &channel_message_table[hdr->msgtype]; |
|---|
| 971 | 1088 | |
|---|
| 972 | 1089 | if (!entry->message_handler) |
|---|
| 973 | 1090 | goto msg_handled; |
|---|
| 974 | 1091 | |
|---|
| 1092 | + if (msg->header.payload_size < entry->min_payload_len) { |
|---|
| 1093 | + WARN_ONCE(1, "message too short: msgtype=%d len=%d\n", |
|---|
| 1094 | + hdr->msgtype, msg->header.payload_size); |
|---|
| 1095 | + goto msg_handled; |
|---|
| 1096 | + } |
|---|
| 1097 | + |
|---|
| 975 | 1098 | if (entry->handler_type == VMHT_BLOCKING) { |
|---|
| 976 | | - ctx = kmalloc(sizeof(*ctx), GFP_ATOMIC); |
|---|
| 1099 | + ctx = kmalloc(sizeof(*ctx) + msg->header.payload_size, |
|---|
| 1100 | + GFP_ATOMIC); |
|---|
| 977 | 1101 | if (ctx == NULL) |
|---|
| 978 | 1102 | return; |
|---|
| 979 | 1103 | |
|---|
| 980 | 1104 | INIT_WORK(&ctx->work, vmbus_onmessage_work); |
|---|
| 981 | | - memcpy(&ctx->msg, msg, sizeof(*msg)); |
|---|
| 1105 | + memcpy(&ctx->msg, msg, sizeof(msg->header) + |
|---|
| 1106 | + msg->header.payload_size); |
|---|
| 982 | 1107 | |
|---|
| 983 | 1108 | /* |
|---|
| 984 | 1109 | * The host can generate a rescind message while we |
|---|
| 985 | 1110 | * may still be handling the original offer. We deal with |
|---|
| 986 | | - * this condition by ensuring the processing is done on the |
|---|
| 987 | | - * same CPU. |
|---|
| 1111 | + * this condition by relying on the synchronization provided |
|---|
| 1112 | + * by offer_in_progress and by channel_mutex. See also the |
|---|
| 1113 | + * inline comments in vmbus_onoffer_rescind(). |
|---|
| 988 | 1114 | */ |
|---|
| 989 | 1115 | switch (hdr->msgtype) { |
|---|
| 990 | 1116 | case CHANNELMSG_RESCIND_CHANNELOFFER: |
|---|
| 991 | 1117 | /* |
|---|
| 992 | 1118 | * If we are handling the rescind message; |
|---|
| 993 | 1119 | * schedule the work on the global work queue. |
|---|
| 1120 | + * |
|---|
| 1121 | + * The OFFER message and the RESCIND message should |
|---|
| 1122 | + * not be handled by the same serialized work queue, |
|---|
| 1123 | + * because the OFFER handler may call vmbus_open(), |
|---|
| 1124 | + * which tries to open the channel by sending an |
|---|
| 1125 | + * OPEN_CHANNEL message to the host and waits for |
|---|
| 1126 | + * the host's response; however, if the host has |
|---|
| 1127 | + * rescinded the channel before it receives the |
|---|
| 1128 | + * OPEN_CHANNEL message, the host just silently |
|---|
| 1129 | + * ignores the OPEN_CHANNEL message; as a result, |
|---|
| 1130 | + * the guest's OFFER handler hangs for ever, if we |
|---|
| 1131 | + * handle the RESCIND message in the same serialized |
|---|
| 1132 | + * work queue: the RESCIND handler can not start to |
|---|
| 1133 | + * run before the OFFER handler finishes. |
|---|
| 994 | 1134 | */ |
|---|
| 995 | | - schedule_work_on(vmbus_connection.connect_cpu, |
|---|
| 996 | | - &ctx->work); |
|---|
| 1135 | + schedule_work(&ctx->work); |
|---|
| 997 | 1136 | break; |
|---|
| 998 | 1137 | |
|---|
| 999 | 1138 | case CHANNELMSG_OFFERCHANNEL: |
|---|
| 1139 | + /* |
|---|
| 1140 | + * The host sends the offer message of a given channel |
|---|
| 1141 | + * before sending the rescind message of the same |
|---|
| 1142 | + * channel. These messages are sent to the guest's |
|---|
| 1143 | + * connect CPU; the guest then starts processing them |
|---|
| 1144 | + * in the tasklet handler on this CPU: |
|---|
| 1145 | + * |
|---|
| 1146 | + * VMBUS_CONNECT_CPU |
|---|
| 1147 | + * |
|---|
| 1148 | + * [vmbus_on_msg_dpc()] |
|---|
| 1149 | + * atomic_inc() // CHANNELMSG_OFFERCHANNEL |
|---|
| 1150 | + * queue_work() |
|---|
| 1151 | + * ... |
|---|
| 1152 | + * [vmbus_on_msg_dpc()] |
|---|
| 1153 | + * schedule_work() // CHANNELMSG_RESCIND_CHANNELOFFER |
|---|
| 1154 | + * |
|---|
| 1155 | + * We rely on the memory-ordering properties of the |
|---|
| 1156 | + * queue_work() and schedule_work() primitives, which |
|---|
| 1157 | + * guarantee that the atomic increment will be visible |
|---|
| 1158 | + * to the CPUs which will execute the offer & rescind |
|---|
| 1159 | + * works by the time these works will start execution. |
|---|
| 1160 | + */ |
|---|
| 1000 | 1161 | atomic_inc(&vmbus_connection.offer_in_progress); |
|---|
| 1001 | | - queue_work_on(vmbus_connection.connect_cpu, |
|---|
| 1002 | | - vmbus_connection.work_queue, |
|---|
| 1003 | | - &ctx->work); |
|---|
| 1004 | | - break; |
|---|
| 1162 | + fallthrough; |
|---|
| 1005 | 1163 | |
|---|
| 1006 | 1164 | default: |
|---|
| 1007 | 1165 | queue_work(vmbus_connection.work_queue, &ctx->work); |
|---|
| .. | .. |
|---|
| 1013 | 1171 | vmbus_signal_eom(msg, message_type); |
|---|
| 1014 | 1172 | } |
|---|
| 1015 | 1173 | |
|---|
| 1016 | | - |
|---|
| 1174 | +#ifdef CONFIG_PM_SLEEP |
|---|
| 1017 | 1175 | /* |
|---|
| 1018 | | - * Direct callback for channels using other deferred processing |
|---|
| 1176 | + * Fake RESCIND_CHANNEL messages to clean up hv_sock channels by force for |
|---|
| 1177 | + * hibernation, because hv_sock connections can not persist across hibernation. |
|---|
| 1019 | 1178 | */ |
|---|
| 1020 | | -static void vmbus_channel_isr(struct vmbus_channel *channel) |
|---|
| 1179 | +static void vmbus_force_channel_rescinded(struct vmbus_channel *channel) |
|---|
| 1021 | 1180 | { |
|---|
| 1022 | | - void (*callback_fn)(void *); |
|---|
| 1181 | + struct onmessage_work_context *ctx; |
|---|
| 1182 | + struct vmbus_channel_rescind_offer *rescind; |
|---|
| 1023 | 1183 | |
|---|
| 1024 | | - callback_fn = READ_ONCE(channel->onchannel_callback); |
|---|
| 1025 | | - if (likely(callback_fn != NULL)) |
|---|
| 1026 | | - (*callback_fn)(channel->channel_callback_context); |
|---|
| 1184 | + WARN_ON(!is_hvsock_channel(channel)); |
|---|
| 1185 | + |
|---|
| 1186 | + /* |
|---|
| 1187 | + * Allocation size is small and the allocation should really not fail, |
|---|
| 1188 | + * otherwise the state of the hv_sock connections ends up in limbo. |
|---|
| 1189 | + */ |
|---|
| 1190 | + ctx = kzalloc(sizeof(*ctx) + sizeof(*rescind), |
|---|
| 1191 | + GFP_KERNEL | __GFP_NOFAIL); |
|---|
| 1192 | + |
|---|
| 1193 | + /* |
|---|
| 1194 | + * So far, these are not really used by Linux. Just set them to the |
|---|
| 1195 | + * reasonable values conforming to the definitions of the fields. |
|---|
| 1196 | + */ |
|---|
| 1197 | + ctx->msg.header.message_type = 1; |
|---|
| 1198 | + ctx->msg.header.payload_size = sizeof(*rescind); |
|---|
| 1199 | + |
|---|
| 1200 | + /* These values are actually used by Linux. */ |
|---|
| 1201 | + rescind = (struct vmbus_channel_rescind_offer *)ctx->msg.payload; |
|---|
| 1202 | + rescind->header.msgtype = CHANNELMSG_RESCIND_CHANNELOFFER; |
|---|
| 1203 | + rescind->child_relid = channel->offermsg.child_relid; |
|---|
| 1204 | + |
|---|
| 1205 | + INIT_WORK(&ctx->work, vmbus_onmessage_work); |
|---|
| 1206 | + |
|---|
| 1207 | + queue_work(vmbus_connection.work_queue, &ctx->work); |
|---|
| 1027 | 1208 | } |
|---|
| 1209 | +#endif /* CONFIG_PM_SLEEP */ |
|---|
| 1028 | 1210 | |
|---|
| 1029 | 1211 | /* |
|---|
| 1030 | 1212 | * Schedule all channels with events pending |
|---|
| .. | .. |
|---|
| 1056 | 1238 | return; |
|---|
| 1057 | 1239 | |
|---|
| 1058 | 1240 | for_each_set_bit(relid, recv_int_page, maxbits) { |
|---|
| 1241 | + void (*callback_fn)(void *context); |
|---|
| 1059 | 1242 | struct vmbus_channel *channel; |
|---|
| 1060 | 1243 | |
|---|
| 1061 | 1244 | if (!sync_test_and_clear_bit(relid, recv_int_page)) |
|---|
| .. | .. |
|---|
| 1065 | 1248 | if (relid == 0) |
|---|
| 1066 | 1249 | continue; |
|---|
| 1067 | 1250 | |
|---|
| 1251 | + /* |
|---|
| 1252 | + * Pairs with the kfree_rcu() in vmbus_chan_release(). |
|---|
| 1253 | + * Guarantees that the channel data structure doesn't |
|---|
| 1254 | + * get freed while the channel pointer below is being |
|---|
| 1255 | + * dereferenced. |
|---|
| 1256 | + */ |
|---|
| 1068 | 1257 | rcu_read_lock(); |
|---|
| 1069 | 1258 | |
|---|
| 1070 | 1259 | /* Find channel based on relid */ |
|---|
| 1071 | | - list_for_each_entry_rcu(channel, &hv_cpu->chan_list, percpu_list) { |
|---|
| 1072 | | - if (channel->offermsg.child_relid != relid) |
|---|
| 1073 | | - continue; |
|---|
| 1260 | + channel = relid2channel(relid); |
|---|
| 1261 | + if (channel == NULL) |
|---|
| 1262 | + goto sched_unlock_rcu; |
|---|
| 1074 | 1263 | |
|---|
| 1075 | | - if (channel->rescind) |
|---|
| 1076 | | - continue; |
|---|
| 1264 | + if (channel->rescind) |
|---|
| 1265 | + goto sched_unlock_rcu; |
|---|
| 1077 | 1266 | |
|---|
| 1078 | | - trace_vmbus_chan_sched(channel); |
|---|
| 1267 | + /* |
|---|
| 1268 | + * Make sure that the ring buffer data structure doesn't get |
|---|
| 1269 | + * freed while we dereference the ring buffer pointer. Test |
|---|
| 1270 | + * for the channel's onchannel_callback being NULL within a |
|---|
| 1271 | + * sched_lock critical section. See also the inline comments |
|---|
| 1272 | + * in vmbus_reset_channel_cb(). |
|---|
| 1273 | + */ |
|---|
| 1274 | + spin_lock(&channel->sched_lock); |
|---|
| 1079 | 1275 | |
|---|
| 1080 | | - ++channel->interrupts; |
|---|
| 1276 | + callback_fn = channel->onchannel_callback; |
|---|
| 1277 | + if (unlikely(callback_fn == NULL)) |
|---|
| 1278 | + goto sched_unlock; |
|---|
| 1081 | 1279 | |
|---|
| 1082 | | - switch (channel->callback_mode) { |
|---|
| 1083 | | - case HV_CALL_ISR: |
|---|
| 1084 | | - vmbus_channel_isr(channel); |
|---|
| 1085 | | - break; |
|---|
| 1280 | + trace_vmbus_chan_sched(channel); |
|---|
| 1086 | 1281 | |
|---|
| 1087 | | - case HV_CALL_BATCHED: |
|---|
| 1088 | | - hv_begin_read(&channel->inbound); |
|---|
| 1089 | | - /* fallthrough */ |
|---|
| 1090 | | - case HV_CALL_DIRECT: |
|---|
| 1091 | | - tasklet_schedule(&channel->callback_event); |
|---|
| 1092 | | - } |
|---|
| 1282 | + ++channel->interrupts; |
|---|
| 1283 | + |
|---|
| 1284 | + switch (channel->callback_mode) { |
|---|
| 1285 | + case HV_CALL_ISR: |
|---|
| 1286 | + (*callback_fn)(channel->channel_callback_context); |
|---|
| 1287 | + break; |
|---|
| 1288 | + |
|---|
| 1289 | + case HV_CALL_BATCHED: |
|---|
| 1290 | + hv_begin_read(&channel->inbound); |
|---|
| 1291 | + fallthrough; |
|---|
| 1292 | + case HV_CALL_DIRECT: |
|---|
| 1293 | + tasklet_schedule(&channel->callback_event); |
|---|
| 1093 | 1294 | } |
|---|
| 1094 | 1295 | |
|---|
| 1296 | +sched_unlock: |
|---|
| 1297 | + spin_unlock(&channel->sched_lock); |
|---|
| 1298 | +sched_unlock_rcu: |
|---|
| 1095 | 1299 | rcu_read_unlock(); |
|---|
| 1096 | 1300 | } |
|---|
| 1097 | 1301 | } |
|---|
| .. | .. |
|---|
| 1140 | 1344 | |
|---|
| 1141 | 1345 | /* Check if there are actual msgs to be processed */ |
|---|
| 1142 | 1346 | if (msg->header.message_type != HVMSG_NONE) { |
|---|
| 1143 | | - if (msg->header.message_type == HVMSG_TIMER_EXPIRED) |
|---|
| 1144 | | - hv_process_timer_expiration(msg, hv_cpu); |
|---|
| 1145 | | - else |
|---|
| 1347 | + if (msg->header.message_type == HVMSG_TIMER_EXPIRED) { |
|---|
| 1348 | + hv_stimer0_isr(); |
|---|
| 1349 | + vmbus_signal_eom(msg, HVMSG_TIMER_EXPIRED); |
|---|
| 1350 | + } else |
|---|
| 1146 | 1351 | tasklet_schedule(&hv_cpu->msg_dpc); |
|---|
| 1147 | 1352 | } |
|---|
| 1148 | 1353 | |
|---|
| 1149 | | - add_interrupt_randomness(HYPERVISOR_CALLBACK_VECTOR, 0); |
|---|
| 1354 | + add_interrupt_randomness(hv_get_vector()); |
|---|
| 1150 | 1355 | } |
|---|
| 1151 | 1356 | |
|---|
| 1152 | 1357 | /* |
|---|
| .. | .. |
|---|
| 1169 | 1374 | * Write dump contents to the page. No need to synchronize; panic should |
|---|
| 1170 | 1375 | * be single-threaded. |
|---|
| 1171 | 1376 | */ |
|---|
| 1172 | | - kmsg_dump_get_buffer(dumper, true, hv_panic_page, PAGE_SIZE, |
|---|
| 1377 | + kmsg_dump_get_buffer(dumper, false, hv_panic_page, HV_HYP_PAGE_SIZE, |
|---|
| 1173 | 1378 | &bytes_written); |
|---|
| 1174 | 1379 | if (bytes_written) |
|---|
| 1175 | 1380 | hyperv_report_panic_msg(panic_pa, bytes_written); |
|---|
| .. | .. |
|---|
| 1180 | 1385 | }; |
|---|
| 1181 | 1386 | |
|---|
| 1182 | 1387 | static struct ctl_table_header *hv_ctl_table_hdr; |
|---|
| 1183 | | -static int zero; |
|---|
| 1184 | | -static int one = 1; |
|---|
| 1185 | 1388 | |
|---|
| 1186 | 1389 | /* |
|---|
| 1187 | 1390 | * sysctl option to allow the user to control whether kmsg data should be |
|---|
| .. | .. |
|---|
| 1194 | 1397 | .maxlen = sizeof(int), |
|---|
| 1195 | 1398 | .mode = 0644, |
|---|
| 1196 | 1399 | .proc_handler = proc_dointvec_minmax, |
|---|
| 1197 | | - .extra1 = &zero, |
|---|
| 1198 | | - .extra2 = &one |
|---|
| 1400 | + .extra1 = SYSCTL_ZERO, |
|---|
| 1401 | + .extra2 = SYSCTL_ONE |
|---|
| 1199 | 1402 | }, |
|---|
| 1200 | 1403 | {} |
|---|
| 1201 | 1404 | }; |
|---|
| .. | .. |
|---|
| 1221 | 1424 | { |
|---|
| 1222 | 1425 | int ret; |
|---|
| 1223 | 1426 | |
|---|
| 1224 | | - /* Hypervisor initialization...setup hypercall page..etc */ |
|---|
| 1225 | 1427 | ret = hv_init(); |
|---|
| 1226 | 1428 | if (ret != 0) { |
|---|
| 1227 | 1429 | pr_err("Unable to initialize the hypervisor - 0x%x\n", ret); |
|---|
| .. | .. |
|---|
| 1232 | 1434 | if (ret) |
|---|
| 1233 | 1435 | return ret; |
|---|
| 1234 | 1436 | |
|---|
| 1235 | | - hv_setup_vmbus_irq(vmbus_isr); |
|---|
| 1437 | + ret = hv_setup_vmbus_irq(vmbus_irq, vmbus_isr); |
|---|
| 1438 | + if (ret) |
|---|
| 1439 | + goto err_setup; |
|---|
| 1236 | 1440 | |
|---|
| 1237 | 1441 | ret = hv_synic_alloc(); |
|---|
| 1238 | 1442 | if (ret) |
|---|
| 1239 | 1443 | goto err_alloc; |
|---|
| 1444 | + |
|---|
| 1240 | 1445 | /* |
|---|
| 1241 | | - * Initialize the per-cpu interrupt state and |
|---|
| 1242 | | - * connect to the host. |
|---|
| 1446 | + * Initialize the per-cpu interrupt state and stimer state. |
|---|
| 1447 | + * Then connect to the host. |
|---|
| 1243 | 1448 | */ |
|---|
| 1244 | 1449 | ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "hyperv/vmbus:online", |
|---|
| 1245 | 1450 | hv_synic_init, hv_synic_cleanup); |
|---|
| 1246 | 1451 | if (ret < 0) |
|---|
| 1247 | | - goto err_alloc; |
|---|
| 1452 | + goto err_cpuhp; |
|---|
| 1248 | 1453 | hyperv_cpuhp_online = ret; |
|---|
| 1249 | 1454 | |
|---|
| 1250 | 1455 | ret = vmbus_connect(); |
|---|
| .. | .. |
|---|
| 1270 | 1475 | */ |
|---|
| 1271 | 1476 | hv_get_crash_ctl(hyperv_crash_ctl); |
|---|
| 1272 | 1477 | if (hyperv_crash_ctl & HV_CRASH_CTL_CRASH_NOTIFY_MSG) { |
|---|
| 1273 | | - hv_panic_page = (void *)get_zeroed_page(GFP_KERNEL); |
|---|
| 1478 | + hv_panic_page = (void *)hv_alloc_hyperv_zeroed_page(); |
|---|
| 1274 | 1479 | if (hv_panic_page) { |
|---|
| 1275 | 1480 | ret = kmsg_dump_register(&hv_kmsg_dumper); |
|---|
| 1276 | 1481 | if (ret) { |
|---|
| 1277 | 1482 | pr_err("Hyper-V: kmsg dump register " |
|---|
| 1278 | 1483 | "error 0x%x\n", ret); |
|---|
| 1279 | | - free_page( |
|---|
| 1484 | + hv_free_hyperv_page( |
|---|
| 1280 | 1485 | (unsigned long)hv_panic_page); |
|---|
| 1281 | 1486 | hv_panic_page = NULL; |
|---|
| 1282 | 1487 | } |
|---|
| .. | .. |
|---|
| 1302 | 1507 | |
|---|
| 1303 | 1508 | err_connect: |
|---|
| 1304 | 1509 | cpuhp_remove_state(hyperv_cpuhp_online); |
|---|
| 1305 | | -err_alloc: |
|---|
| 1510 | +err_cpuhp: |
|---|
| 1306 | 1511 | hv_synic_free(); |
|---|
| 1512 | +err_alloc: |
|---|
| 1307 | 1513 | hv_remove_vmbus_irq(); |
|---|
| 1308 | | - |
|---|
| 1514 | +err_setup: |
|---|
| 1309 | 1515 | bus_unregister(&hv_bus); |
|---|
| 1310 | 1516 | unregister_sysctl_table(hv_ctl_table_hdr); |
|---|
| 1311 | 1517 | hv_ctl_table_hdr = NULL; |
|---|
| .. | .. |
|---|
| 1380 | 1586 | |
|---|
| 1381 | 1587 | struct vmbus_chan_attribute { |
|---|
| 1382 | 1588 | struct attribute attr; |
|---|
| 1383 | | - ssize_t (*show)(const struct vmbus_channel *chan, char *buf); |
|---|
| 1589 | + ssize_t (*show)(struct vmbus_channel *chan, char *buf); |
|---|
| 1384 | 1590 | ssize_t (*store)(struct vmbus_channel *chan, |
|---|
| 1385 | 1591 | const char *buf, size_t count); |
|---|
| 1386 | 1592 | }; |
|---|
| .. | .. |
|---|
| 1399 | 1605 | { |
|---|
| 1400 | 1606 | const struct vmbus_chan_attribute *attribute |
|---|
| 1401 | 1607 | = container_of(attr, struct vmbus_chan_attribute, attr); |
|---|
| 1402 | | - const struct vmbus_channel *chan |
|---|
| 1608 | + struct vmbus_channel *chan |
|---|
| 1403 | 1609 | = container_of(kobj, struct vmbus_channel, kobj); |
|---|
| 1404 | 1610 | |
|---|
| 1405 | 1611 | if (!attribute->show) |
|---|
| 1406 | 1612 | return -EIO; |
|---|
| 1407 | 1613 | |
|---|
| 1408 | | - if (chan->state != CHANNEL_OPENED_STATE) |
|---|
| 1409 | | - return -EINVAL; |
|---|
| 1410 | | - |
|---|
| 1411 | 1614 | return attribute->show(chan, buf); |
|---|
| 1615 | +} |
|---|
| 1616 | + |
|---|
| 1617 | +static ssize_t vmbus_chan_attr_store(struct kobject *kobj, |
|---|
| 1618 | + struct attribute *attr, const char *buf, |
|---|
| 1619 | + size_t count) |
|---|
| 1620 | +{ |
|---|
| 1621 | + const struct vmbus_chan_attribute *attribute |
|---|
| 1622 | + = container_of(attr, struct vmbus_chan_attribute, attr); |
|---|
| 1623 | + struct vmbus_channel *chan |
|---|
| 1624 | + = container_of(kobj, struct vmbus_channel, kobj); |
|---|
| 1625 | + |
|---|
| 1626 | + if (!attribute->store) |
|---|
| 1627 | + return -EIO; |
|---|
| 1628 | + |
|---|
| 1629 | + return attribute->store(chan, buf, count); |
|---|
| 1412 | 1630 | } |
|---|
| 1413 | 1631 | |
|---|
| 1414 | 1632 | static const struct sysfs_ops vmbus_chan_sysfs_ops = { |
|---|
| 1415 | 1633 | .show = vmbus_chan_attr_show, |
|---|
| 1634 | + .store = vmbus_chan_attr_store, |
|---|
| 1416 | 1635 | }; |
|---|
| 1417 | 1636 | |
|---|
| 1418 | | -static ssize_t out_mask_show(const struct vmbus_channel *channel, char *buf) |
|---|
| 1637 | +static ssize_t out_mask_show(struct vmbus_channel *channel, char *buf) |
|---|
| 1419 | 1638 | { |
|---|
| 1420 | | - const struct hv_ring_buffer_info *rbi = &channel->outbound; |
|---|
| 1639 | + struct hv_ring_buffer_info *rbi = &channel->outbound; |
|---|
| 1640 | + ssize_t ret; |
|---|
| 1421 | 1641 | |
|---|
| 1422 | | - return sprintf(buf, "%u\n", rbi->ring_buffer->interrupt_mask); |
|---|
| 1642 | + mutex_lock(&rbi->ring_buffer_mutex); |
|---|
| 1643 | + if (!rbi->ring_buffer) { |
|---|
| 1644 | + mutex_unlock(&rbi->ring_buffer_mutex); |
|---|
| 1645 | + return -EINVAL; |
|---|
| 1646 | + } |
|---|
| 1647 | + |
|---|
| 1648 | + ret = sprintf(buf, "%u\n", rbi->ring_buffer->interrupt_mask); |
|---|
| 1649 | + mutex_unlock(&rbi->ring_buffer_mutex); |
|---|
| 1650 | + return ret; |
|---|
| 1423 | 1651 | } |
|---|
| 1424 | 1652 | static VMBUS_CHAN_ATTR_RO(out_mask); |
|---|
| 1425 | 1653 | |
|---|
| 1426 | | -static ssize_t in_mask_show(const struct vmbus_channel *channel, char *buf) |
|---|
| 1654 | +static ssize_t in_mask_show(struct vmbus_channel *channel, char *buf) |
|---|
| 1427 | 1655 | { |
|---|
| 1428 | | - const struct hv_ring_buffer_info *rbi = &channel->inbound; |
|---|
| 1656 | + struct hv_ring_buffer_info *rbi = &channel->inbound; |
|---|
| 1657 | + ssize_t ret; |
|---|
| 1429 | 1658 | |
|---|
| 1430 | | - return sprintf(buf, "%u\n", rbi->ring_buffer->interrupt_mask); |
|---|
| 1659 | + mutex_lock(&rbi->ring_buffer_mutex); |
|---|
| 1660 | + if (!rbi->ring_buffer) { |
|---|
| 1661 | + mutex_unlock(&rbi->ring_buffer_mutex); |
|---|
| 1662 | + return -EINVAL; |
|---|
| 1663 | + } |
|---|
| 1664 | + |
|---|
| 1665 | + ret = sprintf(buf, "%u\n", rbi->ring_buffer->interrupt_mask); |
|---|
| 1666 | + mutex_unlock(&rbi->ring_buffer_mutex); |
|---|
| 1667 | + return ret; |
|---|
| 1431 | 1668 | } |
|---|
| 1432 | 1669 | static VMBUS_CHAN_ATTR_RO(in_mask); |
|---|
| 1433 | 1670 | |
|---|
| 1434 | | -static ssize_t read_avail_show(const struct vmbus_channel *channel, char *buf) |
|---|
| 1671 | +static ssize_t read_avail_show(struct vmbus_channel *channel, char *buf) |
|---|
| 1435 | 1672 | { |
|---|
| 1436 | | - const struct hv_ring_buffer_info *rbi = &channel->inbound; |
|---|
| 1673 | + struct hv_ring_buffer_info *rbi = &channel->inbound; |
|---|
| 1674 | + ssize_t ret; |
|---|
| 1437 | 1675 | |
|---|
| 1438 | | - return sprintf(buf, "%u\n", hv_get_bytes_to_read(rbi)); |
|---|
| 1676 | + mutex_lock(&rbi->ring_buffer_mutex); |
|---|
| 1677 | + if (!rbi->ring_buffer) { |
|---|
| 1678 | + mutex_unlock(&rbi->ring_buffer_mutex); |
|---|
| 1679 | + return -EINVAL; |
|---|
| 1680 | + } |
|---|
| 1681 | + |
|---|
| 1682 | + ret = sprintf(buf, "%u\n", hv_get_bytes_to_read(rbi)); |
|---|
| 1683 | + mutex_unlock(&rbi->ring_buffer_mutex); |
|---|
| 1684 | + return ret; |
|---|
| 1439 | 1685 | } |
|---|
| 1440 | 1686 | static VMBUS_CHAN_ATTR_RO(read_avail); |
|---|
| 1441 | 1687 | |
|---|
| 1442 | | -static ssize_t write_avail_show(const struct vmbus_channel *channel, char *buf) |
|---|
| 1688 | +static ssize_t write_avail_show(struct vmbus_channel *channel, char *buf) |
|---|
| 1443 | 1689 | { |
|---|
| 1444 | | - const struct hv_ring_buffer_info *rbi = &channel->outbound; |
|---|
| 1690 | + struct hv_ring_buffer_info *rbi = &channel->outbound; |
|---|
| 1691 | + ssize_t ret; |
|---|
| 1445 | 1692 | |
|---|
| 1446 | | - return sprintf(buf, "%u\n", hv_get_bytes_to_write(rbi)); |
|---|
| 1693 | + mutex_lock(&rbi->ring_buffer_mutex); |
|---|
| 1694 | + if (!rbi->ring_buffer) { |
|---|
| 1695 | + mutex_unlock(&rbi->ring_buffer_mutex); |
|---|
| 1696 | + return -EINVAL; |
|---|
| 1697 | + } |
|---|
| 1698 | + |
|---|
| 1699 | + ret = sprintf(buf, "%u\n", hv_get_bytes_to_write(rbi)); |
|---|
| 1700 | + mutex_unlock(&rbi->ring_buffer_mutex); |
|---|
| 1701 | + return ret; |
|---|
| 1447 | 1702 | } |
|---|
| 1448 | 1703 | static VMBUS_CHAN_ATTR_RO(write_avail); |
|---|
| 1449 | 1704 | |
|---|
| 1450 | | -static ssize_t show_target_cpu(const struct vmbus_channel *channel, char *buf) |
|---|
| 1705 | +static ssize_t target_cpu_show(struct vmbus_channel *channel, char *buf) |
|---|
| 1451 | 1706 | { |
|---|
| 1452 | 1707 | return sprintf(buf, "%u\n", channel->target_cpu); |
|---|
| 1453 | 1708 | } |
|---|
| 1454 | | -static VMBUS_CHAN_ATTR(cpu, S_IRUGO, show_target_cpu, NULL); |
|---|
| 1709 | +static ssize_t target_cpu_store(struct vmbus_channel *channel, |
|---|
| 1710 | + const char *buf, size_t count) |
|---|
| 1711 | +{ |
|---|
| 1712 | + u32 target_cpu, origin_cpu; |
|---|
| 1713 | + ssize_t ret = count; |
|---|
| 1455 | 1714 | |
|---|
| 1456 | | -static ssize_t channel_pending_show(const struct vmbus_channel *channel, |
|---|
| 1715 | + if (vmbus_proto_version < VERSION_WIN10_V4_1) |
|---|
| 1716 | + return -EIO; |
|---|
| 1717 | + |
|---|
| 1718 | + if (sscanf(buf, "%uu", &target_cpu) != 1) |
|---|
| 1719 | + return -EIO; |
|---|
| 1720 | + |
|---|
| 1721 | + /* Validate target_cpu for the cpumask_test_cpu() operation below. */ |
|---|
| 1722 | + if (target_cpu >= nr_cpumask_bits) |
|---|
| 1723 | + return -EINVAL; |
|---|
| 1724 | + |
|---|
| 1725 | + /* No CPUs should come up or down during this. */ |
|---|
| 1726 | + cpus_read_lock(); |
|---|
| 1727 | + |
|---|
| 1728 | + if (!cpu_online(target_cpu)) { |
|---|
| 1729 | + cpus_read_unlock(); |
|---|
| 1730 | + return -EINVAL; |
|---|
| 1731 | + } |
|---|
| 1732 | + |
|---|
| 1733 | + /* |
|---|
| 1734 | + * Synchronizes target_cpu_store() and channel closure: |
|---|
| 1735 | + * |
|---|
| 1736 | + * { Initially: state = CHANNEL_OPENED } |
|---|
| 1737 | + * |
|---|
| 1738 | + * CPU1 CPU2 |
|---|
| 1739 | + * |
|---|
| 1740 | + * [target_cpu_store()] [vmbus_disconnect_ring()] |
|---|
| 1741 | + * |
|---|
| 1742 | + * LOCK channel_mutex LOCK channel_mutex |
|---|
| 1743 | + * LOAD r1 = state LOAD r2 = state |
|---|
| 1744 | + * IF (r1 == CHANNEL_OPENED) IF (r2 == CHANNEL_OPENED) |
|---|
| 1745 | + * SEND MODIFYCHANNEL STORE state = CHANNEL_OPEN |
|---|
| 1746 | + * [...] SEND CLOSECHANNEL |
|---|
| 1747 | + * UNLOCK channel_mutex UNLOCK channel_mutex |
|---|
| 1748 | + * |
|---|
| 1749 | + * Forbids: r1 == r2 == CHANNEL_OPENED (i.e., CPU1's LOCK precedes |
|---|
| 1750 | + * CPU2's LOCK) && CPU2's SEND precedes CPU1's SEND |
|---|
| 1751 | + * |
|---|
| 1752 | + * Note. The host processes the channel messages "sequentially", in |
|---|
| 1753 | + * the order in which they are received on a per-partition basis. |
|---|
| 1754 | + */ |
|---|
| 1755 | + mutex_lock(&vmbus_connection.channel_mutex); |
|---|
| 1756 | + |
|---|
| 1757 | + /* |
|---|
| 1758 | + * Hyper-V will ignore MODIFYCHANNEL messages for "non-open" channels; |
|---|
| 1759 | + * avoid sending the message and fail here for such channels. |
|---|
| 1760 | + */ |
|---|
| 1761 | + if (channel->state != CHANNEL_OPENED_STATE) { |
|---|
| 1762 | + ret = -EIO; |
|---|
| 1763 | + goto cpu_store_unlock; |
|---|
| 1764 | + } |
|---|
| 1765 | + |
|---|
| 1766 | + origin_cpu = channel->target_cpu; |
|---|
| 1767 | + if (target_cpu == origin_cpu) |
|---|
| 1768 | + goto cpu_store_unlock; |
|---|
| 1769 | + |
|---|
| 1770 | + if (vmbus_send_modifychannel(channel->offermsg.child_relid, |
|---|
| 1771 | + hv_cpu_number_to_vp_number(target_cpu))) { |
|---|
| 1772 | + ret = -EIO; |
|---|
| 1773 | + goto cpu_store_unlock; |
|---|
| 1774 | + } |
|---|
| 1775 | + |
|---|
| 1776 | + /* |
|---|
| 1777 | + * Warning. At this point, there is *no* guarantee that the host will |
|---|
| 1778 | + * have successfully processed the vmbus_send_modifychannel() request. |
|---|
| 1779 | + * See the header comment of vmbus_send_modifychannel() for more info. |
|---|
| 1780 | + * |
|---|
| 1781 | + * Lags in the processing of the above vmbus_send_modifychannel() can |
|---|
| 1782 | + * result in missed interrupts if the "old" target CPU is taken offline |
|---|
| 1783 | + * before Hyper-V starts sending interrupts to the "new" target CPU. |
|---|
| 1784 | + * But apart from this offlining scenario, the code tolerates such |
|---|
| 1785 | + * lags. It will function correctly even if a channel interrupt comes |
|---|
| 1786 | + * in on a CPU that is different from the channel target_cpu value. |
|---|
| 1787 | + */ |
|---|
| 1788 | + |
|---|
| 1789 | + channel->target_cpu = target_cpu; |
|---|
| 1790 | + |
|---|
| 1791 | + /* See init_vp_index(). */ |
|---|
| 1792 | + if (hv_is_perf_channel(channel)) |
|---|
| 1793 | + hv_update_alloced_cpus(origin_cpu, target_cpu); |
|---|
| 1794 | + |
|---|
| 1795 | + /* Currently set only for storvsc channels. */ |
|---|
| 1796 | + if (channel->change_target_cpu_callback) { |
|---|
| 1797 | + (*channel->change_target_cpu_callback)(channel, |
|---|
| 1798 | + origin_cpu, target_cpu); |
|---|
| 1799 | + } |
|---|
| 1800 | + |
|---|
| 1801 | +cpu_store_unlock: |
|---|
| 1802 | + mutex_unlock(&vmbus_connection.channel_mutex); |
|---|
| 1803 | + cpus_read_unlock(); |
|---|
| 1804 | + return ret; |
|---|
| 1805 | +} |
|---|
| 1806 | +static VMBUS_CHAN_ATTR(cpu, 0644, target_cpu_show, target_cpu_store); |
|---|
| 1807 | + |
|---|
| 1808 | +static ssize_t channel_pending_show(struct vmbus_channel *channel, |
|---|
| 1457 | 1809 | char *buf) |
|---|
| 1458 | 1810 | { |
|---|
| 1459 | 1811 | return sprintf(buf, "%d\n", |
|---|
| .. | .. |
|---|
| 1462 | 1814 | } |
|---|
| 1463 | 1815 | static VMBUS_CHAN_ATTR(pending, S_IRUGO, channel_pending_show, NULL); |
|---|
| 1464 | 1816 | |
|---|
| 1465 | | -static ssize_t channel_latency_show(const struct vmbus_channel *channel, |
|---|
| 1817 | +static ssize_t channel_latency_show(struct vmbus_channel *channel, |
|---|
| 1466 | 1818 | char *buf) |
|---|
| 1467 | 1819 | { |
|---|
| 1468 | 1820 | return sprintf(buf, "%d\n", |
|---|
| .. | .. |
|---|
| 1471 | 1823 | } |
|---|
| 1472 | 1824 | static VMBUS_CHAN_ATTR(latency, S_IRUGO, channel_latency_show, NULL); |
|---|
| 1473 | 1825 | |
|---|
| 1474 | | -static ssize_t channel_interrupts_show(const struct vmbus_channel *channel, char *buf) |
|---|
| 1826 | +static ssize_t channel_interrupts_show(struct vmbus_channel *channel, char *buf) |
|---|
| 1475 | 1827 | { |
|---|
| 1476 | 1828 | return sprintf(buf, "%llu\n", channel->interrupts); |
|---|
| 1477 | 1829 | } |
|---|
| 1478 | 1830 | static VMBUS_CHAN_ATTR(interrupts, S_IRUGO, channel_interrupts_show, NULL); |
|---|
| 1479 | 1831 | |
|---|
| 1480 | | -static ssize_t channel_events_show(const struct vmbus_channel *channel, char *buf) |
|---|
| 1832 | +static ssize_t channel_events_show(struct vmbus_channel *channel, char *buf) |
|---|
| 1481 | 1833 | { |
|---|
| 1482 | 1834 | return sprintf(buf, "%llu\n", channel->sig_events); |
|---|
| 1483 | 1835 | } |
|---|
| 1484 | 1836 | static VMBUS_CHAN_ATTR(events, S_IRUGO, channel_events_show, NULL); |
|---|
| 1485 | 1837 | |
|---|
| 1486 | | -static ssize_t subchannel_monitor_id_show(const struct vmbus_channel *channel, |
|---|
| 1838 | +static ssize_t channel_intr_in_full_show(struct vmbus_channel *channel, |
|---|
| 1839 | + char *buf) |
|---|
| 1840 | +{ |
|---|
| 1841 | + return sprintf(buf, "%llu\n", |
|---|
| 1842 | + (unsigned long long)channel->intr_in_full); |
|---|
| 1843 | +} |
|---|
| 1844 | +static VMBUS_CHAN_ATTR(intr_in_full, 0444, channel_intr_in_full_show, NULL); |
|---|
| 1845 | + |
|---|
| 1846 | +static ssize_t channel_intr_out_empty_show(struct vmbus_channel *channel, |
|---|
| 1847 | + char *buf) |
|---|
| 1848 | +{ |
|---|
| 1849 | + return sprintf(buf, "%llu\n", |
|---|
| 1850 | + (unsigned long long)channel->intr_out_empty); |
|---|
| 1851 | +} |
|---|
| 1852 | +static VMBUS_CHAN_ATTR(intr_out_empty, 0444, channel_intr_out_empty_show, NULL); |
|---|
| 1853 | + |
|---|
| 1854 | +static ssize_t channel_out_full_first_show(struct vmbus_channel *channel, |
|---|
| 1855 | + char *buf) |
|---|
| 1856 | +{ |
|---|
| 1857 | + return sprintf(buf, "%llu\n", |
|---|
| 1858 | + (unsigned long long)channel->out_full_first); |
|---|
| 1859 | +} |
|---|
| 1860 | +static VMBUS_CHAN_ATTR(out_full_first, 0444, channel_out_full_first_show, NULL); |
|---|
| 1861 | + |
|---|
| 1862 | +static ssize_t channel_out_full_total_show(struct vmbus_channel *channel, |
|---|
| 1863 | + char *buf) |
|---|
| 1864 | +{ |
|---|
| 1865 | + return sprintf(buf, "%llu\n", |
|---|
| 1866 | + (unsigned long long)channel->out_full_total); |
|---|
| 1867 | +} |
|---|
| 1868 | +static VMBUS_CHAN_ATTR(out_full_total, 0444, channel_out_full_total_show, NULL); |
|---|
| 1869 | + |
|---|
| 1870 | +static ssize_t subchannel_monitor_id_show(struct vmbus_channel *channel, |
|---|
| 1487 | 1871 | char *buf) |
|---|
| 1488 | 1872 | { |
|---|
| 1489 | 1873 | return sprintf(buf, "%u\n", channel->offermsg.monitorid); |
|---|
| 1490 | 1874 | } |
|---|
| 1491 | 1875 | static VMBUS_CHAN_ATTR(monitor_id, S_IRUGO, subchannel_monitor_id_show, NULL); |
|---|
| 1492 | 1876 | |
|---|
| 1493 | | -static ssize_t subchannel_id_show(const struct vmbus_channel *channel, |
|---|
| 1877 | +static ssize_t subchannel_id_show(struct vmbus_channel *channel, |
|---|
| 1494 | 1878 | char *buf) |
|---|
| 1495 | 1879 | { |
|---|
| 1496 | 1880 | return sprintf(buf, "%u\n", |
|---|
| .. | .. |
|---|
| 1508 | 1892 | &chan_attr_latency.attr, |
|---|
| 1509 | 1893 | &chan_attr_interrupts.attr, |
|---|
| 1510 | 1894 | &chan_attr_events.attr, |
|---|
| 1895 | + &chan_attr_intr_in_full.attr, |
|---|
| 1896 | + &chan_attr_intr_out_empty.attr, |
|---|
| 1897 | + &chan_attr_out_full_first.attr, |
|---|
| 1898 | + &chan_attr_out_full_total.attr, |
|---|
| 1511 | 1899 | &chan_attr_monitor_id.attr, |
|---|
| 1512 | 1900 | &chan_attr_subchannel_id.attr, |
|---|
| 1513 | 1901 | NULL |
|---|
| .. | .. |
|---|
| 1590 | 1978 | * vmbus_device_create - Creates and registers a new child device |
|---|
| 1591 | 1979 | * on the vmbus. |
|---|
| 1592 | 1980 | */ |
|---|
| 1593 | | -struct hv_device *vmbus_device_create(const uuid_le *type, |
|---|
| 1594 | | - const uuid_le *instance, |
|---|
| 1981 | +struct hv_device *vmbus_device_create(const guid_t *type, |
|---|
| 1982 | + const guid_t *instance, |
|---|
| 1595 | 1983 | struct vmbus_channel *channel) |
|---|
| 1596 | 1984 | { |
|---|
| 1597 | 1985 | struct hv_device *child_device_obj; |
|---|
| .. | .. |
|---|
| 1603 | 1991 | } |
|---|
| 1604 | 1992 | |
|---|
| 1605 | 1993 | child_device_obj->channel = channel; |
|---|
| 1606 | | - memcpy(&child_device_obj->dev_type, type, sizeof(uuid_le)); |
|---|
| 1607 | | - memcpy(&child_device_obj->dev_instance, instance, |
|---|
| 1608 | | - sizeof(uuid_le)); |
|---|
| 1994 | + guid_copy(&child_device_obj->dev_type, type); |
|---|
| 1995 | + guid_copy(&child_device_obj->dev_instance, instance); |
|---|
| 1609 | 1996 | child_device_obj->vendor_id = 0x1414; /* MSFT vendor ID */ |
|---|
| 1610 | | - |
|---|
| 1611 | 1997 | |
|---|
| 1612 | 1998 | return child_device_obj; |
|---|
| 1613 | 1999 | } |
|---|
| .. | .. |
|---|
| 1621 | 2007 | int ret; |
|---|
| 1622 | 2008 | |
|---|
| 1623 | 2009 | dev_set_name(&child_device_obj->device, "%pUl", |
|---|
| 1624 | | - child_device_obj->channel->offermsg.offer.if_instance.b); |
|---|
| 2010 | + &child_device_obj->channel->offermsg.offer.if_instance); |
|---|
| 1625 | 2011 | |
|---|
| 1626 | 2012 | child_device_obj->device.bus = &hv_bus; |
|---|
| 1627 | 2013 | child_device_obj->device.parent = &hv_acpi_dev->dev; |
|---|
| .. | .. |
|---|
| 1634 | 2020 | ret = device_register(&child_device_obj->device); |
|---|
| 1635 | 2021 | if (ret) { |
|---|
| 1636 | 2022 | pr_err("Unable to register child device\n"); |
|---|
| 2023 | + put_device(&child_device_obj->device); |
|---|
| 1637 | 2024 | return ret; |
|---|
| 1638 | 2025 | } |
|---|
| 1639 | 2026 | |
|---|
| .. | .. |
|---|
| 1650 | 2037 | pr_err("Unable to register primary channeln"); |
|---|
| 1651 | 2038 | goto err_kset_unregister; |
|---|
| 1652 | 2039 | } |
|---|
| 2040 | + hv_debug_add_dev_dir(child_device_obj); |
|---|
| 1653 | 2041 | |
|---|
| 1654 | 2042 | return 0; |
|---|
| 1655 | 2043 | |
|---|
| .. | .. |
|---|
| 1692 | 2080 | struct resource *new_res; |
|---|
| 1693 | 2081 | struct resource **old_res = &hyperv_mmio; |
|---|
| 1694 | 2082 | struct resource **prev_res = NULL; |
|---|
| 2083 | + struct resource r; |
|---|
| 1695 | 2084 | |
|---|
| 1696 | 2085 | switch (res->type) { |
|---|
| 1697 | 2086 | |
|---|
| .. | .. |
|---|
| 1709 | 2098 | start = res->data.address64.address.minimum; |
|---|
| 1710 | 2099 | end = res->data.address64.address.maximum; |
|---|
| 1711 | 2100 | break; |
|---|
| 2101 | + |
|---|
| 2102 | + /* |
|---|
| 2103 | + * The IRQ information is needed only on ARM64, which Hyper-V |
|---|
| 2104 | + * sets up in the extended format. IRQ information is present |
|---|
| 2105 | + * on x86/x64 in the non-extended format but it is not used by |
|---|
| 2106 | + * Linux. So don't bother checking for the non-extended format. |
|---|
| 2107 | + */ |
|---|
| 2108 | + case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: |
|---|
| 2109 | + if (!acpi_dev_resource_interrupt(res, 0, &r)) { |
|---|
| 2110 | + pr_err("Unable to parse Hyper-V ACPI interrupt\n"); |
|---|
| 2111 | + return AE_ERROR; |
|---|
| 2112 | + } |
|---|
| 2113 | + /* ARM64 INTID for VMbus */ |
|---|
| 2114 | + vmbus_interrupt = res->data.extended_irq.interrupts[0]; |
|---|
| 2115 | + /* Linux IRQ number */ |
|---|
| 2116 | + vmbus_irq = r.start; |
|---|
| 2117 | + return AE_OK; |
|---|
| 1712 | 2118 | |
|---|
| 1713 | 2119 | default: |
|---|
| 1714 | 2120 | /* Unused resource type */ |
|---|
| .. | .. |
|---|
| 1846 | 2252 | bool fb_overlap_ok) |
|---|
| 1847 | 2253 | { |
|---|
| 1848 | 2254 | struct resource *iter, *shadow; |
|---|
| 1849 | | - resource_size_t range_min, range_max, start; |
|---|
| 2255 | + resource_size_t range_min, range_max, start, end; |
|---|
| 1850 | 2256 | const char *dev_n = dev_name(&device_obj->device); |
|---|
| 1851 | 2257 | int retval; |
|---|
| 1852 | 2258 | |
|---|
| 1853 | 2259 | retval = -ENXIO; |
|---|
| 1854 | | - down(&hyperv_mmio_lock); |
|---|
| 2260 | + mutex_lock(&hyperv_mmio_lock); |
|---|
| 1855 | 2261 | |
|---|
| 1856 | 2262 | /* |
|---|
| 1857 | 2263 | * If overlaps with frame buffers are allowed, then first attempt to |
|---|
| .. | .. |
|---|
| 1881 | 2287 | range_max = iter->end; |
|---|
| 1882 | 2288 | start = (range_min + align - 1) & ~(align - 1); |
|---|
| 1883 | 2289 | for (; start + size - 1 <= range_max; start += align) { |
|---|
| 2290 | + end = start + size - 1; |
|---|
| 2291 | + |
|---|
| 2292 | + /* Skip the whole fb_mmio region if not fb_overlap_ok */ |
|---|
| 2293 | + if (!fb_overlap_ok && fb_mmio && |
|---|
| 2294 | + (((start >= fb_mmio->start) && (start <= fb_mmio->end)) || |
|---|
| 2295 | + ((end >= fb_mmio->start) && (end <= fb_mmio->end)))) |
|---|
| 2296 | + continue; |
|---|
| 2297 | + |
|---|
| 1884 | 2298 | shadow = __request_region(iter, start, size, NULL, |
|---|
| 1885 | 2299 | IORESOURCE_BUSY); |
|---|
| 1886 | 2300 | if (!shadow) |
|---|
| .. | .. |
|---|
| 1898 | 2312 | } |
|---|
| 1899 | 2313 | |
|---|
| 1900 | 2314 | exit: |
|---|
| 1901 | | - up(&hyperv_mmio_lock); |
|---|
| 2315 | + mutex_unlock(&hyperv_mmio_lock); |
|---|
| 1902 | 2316 | return retval; |
|---|
| 1903 | 2317 | } |
|---|
| 1904 | 2318 | EXPORT_SYMBOL_GPL(vmbus_allocate_mmio); |
|---|
| .. | .. |
|---|
| 1915 | 2329 | { |
|---|
| 1916 | 2330 | struct resource *iter; |
|---|
| 1917 | 2331 | |
|---|
| 1918 | | - down(&hyperv_mmio_lock); |
|---|
| 2332 | + mutex_lock(&hyperv_mmio_lock); |
|---|
| 1919 | 2333 | for (iter = hyperv_mmio; iter; iter = iter->sibling) { |
|---|
| 1920 | 2334 | if ((iter->start >= start + size) || (iter->end <= start)) |
|---|
| 1921 | 2335 | continue; |
|---|
| .. | .. |
|---|
| 1923 | 2337 | __release_region(iter, start, size); |
|---|
| 1924 | 2338 | } |
|---|
| 1925 | 2339 | release_mem_region(start, size); |
|---|
| 1926 | | - up(&hyperv_mmio_lock); |
|---|
| 2340 | + mutex_unlock(&hyperv_mmio_lock); |
|---|
| 1927 | 2341 | |
|---|
| 1928 | 2342 | } |
|---|
| 1929 | 2343 | EXPORT_SYMBOL_GPL(vmbus_free_mmio); |
|---|
| .. | .. |
|---|
| 1965 | 2379 | return ret_val; |
|---|
| 1966 | 2380 | } |
|---|
| 1967 | 2381 | |
|---|
| 2382 | +#ifdef CONFIG_PM_SLEEP |
|---|
| 2383 | +static int vmbus_bus_suspend(struct device *dev) |
|---|
| 2384 | +{ |
|---|
| 2385 | + struct vmbus_channel *channel, *sc; |
|---|
| 2386 | + |
|---|
| 2387 | + while (atomic_read(&vmbus_connection.offer_in_progress) != 0) { |
|---|
| 2388 | + /* |
|---|
| 2389 | + * We wait here until the completion of any channel |
|---|
| 2390 | + * offers that are currently in progress. |
|---|
| 2391 | + */ |
|---|
| 2392 | + msleep(1); |
|---|
| 2393 | + } |
|---|
| 2394 | + |
|---|
| 2395 | + mutex_lock(&vmbus_connection.channel_mutex); |
|---|
| 2396 | + list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) { |
|---|
| 2397 | + if (!is_hvsock_channel(channel)) |
|---|
| 2398 | + continue; |
|---|
| 2399 | + |
|---|
| 2400 | + vmbus_force_channel_rescinded(channel); |
|---|
| 2401 | + } |
|---|
| 2402 | + mutex_unlock(&vmbus_connection.channel_mutex); |
|---|
| 2403 | + |
|---|
| 2404 | + /* |
|---|
| 2405 | + * Wait until all the sub-channels and hv_sock channels have been |
|---|
| 2406 | + * cleaned up. Sub-channels should be destroyed upon suspend, otherwise |
|---|
| 2407 | + * they would conflict with the new sub-channels that will be created |
|---|
| 2408 | + * in the resume path. hv_sock channels should also be destroyed, but |
|---|
| 2409 | + * a hv_sock channel of an established hv_sock connection can not be |
|---|
| 2410 | + * really destroyed since it may still be referenced by the userspace |
|---|
| 2411 | + * application, so we just force the hv_sock channel to be rescinded |
|---|
| 2412 | + * by vmbus_force_channel_rescinded(), and the userspace application |
|---|
| 2413 | + * will thoroughly destroy the channel after hibernation. |
|---|
| 2414 | + * |
|---|
| 2415 | + * Note: the counter nr_chan_close_on_suspend may never go above 0 if |
|---|
| 2416 | + * the VM has no sub-channel and hv_sock channel, e.g. a 1-vCPU VM. |
|---|
| 2417 | + */ |
|---|
| 2418 | + if (atomic_read(&vmbus_connection.nr_chan_close_on_suspend) > 0) |
|---|
| 2419 | + wait_for_completion(&vmbus_connection.ready_for_suspend_event); |
|---|
| 2420 | + |
|---|
| 2421 | + if (atomic_read(&vmbus_connection.nr_chan_fixup_on_resume) != 0) { |
|---|
| 2422 | + pr_err("Can not suspend due to a previous failed resuming\n"); |
|---|
| 2423 | + return -EBUSY; |
|---|
| 2424 | + } |
|---|
| 2425 | + |
|---|
| 2426 | + mutex_lock(&vmbus_connection.channel_mutex); |
|---|
| 2427 | + |
|---|
| 2428 | + list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) { |
|---|
| 2429 | + /* |
|---|
| 2430 | + * Remove the channel from the array of channels and invalidate |
|---|
| 2431 | + * the channel's relid. Upon resume, vmbus_onoffer() will fix |
|---|
| 2432 | + * up the relid (and other fields, if necessary) and add the |
|---|
| 2433 | + * channel back to the array. |
|---|
| 2434 | + */ |
|---|
| 2435 | + vmbus_channel_unmap_relid(channel); |
|---|
| 2436 | + channel->offermsg.child_relid = INVALID_RELID; |
|---|
| 2437 | + |
|---|
| 2438 | + if (is_hvsock_channel(channel)) { |
|---|
| 2439 | + if (!channel->rescind) { |
|---|
| 2440 | + pr_err("hv_sock channel not rescinded!\n"); |
|---|
| 2441 | + WARN_ON_ONCE(1); |
|---|
| 2442 | + } |
|---|
| 2443 | + continue; |
|---|
| 2444 | + } |
|---|
| 2445 | + |
|---|
| 2446 | + list_for_each_entry(sc, &channel->sc_list, sc_list) { |
|---|
| 2447 | + pr_err("Sub-channel not deleted!\n"); |
|---|
| 2448 | + WARN_ON_ONCE(1); |
|---|
| 2449 | + } |
|---|
| 2450 | + |
|---|
| 2451 | + atomic_inc(&vmbus_connection.nr_chan_fixup_on_resume); |
|---|
| 2452 | + } |
|---|
| 2453 | + |
|---|
| 2454 | + mutex_unlock(&vmbus_connection.channel_mutex); |
|---|
| 2455 | + |
|---|
| 2456 | + vmbus_initiate_unload(false); |
|---|
| 2457 | + |
|---|
| 2458 | + /* Reset the event for the next resume. */ |
|---|
| 2459 | + reinit_completion(&vmbus_connection.ready_for_resume_event); |
|---|
| 2460 | + |
|---|
| 2461 | + return 0; |
|---|
| 2462 | +} |
|---|
| 2463 | + |
|---|
| 2464 | +static int vmbus_bus_resume(struct device *dev) |
|---|
| 2465 | +{ |
|---|
| 2466 | + struct vmbus_channel_msginfo *msginfo; |
|---|
| 2467 | + size_t msgsize; |
|---|
| 2468 | + int ret; |
|---|
| 2469 | + |
|---|
| 2470 | + /* |
|---|
| 2471 | + * We only use the 'vmbus_proto_version', which was in use before |
|---|
| 2472 | + * hibernation, to re-negotiate with the host. |
|---|
| 2473 | + */ |
|---|
| 2474 | + if (!vmbus_proto_version) { |
|---|
| 2475 | + pr_err("Invalid proto version = 0x%x\n", vmbus_proto_version); |
|---|
| 2476 | + return -EINVAL; |
|---|
| 2477 | + } |
|---|
| 2478 | + |
|---|
| 2479 | + msgsize = sizeof(*msginfo) + |
|---|
| 2480 | + sizeof(struct vmbus_channel_initiate_contact); |
|---|
| 2481 | + |
|---|
| 2482 | + msginfo = kzalloc(msgsize, GFP_KERNEL); |
|---|
| 2483 | + |
|---|
| 2484 | + if (msginfo == NULL) |
|---|
| 2485 | + return -ENOMEM; |
|---|
| 2486 | + |
|---|
| 2487 | + ret = vmbus_negotiate_version(msginfo, vmbus_proto_version); |
|---|
| 2488 | + |
|---|
| 2489 | + kfree(msginfo); |
|---|
| 2490 | + |
|---|
| 2491 | + if (ret != 0) |
|---|
| 2492 | + return ret; |
|---|
| 2493 | + |
|---|
| 2494 | + WARN_ON(atomic_read(&vmbus_connection.nr_chan_fixup_on_resume) == 0); |
|---|
| 2495 | + |
|---|
| 2496 | + vmbus_request_offers(); |
|---|
| 2497 | + |
|---|
| 2498 | + if (wait_for_completion_timeout( |
|---|
| 2499 | + &vmbus_connection.ready_for_resume_event, 10 * HZ) == 0) |
|---|
| 2500 | + pr_err("Some vmbus device is missing after suspending?\n"); |
|---|
| 2501 | + |
|---|
| 2502 | + /* Reset the event for the next suspend. */ |
|---|
| 2503 | + reinit_completion(&vmbus_connection.ready_for_suspend_event); |
|---|
| 2504 | + |
|---|
| 2505 | + return 0; |
|---|
| 2506 | +} |
|---|
| 2507 | +#else |
|---|
| 2508 | +#define vmbus_bus_suspend NULL |
|---|
| 2509 | +#define vmbus_bus_resume NULL |
|---|
| 2510 | +#endif /* CONFIG_PM_SLEEP */ |
|---|
| 2511 | + |
|---|
| 1968 | 2512 | static const struct acpi_device_id vmbus_acpi_device_ids[] = { |
|---|
| 1969 | 2513 | {"VMBUS", 0}, |
|---|
| 1970 | 2514 | {"VMBus", 0}, |
|---|
| 1971 | 2515 | {"", 0}, |
|---|
| 1972 | 2516 | }; |
|---|
| 1973 | 2517 | MODULE_DEVICE_TABLE(acpi, vmbus_acpi_device_ids); |
|---|
| 2518 | + |
|---|
| 2519 | +/* |
|---|
| 2520 | + * Note: we must use the "no_irq" ops, otherwise hibernation can not work with |
|---|
| 2521 | + * PCI device assignment, because "pci_dev_pm_ops" uses the "noirq" ops: in |
|---|
| 2522 | + * the resume path, the pci "noirq" restore op runs before "non-noirq" op (see |
|---|
| 2523 | + * resume_target_kernel() -> dpm_resume_start(), and hibernation_restore() -> |
|---|
| 2524 | + * dpm_resume_end()). This means vmbus_bus_resume() and the pci-hyperv's |
|---|
| 2525 | + * resume callback must also run via the "noirq" ops. |
|---|
| 2526 | + * |
|---|
| 2527 | + * Set suspend_noirq/resume_noirq to NULL for Suspend-to-Idle: see the comment |
|---|
| 2528 | + * earlier in this file before vmbus_pm. |
|---|
| 2529 | + */ |
|---|
| 2530 | + |
|---|
| 2531 | +static const struct dev_pm_ops vmbus_bus_pm = { |
|---|
| 2532 | + .suspend_noirq = NULL, |
|---|
| 2533 | + .resume_noirq = NULL, |
|---|
| 2534 | + .freeze_noirq = vmbus_bus_suspend, |
|---|
| 2535 | + .thaw_noirq = vmbus_bus_resume, |
|---|
| 2536 | + .poweroff_noirq = vmbus_bus_suspend, |
|---|
| 2537 | + .restore_noirq = vmbus_bus_resume |
|---|
| 2538 | +}; |
|---|
| 1974 | 2539 | |
|---|
| 1975 | 2540 | static struct acpi_driver vmbus_acpi_driver = { |
|---|
| 1976 | 2541 | .name = "vmbus", |
|---|
| .. | .. |
|---|
| 1979 | 2544 | .add = vmbus_acpi_add, |
|---|
| 1980 | 2545 | .remove = vmbus_acpi_remove, |
|---|
| 1981 | 2546 | }, |
|---|
| 2547 | + .drv.pm = &vmbus_bus_pm, |
|---|
| 1982 | 2548 | }; |
|---|
| 1983 | 2549 | |
|---|
| 1984 | 2550 | static void hv_kexec_handler(void) |
|---|
| 1985 | 2551 | { |
|---|
| 1986 | | - hv_synic_clockevents_cleanup(); |
|---|
| 2552 | + hv_stimer_global_cleanup(); |
|---|
| 1987 | 2553 | vmbus_initiate_unload(false); |
|---|
| 1988 | 2554 | /* Make sure conn_state is set as hv_synic_cleanup checks for it */ |
|---|
| 1989 | 2555 | mb(); |
|---|
| 1990 | 2556 | cpuhp_remove_state(hyperv_cpuhp_online); |
|---|
| 1991 | | - hyperv_cleanup(); |
|---|
| 1992 | 2557 | }; |
|---|
| 1993 | 2558 | |
|---|
| 1994 | 2559 | static void hv_crash_handler(struct pt_regs *regs) |
|---|
| 1995 | 2560 | { |
|---|
| 2561 | + int cpu; |
|---|
| 2562 | + |
|---|
| 1996 | 2563 | vmbus_initiate_unload(true); |
|---|
| 1997 | 2564 | /* |
|---|
| 1998 | 2565 | * In crash handler we can't schedule synic cleanup for all CPUs, |
|---|
| 1999 | 2566 | * doing the cleanup for current CPU only. This should be sufficient |
|---|
| 2000 | 2567 | * for kdump. |
|---|
| 2001 | 2568 | */ |
|---|
| 2002 | | - hv_synic_cleanup(smp_processor_id()); |
|---|
| 2003 | | - hyperv_cleanup(); |
|---|
| 2569 | + cpu = smp_processor_id(); |
|---|
| 2570 | + hv_stimer_cleanup(cpu); |
|---|
| 2571 | + hv_synic_disable_regs(cpu); |
|---|
| 2572 | +}; |
|---|
| 2573 | + |
|---|
| 2574 | +static int hv_synic_suspend(void) |
|---|
| 2575 | +{ |
|---|
| 2576 | + /* |
|---|
| 2577 | + * When we reach here, all the non-boot CPUs have been offlined. |
|---|
| 2578 | + * If we're in a legacy configuration where stimer Direct Mode is |
|---|
| 2579 | + * not enabled, the stimers on the non-boot CPUs have been unbound |
|---|
| 2580 | + * in hv_synic_cleanup() -> hv_stimer_legacy_cleanup() -> |
|---|
| 2581 | + * hv_stimer_cleanup() -> clockevents_unbind_device(). |
|---|
| 2582 | + * |
|---|
| 2583 | + * hv_synic_suspend() only runs on CPU0 with interrupts disabled. |
|---|
| 2584 | + * Here we do not call hv_stimer_legacy_cleanup() on CPU0 because: |
|---|
| 2585 | + * 1) it's unnecessary as interrupts remain disabled between |
|---|
| 2586 | + * syscore_suspend() and syscore_resume(): see create_image() and |
|---|
| 2587 | + * resume_target_kernel() |
|---|
| 2588 | + * 2) the stimer on CPU0 is automatically disabled later by |
|---|
| 2589 | + * syscore_suspend() -> timekeeping_suspend() -> tick_suspend() -> ... |
|---|
| 2590 | + * -> clockevents_shutdown() -> ... -> hv_ce_shutdown() |
|---|
| 2591 | + * 3) a warning would be triggered if we call |
|---|
| 2592 | + * clockevents_unbind_device(), which may sleep, in an |
|---|
| 2593 | + * interrupts-disabled context. |
|---|
| 2594 | + */ |
|---|
| 2595 | + |
|---|
| 2596 | + hv_synic_disable_regs(0); |
|---|
| 2597 | + |
|---|
| 2598 | + return 0; |
|---|
| 2599 | +} |
|---|
| 2600 | + |
|---|
| 2601 | +static void hv_synic_resume(void) |
|---|
| 2602 | +{ |
|---|
| 2603 | + hv_synic_enable_regs(0); |
|---|
| 2604 | + |
|---|
| 2605 | + /* |
|---|
| 2606 | + * Note: we don't need to call hv_stimer_init(0), because the timer |
|---|
| 2607 | + * on CPU0 is not unbound in hv_synic_suspend(), and the timer is |
|---|
| 2608 | + * automatically re-enabled in timekeeping_resume(). |
|---|
| 2609 | + */ |
|---|
| 2610 | +} |
|---|
| 2611 | + |
|---|
| 2612 | +/* The callbacks run only on CPU0, with irqs_disabled. */ |
|---|
| 2613 | +static struct syscore_ops hv_synic_syscore_ops = { |
|---|
| 2614 | + .suspend = hv_synic_suspend, |
|---|
| 2615 | + .resume = hv_synic_resume, |
|---|
| 2004 | 2616 | }; |
|---|
| 2005 | 2617 | |
|---|
| 2006 | 2618 | static int __init hv_acpi_init(void) |
|---|
| .. | .. |
|---|
| 2025 | 2637 | ret = -ETIMEDOUT; |
|---|
| 2026 | 2638 | goto cleanup; |
|---|
| 2027 | 2639 | } |
|---|
| 2640 | + hv_debug_init(); |
|---|
| 2028 | 2641 | |
|---|
| 2029 | 2642 | ret = vmbus_bus_init(); |
|---|
| 2030 | 2643 | if (ret) |
|---|
| .. | .. |
|---|
| 2032 | 2645 | |
|---|
| 2033 | 2646 | hv_setup_kexec_handler(hv_kexec_handler); |
|---|
| 2034 | 2647 | hv_setup_crash_handler(hv_crash_handler); |
|---|
| 2648 | + |
|---|
| 2649 | + register_syscore_ops(&hv_synic_syscore_ops); |
|---|
| 2035 | 2650 | |
|---|
| 2036 | 2651 | return 0; |
|---|
| 2037 | 2652 | |
|---|
| .. | .. |
|---|
| 2045 | 2660 | { |
|---|
| 2046 | 2661 | int cpu; |
|---|
| 2047 | 2662 | |
|---|
| 2663 | + unregister_syscore_ops(&hv_synic_syscore_ops); |
|---|
| 2664 | + |
|---|
| 2048 | 2665 | hv_remove_kexec_handler(); |
|---|
| 2049 | 2666 | hv_remove_crash_handler(); |
|---|
| 2050 | 2667 | vmbus_connection.conn_state = DISCONNECTED; |
|---|
| 2051 | | - hv_synic_clockevents_cleanup(); |
|---|
| 2668 | + hv_stimer_global_cleanup(); |
|---|
| 2052 | 2669 | vmbus_disconnect(); |
|---|
| 2053 | 2670 | hv_remove_vmbus_irq(); |
|---|
| 2054 | 2671 | for_each_online_cpu(cpu) { |
|---|
| .. | .. |
|---|
| 2057 | 2674 | |
|---|
| 2058 | 2675 | tasklet_kill(&hv_cpu->msg_dpc); |
|---|
| 2059 | 2676 | } |
|---|
| 2677 | + hv_debug_rm_all_dir(); |
|---|
| 2678 | + |
|---|
| 2060 | 2679 | vmbus_free_channels(); |
|---|
| 2680 | + kfree(vmbus_connection.channels); |
|---|
| 2061 | 2681 | |
|---|
| 2062 | 2682 | if (ms_hyperv.misc_features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE) { |
|---|
| 2063 | 2683 | kmsg_dump_unregister(&hv_kmsg_dumper); |
|---|
| 2064 | 2684 | unregister_die_notifier(&hyperv_die_block); |
|---|
| 2065 | | - atomic_notifier_chain_unregister(&panic_notifier_list, |
|---|
| 2066 | | - &hyperv_panic_block); |
|---|
| 2067 | 2685 | } |
|---|
| 2686 | + |
|---|
| 2687 | + /* |
|---|
| 2688 | + * The panic notifier is always registered, hence we should |
|---|
| 2689 | + * also unconditionally unregister it here as well. |
|---|
| 2690 | + */ |
|---|
| 2691 | + atomic_notifier_chain_unregister(&panic_notifier_list, |
|---|
| 2692 | + &hyperv_panic_block); |
|---|
| 2068 | 2693 | |
|---|
| 2069 | 2694 | free_page((unsigned long)hv_panic_page); |
|---|
| 2070 | 2695 | unregister_sysctl_table(hv_ctl_table_hdr); |
|---|
| .. | .. |
|---|
| 2078 | 2703 | |
|---|
| 2079 | 2704 | |
|---|
| 2080 | 2705 | MODULE_LICENSE("GPL"); |
|---|
| 2706 | +MODULE_DESCRIPTION("Microsoft Hyper-V VMBus Driver"); |
|---|
| 2081 | 2707 | |
|---|
| 2082 | 2708 | subsys_initcall(hv_acpi_init); |
|---|
| 2083 | 2709 | module_exit(vmbus_exit); |
|---|