aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/vfio/Makefile1
-rw-r--r--drivers/vfio/pci/vfio_pci.c18
-rw-r--r--drivers/vfio/vfio_iommu_spapr_tce.c17
-rw-r--r--drivers/vfio/vfio_spapr_eeh.c87
4 files changed, 118 insertions, 5 deletions
diff --git a/drivers/vfio/Makefile b/drivers/vfio/Makefile
index 72bfabc8629e..50e30bc75e85 100644
--- a/drivers/vfio/Makefile
+++ b/drivers/vfio/Makefile
@@ -1,4 +1,5 @@
1obj-$(CONFIG_VFIO) += vfio.o 1obj-$(CONFIG_VFIO) += vfio.o
2obj-$(CONFIG_VFIO_IOMMU_TYPE1) += vfio_iommu_type1.o 2obj-$(CONFIG_VFIO_IOMMU_TYPE1) += vfio_iommu_type1.o
3obj-$(CONFIG_VFIO_IOMMU_SPAPR_TCE) += vfio_iommu_spapr_tce.o 3obj-$(CONFIG_VFIO_IOMMU_SPAPR_TCE) += vfio_iommu_spapr_tce.o
4obj-$(CONFIG_EEH) += vfio_spapr_eeh.o
4obj-$(CONFIG_VFIO_PCI) += pci/ 5obj-$(CONFIG_VFIO_PCI) += pci/
diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c
index 010e0f8b8e4f..e2ee80f36e3e 100644
--- a/drivers/vfio/pci/vfio_pci.c
+++ b/drivers/vfio/pci/vfio_pci.c
@@ -157,8 +157,10 @@ static void vfio_pci_release(void *device_data)
157{ 157{
158 struct vfio_pci_device *vdev = device_data; 158 struct vfio_pci_device *vdev = device_data;
159 159
160 if (atomic_dec_and_test(&vdev->refcnt)) 160 if (atomic_dec_and_test(&vdev->refcnt)) {
161 vfio_spapr_pci_eeh_release(vdev->pdev);
161 vfio_pci_disable(vdev); 162 vfio_pci_disable(vdev);
163 }
162 164
163 module_put(THIS_MODULE); 165 module_put(THIS_MODULE);
164} 166}
@@ -166,19 +168,27 @@ static void vfio_pci_release(void *device_data)
166static int vfio_pci_open(void *device_data) 168static int vfio_pci_open(void *device_data)
167{ 169{
168 struct vfio_pci_device *vdev = device_data; 170 struct vfio_pci_device *vdev = device_data;
171 int ret;
169 172
170 if (!try_module_get(THIS_MODULE)) 173 if (!try_module_get(THIS_MODULE))
171 return -ENODEV; 174 return -ENODEV;
172 175
173 if (atomic_inc_return(&vdev->refcnt) == 1) { 176 if (atomic_inc_return(&vdev->refcnt) == 1) {
174 int ret = vfio_pci_enable(vdev); 177 ret = vfio_pci_enable(vdev);
178 if (ret)
179 goto error;
180
181 ret = vfio_spapr_pci_eeh_open(vdev->pdev);
175 if (ret) { 182 if (ret) {
176 module_put(THIS_MODULE); 183 vfio_pci_disable(vdev);
177 return ret; 184 goto error;
178 } 185 }
179 } 186 }
180 187
181 return 0; 188 return 0;
189error:
190 module_put(THIS_MODULE);
191 return ret;
182} 192}
183 193
184static int vfio_pci_get_irq_count(struct vfio_pci_device *vdev, int irq_type) 194static int vfio_pci_get_irq_count(struct vfio_pci_device *vdev, int irq_type)
diff --git a/drivers/vfio/vfio_iommu_spapr_tce.c b/drivers/vfio/vfio_iommu_spapr_tce.c
index a84788ba662c..730b4ef3e0cc 100644
--- a/drivers/vfio/vfio_iommu_spapr_tce.c
+++ b/drivers/vfio/vfio_iommu_spapr_tce.c
@@ -156,7 +156,16 @@ static long tce_iommu_ioctl(void *iommu_data,
156 156
157 switch (cmd) { 157 switch (cmd) {
158 case VFIO_CHECK_EXTENSION: 158 case VFIO_CHECK_EXTENSION:
159 return (arg == VFIO_SPAPR_TCE_IOMMU) ? 1 : 0; 159 switch (arg) {
160 case VFIO_SPAPR_TCE_IOMMU:
161 ret = 1;
162 break;
163 default:
164 ret = vfio_spapr_iommu_eeh_ioctl(NULL, cmd, arg);
165 break;
166 }
167
168 return (ret < 0) ? 0 : ret;
160 169
161 case VFIO_IOMMU_SPAPR_TCE_GET_INFO: { 170 case VFIO_IOMMU_SPAPR_TCE_GET_INFO: {
162 struct vfio_iommu_spapr_tce_info info; 171 struct vfio_iommu_spapr_tce_info info;
@@ -283,6 +292,12 @@ static long tce_iommu_ioctl(void *iommu_data,
283 tce_iommu_disable(container); 292 tce_iommu_disable(container);
284 mutex_unlock(&container->lock); 293 mutex_unlock(&container->lock);
285 return 0; 294 return 0;
295 case VFIO_EEH_PE_OP:
296 if (!container->tbl || !container->tbl->it_group)
297 return -ENODEV;
298
299 return vfio_spapr_iommu_eeh_ioctl(container->tbl->it_group,
300 cmd, arg);
286 } 301 }
287 302
288 return -ENOTTY; 303 return -ENOTTY;
diff --git a/drivers/vfio/vfio_spapr_eeh.c b/drivers/vfio/vfio_spapr_eeh.c
new file mode 100644
index 000000000000..f834b4ce1431
--- /dev/null
+++ b/drivers/vfio/vfio_spapr_eeh.c
@@ -0,0 +1,87 @@
1/*
2 * EEH functionality support for VFIO devices. The feature is only
3 * available on sPAPR compatible platforms.
4 *
5 * Copyright Gavin Shan, IBM Corporation 2014.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#include <linux/uaccess.h>
13#include <linux/vfio.h>
14#include <asm/eeh.h>
15
16/* We might build address mapping here for "fast" path later */
17int vfio_spapr_pci_eeh_open(struct pci_dev *pdev)
18{
19 return eeh_dev_open(pdev);
20}
21
22void vfio_spapr_pci_eeh_release(struct pci_dev *pdev)
23{
24 eeh_dev_release(pdev);
25}
26
27long vfio_spapr_iommu_eeh_ioctl(struct iommu_group *group,
28 unsigned int cmd, unsigned long arg)
29{
30 struct eeh_pe *pe;
31 struct vfio_eeh_pe_op op;
32 unsigned long minsz;
33 long ret = -EINVAL;
34
35 switch (cmd) {
36 case VFIO_CHECK_EXTENSION:
37 if (arg == VFIO_EEH)
38 ret = eeh_enabled() ? 1 : 0;
39 else
40 ret = 0;
41 break;
42 case VFIO_EEH_PE_OP:
43 pe = eeh_iommu_group_to_pe(group);
44 if (!pe)
45 return -ENODEV;
46
47 minsz = offsetofend(struct vfio_eeh_pe_op, op);
48 if (copy_from_user(&op, (void __user *)arg, minsz))
49 return -EFAULT;
50 if (op.argsz < minsz || op.flags)
51 return -EINVAL;
52
53 switch (op.op) {
54 case VFIO_EEH_PE_DISABLE:
55 ret = eeh_pe_set_option(pe, EEH_OPT_DISABLE);
56 break;
57 case VFIO_EEH_PE_ENABLE:
58 ret = eeh_pe_set_option(pe, EEH_OPT_ENABLE);
59 break;
60 case VFIO_EEH_PE_UNFREEZE_IO:
61 ret = eeh_pe_set_option(pe, EEH_OPT_THAW_MMIO);
62 break;
63 case VFIO_EEH_PE_UNFREEZE_DMA:
64 ret = eeh_pe_set_option(pe, EEH_OPT_THAW_DMA);
65 break;
66 case VFIO_EEH_PE_GET_STATE:
67 ret = eeh_pe_get_state(pe);
68 break;
69 case VFIO_EEH_PE_RESET_DEACTIVATE:
70 ret = eeh_pe_reset(pe, EEH_RESET_DEACTIVATE);
71 break;
72 case VFIO_EEH_PE_RESET_HOT:
73 ret = eeh_pe_reset(pe, EEH_RESET_HOT);
74 break;
75 case VFIO_EEH_PE_RESET_FUNDAMENTAL:
76 ret = eeh_pe_reset(pe, EEH_RESET_FUNDAMENTAL);
77 break;
78 case VFIO_EEH_PE_CONFIGURE:
79 ret = eeh_pe_configure(pe);
80 break;
81 default:
82 ret = -EINVAL;
83 }
84 }
85
86 return ret;
87}