diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/vfio/Makefile | 1 | ||||
-rw-r--r-- | drivers/vfio/pci/vfio_pci.c | 18 | ||||
-rw-r--r-- | drivers/vfio/vfio_iommu_spapr_tce.c | 17 | ||||
-rw-r--r-- | drivers/vfio/vfio_spapr_eeh.c | 87 |
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 @@ | |||
1 | obj-$(CONFIG_VFIO) += vfio.o | 1 | obj-$(CONFIG_VFIO) += vfio.o |
2 | obj-$(CONFIG_VFIO_IOMMU_TYPE1) += vfio_iommu_type1.o | 2 | obj-$(CONFIG_VFIO_IOMMU_TYPE1) += vfio_iommu_type1.o |
3 | obj-$(CONFIG_VFIO_IOMMU_SPAPR_TCE) += vfio_iommu_spapr_tce.o | 3 | obj-$(CONFIG_VFIO_IOMMU_SPAPR_TCE) += vfio_iommu_spapr_tce.o |
4 | obj-$(CONFIG_EEH) += vfio_spapr_eeh.o | ||
4 | obj-$(CONFIG_VFIO_PCI) += pci/ | 5 | obj-$(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) | |||
166 | static int vfio_pci_open(void *device_data) | 168 | static 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; |
189 | error: | ||
190 | module_put(THIS_MODULE); | ||
191 | return ret; | ||
182 | } | 192 | } |
183 | 193 | ||
184 | static int vfio_pci_get_irq_count(struct vfio_pci_device *vdev, int irq_type) | 194 | static 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 */ | ||
17 | int vfio_spapr_pci_eeh_open(struct pci_dev *pdev) | ||
18 | { | ||
19 | return eeh_dev_open(pdev); | ||
20 | } | ||
21 | |||
22 | void vfio_spapr_pci_eeh_release(struct pci_dev *pdev) | ||
23 | { | ||
24 | eeh_dev_release(pdev); | ||
25 | } | ||
26 | |||
27 | long 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 | } | ||