1 /*
2 * VFIO based AP matrix device assignment
3 *
4 * Copyright 2018 IBM Corp.
5 * Author(s): Tony Krowiak <akrowiak@linux.ibm.com>
6 * Halil Pasic <pasic@linux.ibm.com>
7 *
8 * This work is licensed under the terms of the GNU GPL, version 2 or (at
9 * your option) any later version. See the COPYING file in the top-level
10 * directory.
11 */
12
13 #include "qemu/osdep.h"
14 #include <linux/vfio.h>
15 #include <sys/ioctl.h>
16 #include "qapi/error.h"
17 #include "hw/vfio/vfio-common.h"
18 #include "hw/s390x/ap-device.h"
19 #include "qemu/error-report.h"
20 #include "qemu/event_notifier.h"
21 #include "qemu/main-loop.h"
22 #include "qemu/module.h"
23 #include "qemu/option.h"
24 #include "qemu/config-file.h"
25 #include "kvm/kvm_s390x.h"
26 #include "migration/vmstate.h"
27 #include "hw/qdev-properties.h"
28 #include "hw/s390x/ap-bridge.h"
29 #include "exec/address-spaces.h"
30 #include "qom/object.h"
31
32 #define TYPE_VFIO_AP_DEVICE "vfio-ap"
33
34 struct VFIOAPDevice {
35 APDevice apdev;
36 VFIODevice vdev;
37 EventNotifier req_notifier;
38 };
39
OBJECT_DECLARE_SIMPLE_TYPE(VFIOAPDevice,VFIO_AP_DEVICE)40 OBJECT_DECLARE_SIMPLE_TYPE(VFIOAPDevice, VFIO_AP_DEVICE)
41
42 static void vfio_ap_compute_needs_reset(VFIODevice *vdev)
43 {
44 vdev->needs_reset = false;
45 }
46
47 /*
48 * We don't need vfio_hot_reset_multi and vfio_eoi operations for
49 * vfio-ap device now.
50 */
51 struct VFIODeviceOps vfio_ap_ops = {
52 .vfio_compute_needs_reset = vfio_ap_compute_needs_reset,
53 };
54
vfio_ap_req_notifier_handler(void * opaque)55 static void vfio_ap_req_notifier_handler(void *opaque)
56 {
57 VFIOAPDevice *vapdev = opaque;
58 Error *err = NULL;
59
60 if (!event_notifier_test_and_clear(&vapdev->req_notifier)) {
61 return;
62 }
63
64 qdev_unplug(DEVICE(vapdev), &err);
65
66 if (err) {
67 warn_reportf_err(err, VFIO_MSG_PREFIX, vapdev->vdev.name);
68 }
69 }
70
vfio_ap_register_irq_notifier(VFIOAPDevice * vapdev,unsigned int irq,Error ** errp)71 static void vfio_ap_register_irq_notifier(VFIOAPDevice *vapdev,
72 unsigned int irq, Error **errp)
73 {
74 int fd;
75 size_t argsz;
76 IOHandler *fd_read;
77 EventNotifier *notifier;
78 struct vfio_irq_info *irq_info;
79 VFIODevice *vdev = &vapdev->vdev;
80
81 switch (irq) {
82 case VFIO_AP_REQ_IRQ_INDEX:
83 notifier = &vapdev->req_notifier;
84 fd_read = vfio_ap_req_notifier_handler;
85 break;
86 default:
87 error_setg(errp, "vfio: Unsupported device irq(%d)", irq);
88 return;
89 }
90
91 if (vdev->num_irqs < irq + 1) {
92 error_setg(errp, "vfio: IRQ %u not available (number of irqs %u)",
93 irq, vdev->num_irqs);
94 return;
95 }
96
97 argsz = sizeof(*irq_info);
98 irq_info = g_malloc0(argsz);
99 irq_info->index = irq;
100 irq_info->argsz = argsz;
101
102 if (ioctl(vdev->fd, VFIO_DEVICE_GET_IRQ_INFO,
103 irq_info) < 0 || irq_info->count < 1) {
104 error_setg_errno(errp, errno, "vfio: Error getting irq info");
105 goto out_free_info;
106 }
107
108 if (event_notifier_init(notifier, 0)) {
109 error_setg_errno(errp, errno,
110 "vfio: Unable to init event notifier for irq (%d)",
111 irq);
112 goto out_free_info;
113 }
114
115 fd = event_notifier_get_fd(notifier);
116 qemu_set_fd_handler(fd, fd_read, NULL, vapdev);
117
118 if (vfio_set_irq_signaling(vdev, irq, 0, VFIO_IRQ_SET_ACTION_TRIGGER, fd,
119 errp)) {
120 qemu_set_fd_handler(fd, NULL, NULL, vapdev);
121 event_notifier_cleanup(notifier);
122 }
123
124 out_free_info:
125 g_free(irq_info);
126
127 }
128
vfio_ap_unregister_irq_notifier(VFIOAPDevice * vapdev,unsigned int irq)129 static void vfio_ap_unregister_irq_notifier(VFIOAPDevice *vapdev,
130 unsigned int irq)
131 {
132 Error *err = NULL;
133 EventNotifier *notifier;
134
135 switch (irq) {
136 case VFIO_AP_REQ_IRQ_INDEX:
137 notifier = &vapdev->req_notifier;
138 break;
139 default:
140 error_report("vfio: Unsupported device irq(%d)", irq);
141 return;
142 }
143
144 if (vfio_set_irq_signaling(&vapdev->vdev, irq, 0,
145 VFIO_IRQ_SET_ACTION_TRIGGER, -1, &err)) {
146 warn_reportf_err(err, VFIO_MSG_PREFIX, vapdev->vdev.name);
147 }
148
149 qemu_set_fd_handler(event_notifier_get_fd(notifier),
150 NULL, NULL, vapdev);
151 event_notifier_cleanup(notifier);
152 }
153
vfio_ap_realize(DeviceState * dev,Error ** errp)154 static void vfio_ap_realize(DeviceState *dev, Error **errp)
155 {
156 int ret;
157 Error *err = NULL;
158 VFIOAPDevice *vapdev = VFIO_AP_DEVICE(dev);
159 VFIODevice *vbasedev = &vapdev->vdev;
160
161 vbasedev->name = g_path_get_basename(vbasedev->sysfsdev);
162 vbasedev->ops = &vfio_ap_ops;
163 vbasedev->type = VFIO_DEVICE_TYPE_AP;
164 vbasedev->dev = dev;
165
166 /*
167 * vfio-ap devices operate in a way compatible with discarding of
168 * memory in RAM blocks, as no pages are pinned in the host.
169 * This needs to be set before vfio_get_device() for vfio common to
170 * handle ram_block_discard_disable().
171 */
172 vapdev->vdev.ram_block_discard_allowed = true;
173
174 ret = vfio_attach_device(vbasedev->name, vbasedev,
175 &address_space_memory, errp);
176 if (ret) {
177 goto error;
178 }
179
180 vfio_ap_register_irq_notifier(vapdev, VFIO_AP_REQ_IRQ_INDEX, &err);
181 if (err) {
182 /*
183 * Report this error, but do not make it a failing condition.
184 * Lack of this IRQ in the host does not prevent normal operation.
185 */
186 error_report_err(err);
187 }
188
189 return;
190
191 error:
192 error_prepend(errp, VFIO_MSG_PREFIX, vbasedev->name);
193 g_free(vbasedev->name);
194 }
195
vfio_ap_unrealize(DeviceState * dev)196 static void vfio_ap_unrealize(DeviceState *dev)
197 {
198 VFIOAPDevice *vapdev = VFIO_AP_DEVICE(dev);
199
200 vfio_ap_unregister_irq_notifier(vapdev, VFIO_AP_REQ_IRQ_INDEX);
201 vfio_detach_device(&vapdev->vdev);
202 g_free(vapdev->vdev.name);
203 }
204
205 static Property vfio_ap_properties[] = {
206 DEFINE_PROP_STRING("sysfsdev", VFIOAPDevice, vdev.sysfsdev),
207 DEFINE_PROP_END_OF_LIST(),
208 };
209
vfio_ap_reset(DeviceState * dev)210 static void vfio_ap_reset(DeviceState *dev)
211 {
212 int ret;
213 VFIOAPDevice *vapdev = VFIO_AP_DEVICE(dev);
214
215 ret = ioctl(vapdev->vdev.fd, VFIO_DEVICE_RESET);
216 if (ret) {
217 error_report("%s: failed to reset %s device: %s", __func__,
218 vapdev->vdev.name, strerror(errno));
219 }
220 }
221
222 static const VMStateDescription vfio_ap_vmstate = {
223 .name = "vfio-ap",
224 .unmigratable = 1,
225 };
226
vfio_ap_class_init(ObjectClass * klass,void * data)227 static void vfio_ap_class_init(ObjectClass *klass, void *data)
228 {
229 DeviceClass *dc = DEVICE_CLASS(klass);
230
231 device_class_set_props(dc, vfio_ap_properties);
232 dc->vmsd = &vfio_ap_vmstate;
233 dc->desc = "VFIO-based AP device assignment";
234 set_bit(DEVICE_CATEGORY_MISC, dc->categories);
235 dc->realize = vfio_ap_realize;
236 dc->unrealize = vfio_ap_unrealize;
237 dc->hotpluggable = true;
238 dc->reset = vfio_ap_reset;
239 dc->bus_type = TYPE_AP_BUS;
240 }
241
242 static const TypeInfo vfio_ap_info = {
243 .name = TYPE_VFIO_AP_DEVICE,
244 .parent = TYPE_AP_DEVICE,
245 .instance_size = sizeof(VFIOAPDevice),
246 .class_init = vfio_ap_class_init,
247 };
248
vfio_ap_type_init(void)249 static void vfio_ap_type_init(void)
250 {
251 type_register_static(&vfio_ap_info);
252 }
253
254 type_init(vfio_ap_type_init)
255