Merge tag 'hyperv-next-signed-20230220' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 22 Feb 2023 00:59:23 +0000 (16:59 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 22 Feb 2023 00:59:23 +0000 (16:59 -0800)
Pull hyperv updates from Wei Liu:

 - allow Linux to run as the nested root partition for Microsoft
   Hypervisor (Jinank Jain and Nuno Das Neves)

 - clean up the return type of callback functions (Dawei Li)

* tag 'hyperv-next-signed-20230220' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux:
  x86/hyperv: Fix hv_get/set_register for nested bringup
  Drivers: hv: Make remove callback of hyperv driver void returned
  Drivers: hv: Enable vmbus driver for nested root partition
  x86/hyperv: Add an interface to do nested hypercalls
  Drivers: hv: Setup synic registers in case of nested root partition
  x86/hyperv: Add support for detecting nested hypervisor

20 files changed:
arch/x86/include/asm/hyperv-tlfs.h
arch/x86/include/asm/mshyperv.h
arch/x86/kernel/cpu/mshyperv.c
drivers/gpu/drm/hyperv/hyperv_drm_drv.c
drivers/hid/hid-hyperv.c
drivers/hv/hv.c
drivers/hv/hv_balloon.c
drivers/hv/hv_common.c
drivers/hv/hv_util.c
drivers/hv/vmbus_drv.c
drivers/input/serio/hyperv-keyboard.c
drivers/net/hyperv/netvsc_drv.c
drivers/pci/controller/pci-hyperv.c
drivers/scsi/storvsc_drv.c
drivers/uio/uio_hv_generic.c
drivers/video/fbdev/hyperv_fb.c
include/asm-generic/hyperv-tlfs.h
include/asm-generic/mshyperv.h
include/linux/hyperv.h
net/vmw_vsock/hyperv_transport.c

index 08e822b..566ac26 100644 (file)
 /* Recommend using the newer ExProcessorMasks interface */
 #define HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED          BIT(11)
 
+/* Indicates that the hypervisor is nested within a Hyper-V partition. */
+#define HV_X64_HYPERV_NESTED                           BIT(12)
+
 /* Recommend using enlightened VMCS */
 #define HV_X64_ENLIGHTENED_VMCS_RECOMMENDED            BIT(14)
 
@@ -225,6 +228,17 @@ enum hv_isolation_type {
 #define HV_REGISTER_SINT15                     0x4000009F
 
 /*
+ * Define synthetic interrupt controller model specific registers for
+ * nested hypervisor.
+ */
+#define HV_REGISTER_NESTED_SCONTROL            0x40001080
+#define HV_REGISTER_NESTED_SVERSION            0x40001081
+#define HV_REGISTER_NESTED_SIEFP               0x40001082
+#define HV_REGISTER_NESTED_SIMP                0x40001083
+#define HV_REGISTER_NESTED_EOM                 0x40001084
+#define HV_REGISTER_NESTED_SINT0               0x40001090
+
+/*
  * Synthetic Timer MSRs. Four timers per vcpu.
  */
 #define HV_REGISTER_STIMER0_CONFIG             0x400000B0
@@ -368,7 +382,8 @@ struct hv_nested_enlightenments_control {
                __u32 reserved:31;
        } features;
        struct {
-               __u32 reserved;
+               __u32 inter_partition_comm:1;
+               __u32 reserved:31;
        } hypercallControls;
 } __packed;
 
index 6d502f3..4c4c0ec 100644 (file)
@@ -72,10 +72,16 @@ static inline u64 hv_do_hypercall(u64 control, void *input, void *output)
        return hv_status;
 }
 
+/* Hypercall to the L0 hypervisor */
+static inline u64 hv_do_nested_hypercall(u64 control, void *input, void *output)
+{
+       return hv_do_hypercall(control | HV_HYPERCALL_NESTED, input, output);
+}
+
 /* Fast hypercall with 8 bytes of input and no output */
-static inline u64 hv_do_fast_hypercall8(u16 code, u64 input1)
+static inline u64 _hv_do_fast_hypercall8(u64 control, u64 input1)
 {
-       u64 hv_status, control = (u64)code | HV_HYPERCALL_FAST_BIT;
+       u64 hv_status;
 
 #ifdef CONFIG_X86_64
        {
@@ -103,10 +109,24 @@ static inline u64 hv_do_fast_hypercall8(u16 code, u64 input1)
                return hv_status;
 }
 
+static inline u64 hv_do_fast_hypercall8(u16 code, u64 input1)
+{
+       u64 control = (u64)code | HV_HYPERCALL_FAST_BIT;
+
+       return _hv_do_fast_hypercall8(control, input1);
+}
+
+static inline u64 hv_do_fast_nested_hypercall8(u16 code, u64 input1)
+{
+       u64 control = (u64)code | HV_HYPERCALL_FAST_BIT | HV_HYPERCALL_NESTED;
+
+       return _hv_do_fast_hypercall8(control, input1);
+}
+
 /* Fast hypercall with 16 bytes of input */
-static inline u64 hv_do_fast_hypercall16(u16 code, u64 input1, u64 input2)
+static inline u64 _hv_do_fast_hypercall16(u64 control, u64 input1, u64 input2)
 {
-       u64 hv_status, control = (u64)code | HV_HYPERCALL_FAST_BIT;
+       u64 hv_status;
 
 #ifdef CONFIG_X86_64
        {
@@ -137,6 +157,20 @@ static inline u64 hv_do_fast_hypercall16(u16 code, u64 input1, u64 input2)
        return hv_status;
 }
 
+static inline u64 hv_do_fast_hypercall16(u16 code, u64 input1, u64 input2)
+{
+       u64 control = (u64)code | HV_HYPERCALL_FAST_BIT;
+
+       return _hv_do_fast_hypercall16(control, input1, input2);
+}
+
+static inline u64 hv_do_fast_nested_hypercall16(u16 code, u64 input1, u64 input2)
+{
+       u64 control = (u64)code | HV_HYPERCALL_FAST_BIT | HV_HYPERCALL_NESTED;
+
+       return _hv_do_fast_hypercall16(control, input1, input2);
+}
+
 extern struct hv_vp_assist_page **hv_vp_assist_page;
 
 static inline struct hv_vp_assist_page *hv_get_vp_assist_page(unsigned int cpu)
@@ -190,36 +224,20 @@ extern bool hv_isolation_type_snp(void);
 
 static inline bool hv_is_synic_reg(unsigned int reg)
 {
-       if ((reg >= HV_REGISTER_SCONTROL) &&
-           (reg <= HV_REGISTER_SINT15))
-               return true;
-       return false;
+       return (reg >= HV_REGISTER_SCONTROL) &&
+              (reg <= HV_REGISTER_SINT15);
 }
 
-static inline u64 hv_get_register(unsigned int reg)
+static inline bool hv_is_sint_reg(unsigned int reg)
 {
-       u64 value;
-
-       if (hv_is_synic_reg(reg) && hv_isolation_type_snp())
-               hv_ghcb_msr_read(reg, &value);
-       else
-               rdmsrl(reg, value);
-       return value;
+       return (reg >= HV_REGISTER_SINT0) &&
+              (reg <= HV_REGISTER_SINT15);
 }
 
-static inline void hv_set_register(unsigned int reg, u64 value)
-{
-       if (hv_is_synic_reg(reg) && hv_isolation_type_snp()) {
-               hv_ghcb_msr_write(reg, value);
-
-               /* Write proxy bit via wrmsl instruction */
-               if (reg >= HV_REGISTER_SINT0 &&
-                   reg <= HV_REGISTER_SINT15)
-                       wrmsrl(reg, value | 1 << 20);
-       } else {
-               wrmsrl(reg, value);
-       }
-}
+u64 hv_get_register(unsigned int reg);
+void hv_set_register(unsigned int reg, u64 value);
+u64 hv_get_non_nested_register(unsigned int reg);
+void hv_set_non_nested_register(unsigned int reg, u64 value);
 
 #else /* CONFIG_HYPERV */
 static inline void hyperv_init(void) {}
@@ -239,6 +257,8 @@ static inline int hyperv_flush_guest_mapping_range(u64 as,
 }
 static inline void hv_set_register(unsigned int reg, u64 value) { }
 static inline u64 hv_get_register(unsigned int reg) { return 0; }
+static inline void hv_set_non_nested_register(unsigned int reg, u64 value) { }
+static inline u64 hv_get_non_nested_register(unsigned int reg) { return 0; }
 static inline int hv_set_mem_host_visibility(unsigned long addr, int numpages,
                                             bool visible)
 {
index 46668e2..f924a76 100644 (file)
 
 /* Is Linux running as the root partition? */
 bool hv_root_partition;
+/* Is Linux running on nested Microsoft Hypervisor */
+bool hv_nested;
 struct ms_hyperv_info ms_hyperv;
 
 #if IS_ENABLED(CONFIG_HYPERV)
+static inline unsigned int hv_get_nested_reg(unsigned int reg)
+{
+       if (hv_is_sint_reg(reg))
+               return reg - HV_REGISTER_SINT0 + HV_REGISTER_NESTED_SINT0;
+
+       switch (reg) {
+       case HV_REGISTER_SIMP:
+               return HV_REGISTER_NESTED_SIMP;
+       case HV_REGISTER_SIEFP:
+               return HV_REGISTER_NESTED_SIEFP;
+       case HV_REGISTER_SVERSION:
+               return HV_REGISTER_NESTED_SVERSION;
+       case HV_REGISTER_SCONTROL:
+               return HV_REGISTER_NESTED_SCONTROL;
+       case HV_REGISTER_EOM:
+               return HV_REGISTER_NESTED_EOM;
+       default:
+               return reg;
+       }
+}
+
+u64 hv_get_non_nested_register(unsigned int reg)
+{
+       u64 value;
+
+       if (hv_is_synic_reg(reg) && hv_isolation_type_snp())
+               hv_ghcb_msr_read(reg, &value);
+       else
+               rdmsrl(reg, value);
+       return value;
+}
+EXPORT_SYMBOL_GPL(hv_get_non_nested_register);
+
+void hv_set_non_nested_register(unsigned int reg, u64 value)
+{
+       if (hv_is_synic_reg(reg) && hv_isolation_type_snp()) {
+               hv_ghcb_msr_write(reg, value);
+
+               /* Write proxy bit via wrmsl instruction */
+               if (hv_is_sint_reg(reg))
+                       wrmsrl(reg, value | 1 << 20);
+       } else {
+               wrmsrl(reg, value);
+       }
+}
+EXPORT_SYMBOL_GPL(hv_set_non_nested_register);
+
+u64 hv_get_register(unsigned int reg)
+{
+       if (hv_nested)
+               reg = hv_get_nested_reg(reg);
+
+       return hv_get_non_nested_register(reg);
+}
+EXPORT_SYMBOL_GPL(hv_get_register);
+
+void hv_set_register(unsigned int reg, u64 value)
+{
+       if (hv_nested)
+               reg = hv_get_nested_reg(reg);
+
+       hv_set_non_nested_register(reg, value);
+}
+EXPORT_SYMBOL_GPL(hv_set_register);
+
 static void (*vmbus_handler)(void);
 static void (*hv_stimer0_handler)(void);
 static void (*hv_kexec_handler)(void);
@@ -301,6 +368,11 @@ static void __init ms_hyperv_init_platform(void)
                pr_info("Hyper-V: running as root partition\n");
        }
 
+       if (ms_hyperv.hints & HV_X64_HYPERV_NESTED) {
+               hv_nested = true;
+               pr_info("Hyper-V: running on a nested hypervisor\n");
+       }
+
        /*
         * Extract host information.
         */
index 427c20b..f830d62 100644 (file)
@@ -165,7 +165,7 @@ err_hv_set_drv_data:
        return ret;
 }
 
-static int hyperv_vmbus_remove(struct hv_device *hdev)
+static void hyperv_vmbus_remove(struct hv_device *hdev)
 {
        struct drm_device *dev = hv_get_drvdata(hdev);
        struct hyperv_drm_device *hv = to_hv(dev);
@@ -176,8 +176,6 @@ static int hyperv_vmbus_remove(struct hv_device *hdev)
        hv_set_drvdata(hdev, NULL);
 
        vmbus_free_mmio(hv->mem->start, hv->fb_size);
-
-       return 0;
 }
 
 static int hyperv_vmbus_suspend(struct hv_device *hdev)
index cf12f17..2a0aabd 100644 (file)
@@ -524,7 +524,7 @@ probe_err0:
 }
 
 
-static int mousevsc_remove(struct hv_device *dev)
+static void mousevsc_remove(struct hv_device *dev)
 {
        struct mousevsc_dev *input_dev = hv_get_drvdata(dev);
 
@@ -533,8 +533,6 @@ static int mousevsc_remove(struct hv_device *dev)
        hid_hw_stop(input_dev->hid_device);
        hid_destroy_device(input_dev->hid_device);
        mousevsc_free_device(input_dev);
-
-       return 0;
 }
 
 static int mousevsc_suspend(struct hv_device *dev)
index 4d6480d..8b0dd8e 100644 (file)
@@ -147,7 +147,7 @@ int hv_synic_alloc(void)
                 * Synic message and event pages are allocated by paravisor.
                 * Skip these pages allocation here.
                 */
-               if (!hv_isolation_type_snp()) {
+               if (!hv_isolation_type_snp() && !hv_root_partition) {
                        hv_cpu->synic_message_page =
                                (void *)get_zeroed_page(GFP_ATOMIC);
                        if (hv_cpu->synic_message_page == NULL) {
@@ -216,7 +216,7 @@ void hv_synic_enable_regs(unsigned int cpu)
        simp.as_uint64 = hv_get_register(HV_REGISTER_SIMP);
        simp.simp_enabled = 1;
 
-       if (hv_isolation_type_snp()) {
+       if (hv_isolation_type_snp() || hv_root_partition) {
                hv_cpu->synic_message_page
                        = memremap(simp.base_simp_gpa << HV_HYP_PAGE_SHIFT,
                                   HV_HYP_PAGE_SIZE, MEMREMAP_WB);
@@ -233,7 +233,7 @@ void hv_synic_enable_regs(unsigned int cpu)
        siefp.as_uint64 = hv_get_register(HV_REGISTER_SIEFP);
        siefp.siefp_enabled = 1;
 
-       if (hv_isolation_type_snp()) {
+       if (hv_isolation_type_snp() || hv_root_partition) {
                hv_cpu->synic_event_page =
                        memremap(siefp.base_siefp_gpa << HV_HYP_PAGE_SHIFT,
                                 HV_HYP_PAGE_SIZE, MEMREMAP_WB);
@@ -315,20 +315,24 @@ void hv_synic_disable_regs(unsigned int cpu)
         * addresses.
         */
        simp.simp_enabled = 0;
-       if (hv_isolation_type_snp())
+       if (hv_isolation_type_snp() || hv_root_partition) {
                memunmap(hv_cpu->synic_message_page);
-       else
+               hv_cpu->synic_message_page = NULL;
+       } else {
                simp.base_simp_gpa = 0;
+       }
 
        hv_set_register(HV_REGISTER_SIMP, simp.as_uint64);
 
        siefp.as_uint64 = hv_get_register(HV_REGISTER_SIEFP);
        siefp.siefp_enabled = 0;
 
-       if (hv_isolation_type_snp())
+       if (hv_isolation_type_snp() || hv_root_partition) {
                memunmap(hv_cpu->synic_event_page);
-       else
+               hv_cpu->synic_event_page = NULL;
+       } else {
                siefp.base_siefp_gpa = 0;
+       }
 
        hv_set_register(HV_REGISTER_SIEFP, siefp.as_uint64);
 
index 64ac5bd..dffcc89 100644 (file)
@@ -2042,7 +2042,7 @@ connect_error:
        return ret;
 }
 
-static int balloon_remove(struct hv_device *dev)
+static void balloon_remove(struct hv_device *dev)
 {
        struct hv_dynmem_device *dm = hv_get_drvdata(dev);
        struct hv_hotadd_state *has, *tmp;
@@ -2083,8 +2083,6 @@ static int balloon_remove(struct hv_device *dev)
                kfree(has);
        }
        spin_unlock_irqrestore(&dm_device.ha_lock, flags);
-
-       return 0;
 }
 
 static int balloon_suspend(struct hv_device *hv_dev)
index ae68298..52a6f89 100644 (file)
 #include <asm/mshyperv.h>
 
 /*
- * hv_root_partition and ms_hyperv are defined here with other Hyper-V
- * specific globals so they are shared across all architectures and are
+ * hv_root_partition, ms_hyperv and hv_nested are defined here with other
+ * Hyper-V specific globals so they are shared across all architectures and are
  * built only when CONFIG_HYPERV is defined.  But on x86,
  * ms_hyperv_init_platform() is built even when CONFIG_HYPERV is not
- * defined, and it uses these two variables.  So mark them as __weak
+ * defined, and it uses these three variables.  So mark them as __weak
  * here, allowing for an overriding definition in the module containing
  * ms_hyperv_init_platform().
  */
 bool __weak hv_root_partition;
 EXPORT_SYMBOL_GPL(hv_root_partition);
 
+bool __weak hv_nested;
+EXPORT_SYMBOL_GPL(hv_nested);
+
 struct ms_hyperv_info __weak ms_hyperv;
 EXPORT_SYMBOL_GPL(ms_hyperv);
 
index d776074..42aec2c 100644 (file)
@@ -602,7 +602,7 @@ error1:
        return ret;
 }
 
-static int util_remove(struct hv_device *dev)
+static void util_remove(struct hv_device *dev)
 {
        struct hv_util_service *srv = hv_get_drvdata(dev);
 
@@ -610,8 +610,6 @@ static int util_remove(struct hv_device *dev)
                srv->util_deinit();
        vmbus_close(dev->channel);
        kfree(srv->recv_buffer);
-
-       return 0;
 }
 
 /*
index 3146710..1901556 100644 (file)
@@ -2744,7 +2744,7 @@ static int __init hv_acpi_init(void)
        if (!hv_is_hyperv_initialized())
                return -ENODEV;
 
-       if (hv_root_partition)
+       if (hv_root_partition && !hv_nested)
                return 0;
 
        /*
index d62aefb..31def6c 100644 (file)
@@ -369,7 +369,7 @@ err_free_mem:
        return error;
 }
 
-static int hv_kbd_remove(struct hv_device *hv_dev)
+static void hv_kbd_remove(struct hv_device *hv_dev)
 {
        struct hv_kbd_dev *kbd_dev = hv_get_drvdata(hv_dev);
 
@@ -378,8 +378,6 @@ static int hv_kbd_remove(struct hv_device *hv_dev)
        kfree(kbd_dev);
 
        hv_set_drvdata(hv_dev, NULL);
-
-       return 0;
 }
 
 static int hv_kbd_suspend(struct hv_device *hv_dev)
index f9b219e..4216216 100644 (file)
@@ -2594,7 +2594,7 @@ no_net:
        return ret;
 }
 
-static int netvsc_remove(struct hv_device *dev)
+static void netvsc_remove(struct hv_device *dev)
 {
        struct net_device_context *ndev_ctx;
        struct net_device *vf_netdev, *net;
@@ -2603,7 +2603,7 @@ static int netvsc_remove(struct hv_device *dev)
        net = hv_get_drvdata(dev);
        if (net == NULL) {
                dev_err(&dev->device, "No net device to remove\n");
-               return 0;
+               return;
        }
 
        ndev_ctx = netdev_priv(net);
@@ -2637,7 +2637,6 @@ static int netvsc_remove(struct hv_device *dev)
 
        free_percpu(ndev_ctx->vf_stats);
        free_netdev(net);
-       return 0;
 }
 
 static int netvsc_suspend(struct hv_device *dev)
index 084f531..f33370b 100644 (file)
@@ -3800,13 +3800,10 @@ static int hv_pci_bus_exit(struct hv_device *hdev, bool keep_devs)
 /**
  * hv_pci_remove() - Remove routine for this VMBus channel
  * @hdev:      VMBus's tracking struct for this root PCI bus
- *
- * Return: 0 on success, -errno on failure
  */
-static int hv_pci_remove(struct hv_device *hdev)
+static void hv_pci_remove(struct hv_device *hdev)
 {
        struct hv_pcibus_device *hbus;
-       int ret;
 
        hbus = hv_get_drvdata(hdev);
        if (hbus->state == hv_pcibus_installed) {
@@ -3829,7 +3826,7 @@ static int hv_pci_remove(struct hv_device *hdev)
                pci_unlock_rescan_remove();
        }
 
-       ret = hv_pci_bus_exit(hdev, false);
+       hv_pci_bus_exit(hdev, false);
 
        vmbus_close(hdev->channel);
 
@@ -3842,7 +3839,6 @@ static int hv_pci_remove(struct hv_device *hdev)
        hv_put_dom_num(hbus->bridge->domain_nr);
 
        kfree(hbus);
-       return ret;
 }
 
 static int hv_pci_suspend(struct hv_device *hdev)
index 22705eb..33f568b 100644 (file)
@@ -2095,7 +2095,7 @@ static int storvsc_change_queue_depth(struct scsi_device *sdev, int queue_depth)
        return scsi_change_queue_depth(sdev, queue_depth);
 }
 
-static int storvsc_remove(struct hv_device *dev)
+static void storvsc_remove(struct hv_device *dev)
 {
        struct storvsc_device *stor_device = hv_get_drvdata(dev);
        struct Scsi_Host *host = stor_device->host;
@@ -2111,8 +2111,6 @@ static int storvsc_remove(struct hv_device *dev)
        scsi_remove_host(host);
        storvsc_dev_remove(dev);
        scsi_host_put(host);
-
-       return 0;
 }
 
 static int storvsc_suspend(struct hv_device *hv_dev)
index c08a6cf..20d9762 100644 (file)
@@ -355,20 +355,19 @@ fail_free_ring:
        return ret;
 }
 
-static int
+static void
 hv_uio_remove(struct hv_device *dev)
 {
        struct hv_uio_private_data *pdata = hv_get_drvdata(dev);
 
        if (!pdata)
-               return 0;
+               return;
 
        sysfs_remove_bin_file(&dev->channel->kobj, &ring_buffer_bin_attr);
        uio_unregister_device(&pdata->info);
        hv_uio_cleanup(dev, pdata);
 
        vmbus_free_ring(dev->channel);
-       return 0;
 }
 
 static struct hv_driver hv_uio_drv = {
index fdbf02b..a7f79f5 100644 (file)
@@ -1239,8 +1239,7 @@ error1:
        return ret;
 }
 
-
-static int hvfb_remove(struct hv_device *hdev)
+static void hvfb_remove(struct hv_device *hdev)
 {
        struct fb_info *info = hv_get_drvdata(hdev);
        struct hvfb_par *par = info->par;
@@ -1261,8 +1260,6 @@ static int hvfb_remove(struct hv_device *hdev)
 
        hvfb_putmem(hdev, info);
        framebuffer_release(info);
-
-       return 0;
 }
 
 static int hvfb_suspend(struct hv_device *hdev)
index e29ccab..b870983 100644 (file)
@@ -194,6 +194,7 @@ enum HV_GENERIC_SET_FORMAT {
 #define HV_HYPERCALL_VARHEAD_OFFSET    17
 #define HV_HYPERCALL_VARHEAD_MASK      GENMASK_ULL(26, 17)
 #define HV_HYPERCALL_RSVD0_MASK                GENMASK_ULL(31, 27)
+#define HV_HYPERCALL_NESTED            BIT_ULL(31)
 #define HV_HYPERCALL_REP_COMP_OFFSET   32
 #define HV_HYPERCALL_REP_COMP_1                BIT_ULL(32)
 #define HV_HYPERCALL_REP_COMP_MASK     GENMASK_ULL(43, 32)
index d55d283..8845a2e 100644 (file)
@@ -48,6 +48,7 @@ struct ms_hyperv_info {
        u64 shared_gpa_boundary;
 };
 extern struct ms_hyperv_info ms_hyperv;
+extern bool hv_nested;
 
 extern void * __percpu *hyperv_pcpu_input_arg;
 extern void * __percpu *hyperv_pcpu_output_arg;
index 85f7c5a..cd5cb9f 100644 (file)
@@ -1273,7 +1273,7 @@ struct hv_driver {
        } dynids;
 
        int (*probe)(struct hv_device *, const struct hv_vmbus_device_id *);
-       int (*remove)(struct hv_device *);
+       void (*remove)(struct hv_device *dev);
        void (*shutdown)(struct hv_device *);
 
        int (*suspend)(struct hv_device *);
index 59c3e26..7cb1a9d 100644 (file)
@@ -879,13 +879,11 @@ static int hvs_probe(struct hv_device *hdev,
        return 0;
 }
 
-static int hvs_remove(struct hv_device *hdev)
+static void hvs_remove(struct hv_device *hdev)
 {
        struct vmbus_channel *chan = hdev->channel;
 
        vmbus_close(chan);
-
-       return 0;
 }
 
 /* hv_sock connections can not persist across hibernation, and all the hv_sock