From 51ef3a004b1eb6241e56b3aa8495769a092a4dc2 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Sat, 9 Feb 2019 13:43:30 -0700 Subject: vfio/pci: Restore device state on PM transition PCI core handles save and restore of device state around reset, but when using pci_set_power_state() we can unintentionally trigger a soft reset of the device, where PCI core only restores the BAR state. If we're using vfio-pci's idle D3 support to try to put devices into low power when unused, this might trigger a reset when the device is woken for use. Also power state management by the user, or within a guest, can put the device into D3 power state with potentially limited ability to restore the device if it should undergo a reset. The PCI spec does not define the extent of a soft reset and many devices reporting soft reset on D3->D0 transition do not undergo a PCI config space reset. It's therefore assumed safe to unconditionally restore the remainder of the state if the device indicates soft reset support, even on a user initiated wakeup. Implement a wrapper in vfio-pci to tag devices reporting PM reset support, save their state on transitions into D3 and restore on transitions back to D0. Reported-by: Alexander Duyck Signed-off-by: Alex Williamson --- drivers/vfio/pci/vfio_pci_private.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/vfio/pci/vfio_pci_private.h') diff --git a/drivers/vfio/pci/vfio_pci_private.h b/drivers/vfio/pci/vfio_pci_private.h index 8c0009f00818..1812cf22fc4f 100644 --- a/drivers/vfio/pci/vfio_pci_private.h +++ b/drivers/vfio/pci/vfio_pci_private.h @@ -114,7 +114,9 @@ struct vfio_pci_device { bool has_vga; bool needs_reset; bool nointx; + bool needs_pm_restore; struct pci_saved_state *pci_saved_state; + struct pci_saved_state *pm_save; struct vfio_pci_reflck *reflck; int refcnt; int ioeventfds_nr; @@ -161,6 +163,10 @@ extern int vfio_pci_register_dev_region(struct vfio_pci_device *vdev, unsigned int type, unsigned int subtype, const struct vfio_pci_regops *ops, size_t size, u32 flags, void *data); + +extern int vfio_pci_set_power_state(struct vfio_pci_device *vdev, + pci_power_t state); + #ifdef CONFIG_VFIO_PCI_IGD extern int vfio_pci_igd_init(struct vfio_pci_device *vdev); #else -- cgit v1.2.3