Drivers: hv: vmbus: Suspend/resume the vmbus itself for hibernation
Before Linux enters hibernation, it sends the CHANNELMSG_UNLOAD message to the host so all the offers are gone. After hibernation, Linux needs to re-negotiate with the host using the same vmbus protocol version (which was in use before hibernation), and ask the host to re-offer the vmbus devices. Signed-off-by: Dexuan Cui <decui@microsoft.com> Reviewed-by: Michael Kelley <mikelley@microsoft.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
e3ede02add
commit
f53335e328
@ -59,8 +59,7 @@ static __u32 vmbus_get_next_version(__u32 current_version)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo,
|
int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version)
|
||||||
__u32 version)
|
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
unsigned int cur_cpu;
|
unsigned int cur_cpu;
|
||||||
|
@ -274,6 +274,8 @@ struct vmbus_msginfo {
|
|||||||
|
|
||||||
extern struct vmbus_connection vmbus_connection;
|
extern struct vmbus_connection vmbus_connection;
|
||||||
|
|
||||||
|
int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version);
|
||||||
|
|
||||||
static inline void vmbus_send_interrupt(u32 relid)
|
static inline void vmbus_send_interrupt(u32 relid)
|
||||||
{
|
{
|
||||||
sync_set_bit(relid, vmbus_connection.send_int_page);
|
sync_set_bit(relid, vmbus_connection.send_int_page);
|
||||||
|
@ -2089,6 +2089,51 @@ acpi_walk_err:
|
|||||||
return ret_val;
|
return ret_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int vmbus_bus_suspend(struct device *dev)
|
||||||
|
{
|
||||||
|
vmbus_initiate_unload(false);
|
||||||
|
|
||||||
|
vmbus_connection.conn_state = DISCONNECTED;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vmbus_bus_resume(struct device *dev)
|
||||||
|
{
|
||||||
|
struct vmbus_channel_msginfo *msginfo;
|
||||||
|
size_t msgsize;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We only use the 'vmbus_proto_version', which was in use before
|
||||||
|
* hibernation, to re-negotiate with the host.
|
||||||
|
*/
|
||||||
|
if (vmbus_proto_version == VERSION_INVAL ||
|
||||||
|
vmbus_proto_version == 0) {
|
||||||
|
pr_err("Invalid proto version = 0x%x\n", vmbus_proto_version);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
msgsize = sizeof(*msginfo) +
|
||||||
|
sizeof(struct vmbus_channel_initiate_contact);
|
||||||
|
|
||||||
|
msginfo = kzalloc(msgsize, GFP_KERNEL);
|
||||||
|
|
||||||
|
if (msginfo == NULL)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
ret = vmbus_negotiate_version(msginfo, vmbus_proto_version);
|
||||||
|
|
||||||
|
kfree(msginfo);
|
||||||
|
|
||||||
|
if (ret != 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
vmbus_request_offers();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct acpi_device_id vmbus_acpi_device_ids[] = {
|
static const struct acpi_device_id vmbus_acpi_device_ids[] = {
|
||||||
{"VMBUS", 0},
|
{"VMBUS", 0},
|
||||||
{"VMBus", 0},
|
{"VMBus", 0},
|
||||||
@ -2096,6 +2141,19 @@ static const struct acpi_device_id vmbus_acpi_device_ids[] = {
|
|||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(acpi, vmbus_acpi_device_ids);
|
MODULE_DEVICE_TABLE(acpi, vmbus_acpi_device_ids);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note: we must use SET_NOIRQ_SYSTEM_SLEEP_PM_OPS rather than
|
||||||
|
* SET_SYSTEM_SLEEP_PM_OPS, otherwise NIC SR-IOV can not work, because the
|
||||||
|
* "pci_dev_pm_ops" uses the "noirq" callbacks: in the resume path, the
|
||||||
|
* pci "noirq" restore callback runs before "non-noirq" callbacks (see
|
||||||
|
* resume_target_kernel() -> dpm_resume_start(), and hibernation_restore() ->
|
||||||
|
* dpm_resume_end()). This means vmbus_bus_resume() and the pci-hyperv's
|
||||||
|
* resume callback must also run via the "noirq" callbacks.
|
||||||
|
*/
|
||||||
|
static const struct dev_pm_ops vmbus_bus_pm = {
|
||||||
|
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(vmbus_bus_suspend, vmbus_bus_resume)
|
||||||
|
};
|
||||||
|
|
||||||
static struct acpi_driver vmbus_acpi_driver = {
|
static struct acpi_driver vmbus_acpi_driver = {
|
||||||
.name = "vmbus",
|
.name = "vmbus",
|
||||||
.ids = vmbus_acpi_device_ids,
|
.ids = vmbus_acpi_device_ids,
|
||||||
@ -2103,6 +2161,7 @@ static struct acpi_driver vmbus_acpi_driver = {
|
|||||||
.add = vmbus_acpi_add,
|
.add = vmbus_acpi_add,
|
||||||
.remove = vmbus_acpi_remove,
|
.remove = vmbus_acpi_remove,
|
||||||
},
|
},
|
||||||
|
.drv.pm = &vmbus_bus_pm,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void hv_kexec_handler(void)
|
static void hv_kexec_handler(void)
|
||||||
|
Loading…
Reference in New Issue
Block a user