diff options
author | Alex Williamson <alex.williamson@redhat.com> | 2014-08-07 13:12:07 -0400 |
---|---|---|
committer | Alex Williamson <alex.williamson@redhat.com> | 2014-08-07 13:12:07 -0400 |
commit | bc4fba77124e2fe4eb14bcb52875c0b0228deace (patch) | |
tree | 32c9a964e7e40735ef6e9841f2509053f5e24729 /drivers/vfio/pci/vfio_pci.c | |
parent | 61d792562b53c610f9fe917f2bbc22218aa39c22 (diff) |
vfio-pci: Attempt bus/slot reset on release
Each time a device is released, mark whether a local reset was
successful or whether a bus/slot reset is needed. If a reset is
needed and all of the affected devices are bound to vfio-pci and
unused, allow the reset. This is most useful when the userspace
driver is killed and releases all the devices in an unclean state,
such as when a QEMU VM quits.
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
Diffstat (limited to 'drivers/vfio/pci/vfio_pci.c')
-rw-r--r-- | drivers/vfio/pci/vfio_pci.c | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c index c9d756b7ee9e..1651c0769b72 100644 --- a/drivers/vfio/pci/vfio_pci.c +++ b/drivers/vfio/pci/vfio_pci.c | |||
@@ -39,6 +39,8 @@ MODULE_PARM_DESC(nointxmask, | |||
39 | 39 | ||
40 | static DEFINE_MUTEX(driver_lock); | 40 | static DEFINE_MUTEX(driver_lock); |
41 | 41 | ||
42 | static void vfio_pci_try_bus_reset(struct vfio_pci_device *vdev); | ||
43 | |||
42 | static int vfio_pci_enable(struct vfio_pci_device *vdev) | 44 | static int vfio_pci_enable(struct vfio_pci_device *vdev) |
43 | { | 45 | { |
44 | struct pci_dev *pdev = vdev->pdev; | 46 | struct pci_dev *pdev = vdev->pdev; |
@@ -123,6 +125,8 @@ static void vfio_pci_disable(struct vfio_pci_device *vdev) | |||
123 | vdev->barmap[bar] = NULL; | 125 | vdev->barmap[bar] = NULL; |
124 | } | 126 | } |
125 | 127 | ||
128 | vdev->needs_reset = true; | ||
129 | |||
126 | /* | 130 | /* |
127 | * If we have saved state, restore it. If we can reset the device, | 131 | * If we have saved state, restore it. If we can reset the device, |
128 | * even better. Resetting with current state seems better than | 132 | * even better. Resetting with current state seems better than |
@@ -154,11 +158,15 @@ static void vfio_pci_disable(struct vfio_pci_device *vdev) | |||
154 | if (ret) | 158 | if (ret) |
155 | pr_warn("%s: Failed to reset device %s (%d)\n", | 159 | pr_warn("%s: Failed to reset device %s (%d)\n", |
156 | __func__, dev_name(&pdev->dev), ret); | 160 | __func__, dev_name(&pdev->dev), ret); |
161 | else | ||
162 | vdev->needs_reset = false; | ||
157 | } | 163 | } |
158 | 164 | ||
159 | pci_restore_state(pdev); | 165 | pci_restore_state(pdev); |
160 | out: | 166 | out: |
161 | pci_disable_device(pdev); | 167 | pci_disable_device(pdev); |
168 | |||
169 | vfio_pci_try_bus_reset(vdev); | ||
162 | } | 170 | } |
163 | 171 | ||
164 | static void vfio_pci_release(void *device_data) | 172 | static void vfio_pci_release(void *device_data) |
@@ -923,6 +931,110 @@ static struct pci_driver vfio_pci_driver = { | |||
923 | .err_handler = &vfio_err_handlers, | 931 | .err_handler = &vfio_err_handlers, |
924 | }; | 932 | }; |
925 | 933 | ||
934 | /* | ||
935 | * Test whether a reset is necessary and possible. We mark devices as | ||
936 | * needs_reset when they are released, but don't have a function-local reset | ||
937 | * available. If any of these exist in the affected devices, we want to do | ||
938 | * a bus/slot reset. We also need all of the affected devices to be unused, | ||
939 | * so we abort if any device has a non-zero refcnt. driver_lock prevents a | ||
940 | * device from being opened during the scan or unbound from vfio-pci. | ||
941 | */ | ||
942 | static int vfio_pci_test_bus_reset(struct pci_dev *pdev, void *data) | ||
943 | { | ||
944 | bool *needs_reset = data; | ||
945 | struct pci_driver *pci_drv = ACCESS_ONCE(pdev->driver); | ||
946 | int ret = -EBUSY; | ||
947 | |||
948 | if (pci_drv == &vfio_pci_driver) { | ||
949 | struct vfio_device *device; | ||
950 | struct vfio_pci_device *vdev; | ||
951 | |||
952 | device = vfio_device_get_from_dev(&pdev->dev); | ||
953 | if (!device) | ||
954 | return ret; | ||
955 | |||
956 | vdev = vfio_device_data(device); | ||
957 | if (vdev) { | ||
958 | if (vdev->needs_reset) | ||
959 | *needs_reset = true; | ||
960 | |||
961 | if (!vdev->refcnt) | ||
962 | ret = 0; | ||
963 | } | ||
964 | |||
965 | vfio_device_put(device); | ||
966 | } | ||
967 | |||
968 | /* | ||
969 | * TODO: vfio-core considers groups to be viable even if some devices | ||
970 | * are attached to known drivers, like pci-stub or pcieport. We can't | ||
971 | * freeze devices from being unbound to those drivers like we can | ||
972 | * here though, so it would be racy to test for them. We also can't | ||
973 | * use device_lock() to prevent changes as that would interfere with | ||
974 | * PCI-core taking device_lock during bus reset. For now, we require | ||
975 | * devices to be bound to vfio-pci to get a bus/slot reset on release. | ||
976 | */ | ||
977 | |||
978 | return ret; | ||
979 | } | ||
980 | |||
981 | /* Clear needs_reset on all affected devices after successful bus/slot reset */ | ||
982 | static int vfio_pci_clear_needs_reset(struct pci_dev *pdev, void *data) | ||
983 | { | ||
984 | struct pci_driver *pci_drv = ACCESS_ONCE(pdev->driver); | ||
985 | |||
986 | if (pci_drv == &vfio_pci_driver) { | ||
987 | struct vfio_device *device; | ||
988 | struct vfio_pci_device *vdev; | ||
989 | |||
990 | device = vfio_device_get_from_dev(&pdev->dev); | ||
991 | if (!device) | ||
992 | return 0; | ||
993 | |||
994 | vdev = vfio_device_data(device); | ||
995 | if (vdev) | ||
996 | vdev->needs_reset = false; | ||
997 | |||
998 | vfio_device_put(device); | ||
999 | } | ||
1000 | |||
1001 | return 0; | ||
1002 | } | ||
1003 | |||
1004 | /* | ||
1005 | * Attempt to do a bus/slot reset if there are devices affected by a reset for | ||
1006 | * this device that are needs_reset and all of the affected devices are unused | ||
1007 | * (!refcnt). Callers of this function are required to hold driver_lock such | ||
1008 | * that devices can not be unbound from vfio-pci or opened by a user while we | ||
1009 | * test for and perform a bus/slot reset. | ||
1010 | */ | ||
1011 | static void vfio_pci_try_bus_reset(struct vfio_pci_device *vdev) | ||
1012 | { | ||
1013 | bool needs_reset = false, slot = false; | ||
1014 | int ret; | ||
1015 | |||
1016 | if (!pci_probe_reset_slot(vdev->pdev->slot)) | ||
1017 | slot = true; | ||
1018 | else if (pci_probe_reset_bus(vdev->pdev->bus)) | ||
1019 | return; | ||
1020 | |||
1021 | if (vfio_pci_for_each_slot_or_bus(vdev->pdev, | ||
1022 | vfio_pci_test_bus_reset, | ||
1023 | &needs_reset, slot) || !needs_reset) | ||
1024 | return; | ||
1025 | |||
1026 | if (slot) | ||
1027 | ret = pci_try_reset_slot(vdev->pdev->slot); | ||
1028 | else | ||
1029 | ret = pci_try_reset_bus(vdev->pdev->bus); | ||
1030 | |||
1031 | if (ret) | ||
1032 | return; | ||
1033 | |||
1034 | vfio_pci_for_each_slot_or_bus(vdev->pdev, | ||
1035 | vfio_pci_clear_needs_reset, NULL, slot); | ||
1036 | } | ||
1037 | |||
926 | static void __exit vfio_pci_cleanup(void) | 1038 | static void __exit vfio_pci_cleanup(void) |
927 | { | 1039 | { |
928 | pci_unregister_driver(&vfio_pci_driver); | 1040 | pci_unregister_driver(&vfio_pci_driver); |