History

Merge tag 'vfio-v3.17-rc1' of git://github.com/awilliam/linux-vfio

Pull VFIO updates from Alex Williamson: - enable support for bus reset on device release - fixes for EEH support * tag 'vfio-v3.17-rc1' of git://github.com/awilliam/linux-vfio: drivers/vfio: Enable VFIO if EEH is not supported drivers/vfio: Allow EEH to be built as module drivers/vfio: Fix EEH build error vfio-pci: Attempt bus/slot reset on release vfio-pci: Use mutex around open, release, and remove vfio-pci: Release devices with BusMaster disabled

Linus Torvalds committed 12 years ago

Commit cc8a44c2 parents 4dacb91 9b936c96 files · +170 −25Browse files

Unified · Split

6 files
  1. drivers/vfio/Kconfig +6 −0
  2. drivers/vfio/Makefile +1 −1
  3. drivers/vfio/pci/vfio_pci.c +143 −18
  4. drivers/vfio/pci/vfio_pci_private.h +2 −1
  5. drivers/vfio/vfio_spapr_eeh.c +15 −2
  6. include/linux/vfio.h +3 −3
drivers/vfio/Kconfig+6−0
@@ -8,11 +8,17 @@ config VFIO_IOMMU_SPAPR_TCE · 7 unmodified lines
88 depends on VFIO && SPAPR_TCE_IOMMU
99 default n
1010
11+config VFIO_SPAPR_EEH
12+ tristate
13+ depends on EEH && VFIO_IOMMU_SPAPR_TCE
14+ default n
15+
1116 menuconfig VFIO
1217 tristate "VFIO Non-Privileged userspace driver framework"
1318 depends on IOMMU_API
1419 select VFIO_IOMMU_TYPE1 if X86
1520 select VFIO_IOMMU_SPAPR_TCE if (PPC_POWERNV || PPC_PSERIES)
21+ select VFIO_SPAPR_EEH if (PPC_POWERNV || PPC_PSERIES)
1622 select ANON_INODES
1723 help
1824 VFIO provides a framework for secure userspace device drivers.
drivers/vfio/Makefile+1−1
@@ -1,5 +1,5 @@
11 obj-$(CONFIG_VFIO) += vfio.o
22 obj-$(CONFIG_VFIO_IOMMU_TYPE1) += vfio_iommu_type1.o
33 obj-$(CONFIG_VFIO_IOMMU_SPAPR_TCE) += vfio_iommu_spapr_tce.o
4−obj-$(CONFIG_EEH) += vfio_spapr_eeh.o
4+obj-$(CONFIG_VFIO_SPAPR_EEH) += vfio_spapr_eeh.o
55 obj-$(CONFIG_VFIO_PCI) += pci/
drivers/vfio/pci/vfio_pci.c+143−18
@@ -37,6 +37,10 @@ module_param_named(nointxmask, nointxmask, bool, S_IRUGO | S_IWUSR); · 36 unmodified lines
3737 MODULE_PARM_DESC(nointxmask,
3838 "Disable support for PCI 2.3 style INTx masking. If this resolves problems for specific devices, report lspci -vvvxxx to linux-pci@vger.kernel.org so the device can be fixed automatically via the broken_intx_masking flag.");
3939
40+static DEFINE_MUTEX(driver_lock);
41+
42+static void vfio_pci_try_bus_reset(struct vfio_pci_device *vdev);
43+
4044 static int vfio_pci_enable(struct vfio_pci_device *vdev)
4145 {
4246 struct pci_dev *pdev = vdev->pdev;
@@ -44,6 +48,9 @@ static int vfio_pci_enable(struct vfio_pci_device *vdev) · 1 unmodified line
4448 u16 cmd;
4549 u8 msix_pos;
4650
51+ /* Don't allow our initial saved state to include busmaster */
52+ pci_clear_master(pdev);
53+
4754 ret = pci_enable_device(pdev);
4855 if (ret)
4956 return ret;
@@ -99,7 +106,8 @@ static void vfio_pci_disable(struct vfio_pci_device *vdev) · 49 unmodified lines
99106 struct pci_dev *pdev = vdev->pdev;
100107 int bar;
101108
102− pci_disable_device(pdev);
109+ /* Stop the device from further DMA */
110+ pci_clear_master(pdev);
103111
104112 vfio_pci_set_irqs_ioctl(vdev, VFIO_IRQ_SET_DATA_NONE |
105113 VFIO_IRQ_SET_ACTION_TRIGGER,
@@ -117,6 +125,8 @@ static void vfio_pci_disable(struct vfio_pci_device *vdev) · 11 unmodified lines
117125 vdev->barmap[bar] = NULL;
118126 }
119127
128+ vdev->needs_reset = true;
129+
120130 /*
121131 * If we have saved state, restore it. If we can reset the device,
122132 * even better. Resetting with current state seems better than
@@ -128,7 +138,7 @@ static void vfio_pci_disable(struct vfio_pci_device *vdev) · 5 unmodified lines
128138 __func__, dev_name(&pdev->dev));
129139
130140 if (!vdev->reset_works)
131− return;
141+ goto out;
132142
133143 pci_save_state(pdev);
134144 }
@@ -148,46 +158,55 @@ static void vfio_pci_disable(struct vfio_pci_device *vdev) · 13 unmodified lines
148158 if (ret)
149159 pr_warn("%s: Failed to reset device %s (%d)\n",
150160 __func__, dev_name(&pdev->dev), ret);
161+ else
162+ vdev->needs_reset = false;
151163 }
152164
153165 pci_restore_state(pdev);
166+out:
167+ pci_disable_device(pdev);
168+
169+ vfio_pci_try_bus_reset(vdev);
154170 }
155171
156172 static void vfio_pci_release(void *device_data)
157173 {
158174 struct vfio_pci_device *vdev = device_data;
159175
160− if (atomic_dec_and_test(&vdev->refcnt)) {
176+ mutex_lock(&driver_lock);
177+
178+ if (!(--vdev->refcnt)) {
161179 vfio_spapr_pci_eeh_release(vdev->pdev);
162180 vfio_pci_disable(vdev);
163181 }
164182
183+ mutex_unlock(&driver_lock);
184+
165185 module_put(THIS_MODULE);
166186 }
167187
168188 static int vfio_pci_open(void *device_data)
169189 {
170190 struct vfio_pci_device *vdev = device_data;
171− int ret;
191+ int ret = 0;
172192
173193 if (!try_module_get(THIS_MODULE))
174194 return -ENODEV;
175195
176− if (atomic_inc_return(&vdev->refcnt) == 1) {
196+ mutex_lock(&driver_lock);
197+
198+ if (!vdev->refcnt) {
177199 ret = vfio_pci_enable(vdev);
178200 if (ret)
179201 goto error;
180202
181− ret = vfio_spapr_pci_eeh_open(vdev->pdev);
182− if (ret) {
183− vfio_pci_disable(vdev);
184− goto error;
185− }
203+ vfio_spapr_pci_eeh_open(vdev->pdev);
186204 }
187−
188− return 0;
205+ vdev->refcnt++;
189206 error:
190− module_put(THIS_MODULE);
207+ mutex_unlock(&driver_lock);
208+ if (ret)
209+ module_put(THIS_MODULE);
191210 return ret;
192211 }
193212
@@ -843,7 +862,6 @@ static int vfio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) · 649 unmodified lines
843862 vdev->irq_type = VFIO_PCI_NUM_IRQS;
844863 mutex_init(&vdev->igate);
845864 spin_lock_init(&vdev->irqlock);
846− atomic_set(&vdev->refcnt, 0);
847865
848866 ret = vfio_add_group_dev(&pdev->dev, &vfio_pci_ops, vdev);
849867 if (ret) {
@@ -858,12 +876,15 @@ static void vfio_pci_remove(struct pci_dev *pdev) · 8 unmodified lines
858876 {
859877 struct vfio_pci_device *vdev;
860878
879+ mutex_lock(&driver_lock);
880+
861881 vdev = vfio_del_group_dev(&pdev->dev);
862− if (!vdev)
863− return;
882+ if (vdev) {
883+ iommu_group_put(pdev->dev.iommu_group);
884+ kfree(vdev);
885+ }
864886
865− iommu_group_put(pdev->dev.iommu_group);
866− kfree(vdev);
887+ mutex_unlock(&driver_lock);
867888 }
868889
869890 static pci_ers_result_t vfio_pci_aer_err_detected(struct pci_dev *pdev,
@@ -906,6 +927,110 @@ static struct pci_driver vfio_pci_driver = { · 36 unmodified lines
906927 .err_handler = &vfio_err_handlers,
907928 };
908929
930+/*
931+ * Test whether a reset is necessary and possible. We mark devices as
932+ * needs_reset when they are released, but don't have a function-local reset
933+ * available. If any of these exist in the affected devices, we want to do
934+ * a bus/slot reset. We also need all of the affected devices to be unused,
935+ * so we abort if any device has a non-zero refcnt. driver_lock prevents a
936+ * device from being opened during the scan or unbound from vfio-pci.
937+ */
938+static int vfio_pci_test_bus_reset(struct pci_dev *pdev, void *data)
939+{
940+ bool *needs_reset = data;
941+ struct pci_driver *pci_drv = ACCESS_ONCE(pdev->driver);
942+ int ret = -EBUSY;
943+
944+ if (pci_drv == &vfio_pci_driver) {
945+ struct vfio_device *device;
946+ struct vfio_pci_device *vdev;
947+
948+ device = vfio_device_get_from_dev(&pdev->dev);
949+ if (!device)
950+ return ret;
951+
952+ vdev = vfio_device_data(device);
953+ if (vdev) {
954+ if (vdev->needs_reset)
955+ *needs_reset = true;
956+
957+ if (!vdev->refcnt)
958+ ret = 0;
959+ }
960+
961+ vfio_device_put(device);
962+ }
963+
964+ /*
965+ * TODO: vfio-core considers groups to be viable even if some devices
966+ * are attached to known drivers, like pci-stub or pcieport. We can't
967+ * freeze devices from being unbound to those drivers like we can
968+ * here though, so it would be racy to test for them. We also can't
969+ * use device_lock() to prevent changes as that would interfere with
970+ * PCI-core taking device_lock during bus reset. For now, we require
971+ * devices to be bound to vfio-pci to get a bus/slot reset on release.
972+ */
973+
974+ return ret;
975+}
976+
977+/* Clear needs_reset on all affected devices after successful bus/slot reset */
978+static int vfio_pci_clear_needs_reset(struct pci_dev *pdev, void *data)
979+{
980+ struct pci_driver *pci_drv = ACCESS_ONCE(pdev->driver);
981+
982+ if (pci_drv == &vfio_pci_driver) {
983+ struct vfio_device *device;
984+ struct vfio_pci_device *vdev;
985+
986+ device = vfio_device_get_from_dev(&pdev->dev);
987+ if (!device)
988+ return 0;
989+
990+ vdev = vfio_device_data(device);
991+ if (vdev)
992+ vdev->needs_reset = false;
993+
994+ vfio_device_put(device);
995+ }
996+
997+ return 0;
998+}
999+
1000+/*
1001+ * Attempt to do a bus/slot reset if there are devices affected by a reset for
1002+ * this device that are needs_reset and all of the affected devices are unused
1003+ * (!refcnt). Callers of this function are required to hold driver_lock such
1004+ * that devices can not be unbound from vfio-pci or opened by a user while we
1005+ * test for and perform a bus/slot reset.
1006+ */
1007+static void vfio_pci_try_bus_reset(struct vfio_pci_device *vdev)
1008+{
1009+ bool needs_reset = false, slot = false;
1010+ int ret;
1011+
1012+ if (!pci_probe_reset_slot(vdev->pdev->slot))
1013+ slot = true;
1014+ else if (pci_probe_reset_bus(vdev->pdev->bus))
1015+ return;
1016+
1017+ if (vfio_pci_for_each_slot_or_bus(vdev->pdev,
1018+ vfio_pci_test_bus_reset,
1019+ &needs_reset, slot) || !needs_reset)
1020+ return;
1021+
1022+ if (slot)
1023+ ret = pci_try_reset_slot(vdev->pdev->slot);
1024+ else
1025+ ret = pci_try_reset_bus(vdev->pdev->bus);
1026+
1027+ if (ret)
1028+ return;
1029+
1030+ vfio_pci_for_each_slot_or_bus(vdev->pdev,
1031+ vfio_pci_clear_needs_reset, NULL, slot);
1032+}
1033+
9091034 static void __exit vfio_pci_cleanup(void)
9101035 {
9111036 pci_unregister_driver(&vfio_pci_driver);
drivers/vfio/pci/vfio_pci_private.h+2−1
@@ -54,8 +54,9 @@ struct vfio_pci_device { · 53 unmodified lines
5454 bool extended_caps;
5555 bool bardirty;
5656 bool has_vga;
57+ bool needs_reset;
5758 struct pci_saved_state *pci_saved_state;
58− atomic_t refcnt;
59+ int refcnt;
5960 struct eventfd_ctx *err_trigger;
6061 };
6162
drivers/vfio/vfio_spapr_eeh.c+15−2
@@ -9,20 +9,27 @@ · 8 unmodified lines
99 * published by the Free Software Foundation.
1010 */
1111
12+#include <linux/module.h>
1213 #include <linux/uaccess.h>
1314 #include <linux/vfio.h>
1415 #include <asm/eeh.h>
1516
17+#define DRIVER_VERSION "0.1"
18+#define DRIVER_AUTHOR "Gavin Shan, IBM Corporation"
19+#define DRIVER_DESC "VFIO IOMMU SPAPR EEH"
20+
1621 /* We might build address mapping here for "fast" path later */
17−int vfio_spapr_pci_eeh_open(struct pci_dev *pdev)
22+void vfio_spapr_pci_eeh_open(struct pci_dev *pdev)
1823 {
19− return eeh_dev_open(pdev);
24+ eeh_dev_open(pdev);
2025 }
26+EXPORT_SYMBOL_GPL(vfio_spapr_pci_eeh_open);
2127
2228 void vfio_spapr_pci_eeh_release(struct pci_dev *pdev)
2329 {
2430 eeh_dev_release(pdev);
2531 }
32+EXPORT_SYMBOL_GPL(vfio_spapr_pci_eeh_release);
2633
2734 long vfio_spapr_iommu_eeh_ioctl(struct iommu_group *group,
2835 unsigned int cmd, unsigned long arg)
@@ -85,3 +92,9 @@ long vfio_spapr_iommu_eeh_ioctl(struct iommu_group *group, · 56 unmodified lines
8592
8693 return ret;
8794 }
95+EXPORT_SYMBOL(vfio_spapr_iommu_eeh_ioctl);
96+
97+MODULE_VERSION(DRIVER_VERSION);
98+MODULE_LICENSE("GPL v2");
99+MODULE_AUTHOR(DRIVER_AUTHOR);
100+MODULE_DESCRIPTION(DRIVER_DESC);
include/linux/vfio.h+3−3
@@ -98,16 +98,16 @@ extern int vfio_external_user_iommu_id(struct vfio_group *group); · 97 unmodified lines
9898 extern long vfio_external_check_extension(struct vfio_group *group,
9999 unsigned long arg);
100100
101+struct pci_dev;
101102 #ifdef CONFIG_EEH
102−extern int vfio_spapr_pci_eeh_open(struct pci_dev *pdev);
103+extern void vfio_spapr_pci_eeh_open(struct pci_dev *pdev);
103104 extern void vfio_spapr_pci_eeh_release(struct pci_dev *pdev);
104105 extern long vfio_spapr_iommu_eeh_ioctl(struct iommu_group *group,
105106 unsigned int cmd,
106107 unsigned long arg);
107108 #else
108−static inline int vfio_spapr_pci_eeh_open(struct pci_dev *pdev)
109+static inline void vfio_spapr_pci_eeh_open(struct pci_dev *pdev)
109110 {
110− return 0;
111111 }
112112
113113 static inline void vfio_spapr_pci_eeh_release(struct pci_dev *pdev)