Patch "vfio/pci: wake-up devices around reset functions" has been added to the 5.17-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    vfio/pci: wake-up devices around reset functions

to the 5.17-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     vfio-pci-wake-up-devices-around-reset-functions.patch
and it can be found in the queue-5.17 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit cdfe46e7a1ac57c82961bf9c0d9fb5becd18f545
Author: Abhishek Sahu <abhsahu@xxxxxxxxxx>
Date:   Thu Feb 17 17:51:07 2022 +0530

    vfio/pci: wake-up devices around reset functions
    
    [ Upstream commit 26a17b12d7f3dd8a7aa45a290e5b46e9cc775ddf ]
    
    If 'vfio_pci_core_device::needs_pm_restore' is set (PCI device does
    not have No_Soft_Reset bit set in its PMCSR config register), then the
    current PCI state will be saved locally in
    'vfio_pci_core_device::pm_save' during D0->D3hot transition and same
    will be restored back during D3hot->D0 transition. For reset-related
    functionalities, vfio driver uses PCI reset API's. These
    API's internally change the PCI power state back to D0 first if
    the device power state is non-D0. This state change to D0 will happen
    without the involvement of vfio driver.
    
    Let's consider the following example:
    
    1. The device is in D3hot.
    2. User invokes VFIO_DEVICE_RESET ioctl.
    3. pci_try_reset_function() will be called which internally
       invokes pci_dev_save_and_disable().
    4. pci_set_power_state(dev, PCI_D0) will be called first.
    5. pci_save_state() will happen then.
    
    Now, for the devices which has NoSoftRst-, the pci_set_power_state()
    can trigger soft reset and the original PCI config state will be lost
    at step (4) and this state cannot be restored again. This original PCI
    state can include any setting which is performed by SBIOS or host
    linux kernel (for example LTR, ASPM L1 substates, etc.). When this
    soft reset will be triggered, then all these settings will be reset,
    and the device state saved at step (5) will also have this setting
    cleared so it cannot be restored. Since the vfio driver only exposes
    limited PCI capabilities to its user, so the vfio driver user also
    won't have the option to save and restore these capabilities state
    either and these original settings will be permanently lost.
    
    For pci_reset_bus() also, we can have the above situation.
    The other functions/devices can be in D3hot and the reset will change
    the power state of all devices to D0 without the involvement of vfio
    driver.
    
    So, before calling any reset-related API's, we need to make sure that
    the device state is D0. This is mainly to preserve the state around
    soft reset.
    
    For vfio_pci_core_disable(), we use __pci_reset_function_locked()
    which internally can use pci_pm_reset() for the function reset.
    pci_pm_reset() requires the device power state to be in D0, otherwise
    it returns error.
    
    This patch changes the device power state to D0 by invoking
    vfio_pci_set_power_state() explicitly before calling any reset related
    API's.
    
    Fixes: 51ef3a004b1e ("vfio/pci: Restore device state on PM transition")
    Signed-off-by: Abhishek Sahu <abhsahu@xxxxxxxxxx>
    Link: https://lore.kernel.org/r/20220217122107.22434-3-abhsahu@xxxxxxxxxx
    Signed-off-by: Alex Williamson <alex.williamson@xxxxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c
index 87b288affc13..2e6409cc11ad 100644
--- a/drivers/vfio/pci/vfio_pci_core.c
+++ b/drivers/vfio/pci/vfio_pci_core.c
@@ -335,6 +335,17 @@ void vfio_pci_core_disable(struct vfio_pci_core_device *vdev)
 	/* For needs_reset */
 	lockdep_assert_held(&vdev->vdev.dev_set->lock);
 
+	/*
+	 * This function can be invoked while the power state is non-D0.
+	 * This function calls __pci_reset_function_locked() which internally
+	 * can use pci_pm_reset() for the function reset. pci_pm_reset() will
+	 * fail if the power state is non-D0. Also, for the devices which
+	 * have NoSoftRst-, the reset function can cause the PCI config space
+	 * reset without restoring the original state (saved locally in
+	 * 'vdev->pm_save').
+	 */
+	vfio_pci_set_power_state(vdev, PCI_D0);
+
 	/* Stop the device from further DMA */
 	pci_clear_master(pdev);
 
@@ -934,6 +945,19 @@ long vfio_pci_core_ioctl(struct vfio_device *core_vdev, unsigned int cmd,
 			return -EINVAL;
 
 		vfio_pci_zap_and_down_write_memory_lock(vdev);
+
+		/*
+		 * This function can be invoked while the power state is non-D0.
+		 * If pci_try_reset_function() has been called while the power
+		 * state is non-D0, then pci_try_reset_function() will
+		 * internally set the power state to D0 without vfio driver
+		 * involvement. For the devices which have NoSoftRst-, the
+		 * reset function can cause the PCI config space reset without
+		 * restoring the original state (saved locally in
+		 * 'vdev->pm_save').
+		 */
+		vfio_pci_set_power_state(vdev, PCI_D0);
+
 		ret = pci_try_reset_function(vdev->pdev);
 		up_write(&vdev->memory_lock);
 
@@ -2068,6 +2092,18 @@ static int vfio_pci_dev_set_hot_reset(struct vfio_device_set *dev_set,
 	}
 	cur_mem = NULL;
 
+	/*
+	 * The pci_reset_bus() will reset all the devices in the bus.
+	 * The power state can be non-D0 for some of the devices in the bus.
+	 * For these devices, the pci_reset_bus() will internally set
+	 * the power state to D0 without vfio driver involvement.
+	 * For the devices which have NoSoftRst-, the reset function can
+	 * cause the PCI config space reset without restoring the original
+	 * state (saved locally in 'vdev->pm_save').
+	 */
+	list_for_each_entry(cur, &dev_set->device_list, vdev.dev_set_list)
+		vfio_pci_set_power_state(cur, PCI_D0);
+
 	ret = pci_reset_bus(pdev);
 
 err_undo:
@@ -2121,6 +2157,18 @@ static bool vfio_pci_dev_set_try_reset(struct vfio_device_set *dev_set)
 	if (!pdev)
 		return false;
 
+	/*
+	 * The pci_reset_bus() will reset all the devices in the bus.
+	 * The power state can be non-D0 for some of the devices in the bus.
+	 * For these devices, the pci_reset_bus() will internally set
+	 * the power state to D0 without vfio driver involvement.
+	 * For the devices which have NoSoftRst-, the reset function can
+	 * cause the PCI config space reset without restoring the original
+	 * state (saved locally in 'vdev->pm_save').
+	 */
+	list_for_each_entry(cur, &dev_set->device_list, vdev.dev_set_list)
+		vfio_pci_set_power_state(cur, PCI_D0);
+
 	ret = pci_reset_bus(pdev);
 	if (ret)
 		return false;



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux