aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-04-14 21:06:47 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2015-04-14 21:06:47 -0400
commit8c194f3bd322a8bd44d079092d870549b8ae62d1 (patch)
treec194690d0a01b6e5313d6af133e394a056a3015f
parent07e492eb8921a8aa53fd2bf637bee3da94cc03fe (diff)
parent5a0ff17741c1785b27229a16b5ab77470d71b170 (diff)
Merge tag 'vfio-v4.1-rc1' of git://github.com/awilliam/linux-vfio
Pull VFIO updates from Alex Williamson: - VFIO platform bus driver support (Baptiste Reynal, Antonios Motakis, testing and review by Eric Auger) - Split VFIO irqfd support to separate module (Alex Williamson) - vfio-pci VGA arbiter client (Alex Williamson) - New vfio-pci.ids= module option (Alex Williamson) - vfio-pci D3 power state support for idle devices (Alex Williamson) * tag 'vfio-v4.1-rc1' of git://github.com/awilliam/linux-vfio: (30 commits) vfio-pci: Fix use after free vfio-pci: Move idle devices to D3hot power state vfio-pci: Remove warning if try-reset fails vfio-pci: Allow PCI IDs to be specified as module options vfio-pci: Add VGA arbiter client vfio-pci: Add module option to disable VGA region access vgaarb: Stub vga_set_legacy_decoding() vfio: Split virqfd into a separate module for vfio bus drivers vfio: virqfd_lock can be static vfio: put off the allocation of "minor" in vfio_create_group vfio/platform: implement IRQ masking/unmasking via an eventfd vfio: initialize the virqfd workqueue in VFIO generic code vfio: move eventfd support code for VFIO_PCI to a separate file vfio: pass an opaque pointer on virqfd initialization vfio: add local lock for virqfd instead of depending on VFIO PCI vfio: virqfd: rename vfio_pci_virqfd_init and vfio_pci_virqfd_exit vfio: add a vfio_ prefix to virqfd_enable and virqfd_disable and export vfio/platform: support for level sensitive interrupts vfio/platform: trigger an interrupt via eventfd vfio/platform: initial interrupts support code ...
-rw-r--r--drivers/vfio/Kconfig6
-rw-r--r--drivers/vfio/Makefile4
-rw-r--r--drivers/vfio/pci/Kconfig1
-rw-r--r--drivers/vfio/pci/vfio_pci.c188
-rw-r--r--drivers/vfio/pci/vfio_pci_intrs.c238
-rw-r--r--drivers/vfio/pci/vfio_pci_private.h3
-rw-r--r--drivers/vfio/platform/Kconfig20
-rw-r--r--drivers/vfio/platform/Makefile8
-rw-r--r--drivers/vfio/platform/vfio_amba.c115
-rw-r--r--drivers/vfio/platform/vfio_platform.c103
-rw-r--r--drivers/vfio/platform/vfio_platform_common.c521
-rw-r--r--drivers/vfio/platform/vfio_platform_irq.c336
-rw-r--r--drivers/vfio/platform/vfio_platform_private.h85
-rw-r--r--drivers/vfio/vfio.c13
-rw-r--r--drivers/vfio/virqfd.c226
-rw-r--r--include/linux/vfio.h25
-rw-r--r--include/linux/vgaarb.h5
-rw-r--r--include/uapi/linux/vfio.h2
18 files changed, 1640 insertions, 259 deletions
diff --git a/drivers/vfio/Kconfig b/drivers/vfio/Kconfig
index 14e27ab32456..7d092ddc8119 100644
--- a/drivers/vfio/Kconfig
+++ b/drivers/vfio/Kconfig
@@ -13,6 +13,11 @@ config VFIO_SPAPR_EEH
13 depends on EEH && VFIO_IOMMU_SPAPR_TCE 13 depends on EEH && VFIO_IOMMU_SPAPR_TCE
14 default n 14 default n
15 15
16config VFIO_VIRQFD
17 tristate
18 depends on VFIO && EVENTFD
19 default n
20
16menuconfig VFIO 21menuconfig VFIO
17 tristate "VFIO Non-Privileged userspace driver framework" 22 tristate "VFIO Non-Privileged userspace driver framework"
18 depends on IOMMU_API 23 depends on IOMMU_API
@@ -27,3 +32,4 @@ menuconfig VFIO
27 If you don't know what to do here, say N. 32 If you don't know what to do here, say N.
28 33
29source "drivers/vfio/pci/Kconfig" 34source "drivers/vfio/pci/Kconfig"
35source "drivers/vfio/platform/Kconfig"
diff --git a/drivers/vfio/Makefile b/drivers/vfio/Makefile
index 0b035b12600a..7b8a31f63fea 100644
--- a/drivers/vfio/Makefile
+++ b/drivers/vfio/Makefile
@@ -1,5 +1,9 @@
1vfio_virqfd-y := virqfd.o
2
1obj-$(CONFIG_VFIO) += vfio.o 3obj-$(CONFIG_VFIO) += vfio.o
4obj-$(CONFIG_VFIO_VIRQFD) += vfio_virqfd.o
2obj-$(CONFIG_VFIO_IOMMU_TYPE1) += vfio_iommu_type1.o 5obj-$(CONFIG_VFIO_IOMMU_TYPE1) += vfio_iommu_type1.o
3obj-$(CONFIG_VFIO_IOMMU_SPAPR_TCE) += vfio_iommu_spapr_tce.o 6obj-$(CONFIG_VFIO_IOMMU_SPAPR_TCE) += vfio_iommu_spapr_tce.o
4obj-$(CONFIG_VFIO_SPAPR_EEH) += vfio_spapr_eeh.o 7obj-$(CONFIG_VFIO_SPAPR_EEH) += vfio_spapr_eeh.o
5obj-$(CONFIG_VFIO_PCI) += pci/ 8obj-$(CONFIG_VFIO_PCI) += pci/
9obj-$(CONFIG_VFIO_PLATFORM) += platform/
diff --git a/drivers/vfio/pci/Kconfig b/drivers/vfio/pci/Kconfig
index c6bb5da2d2a7..579d83bf5358 100644
--- a/drivers/vfio/pci/Kconfig
+++ b/drivers/vfio/pci/Kconfig
@@ -1,6 +1,7 @@
1config VFIO_PCI 1config VFIO_PCI
2 tristate "VFIO support for PCI devices" 2 tristate "VFIO support for PCI devices"
3 depends on VFIO && PCI && EVENTFD 3 depends on VFIO && PCI && EVENTFD
4 select VFIO_VIRQFD
4 help 5 help
5 Support for the PCI VFIO bus driver. This is required to make 6 Support for the PCI VFIO bus driver. This is required to make
6 use of PCI drivers using the VFIO framework. 7 use of PCI drivers using the VFIO framework.
diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c
index f8a186381ae8..69fab0fd15ae 100644
--- a/drivers/vfio/pci/vfio_pci.c
+++ b/drivers/vfio/pci/vfio_pci.c
@@ -11,6 +11,8 @@
11 * Author: Tom Lyon, pugs@cisco.com 11 * Author: Tom Lyon, pugs@cisco.com
12 */ 12 */
13 13
14#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
15
14#include <linux/device.h> 16#include <linux/device.h>
15#include <linux/eventfd.h> 17#include <linux/eventfd.h>
16#include <linux/file.h> 18#include <linux/file.h>
@@ -25,6 +27,7 @@
25#include <linux/types.h> 27#include <linux/types.h>
26#include <linux/uaccess.h> 28#include <linux/uaccess.h>
27#include <linux/vfio.h> 29#include <linux/vfio.h>
30#include <linux/vgaarb.h>
28 31
29#include "vfio_pci_private.h" 32#include "vfio_pci_private.h"
30 33
@@ -32,13 +35,81 @@
32#define DRIVER_AUTHOR "Alex Williamson <alex.williamson@redhat.com>" 35#define DRIVER_AUTHOR "Alex Williamson <alex.williamson@redhat.com>"
33#define DRIVER_DESC "VFIO PCI - User Level meta-driver" 36#define DRIVER_DESC "VFIO PCI - User Level meta-driver"
34 37
38static char ids[1024] __initdata;
39module_param_string(ids, ids, sizeof(ids), 0);
40MODULE_PARM_DESC(ids, "Initial PCI IDs to add to the vfio driver, format is \"vendor:device[:subvendor[:subdevice[:class[:class_mask]]]]\" and multiple comma separated entries can be specified");
41
35static bool nointxmask; 42static bool nointxmask;
36module_param_named(nointxmask, nointxmask, bool, S_IRUGO | S_IWUSR); 43module_param_named(nointxmask, nointxmask, bool, S_IRUGO | S_IWUSR);
37MODULE_PARM_DESC(nointxmask, 44MODULE_PARM_DESC(nointxmask,
38 "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."); 45 "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.");
39 46
47#ifdef CONFIG_VFIO_PCI_VGA
48static bool disable_vga;
49module_param(disable_vga, bool, S_IRUGO);
50MODULE_PARM_DESC(disable_vga, "Disable VGA resource access through vfio-pci");
51#endif
52
53static bool disable_idle_d3;
54module_param(disable_idle_d3, bool, S_IRUGO | S_IWUSR);
55MODULE_PARM_DESC(disable_idle_d3,
56 "Disable using the PCI D3 low power state for idle, unused devices");
57
40static DEFINE_MUTEX(driver_lock); 58static DEFINE_MUTEX(driver_lock);
41 59
60static inline bool vfio_vga_disabled(void)
61{
62#ifdef CONFIG_VFIO_PCI_VGA
63 return disable_vga;
64#else
65 return true;
66#endif
67}
68
69/*
70 * Our VGA arbiter participation is limited since we don't know anything
71 * about the device itself. However, if the device is the only VGA device
72 * downstream of a bridge and VFIO VGA support is disabled, then we can
73 * safely return legacy VGA IO and memory as not decoded since the user
74 * has no way to get to it and routing can be disabled externally at the
75 * bridge.
76 */
77static unsigned int vfio_pci_set_vga_decode(void *opaque, bool single_vga)
78{
79 struct vfio_pci_device *vdev = opaque;
80 struct pci_dev *tmp = NULL, *pdev = vdev->pdev;
81 unsigned char max_busnr;
82 unsigned int decodes;
83
84 if (single_vga || !vfio_vga_disabled() || pci_is_root_bus(pdev->bus))
85 return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM |
86 VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM;
87
88 max_busnr = pci_bus_max_busnr(pdev->bus);
89 decodes = VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
90
91 while ((tmp = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, tmp)) != NULL) {
92 if (tmp == pdev ||
93 pci_domain_nr(tmp->bus) != pci_domain_nr(pdev->bus) ||
94 pci_is_root_bus(tmp->bus))
95 continue;
96
97 if (tmp->bus->number >= pdev->bus->number &&
98 tmp->bus->number <= max_busnr) {
99 pci_dev_put(tmp);
100 decodes |= VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM;
101 break;
102 }
103 }
104
105 return decodes;
106}
107
108static inline bool vfio_pci_is_vga(struct pci_dev *pdev)
109{
110 return (pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA;
111}
112
42static void vfio_pci_try_bus_reset(struct vfio_pci_device *vdev); 113static void vfio_pci_try_bus_reset(struct vfio_pci_device *vdev);
43 114
44static int vfio_pci_enable(struct vfio_pci_device *vdev) 115static int vfio_pci_enable(struct vfio_pci_device *vdev)
@@ -48,6 +119,8 @@ static int vfio_pci_enable(struct vfio_pci_device *vdev)
48 u16 cmd; 119 u16 cmd;
49 u8 msix_pos; 120 u8 msix_pos;
50 121
122 pci_set_power_state(pdev, PCI_D0);
123
51 /* Don't allow our initial saved state to include busmaster */ 124 /* Don't allow our initial saved state to include busmaster */
52 pci_clear_master(pdev); 125 pci_clear_master(pdev);
53 126
@@ -93,10 +166,8 @@ static int vfio_pci_enable(struct vfio_pci_device *vdev)
93 } else 166 } else
94 vdev->msix_bar = 0xFF; 167 vdev->msix_bar = 0xFF;
95 168
96#ifdef CONFIG_VFIO_PCI_VGA 169 if (!vfio_vga_disabled() && vfio_pci_is_vga(pdev))
97 if ((pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA)
98 vdev->has_vga = true; 170 vdev->has_vga = true;
99#endif
100 171
101 return 0; 172 return 0;
102} 173}
@@ -153,20 +224,17 @@ static void vfio_pci_disable(struct vfio_pci_device *vdev)
153 * Try to reset the device. The success of this is dependent on 224 * Try to reset the device. The success of this is dependent on
154 * being able to lock the device, which is not always possible. 225 * being able to lock the device, which is not always possible.
155 */ 226 */
156 if (vdev->reset_works) { 227 if (vdev->reset_works && !pci_try_reset_function(pdev))
157 int ret = pci_try_reset_function(pdev); 228 vdev->needs_reset = false;
158 if (ret)
159 pr_warn("%s: Failed to reset device %s (%d)\n",
160 __func__, dev_name(&pdev->dev), ret);
161 else
162 vdev->needs_reset = false;
163 }
164 229
165 pci_restore_state(pdev); 230 pci_restore_state(pdev);
166out: 231out:
167 pci_disable_device(pdev); 232 pci_disable_device(pdev);
168 233
169 vfio_pci_try_bus_reset(vdev); 234 vfio_pci_try_bus_reset(vdev);
235
236 if (!disable_idle_d3)
237 pci_set_power_state(pdev, PCI_D3hot);
170} 238}
171 239
172static void vfio_pci_release(void *device_data) 240static void vfio_pci_release(void *device_data)
@@ -885,6 +953,27 @@ static int vfio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
885 if (ret) { 953 if (ret) {
886 iommu_group_put(group); 954 iommu_group_put(group);
887 kfree(vdev); 955 kfree(vdev);
956 return ret;
957 }
958
959 if (vfio_pci_is_vga(pdev)) {
960 vga_client_register(pdev, vdev, NULL, vfio_pci_set_vga_decode);
961 vga_set_legacy_decoding(pdev,
962 vfio_pci_set_vga_decode(vdev, false));
963 }
964
965 if (!disable_idle_d3) {
966 /*
967 * pci-core sets the device power state to an unknown value at
968 * bootup and after being removed from a driver. The only
969 * transition it allows from this unknown state is to D0, which
970 * typically happens when a driver calls pci_enable_device().
971 * We're not ready to enable the device yet, but we do want to
972 * be able to get to D3. Therefore first do a D0 transition
973 * before going to D3.
974 */
975 pci_set_power_state(pdev, PCI_D0);
976 pci_set_power_state(pdev, PCI_D3hot);
888 } 977 }
889 978
890 return ret; 979 return ret;
@@ -895,10 +984,21 @@ static void vfio_pci_remove(struct pci_dev *pdev)
895 struct vfio_pci_device *vdev; 984 struct vfio_pci_device *vdev;
896 985
897 vdev = vfio_del_group_dev(&pdev->dev); 986 vdev = vfio_del_group_dev(&pdev->dev);
898 if (vdev) { 987 if (!vdev)
899 iommu_group_put(pdev->dev.iommu_group); 988 return;
900 kfree(vdev); 989
990 iommu_group_put(pdev->dev.iommu_group);
991 kfree(vdev);
992
993 if (vfio_pci_is_vga(pdev)) {
994 vga_client_register(pdev, NULL, NULL, NULL);
995 vga_set_legacy_decoding(pdev,
996 VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM |
997 VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM);
901 } 998 }
999
1000 if (!disable_idle_d3)
1001 pci_set_power_state(pdev, PCI_D0);
902} 1002}
903 1003
904static pci_ers_result_t vfio_pci_aer_err_detected(struct pci_dev *pdev, 1004static pci_ers_result_t vfio_pci_aer_err_detected(struct pci_dev *pdev,
@@ -1017,10 +1117,13 @@ static void vfio_pci_try_bus_reset(struct vfio_pci_device *vdev)
1017 1117
1018put_devs: 1118put_devs:
1019 for (i = 0; i < devs.cur_index; i++) { 1119 for (i = 0; i < devs.cur_index; i++) {
1020 if (!ret) { 1120 tmp = vfio_device_data(devs.devices[i]);
1021 tmp = vfio_device_data(devs.devices[i]); 1121 if (!ret)
1022 tmp->needs_reset = false; 1122 tmp->needs_reset = false;
1023 } 1123
1124 if (!tmp->refcnt && !disable_idle_d3)
1125 pci_set_power_state(tmp->pdev, PCI_D3hot);
1126
1024 vfio_device_put(devs.devices[i]); 1127 vfio_device_put(devs.devices[i]);
1025 } 1128 }
1026 1129
@@ -1030,10 +1133,50 @@ put_devs:
1030static void __exit vfio_pci_cleanup(void) 1133static void __exit vfio_pci_cleanup(void)
1031{ 1134{
1032 pci_unregister_driver(&vfio_pci_driver); 1135 pci_unregister_driver(&vfio_pci_driver);
1033 vfio_pci_virqfd_exit();
1034 vfio_pci_uninit_perm_bits(); 1136 vfio_pci_uninit_perm_bits();
1035} 1137}
1036 1138
1139static void __init vfio_pci_fill_ids(void)
1140{
1141 char *p, *id;
1142 int rc;
1143
1144 /* no ids passed actually */
1145 if (ids[0] == '\0')
1146 return;
1147
1148 /* add ids specified in the module parameter */
1149 p = ids;
1150 while ((id = strsep(&p, ","))) {
1151 unsigned int vendor, device, subvendor = PCI_ANY_ID,
1152 subdevice = PCI_ANY_ID, class = 0, class_mask = 0;
1153 int fields;
1154
1155 if (!strlen(id))
1156 continue;
1157
1158 fields = sscanf(id, "%x:%x:%x:%x:%x:%x",
1159 &vendor, &device, &subvendor, &subdevice,
1160 &class, &class_mask);
1161
1162 if (fields < 2) {
1163 pr_warn("invalid id string \"%s\"\n", id);
1164 continue;
1165 }
1166
1167 rc = pci_add_dynid(&vfio_pci_driver, vendor, device,
1168 subvendor, subdevice, class, class_mask, 0);
1169 if (rc)
1170 pr_warn("failed to add dynamic id [%04hx:%04hx[%04hx:%04hx]] class %#08x/%08x (%d)\n",
1171 vendor, device, subvendor, subdevice,
1172 class, class_mask, rc);
1173 else
1174 pr_info("add [%04hx:%04hx[%04hx:%04hx]] class %#08x/%08x\n",
1175 vendor, device, subvendor, subdevice,
1176 class, class_mask);
1177 }
1178}
1179
1037static int __init vfio_pci_init(void) 1180static int __init vfio_pci_init(void)
1038{ 1181{
1039 int ret; 1182 int ret;
@@ -1043,21 +1186,16 @@ static int __init vfio_pci_init(void)
1043 if (ret) 1186 if (ret)
1044 return ret; 1187 return ret;
1045 1188
1046 /* Start the virqfd cleanup handler */
1047 ret = vfio_pci_virqfd_init();
1048 if (ret)
1049 goto out_virqfd;
1050
1051 /* Register and scan for devices */ 1189 /* Register and scan for devices */
1052 ret = pci_register_driver(&vfio_pci_driver); 1190 ret = pci_register_driver(&vfio_pci_driver);
1053 if (ret) 1191 if (ret)
1054 goto out_driver; 1192 goto out_driver;
1055 1193
1194 vfio_pci_fill_ids();
1195
1056 return 0; 1196 return 0;
1057 1197
1058out_driver: 1198out_driver:
1059 vfio_pci_virqfd_exit();
1060out_virqfd:
1061 vfio_pci_uninit_perm_bits(); 1199 vfio_pci_uninit_perm_bits();
1062 return ret; 1200 return ret;
1063} 1201}
diff --git a/drivers/vfio/pci/vfio_pci_intrs.c b/drivers/vfio/pci/vfio_pci_intrs.c
index 2027a27546ef..1f577b4ac126 100644
--- a/drivers/vfio/pci/vfio_pci_intrs.c
+++ b/drivers/vfio/pci/vfio_pci_intrs.c
@@ -19,230 +19,19 @@
19#include <linux/msi.h> 19#include <linux/msi.h>
20#include <linux/pci.h> 20#include <linux/pci.h>
21#include <linux/file.h> 21#include <linux/file.h>
22#include <linux/poll.h>
23#include <linux/vfio.h> 22#include <linux/vfio.h>
24#include <linux/wait.h> 23#include <linux/wait.h>
25#include <linux/workqueue.h>
26#include <linux/slab.h> 24#include <linux/slab.h>
27 25
28#include "vfio_pci_private.h" 26#include "vfio_pci_private.h"
29 27
30/* 28/*
31 * IRQfd - generic
32 */
33struct virqfd {
34 struct vfio_pci_device *vdev;
35 struct eventfd_ctx *eventfd;
36 int (*handler)(struct vfio_pci_device *, void *);
37 void (*thread)(struct vfio_pci_device *, void *);
38 void *data;
39 struct work_struct inject;
40 wait_queue_t wait;
41 poll_table pt;
42 struct work_struct shutdown;
43 struct virqfd **pvirqfd;
44};
45
46static struct workqueue_struct *vfio_irqfd_cleanup_wq;
47
48int __init vfio_pci_virqfd_init(void)
49{
50 vfio_irqfd_cleanup_wq =
51 create_singlethread_workqueue("vfio-irqfd-cleanup");
52 if (!vfio_irqfd_cleanup_wq)
53 return -ENOMEM;
54
55 return 0;
56}
57
58void vfio_pci_virqfd_exit(void)
59{
60 destroy_workqueue(vfio_irqfd_cleanup_wq);
61}
62
63static void virqfd_deactivate(struct virqfd *virqfd)
64{
65 queue_work(vfio_irqfd_cleanup_wq, &virqfd->shutdown);
66}
67
68static int virqfd_wakeup(wait_queue_t *wait, unsigned mode, int sync, void *key)
69{
70 struct virqfd *virqfd = container_of(wait, struct virqfd, wait);
71 unsigned long flags = (unsigned long)key;
72
73 if (flags & POLLIN) {
74 /* An event has been signaled, call function */
75 if ((!virqfd->handler ||
76 virqfd->handler(virqfd->vdev, virqfd->data)) &&
77 virqfd->thread)
78 schedule_work(&virqfd->inject);
79 }
80
81 if (flags & POLLHUP) {
82 unsigned long flags;
83 spin_lock_irqsave(&virqfd->vdev->irqlock, flags);
84
85 /*
86 * The eventfd is closing, if the virqfd has not yet been
87 * queued for release, as determined by testing whether the
88 * vdev pointer to it is still valid, queue it now. As
89 * with kvm irqfds, we know we won't race against the virqfd
90 * going away because we hold wqh->lock to get here.
91 */
92 if (*(virqfd->pvirqfd) == virqfd) {
93 *(virqfd->pvirqfd) = NULL;
94 virqfd_deactivate(virqfd);
95 }
96
97 spin_unlock_irqrestore(&virqfd->vdev->irqlock, flags);
98 }
99
100 return 0;
101}
102
103static void virqfd_ptable_queue_proc(struct file *file,
104 wait_queue_head_t *wqh, poll_table *pt)
105{
106 struct virqfd *virqfd = container_of(pt, struct virqfd, pt);
107 add_wait_queue(wqh, &virqfd->wait);
108}
109
110static void virqfd_shutdown(struct work_struct *work)
111{
112 struct virqfd *virqfd = container_of(work, struct virqfd, shutdown);
113 u64 cnt;
114
115 eventfd_ctx_remove_wait_queue(virqfd->eventfd, &virqfd->wait, &cnt);
116 flush_work(&virqfd->inject);
117 eventfd_ctx_put(virqfd->eventfd);
118
119 kfree(virqfd);
120}
121
122static void virqfd_inject(struct work_struct *work)
123{
124 struct virqfd *virqfd = container_of(work, struct virqfd, inject);
125 if (virqfd->thread)
126 virqfd->thread(virqfd->vdev, virqfd->data);
127}
128
129static int virqfd_enable(struct vfio_pci_device *vdev,
130 int (*handler)(struct vfio_pci_device *, void *),
131 void (*thread)(struct vfio_pci_device *, void *),
132 void *data, struct virqfd **pvirqfd, int fd)
133{
134 struct fd irqfd;
135 struct eventfd_ctx *ctx;
136 struct virqfd *virqfd;
137 int ret = 0;
138 unsigned int events;
139
140 virqfd = kzalloc(sizeof(*virqfd), GFP_KERNEL);
141 if (!virqfd)
142 return -ENOMEM;
143
144 virqfd->pvirqfd = pvirqfd;
145 virqfd->vdev = vdev;
146 virqfd->handler = handler;
147 virqfd->thread = thread;
148 virqfd->data = data;
149
150 INIT_WORK(&virqfd->shutdown, virqfd_shutdown);
151 INIT_WORK(&virqfd->inject, virqfd_inject);
152
153 irqfd = fdget(fd);
154 if (!irqfd.file) {
155 ret = -EBADF;
156 goto err_fd;
157 }
158
159 ctx = eventfd_ctx_fileget(irqfd.file);
160 if (IS_ERR(ctx)) {
161 ret = PTR_ERR(ctx);
162 goto err_ctx;
163 }
164
165 virqfd->eventfd = ctx;
166
167 /*
168 * virqfds can be released by closing the eventfd or directly
169 * through ioctl. These are both done through a workqueue, so
170 * we update the pointer to the virqfd under lock to avoid
171 * pushing multiple jobs to release the same virqfd.
172 */
173 spin_lock_irq(&vdev->irqlock);
174
175 if (*pvirqfd) {
176 spin_unlock_irq(&vdev->irqlock);
177 ret = -EBUSY;
178 goto err_busy;
179 }
180 *pvirqfd = virqfd;
181
182 spin_unlock_irq(&vdev->irqlock);
183
184 /*
185 * Install our own custom wake-up handling so we are notified via
186 * a callback whenever someone signals the underlying eventfd.
187 */
188 init_waitqueue_func_entry(&virqfd->wait, virqfd_wakeup);
189 init_poll_funcptr(&virqfd->pt, virqfd_ptable_queue_proc);
190
191 events = irqfd.file->f_op->poll(irqfd.file, &virqfd->pt);
192
193 /*
194 * Check if there was an event already pending on the eventfd
195 * before we registered and trigger it as if we didn't miss it.
196 */
197 if (events & POLLIN) {
198 if ((!handler || handler(vdev, data)) && thread)
199 schedule_work(&virqfd->inject);
200 }
201
202 /*
203 * Do not drop the file until the irqfd is fully initialized,
204 * otherwise we might race against the POLLHUP.
205 */
206 fdput(irqfd);
207
208 return 0;
209err_busy:
210 eventfd_ctx_put(ctx);
211err_ctx:
212 fdput(irqfd);
213err_fd:
214 kfree(virqfd);
215
216 return ret;
217}
218
219static void virqfd_disable(struct vfio_pci_device *vdev,
220 struct virqfd **pvirqfd)
221{
222 unsigned long flags;
223
224 spin_lock_irqsave(&vdev->irqlock, flags);
225
226 if (*pvirqfd) {
227 virqfd_deactivate(*pvirqfd);
228 *pvirqfd = NULL;
229 }
230
231 spin_unlock_irqrestore(&vdev->irqlock, flags);
232
233 /*
234 * Block until we know all outstanding shutdown jobs have completed.
235 * Even if we don't queue the job, flush the wq to be sure it's
236 * been released.
237 */
238 flush_workqueue(vfio_irqfd_cleanup_wq);
239}
240
241/*
242 * INTx 29 * INTx
243 */ 30 */
244static void vfio_send_intx_eventfd(struct vfio_pci_device *vdev, void *unused) 31static void vfio_send_intx_eventfd(void *opaque, void *unused)
245{ 32{
33 struct vfio_pci_device *vdev = opaque;
34
246 if (likely(is_intx(vdev) && !vdev->virq_disabled)) 35 if (likely(is_intx(vdev) && !vdev->virq_disabled))
247 eventfd_signal(vdev->ctx[0].trigger, 1); 36 eventfd_signal(vdev->ctx[0].trigger, 1);
248} 37}
@@ -285,9 +74,9 @@ void vfio_pci_intx_mask(struct vfio_pci_device *vdev)
285 * a signal is necessary, which can then be handled via a work queue 74 * a signal is necessary, which can then be handled via a work queue
286 * or directly depending on the caller. 75 * or directly depending on the caller.
287 */ 76 */
288static int vfio_pci_intx_unmask_handler(struct vfio_pci_device *vdev, 77static int vfio_pci_intx_unmask_handler(void *opaque, void *unused)
289 void *unused)
290{ 78{
79 struct vfio_pci_device *vdev = opaque;
291 struct pci_dev *pdev = vdev->pdev; 80 struct pci_dev *pdev = vdev->pdev;
292 unsigned long flags; 81 unsigned long flags;
293 int ret = 0; 82 int ret = 0;
@@ -440,8 +229,8 @@ static int vfio_intx_set_signal(struct vfio_pci_device *vdev, int fd)
440static void vfio_intx_disable(struct vfio_pci_device *vdev) 229static void vfio_intx_disable(struct vfio_pci_device *vdev)
441{ 230{
442 vfio_intx_set_signal(vdev, -1); 231 vfio_intx_set_signal(vdev, -1);
443 virqfd_disable(vdev, &vdev->ctx[0].unmask); 232 vfio_virqfd_disable(&vdev->ctx[0].unmask);
444 virqfd_disable(vdev, &vdev->ctx[0].mask); 233 vfio_virqfd_disable(&vdev->ctx[0].mask);
445 vdev->irq_type = VFIO_PCI_NUM_IRQS; 234 vdev->irq_type = VFIO_PCI_NUM_IRQS;
446 vdev->num_ctx = 0; 235 vdev->num_ctx = 0;
447 kfree(vdev->ctx); 236 kfree(vdev->ctx);
@@ -605,8 +394,8 @@ static void vfio_msi_disable(struct vfio_pci_device *vdev, bool msix)
605 vfio_msi_set_block(vdev, 0, vdev->num_ctx, NULL, msix); 394 vfio_msi_set_block(vdev, 0, vdev->num_ctx, NULL, msix);
606 395
607 for (i = 0; i < vdev->num_ctx; i++) { 396 for (i = 0; i < vdev->num_ctx; i++) {
608 virqfd_disable(vdev, &vdev->ctx[i].unmask); 397 vfio_virqfd_disable(&vdev->ctx[i].unmask);
609 virqfd_disable(vdev, &vdev->ctx[i].mask); 398 vfio_virqfd_disable(&vdev->ctx[i].mask);
610 } 399 }
611 400
612 if (msix) { 401 if (msix) {
@@ -639,11 +428,12 @@ static int vfio_pci_set_intx_unmask(struct vfio_pci_device *vdev,
639 } else if (flags & VFIO_IRQ_SET_DATA_EVENTFD) { 428 } else if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
640 int32_t fd = *(int32_t *)data; 429 int32_t fd = *(int32_t *)data;
641 if (fd >= 0) 430 if (fd >= 0)
642 return virqfd_enable(vdev, vfio_pci_intx_unmask_handler, 431 return vfio_virqfd_enable((void *) vdev,
643 vfio_send_intx_eventfd, NULL, 432 vfio_pci_intx_unmask_handler,
644 &vdev->ctx[0].unmask, fd); 433 vfio_send_intx_eventfd, NULL,
434 &vdev->ctx[0].unmask, fd);
645 435
646 virqfd_disable(vdev, &vdev->ctx[0].unmask); 436 vfio_virqfd_disable(&vdev->ctx[0].unmask);
647 } 437 }
648 438
649 return 0; 439 return 0;
diff --git a/drivers/vfio/pci/vfio_pci_private.h b/drivers/vfio/pci/vfio_pci_private.h
index c9f9b323f152..ae0e1b4c1711 100644
--- a/drivers/vfio/pci/vfio_pci_private.h
+++ b/drivers/vfio/pci/vfio_pci_private.h
@@ -87,9 +87,6 @@ extern ssize_t vfio_pci_vga_rw(struct vfio_pci_device *vdev, char __user *buf,
87extern int vfio_pci_init_perm_bits(void); 87extern int vfio_pci_init_perm_bits(void);
88extern void vfio_pci_uninit_perm_bits(void); 88extern void vfio_pci_uninit_perm_bits(void);
89 89
90extern int vfio_pci_virqfd_init(void);
91extern void vfio_pci_virqfd_exit(void);
92
93extern int vfio_config_init(struct vfio_pci_device *vdev); 90extern int vfio_config_init(struct vfio_pci_device *vdev);
94extern void vfio_config_free(struct vfio_pci_device *vdev); 91extern void vfio_config_free(struct vfio_pci_device *vdev);
95#endif /* VFIO_PCI_PRIVATE_H */ 92#endif /* VFIO_PCI_PRIVATE_H */
diff --git a/drivers/vfio/platform/Kconfig b/drivers/vfio/platform/Kconfig
new file mode 100644
index 000000000000..9a4403e2a36c
--- /dev/null
+++ b/drivers/vfio/platform/Kconfig
@@ -0,0 +1,20 @@
1config VFIO_PLATFORM
2 tristate "VFIO support for platform devices"
3 depends on VFIO && EVENTFD && ARM
4 select VFIO_VIRQFD
5 help
6 Support for platform devices with VFIO. This is required to make
7 use of platform devices present on the system using the VFIO
8 framework.
9
10 If you don't know what to do here, say N.
11
12config VFIO_AMBA
13 tristate "VFIO support for AMBA devices"
14 depends on VFIO_PLATFORM && ARM_AMBA
15 help
16 Support for ARM AMBA devices with VFIO. This is required to make
17 use of ARM AMBA devices present on the system using the VFIO
18 framework.
19
20 If you don't know what to do here, say N.
diff --git a/drivers/vfio/platform/Makefile b/drivers/vfio/platform/Makefile
new file mode 100644
index 000000000000..81de144c0eaa
--- /dev/null
+++ b/drivers/vfio/platform/Makefile
@@ -0,0 +1,8 @@
1
2vfio-platform-y := vfio_platform.o vfio_platform_common.o vfio_platform_irq.o
3
4obj-$(CONFIG_VFIO_PLATFORM) += vfio-platform.o
5
6vfio-amba-y := vfio_amba.o
7
8obj-$(CONFIG_VFIO_AMBA) += vfio-amba.o
diff --git a/drivers/vfio/platform/vfio_amba.c b/drivers/vfio/platform/vfio_amba.c
new file mode 100644
index 000000000000..ff0331f72526
--- /dev/null
+++ b/drivers/vfio/platform/vfio_amba.c
@@ -0,0 +1,115 @@
1/*
2 * Copyright (C) 2013 - Virtual Open Systems
3 * Author: Antonios Motakis <a.motakis@virtualopensystems.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License, version 2, as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15#include <linux/module.h>
16#include <linux/slab.h>
17#include <linux/vfio.h>
18#include <linux/amba/bus.h>
19
20#include "vfio_platform_private.h"
21
22#define DRIVER_VERSION "0.10"
23#define DRIVER_AUTHOR "Antonios Motakis <a.motakis@virtualopensystems.com>"
24#define DRIVER_DESC "VFIO for AMBA devices - User Level meta-driver"
25
26/* probing devices from the AMBA bus */
27
28static struct resource *get_amba_resource(struct vfio_platform_device *vdev,
29 int i)
30{
31 struct amba_device *adev = (struct amba_device *) vdev->opaque;
32
33 if (i == 0)
34 return &adev->res;
35
36 return NULL;
37}
38
39static int get_amba_irq(struct vfio_platform_device *vdev, int i)
40{
41 struct amba_device *adev = (struct amba_device *) vdev->opaque;
42 int ret = 0;
43
44 if (i < AMBA_NR_IRQS)
45 ret = adev->irq[i];
46
47 /* zero is an unset IRQ for AMBA devices */
48 return ret ? ret : -ENXIO;
49}
50
51static int vfio_amba_probe(struct amba_device *adev, const struct amba_id *id)
52{
53 struct vfio_platform_device *vdev;
54 int ret;
55
56 vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
57 if (!vdev)
58 return -ENOMEM;
59
60 vdev->name = kasprintf(GFP_KERNEL, "vfio-amba-%08x", adev->periphid);
61 if (!vdev->name) {
62 kfree(vdev);
63 return -ENOMEM;
64 }
65
66 vdev->opaque = (void *) adev;
67 vdev->flags = VFIO_DEVICE_FLAGS_AMBA;
68 vdev->get_resource = get_amba_resource;
69 vdev->get_irq = get_amba_irq;
70
71 ret = vfio_platform_probe_common(vdev, &adev->dev);
72 if (ret) {
73 kfree(vdev->name);
74 kfree(vdev);
75 }
76
77 return ret;
78}
79
80static int vfio_amba_remove(struct amba_device *adev)
81{
82 struct vfio_platform_device *vdev;
83
84 vdev = vfio_platform_remove_common(&adev->dev);
85 if (vdev) {
86 kfree(vdev->name);
87 kfree(vdev);
88 return 0;
89 }
90
91 return -EINVAL;
92}
93
94static struct amba_id pl330_ids[] = {
95 { 0, 0 },
96};
97
98MODULE_DEVICE_TABLE(amba, pl330_ids);
99
100static struct amba_driver vfio_amba_driver = {
101 .probe = vfio_amba_probe,
102 .remove = vfio_amba_remove,
103 .id_table = pl330_ids,
104 .drv = {
105 .name = "vfio-amba",
106 .owner = THIS_MODULE,
107 },
108};
109
110module_amba_driver(vfio_amba_driver);
111
112MODULE_VERSION(DRIVER_VERSION);
113MODULE_LICENSE("GPL v2");
114MODULE_AUTHOR(DRIVER_AUTHOR);
115MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/vfio/platform/vfio_platform.c b/drivers/vfio/platform/vfio_platform.c
new file mode 100644
index 000000000000..cef645c83996
--- /dev/null
+++ b/drivers/vfio/platform/vfio_platform.c
@@ -0,0 +1,103 @@
1/*
2 * Copyright (C) 2013 - Virtual Open Systems
3 * Author: Antonios Motakis <a.motakis@virtualopensystems.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License, version 2, as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15#include <linux/module.h>
16#include <linux/slab.h>
17#include <linux/vfio.h>
18#include <linux/platform_device.h>
19
20#include "vfio_platform_private.h"
21
22#define DRIVER_VERSION "0.10"
23#define DRIVER_AUTHOR "Antonios Motakis <a.motakis@virtualopensystems.com>"
24#define DRIVER_DESC "VFIO for platform devices - User Level meta-driver"
25
26/* probing devices from the linux platform bus */
27
28static struct resource *get_platform_resource(struct vfio_platform_device *vdev,
29 int num)
30{
31 struct platform_device *dev = (struct platform_device *) vdev->opaque;
32 int i;
33
34 for (i = 0; i < dev->num_resources; i++) {
35 struct resource *r = &dev->resource[i];
36
37 if (resource_type(r) & (IORESOURCE_MEM|IORESOURCE_IO)) {
38 if (!num)
39 return r;
40
41 num--;
42 }
43 }
44 return NULL;
45}
46
47static int get_platform_irq(struct vfio_platform_device *vdev, int i)
48{
49 struct platform_device *pdev = (struct platform_device *) vdev->opaque;
50
51 return platform_get_irq(pdev, i);
52}
53
54static int vfio_platform_probe(struct platform_device *pdev)
55{
56 struct vfio_platform_device *vdev;
57 int ret;
58
59 vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
60 if (!vdev)
61 return -ENOMEM;
62
63 vdev->opaque = (void *) pdev;
64 vdev->name = pdev->name;
65 vdev->flags = VFIO_DEVICE_FLAGS_PLATFORM;
66 vdev->get_resource = get_platform_resource;
67 vdev->get_irq = get_platform_irq;
68
69 ret = vfio_platform_probe_common(vdev, &pdev->dev);
70 if (ret)
71 kfree(vdev);
72
73 return ret;
74}
75
76static int vfio_platform_remove(struct platform_device *pdev)
77{
78 struct vfio_platform_device *vdev;
79
80 vdev = vfio_platform_remove_common(&pdev->dev);
81 if (vdev) {
82 kfree(vdev);
83 return 0;
84 }
85
86 return -EINVAL;
87}
88
89static struct platform_driver vfio_platform_driver = {
90 .probe = vfio_platform_probe,
91 .remove = vfio_platform_remove,
92 .driver = {
93 .name = "vfio-platform",
94 .owner = THIS_MODULE,
95 },
96};
97
98module_platform_driver(vfio_platform_driver);
99
100MODULE_VERSION(DRIVER_VERSION);
101MODULE_LICENSE("GPL v2");
102MODULE_AUTHOR(DRIVER_AUTHOR);
103MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/vfio/platform/vfio_platform_common.c b/drivers/vfio/platform/vfio_platform_common.c
new file mode 100644
index 000000000000..abcff7a1aa66
--- /dev/null
+++ b/drivers/vfio/platform/vfio_platform_common.c
@@ -0,0 +1,521 @@
1/*
2 * Copyright (C) 2013 - Virtual Open Systems
3 * Author: Antonios Motakis <a.motakis@virtualopensystems.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License, version 2, as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15#include <linux/device.h>
16#include <linux/iommu.h>
17#include <linux/module.h>
18#include <linux/mutex.h>
19#include <linux/slab.h>
20#include <linux/types.h>
21#include <linux/uaccess.h>
22#include <linux/vfio.h>
23
24#include "vfio_platform_private.h"
25
26static DEFINE_MUTEX(driver_lock);
27
28static int vfio_platform_regions_init(struct vfio_platform_device *vdev)
29{
30 int cnt = 0, i;
31
32 while (vdev->get_resource(vdev, cnt))
33 cnt++;
34
35 vdev->regions = kcalloc(cnt, sizeof(struct vfio_platform_region),
36 GFP_KERNEL);
37 if (!vdev->regions)
38 return -ENOMEM;
39
40 for (i = 0; i < cnt; i++) {
41 struct resource *res =
42 vdev->get_resource(vdev, i);
43
44 if (!res)
45 goto err;
46
47 vdev->regions[i].addr = res->start;
48 vdev->regions[i].size = resource_size(res);
49 vdev->regions[i].flags = 0;
50
51 switch (resource_type(res)) {
52 case IORESOURCE_MEM:
53 vdev->regions[i].type = VFIO_PLATFORM_REGION_TYPE_MMIO;
54 vdev->regions[i].flags |= VFIO_REGION_INFO_FLAG_READ;
55 if (!(res->flags & IORESOURCE_READONLY))
56 vdev->regions[i].flags |=
57 VFIO_REGION_INFO_FLAG_WRITE;
58
59 /*
60 * Only regions addressed with PAGE granularity may be
61 * MMAPed securely.
62 */
63 if (!(vdev->regions[i].addr & ~PAGE_MASK) &&
64 !(vdev->regions[i].size & ~PAGE_MASK))
65 vdev->regions[i].flags |=
66 VFIO_REGION_INFO_FLAG_MMAP;
67
68 break;
69 case IORESOURCE_IO:
70 vdev->regions[i].type = VFIO_PLATFORM_REGION_TYPE_PIO;
71 break;
72 default:
73 goto err;
74 }
75 }
76
77 vdev->num_regions = cnt;
78
79 return 0;
80err:
81 kfree(vdev->regions);
82 return -EINVAL;
83}
84
85static void vfio_platform_regions_cleanup(struct vfio_platform_device *vdev)
86{
87 int i;
88
89 for (i = 0; i < vdev->num_regions; i++)
90 iounmap(vdev->regions[i].ioaddr);
91
92 vdev->num_regions = 0;
93 kfree(vdev->regions);
94}
95
96static void vfio_platform_release(void *device_data)
97{
98 struct vfio_platform_device *vdev = device_data;
99
100 mutex_lock(&driver_lock);
101
102 if (!(--vdev->refcnt)) {
103 vfio_platform_regions_cleanup(vdev);
104 vfio_platform_irq_cleanup(vdev);
105 }
106
107 mutex_unlock(&driver_lock);
108
109 module_put(THIS_MODULE);
110}
111
112static int vfio_platform_open(void *device_data)
113{
114 struct vfio_platform_device *vdev = device_data;
115 int ret;
116
117 if (!try_module_get(THIS_MODULE))
118 return -ENODEV;
119
120 mutex_lock(&driver_lock);
121
122 if (!vdev->refcnt) {
123 ret = vfio_platform_regions_init(vdev);
124 if (ret)
125 goto err_reg;
126
127 ret = vfio_platform_irq_init(vdev);
128 if (ret)
129 goto err_irq;
130 }
131
132 vdev->refcnt++;
133
134 mutex_unlock(&driver_lock);
135 return 0;
136
137err_irq:
138 vfio_platform_regions_cleanup(vdev);
139err_reg:
140 mutex_unlock(&driver_lock);
141 module_put(THIS_MODULE);
142 return ret;
143}
144
145static long vfio_platform_ioctl(void *device_data,
146 unsigned int cmd, unsigned long arg)
147{
148 struct vfio_platform_device *vdev = device_data;
149 unsigned long minsz;
150
151 if (cmd == VFIO_DEVICE_GET_INFO) {
152 struct vfio_device_info info;
153
154 minsz = offsetofend(struct vfio_device_info, num_irqs);
155
156 if (copy_from_user(&info, (void __user *)arg, minsz))
157 return -EFAULT;
158
159 if (info.argsz < minsz)
160 return -EINVAL;
161
162 info.flags = vdev->flags;
163 info.num_regions = vdev->num_regions;
164 info.num_irqs = vdev->num_irqs;
165
166 return copy_to_user((void __user *)arg, &info, minsz);
167
168 } else if (cmd == VFIO_DEVICE_GET_REGION_INFO) {
169 struct vfio_region_info info;
170
171 minsz = offsetofend(struct vfio_region_info, offset);
172
173 if (copy_from_user(&info, (void __user *)arg, minsz))
174 return -EFAULT;
175
176 if (info.argsz < minsz)
177 return -EINVAL;
178
179 if (info.index >= vdev->num_regions)
180 return -EINVAL;
181
182 /* map offset to the physical address */
183 info.offset = VFIO_PLATFORM_INDEX_TO_OFFSET(info.index);
184 info.size = vdev->regions[info.index].size;
185 info.flags = vdev->regions[info.index].flags;
186
187 return copy_to_user((void __user *)arg, &info, minsz);
188
189 } else if (cmd == VFIO_DEVICE_GET_IRQ_INFO) {
190 struct vfio_irq_info info;
191
192 minsz = offsetofend(struct vfio_irq_info, count);
193
194 if (copy_from_user(&info, (void __user *)arg, minsz))
195 return -EFAULT;
196
197 if (info.argsz < minsz)
198 return -EINVAL;
199
200 if (info.index >= vdev->num_irqs)
201 return -EINVAL;
202
203 info.flags = vdev->irqs[info.index].flags;
204 info.count = vdev->irqs[info.index].count;
205
206 return copy_to_user((void __user *)arg, &info, minsz);
207
208 } else if (cmd == VFIO_DEVICE_SET_IRQS) {
209 struct vfio_irq_set hdr;
210 u8 *data = NULL;
211 int ret = 0;
212
213 minsz = offsetofend(struct vfio_irq_set, count);
214
215 if (copy_from_user(&hdr, (void __user *)arg, minsz))
216 return -EFAULT;
217
218 if (hdr.argsz < minsz)
219 return -EINVAL;
220
221 if (hdr.index >= vdev->num_irqs)
222 return -EINVAL;
223
224 if (hdr.flags & ~(VFIO_IRQ_SET_DATA_TYPE_MASK |
225 VFIO_IRQ_SET_ACTION_TYPE_MASK))
226 return -EINVAL;
227
228 if (!(hdr.flags & VFIO_IRQ_SET_DATA_NONE)) {
229 size_t size;
230
231 if (hdr.flags & VFIO_IRQ_SET_DATA_BOOL)
232 size = sizeof(uint8_t);
233 else if (hdr.flags & VFIO_IRQ_SET_DATA_EVENTFD)
234 size = sizeof(int32_t);
235 else
236 return -EINVAL;
237
238 if (hdr.argsz - minsz < size)
239 return -EINVAL;
240
241 data = memdup_user((void __user *)(arg + minsz), size);
242 if (IS_ERR(data))
243 return PTR_ERR(data);
244 }
245
246 mutex_lock(&vdev->igate);
247
248 ret = vfio_platform_set_irqs_ioctl(vdev, hdr.flags, hdr.index,
249 hdr.start, hdr.count, data);
250 mutex_unlock(&vdev->igate);
251 kfree(data);
252
253 return ret;
254
255 } else if (cmd == VFIO_DEVICE_RESET)
256 return -EINVAL;
257
258 return -ENOTTY;
259}
260
261static ssize_t vfio_platform_read_mmio(struct vfio_platform_region reg,
262 char __user *buf, size_t count,
263 loff_t off)
264{
265 unsigned int done = 0;
266
267 if (!reg.ioaddr) {
268 reg.ioaddr =
269 ioremap_nocache(reg.addr, reg.size);
270
271 if (!reg.ioaddr)
272 return -ENOMEM;
273 }
274
275 while (count) {
276 size_t filled;
277
278 if (count >= 4 && !(off % 4)) {
279 u32 val;
280
281 val = ioread32(reg.ioaddr + off);
282 if (copy_to_user(buf, &val, 4))
283 goto err;
284
285 filled = 4;
286 } else if (count >= 2 && !(off % 2)) {
287 u16 val;
288
289 val = ioread16(reg.ioaddr + off);
290 if (copy_to_user(buf, &val, 2))
291 goto err;
292
293 filled = 2;
294 } else {
295 u8 val;
296
297 val = ioread8(reg.ioaddr + off);
298 if (copy_to_user(buf, &val, 1))
299 goto err;
300
301 filled = 1;
302 }
303
304
305 count -= filled;
306 done += filled;
307 off += filled;
308 buf += filled;
309 }
310
311 return done;
312err:
313 return -EFAULT;
314}
315
316static ssize_t vfio_platform_read(void *device_data, char __user *buf,
317 size_t count, loff_t *ppos)
318{
319 struct vfio_platform_device *vdev = device_data;
320 unsigned int index = VFIO_PLATFORM_OFFSET_TO_INDEX(*ppos);
321 loff_t off = *ppos & VFIO_PLATFORM_OFFSET_MASK;
322
323 if (index >= vdev->num_regions)
324 return -EINVAL;
325
326 if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_READ))
327 return -EINVAL;
328
329 if (vdev->regions[index].type & VFIO_PLATFORM_REGION_TYPE_MMIO)
330 return vfio_platform_read_mmio(vdev->regions[index],
331 buf, count, off);
332 else if (vdev->regions[index].type & VFIO_PLATFORM_REGION_TYPE_PIO)
333 return -EINVAL; /* not implemented */
334
335 return -EINVAL;
336}
337
338static ssize_t vfio_platform_write_mmio(struct vfio_platform_region reg,
339 const char __user *buf, size_t count,
340 loff_t off)
341{
342 unsigned int done = 0;
343
344 if (!reg.ioaddr) {
345 reg.ioaddr =
346 ioremap_nocache(reg.addr, reg.size);
347
348 if (!reg.ioaddr)
349 return -ENOMEM;
350 }
351
352 while (count) {
353 size_t filled;
354
355 if (count >= 4 && !(off % 4)) {
356 u32 val;
357
358 if (copy_from_user(&val, buf, 4))
359 goto err;
360 iowrite32(val, reg.ioaddr + off);
361
362 filled = 4;
363 } else if (count >= 2 && !(off % 2)) {
364 u16 val;
365
366 if (copy_from_user(&val, buf, 2))
367 goto err;
368 iowrite16(val, reg.ioaddr + off);
369
370 filled = 2;
371 } else {
372 u8 val;
373
374 if (copy_from_user(&val, buf, 1))
375 goto err;
376 iowrite8(val, reg.ioaddr + off);
377
378 filled = 1;
379 }
380
381 count -= filled;
382 done += filled;
383 off += filled;
384 buf += filled;
385 }
386
387 return done;
388err:
389 return -EFAULT;
390}
391
392static ssize_t vfio_platform_write(void *device_data, const char __user *buf,
393 size_t count, loff_t *ppos)
394{
395 struct vfio_platform_device *vdev = device_data;
396 unsigned int index = VFIO_PLATFORM_OFFSET_TO_INDEX(*ppos);
397 loff_t off = *ppos & VFIO_PLATFORM_OFFSET_MASK;
398
399 if (index >= vdev->num_regions)
400 return -EINVAL;
401
402 if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_WRITE))
403 return -EINVAL;
404
405 if (vdev->regions[index].type & VFIO_PLATFORM_REGION_TYPE_MMIO)
406 return vfio_platform_write_mmio(vdev->regions[index],
407 buf, count, off);
408 else if (vdev->regions[index].type & VFIO_PLATFORM_REGION_TYPE_PIO)
409 return -EINVAL; /* not implemented */
410
411 return -EINVAL;
412}
413
414static int vfio_platform_mmap_mmio(struct vfio_platform_region region,
415 struct vm_area_struct *vma)
416{
417 u64 req_len, pgoff, req_start;
418
419 req_len = vma->vm_end - vma->vm_start;
420 pgoff = vma->vm_pgoff &
421 ((1U << (VFIO_PLATFORM_OFFSET_SHIFT - PAGE_SHIFT)) - 1);
422 req_start = pgoff << PAGE_SHIFT;
423
424 if (region.size < PAGE_SIZE || req_start + req_len > region.size)
425 return -EINVAL;
426
427 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
428 vma->vm_pgoff = (region.addr >> PAGE_SHIFT) + pgoff;
429
430 return remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
431 req_len, vma->vm_page_prot);
432}
433
434static int vfio_platform_mmap(void *device_data, struct vm_area_struct *vma)
435{
436 struct vfio_platform_device *vdev = device_data;
437 unsigned int index;
438
439 index = vma->vm_pgoff >> (VFIO_PLATFORM_OFFSET_SHIFT - PAGE_SHIFT);
440
441 if (vma->vm_end < vma->vm_start)
442 return -EINVAL;
443 if (!(vma->vm_flags & VM_SHARED))
444 return -EINVAL;
445 if (index >= vdev->num_regions)
446 return -EINVAL;
447 if (vma->vm_start & ~PAGE_MASK)
448 return -EINVAL;
449 if (vma->vm_end & ~PAGE_MASK)
450 return -EINVAL;
451
452 if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_MMAP))
453 return -EINVAL;
454
455 if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_READ)
456 && (vma->vm_flags & VM_READ))
457 return -EINVAL;
458
459 if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_WRITE)
460 && (vma->vm_flags & VM_WRITE))
461 return -EINVAL;
462
463 vma->vm_private_data = vdev;
464
465 if (vdev->regions[index].type & VFIO_PLATFORM_REGION_TYPE_MMIO)
466 return vfio_platform_mmap_mmio(vdev->regions[index], vma);
467
468 else if (vdev->regions[index].type & VFIO_PLATFORM_REGION_TYPE_PIO)
469 return -EINVAL; /* not implemented */
470
471 return -EINVAL;
472}
473
474static const struct vfio_device_ops vfio_platform_ops = {
475 .name = "vfio-platform",
476 .open = vfio_platform_open,
477 .release = vfio_platform_release,
478 .ioctl = vfio_platform_ioctl,
479 .read = vfio_platform_read,
480 .write = vfio_platform_write,
481 .mmap = vfio_platform_mmap,
482};
483
484int vfio_platform_probe_common(struct vfio_platform_device *vdev,
485 struct device *dev)
486{
487 struct iommu_group *group;
488 int ret;
489
490 if (!vdev)
491 return -EINVAL;
492
493 group = iommu_group_get(dev);
494 if (!group) {
495 pr_err("VFIO: No IOMMU group for device %s\n", vdev->name);
496 return -EINVAL;
497 }
498
499 ret = vfio_add_group_dev(dev, &vfio_platform_ops, vdev);
500 if (ret) {
501 iommu_group_put(group);
502 return ret;
503 }
504
505 mutex_init(&vdev->igate);
506
507 return 0;
508}
509EXPORT_SYMBOL_GPL(vfio_platform_probe_common);
510
511struct vfio_platform_device *vfio_platform_remove_common(struct device *dev)
512{
513 struct vfio_platform_device *vdev;
514
515 vdev = vfio_del_group_dev(dev);
516 if (vdev)
517 iommu_group_put(dev->iommu_group);
518
519 return vdev;
520}
521EXPORT_SYMBOL_GPL(vfio_platform_remove_common);
diff --git a/drivers/vfio/platform/vfio_platform_irq.c b/drivers/vfio/platform/vfio_platform_irq.c
new file mode 100644
index 000000000000..88bba57b30a8
--- /dev/null
+++ b/drivers/vfio/platform/vfio_platform_irq.c
@@ -0,0 +1,336 @@
1/*
2 * VFIO platform devices interrupt handling
3 *
4 * Copyright (C) 2013 - Virtual Open Systems
5 * Author: Antonios Motakis <a.motakis@virtualopensystems.com>
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 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17#include <linux/eventfd.h>
18#include <linux/interrupt.h>
19#include <linux/slab.h>
20#include <linux/types.h>
21#include <linux/vfio.h>
22#include <linux/irq.h>
23
24#include "vfio_platform_private.h"
25
26static void vfio_platform_mask(struct vfio_platform_irq *irq_ctx)
27{
28 unsigned long flags;
29
30 spin_lock_irqsave(&irq_ctx->lock, flags);
31
32 if (!irq_ctx->masked) {
33 disable_irq_nosync(irq_ctx->hwirq);
34 irq_ctx->masked = true;
35 }
36
37 spin_unlock_irqrestore(&irq_ctx->lock, flags);
38}
39
40static int vfio_platform_mask_handler(void *opaque, void *unused)
41{
42 struct vfio_platform_irq *irq_ctx = opaque;
43
44 vfio_platform_mask(irq_ctx);
45
46 return 0;
47}
48
49static int vfio_platform_set_irq_mask(struct vfio_platform_device *vdev,
50 unsigned index, unsigned start,
51 unsigned count, uint32_t flags,
52 void *data)
53{
54 if (start != 0 || count != 1)
55 return -EINVAL;
56
57 if (!(vdev->irqs[index].flags & VFIO_IRQ_INFO_MASKABLE))
58 return -EINVAL;
59
60 if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
61 int32_t fd = *(int32_t *)data;
62
63 if (fd >= 0)
64 return vfio_virqfd_enable((void *) &vdev->irqs[index],
65 vfio_platform_mask_handler,
66 NULL, NULL,
67 &vdev->irqs[index].mask, fd);
68
69 vfio_virqfd_disable(&vdev->irqs[index].mask);
70 return 0;
71 }
72
73 if (flags & VFIO_IRQ_SET_DATA_NONE) {
74 vfio_platform_mask(&vdev->irqs[index]);
75
76 } else if (flags & VFIO_IRQ_SET_DATA_BOOL) {
77 uint8_t mask = *(uint8_t *)data;
78
79 if (mask)
80 vfio_platform_mask(&vdev->irqs[index]);
81 }
82
83 return 0;
84}
85
86static void vfio_platform_unmask(struct vfio_platform_irq *irq_ctx)
87{
88 unsigned long flags;
89
90 spin_lock_irqsave(&irq_ctx->lock, flags);
91
92 if (irq_ctx->masked) {
93 enable_irq(irq_ctx->hwirq);
94 irq_ctx->masked = false;
95 }
96
97 spin_unlock_irqrestore(&irq_ctx->lock, flags);
98}
99
100static int vfio_platform_unmask_handler(void *opaque, void *unused)
101{
102 struct vfio_platform_irq *irq_ctx = opaque;
103
104 vfio_platform_unmask(irq_ctx);
105
106 return 0;
107}
108
109static int vfio_platform_set_irq_unmask(struct vfio_platform_device *vdev,
110 unsigned index, unsigned start,
111 unsigned count, uint32_t flags,
112 void *data)
113{
114 if (start != 0 || count != 1)
115 return -EINVAL;
116
117 if (!(vdev->irqs[index].flags & VFIO_IRQ_INFO_MASKABLE))
118 return -EINVAL;
119
120 if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
121 int32_t fd = *(int32_t *)data;
122
123 if (fd >= 0)
124 return vfio_virqfd_enable((void *) &vdev->irqs[index],
125 vfio_platform_unmask_handler,
126 NULL, NULL,
127 &vdev->irqs[index].unmask,
128 fd);
129
130 vfio_virqfd_disable(&vdev->irqs[index].unmask);
131 return 0;
132 }
133
134 if (flags & VFIO_IRQ_SET_DATA_NONE) {
135 vfio_platform_unmask(&vdev->irqs[index]);
136
137 } else if (flags & VFIO_IRQ_SET_DATA_BOOL) {
138 uint8_t unmask = *(uint8_t *)data;
139
140 if (unmask)
141 vfio_platform_unmask(&vdev->irqs[index]);
142 }
143
144 return 0;
145}
146
147static irqreturn_t vfio_automasked_irq_handler(int irq, void *dev_id)
148{
149 struct vfio_platform_irq *irq_ctx = dev_id;
150 unsigned long flags;
151 int ret = IRQ_NONE;
152
153 spin_lock_irqsave(&irq_ctx->lock, flags);
154
155 if (!irq_ctx->masked) {
156 ret = IRQ_HANDLED;
157
158 /* automask maskable interrupts */
159 disable_irq_nosync(irq_ctx->hwirq);
160 irq_ctx->masked = true;
161 }
162
163 spin_unlock_irqrestore(&irq_ctx->lock, flags);
164
165 if (ret == IRQ_HANDLED)
166 eventfd_signal(irq_ctx->trigger, 1);
167
168 return ret;
169}
170
171static irqreturn_t vfio_irq_handler(int irq, void *dev_id)
172{
173 struct vfio_platform_irq *irq_ctx = dev_id;
174
175 eventfd_signal(irq_ctx->trigger, 1);
176
177 return IRQ_HANDLED;
178}
179
180static int vfio_set_trigger(struct vfio_platform_device *vdev, int index,
181 int fd, irq_handler_t handler)
182{
183 struct vfio_platform_irq *irq = &vdev->irqs[index];
184 struct eventfd_ctx *trigger;
185 int ret;
186
187 if (irq->trigger) {
188 free_irq(irq->hwirq, irq);
189 kfree(irq->name);
190 eventfd_ctx_put(irq->trigger);
191 irq->trigger = NULL;
192 }
193
194 if (fd < 0) /* Disable only */
195 return 0;
196
197 irq->name = kasprintf(GFP_KERNEL, "vfio-irq[%d](%s)",
198 irq->hwirq, vdev->name);
199 if (!irq->name)
200 return -ENOMEM;
201
202 trigger = eventfd_ctx_fdget(fd);
203 if (IS_ERR(trigger)) {
204 kfree(irq->name);
205 return PTR_ERR(trigger);
206 }
207
208 irq->trigger = trigger;
209
210 irq_set_status_flags(irq->hwirq, IRQ_NOAUTOEN);
211 ret = request_irq(irq->hwirq, handler, 0, irq->name, irq);
212 if (ret) {
213 kfree(irq->name);
214 eventfd_ctx_put(trigger);
215 irq->trigger = NULL;
216 return ret;
217 }
218
219 if (!irq->masked)
220 enable_irq(irq->hwirq);
221
222 return 0;
223}
224
225static int vfio_platform_set_irq_trigger(struct vfio_platform_device *vdev,
226 unsigned index, unsigned start,
227 unsigned count, uint32_t flags,
228 void *data)
229{
230 struct vfio_platform_irq *irq = &vdev->irqs[index];
231 irq_handler_t handler;
232
233 if (vdev->irqs[index].flags & VFIO_IRQ_INFO_AUTOMASKED)
234 handler = vfio_automasked_irq_handler;
235 else
236 handler = vfio_irq_handler;
237
238 if (!count && (flags & VFIO_IRQ_SET_DATA_NONE))
239 return vfio_set_trigger(vdev, index, -1, handler);
240
241 if (start != 0 || count != 1)
242 return -EINVAL;
243
244 if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
245 int32_t fd = *(int32_t *)data;
246
247 return vfio_set_trigger(vdev, index, fd, handler);
248 }
249
250 if (flags & VFIO_IRQ_SET_DATA_NONE) {
251 handler(irq->hwirq, irq);
252
253 } else if (flags & VFIO_IRQ_SET_DATA_BOOL) {
254 uint8_t trigger = *(uint8_t *)data;
255
256 if (trigger)
257 handler(irq->hwirq, irq);
258 }
259
260 return 0;
261}
262
263int vfio_platform_set_irqs_ioctl(struct vfio_platform_device *vdev,
264 uint32_t flags, unsigned index, unsigned start,
265 unsigned count, void *data)
266{
267 int (*func)(struct vfio_platform_device *vdev, unsigned index,
268 unsigned start, unsigned count, uint32_t flags,
269 void *data) = NULL;
270
271 switch (flags & VFIO_IRQ_SET_ACTION_TYPE_MASK) {
272 case VFIO_IRQ_SET_ACTION_MASK:
273 func = vfio_platform_set_irq_mask;
274 break;
275 case VFIO_IRQ_SET_ACTION_UNMASK:
276 func = vfio_platform_set_irq_unmask;
277 break;
278 case VFIO_IRQ_SET_ACTION_TRIGGER:
279 func = vfio_platform_set_irq_trigger;
280 break;
281 }
282
283 if (!func)
284 return -ENOTTY;
285
286 return func(vdev, index, start, count, flags, data);
287}
288
289int vfio_platform_irq_init(struct vfio_platform_device *vdev)
290{
291 int cnt = 0, i;
292
293 while (vdev->get_irq(vdev, cnt) >= 0)
294 cnt++;
295
296 vdev->irqs = kcalloc(cnt, sizeof(struct vfio_platform_irq), GFP_KERNEL);
297 if (!vdev->irqs)
298 return -ENOMEM;
299
300 for (i = 0; i < cnt; i++) {
301 int hwirq = vdev->get_irq(vdev, i);
302
303 if (hwirq < 0)
304 goto err;
305
306 spin_lock_init(&vdev->irqs[i].lock);
307
308 vdev->irqs[i].flags = VFIO_IRQ_INFO_EVENTFD;
309
310 if (irq_get_trigger_type(hwirq) & IRQ_TYPE_LEVEL_MASK)
311 vdev->irqs[i].flags |= VFIO_IRQ_INFO_MASKABLE
312 | VFIO_IRQ_INFO_AUTOMASKED;
313
314 vdev->irqs[i].count = 1;
315 vdev->irqs[i].hwirq = hwirq;
316 vdev->irqs[i].masked = false;
317 }
318
319 vdev->num_irqs = cnt;
320
321 return 0;
322err:
323 kfree(vdev->irqs);
324 return -EINVAL;
325}
326
327void vfio_platform_irq_cleanup(struct vfio_platform_device *vdev)
328{
329 int i;
330
331 for (i = 0; i < vdev->num_irqs; i++)
332 vfio_set_trigger(vdev, i, -1, NULL);
333
334 vdev->num_irqs = 0;
335 kfree(vdev->irqs);
336}
diff --git a/drivers/vfio/platform/vfio_platform_private.h b/drivers/vfio/platform/vfio_platform_private.h
new file mode 100644
index 000000000000..5d31e0473406
--- /dev/null
+++ b/drivers/vfio/platform/vfio_platform_private.h
@@ -0,0 +1,85 @@
1/*
2 * Copyright (C) 2013 - Virtual Open Systems
3 * Author: Antonios Motakis <a.motakis@virtualopensystems.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License, version 2, as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15#ifndef VFIO_PLATFORM_PRIVATE_H
16#define VFIO_PLATFORM_PRIVATE_H
17
18#include <linux/types.h>
19#include <linux/interrupt.h>
20
21#define VFIO_PLATFORM_OFFSET_SHIFT 40
22#define VFIO_PLATFORM_OFFSET_MASK (((u64)(1) << VFIO_PLATFORM_OFFSET_SHIFT) - 1)
23
24#define VFIO_PLATFORM_OFFSET_TO_INDEX(off) \
25 (off >> VFIO_PLATFORM_OFFSET_SHIFT)
26
27#define VFIO_PLATFORM_INDEX_TO_OFFSET(index) \
28 ((u64)(index) << VFIO_PLATFORM_OFFSET_SHIFT)
29
30struct vfio_platform_irq {
31 u32 flags;
32 u32 count;
33 int hwirq;
34 char *name;
35 struct eventfd_ctx *trigger;
36 bool masked;
37 spinlock_t lock;
38 struct virqfd *unmask;
39 struct virqfd *mask;
40};
41
42struct vfio_platform_region {
43 u64 addr;
44 resource_size_t size;
45 u32 flags;
46 u32 type;
47#define VFIO_PLATFORM_REGION_TYPE_MMIO 1
48#define VFIO_PLATFORM_REGION_TYPE_PIO 2
49 void __iomem *ioaddr;
50};
51
52struct vfio_platform_device {
53 struct vfio_platform_region *regions;
54 u32 num_regions;
55 struct vfio_platform_irq *irqs;
56 u32 num_irqs;
57 int refcnt;
58 struct mutex igate;
59
60 /*
61 * These fields should be filled by the bus specific binder
62 */
63 void *opaque;
64 const char *name;
65 uint32_t flags;
66 /* callbacks to discover device resources */
67 struct resource*
68 (*get_resource)(struct vfio_platform_device *vdev, int i);
69 int (*get_irq)(struct vfio_platform_device *vdev, int i);
70};
71
72extern int vfio_platform_probe_common(struct vfio_platform_device *vdev,
73 struct device *dev);
74extern struct vfio_platform_device *vfio_platform_remove_common
75 (struct device *dev);
76
77extern int vfio_platform_irq_init(struct vfio_platform_device *vdev);
78extern void vfio_platform_irq_cleanup(struct vfio_platform_device *vdev);
79
80extern int vfio_platform_set_irqs_ioctl(struct vfio_platform_device *vdev,
81 uint32_t flags, unsigned index,
82 unsigned start, unsigned count,
83 void *data);
84
85#endif /* VFIO_PLATFORM_PRIVATE_H */
diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c
index 4cde85501444..0d336625ac71 100644
--- a/drivers/vfio/vfio.c
+++ b/drivers/vfio/vfio.c
@@ -234,22 +234,21 @@ static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group)
234 234
235 mutex_lock(&vfio.group_lock); 235 mutex_lock(&vfio.group_lock);
236 236
237 minor = vfio_alloc_group_minor(group);
238 if (minor < 0) {
239 vfio_group_unlock_and_free(group);
240 return ERR_PTR(minor);
241 }
242
243 /* Did we race creating this group? */ 237 /* Did we race creating this group? */
244 list_for_each_entry(tmp, &vfio.group_list, vfio_next) { 238 list_for_each_entry(tmp, &vfio.group_list, vfio_next) {
245 if (tmp->iommu_group == iommu_group) { 239 if (tmp->iommu_group == iommu_group) {
246 vfio_group_get(tmp); 240 vfio_group_get(tmp);
247 vfio_free_group_minor(minor);
248 vfio_group_unlock_and_free(group); 241 vfio_group_unlock_and_free(group);
249 return tmp; 242 return tmp;
250 } 243 }
251 } 244 }
252 245
246 minor = vfio_alloc_group_minor(group);
247 if (minor < 0) {
248 vfio_group_unlock_and_free(group);
249 return ERR_PTR(minor);
250 }
251
253 dev = device_create(vfio.class, NULL, 252 dev = device_create(vfio.class, NULL,
254 MKDEV(MAJOR(vfio.group_devt), minor), 253 MKDEV(MAJOR(vfio.group_devt), minor),
255 group, "%d", iommu_group_id(iommu_group)); 254 group, "%d", iommu_group_id(iommu_group));
diff --git a/drivers/vfio/virqfd.c b/drivers/vfio/virqfd.c
new file mode 100644
index 000000000000..27c89cd5d70b
--- /dev/null
+++ b/drivers/vfio/virqfd.c
@@ -0,0 +1,226 @@
1/*
2 * VFIO generic eventfd code for IRQFD support.
3 * Derived from drivers/vfio/pci/vfio_pci_intrs.c
4 *
5 * Copyright (C) 2012 Red Hat, Inc. All rights reserved.
6 * Author: Alex Williamson <alex.williamson@redhat.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/vfio.h>
14#include <linux/eventfd.h>
15#include <linux/file.h>
16#include <linux/module.h>
17#include <linux/slab.h>
18
19#define DRIVER_VERSION "0.1"
20#define DRIVER_AUTHOR "Alex Williamson <alex.williamson@redhat.com>"
21#define DRIVER_DESC "IRQFD support for VFIO bus drivers"
22
23static struct workqueue_struct *vfio_irqfd_cleanup_wq;
24static DEFINE_SPINLOCK(virqfd_lock);
25
26static int __init vfio_virqfd_init(void)
27{
28 vfio_irqfd_cleanup_wq =
29 create_singlethread_workqueue("vfio-irqfd-cleanup");
30 if (!vfio_irqfd_cleanup_wq)
31 return -ENOMEM;
32
33 return 0;
34}
35
36static void __exit vfio_virqfd_exit(void)
37{
38 destroy_workqueue(vfio_irqfd_cleanup_wq);
39}
40
41static void virqfd_deactivate(struct virqfd *virqfd)
42{
43 queue_work(vfio_irqfd_cleanup_wq, &virqfd->shutdown);
44}
45
46static int virqfd_wakeup(wait_queue_t *wait, unsigned mode, int sync, void *key)
47{
48 struct virqfd *virqfd = container_of(wait, struct virqfd, wait);
49 unsigned long flags = (unsigned long)key;
50
51 if (flags & POLLIN) {
52 /* An event has been signaled, call function */
53 if ((!virqfd->handler ||
54 virqfd->handler(virqfd->opaque, virqfd->data)) &&
55 virqfd->thread)
56 schedule_work(&virqfd->inject);
57 }
58
59 if (flags & POLLHUP) {
60 unsigned long flags;
61 spin_lock_irqsave(&virqfd_lock, flags);
62
63 /*
64 * The eventfd is closing, if the virqfd has not yet been
65 * queued for release, as determined by testing whether the
66 * virqfd pointer to it is still valid, queue it now. As
67 * with kvm irqfds, we know we won't race against the virqfd
68 * going away because we hold the lock to get here.
69 */
70 if (*(virqfd->pvirqfd) == virqfd) {
71 *(virqfd->pvirqfd) = NULL;
72 virqfd_deactivate(virqfd);
73 }
74
75 spin_unlock_irqrestore(&virqfd_lock, flags);
76 }
77
78 return 0;
79}
80
81static void virqfd_ptable_queue_proc(struct file *file,
82 wait_queue_head_t *wqh, poll_table *pt)
83{
84 struct virqfd *virqfd = container_of(pt, struct virqfd, pt);
85 add_wait_queue(wqh, &virqfd->wait);
86}
87
88static void virqfd_shutdown(struct work_struct *work)
89{
90 struct virqfd *virqfd = container_of(work, struct virqfd, shutdown);
91 u64 cnt;
92
93 eventfd_ctx_remove_wait_queue(virqfd->eventfd, &virqfd->wait, &cnt);
94 flush_work(&virqfd->inject);
95 eventfd_ctx_put(virqfd->eventfd);
96
97 kfree(virqfd);
98}
99
100static void virqfd_inject(struct work_struct *work)
101{
102 struct virqfd *virqfd = container_of(work, struct virqfd, inject);
103 if (virqfd->thread)
104 virqfd->thread(virqfd->opaque, virqfd->data);
105}
106
107int vfio_virqfd_enable(void *opaque,
108 int (*handler)(void *, void *),
109 void (*thread)(void *, void *),
110 void *data, struct virqfd **pvirqfd, int fd)
111{
112 struct fd irqfd;
113 struct eventfd_ctx *ctx;
114 struct virqfd *virqfd;
115 int ret = 0;
116 unsigned int events;
117
118 virqfd = kzalloc(sizeof(*virqfd), GFP_KERNEL);
119 if (!virqfd)
120 return -ENOMEM;
121
122 virqfd->pvirqfd = pvirqfd;
123 virqfd->opaque = opaque;
124 virqfd->handler = handler;
125 virqfd->thread = thread;
126 virqfd->data = data;
127
128 INIT_WORK(&virqfd->shutdown, virqfd_shutdown);
129 INIT_WORK(&virqfd->inject, virqfd_inject);
130
131 irqfd = fdget(fd);
132 if (!irqfd.file) {
133 ret = -EBADF;
134 goto err_fd;
135 }
136
137 ctx = eventfd_ctx_fileget(irqfd.file);
138 if (IS_ERR(ctx)) {
139 ret = PTR_ERR(ctx);
140 goto err_ctx;
141 }
142
143 virqfd->eventfd = ctx;
144
145 /*
146 * virqfds can be released by closing the eventfd or directly
147 * through ioctl. These are both done through a workqueue, so
148 * we update the pointer to the virqfd under lock to avoid
149 * pushing multiple jobs to release the same virqfd.
150 */
151 spin_lock_irq(&virqfd_lock);
152
153 if (*pvirqfd) {
154 spin_unlock_irq(&virqfd_lock);
155 ret = -EBUSY;
156 goto err_busy;
157 }
158 *pvirqfd = virqfd;
159
160 spin_unlock_irq(&virqfd_lock);
161
162 /*
163 * Install our own custom wake-up handling so we are notified via
164 * a callback whenever someone signals the underlying eventfd.
165 */
166 init_waitqueue_func_entry(&virqfd->wait, virqfd_wakeup);
167 init_poll_funcptr(&virqfd->pt, virqfd_ptable_queue_proc);
168
169 events = irqfd.file->f_op->poll(irqfd.file, &virqfd->pt);
170
171 /*
172 * Check if there was an event already pending on the eventfd
173 * before we registered and trigger it as if we didn't miss it.
174 */
175 if (events & POLLIN) {
176 if ((!handler || handler(opaque, data)) && thread)
177 schedule_work(&virqfd->inject);
178 }
179
180 /*
181 * Do not drop the file until the irqfd is fully initialized,
182 * otherwise we might race against the POLLHUP.
183 */
184 fdput(irqfd);
185
186 return 0;
187err_busy:
188 eventfd_ctx_put(ctx);
189err_ctx:
190 fdput(irqfd);
191err_fd:
192 kfree(virqfd);
193
194 return ret;
195}
196EXPORT_SYMBOL_GPL(vfio_virqfd_enable);
197
198void vfio_virqfd_disable(struct virqfd **pvirqfd)
199{
200 unsigned long flags;
201
202 spin_lock_irqsave(&virqfd_lock, flags);
203
204 if (*pvirqfd) {
205 virqfd_deactivate(*pvirqfd);
206 *pvirqfd = NULL;
207 }
208
209 spin_unlock_irqrestore(&virqfd_lock, flags);
210
211 /*
212 * Block until we know all outstanding shutdown jobs have completed.
213 * Even if we don't queue the job, flush the wq to be sure it's
214 * been released.
215 */
216 flush_workqueue(vfio_irqfd_cleanup_wq);
217}
218EXPORT_SYMBOL_GPL(vfio_virqfd_disable);
219
220module_init(vfio_virqfd_init);
221module_exit(vfio_virqfd_exit);
222
223MODULE_VERSION(DRIVER_VERSION);
224MODULE_LICENSE("GPL v2");
225MODULE_AUTHOR(DRIVER_AUTHOR);
226MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/include/linux/vfio.h b/include/linux/vfio.h
index 049b2f497bc7..ddb440975382 100644
--- a/include/linux/vfio.h
+++ b/include/linux/vfio.h
@@ -14,6 +14,8 @@
14 14
15#include <linux/iommu.h> 15#include <linux/iommu.h>
16#include <linux/mm.h> 16#include <linux/mm.h>
17#include <linux/workqueue.h>
18#include <linux/poll.h>
17#include <uapi/linux/vfio.h> 19#include <uapi/linux/vfio.h>
18 20
19/** 21/**
@@ -110,4 +112,27 @@ static inline long vfio_spapr_iommu_eeh_ioctl(struct iommu_group *group,
110 return -ENOTTY; 112 return -ENOTTY;
111} 113}
112#endif /* CONFIG_EEH */ 114#endif /* CONFIG_EEH */
115
116/*
117 * IRQfd - generic
118 */
119struct virqfd {
120 void *opaque;
121 struct eventfd_ctx *eventfd;
122 int (*handler)(void *, void *);
123 void (*thread)(void *, void *);
124 void *data;
125 struct work_struct inject;
126 wait_queue_t wait;
127 poll_table pt;
128 struct work_struct shutdown;
129 struct virqfd **pvirqfd;
130};
131
132extern int vfio_virqfd_enable(void *opaque,
133 int (*handler)(void *, void *),
134 void (*thread)(void *, void *),
135 void *data, struct virqfd **pvirqfd, int fd);
136extern void vfio_virqfd_disable(struct virqfd **pvirqfd);
137
113#endif /* VFIO_H */ 138#endif /* VFIO_H */
diff --git a/include/linux/vgaarb.h b/include/linux/vgaarb.h
index c37bd4d06739..8c3b412d84df 100644
--- a/include/linux/vgaarb.h
+++ b/include/linux/vgaarb.h
@@ -65,8 +65,13 @@ struct pci_dev;
65 * out of the arbitration process (and can be safe to take 65 * out of the arbitration process (and can be safe to take
66 * interrupts at any time. 66 * interrupts at any time.
67 */ 67 */
68#if defined(CONFIG_VGA_ARB)
68extern void vga_set_legacy_decoding(struct pci_dev *pdev, 69extern void vga_set_legacy_decoding(struct pci_dev *pdev,
69 unsigned int decodes); 70 unsigned int decodes);
71#else
72static inline void vga_set_legacy_decoding(struct pci_dev *pdev,
73 unsigned int decodes) { };
74#endif
70 75
71/** 76/**
72 * vga_get - acquire & locks VGA resources 77 * vga_get - acquire & locks VGA resources
diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h
index 82889c30f4f5..b57b750c222f 100644
--- a/include/uapi/linux/vfio.h
+++ b/include/uapi/linux/vfio.h
@@ -160,6 +160,8 @@ struct vfio_device_info {
160 __u32 flags; 160 __u32 flags;
161#define VFIO_DEVICE_FLAGS_RESET (1 << 0) /* Device supports reset */ 161#define VFIO_DEVICE_FLAGS_RESET (1 << 0) /* Device supports reset */
162#define VFIO_DEVICE_FLAGS_PCI (1 << 1) /* vfio-pci device */ 162#define VFIO_DEVICE_FLAGS_PCI (1 << 1) /* vfio-pci device */
163#define VFIO_DEVICE_FLAGS_PLATFORM (1 << 2) /* vfio-platform device */
164#define VFIO_DEVICE_FLAGS_AMBA (1 << 3) /* vfio-amba device */
163 __u32 num_regions; /* Max region index + 1 */ 165 __u32 num_regions; /* Max region index + 1 */
164 __u32 num_irqs; /* Max IRQ index + 1 */ 166 __u32 num_irqs; /* Max IRQ index + 1 */
165}; 167};