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 <stdbool.h>
14 #include "qemu/osdep.h"
15 #include CONFIG_DEVICES /* CONFIG_IOMMUFD */
16 #include <linux/vfio.h>
17 #include <sys/ioctl.h>
18 #include "qapi/error.h"
19 #include "hw/vfio/vfio-device.h"
20 #include "system/iommufd.h"
21 #include "hw/s390x/ap-device.h"
22 #include "hw/s390x/css.h"
23 #include "qemu/error-report.h"
24 #include "qemu/event_notifier.h"
25 #include "qemu/lockable.h"
26 #include "qemu/main-loop.h"
27 #include "qemu/module.h"
28 #include "qemu/option.h"
29 #include "qemu/config-file.h"
30 #include "kvm/kvm_s390x.h"
31 #include "migration/vmstate.h"
32 #include "hw/qdev-properties.h"
33 #include "hw/s390x/ap-bridge.h"
34 #include "system/address-spaces.h"
35 #include "qom/object.h"
36
37 #define TYPE_VFIO_AP_DEVICE "vfio-ap"
38
39 struct VFIOAPDevice {
40 APDevice apdev;
41 VFIODevice vdev;
42 EventNotifier req_notifier;
43 EventNotifier cfg_notifier;
44 };
45
46 typedef struct APConfigChgEvent {
47 QTAILQ_ENTRY(APConfigChgEvent) next;
48 } APConfigChgEvent;
49
50 static QTAILQ_HEAD(, APConfigChgEvent) cfg_chg_events =
51 QTAILQ_HEAD_INITIALIZER(cfg_chg_events);
52
53 static QemuMutex cfg_chg_events_lock;
54
vfio_ap_global_init(void)55 static void __attribute__((constructor)) vfio_ap_global_init(void)
56 {
57 qemu_mutex_init(&cfg_chg_events_lock);
58 }
59
OBJECT_DECLARE_SIMPLE_TYPE(VFIOAPDevice,VFIO_AP_DEVICE)60 OBJECT_DECLARE_SIMPLE_TYPE(VFIOAPDevice, VFIO_AP_DEVICE)
61
62 static void vfio_ap_compute_needs_reset(VFIODevice *vdev)
63 {
64 vdev->needs_reset = false;
65 }
66
67 /*
68 * We don't need vfio_hot_reset_multi and vfio_eoi operations for
69 * vfio-ap device now.
70 */
71 struct VFIODeviceOps vfio_ap_ops = {
72 .vfio_compute_needs_reset = vfio_ap_compute_needs_reset,
73 };
74
vfio_ap_req_notifier_handler(void * opaque)75 static void vfio_ap_req_notifier_handler(void *opaque)
76 {
77 VFIOAPDevice *vapdev = opaque;
78 Error *err = NULL;
79
80 if (!event_notifier_test_and_clear(&vapdev->req_notifier)) {
81 return;
82 }
83
84 qdev_unplug(DEVICE(vapdev), &err);
85
86 if (err) {
87 warn_reportf_err(err, VFIO_MSG_PREFIX, vapdev->vdev.name);
88 }
89 }
90
vfio_ap_cfg_chg_notifier_handler(void * opaque)91 static void vfio_ap_cfg_chg_notifier_handler(void *opaque)
92 {
93 APConfigChgEvent *cfg_chg_event;
94 VFIOAPDevice *vapdev = opaque;
95
96 if (!event_notifier_test_and_clear(&vapdev->cfg_notifier)) {
97 return;
98 }
99
100 cfg_chg_event = g_new0(APConfigChgEvent, 1);
101
102 WITH_QEMU_LOCK_GUARD(&cfg_chg_events_lock) {
103 QTAILQ_INSERT_TAIL(&cfg_chg_events, cfg_chg_event, next);
104 }
105
106 css_generate_css_crws(0);
107
108 }
109
ap_chsc_sei_nt0_get_event(void * res)110 int ap_chsc_sei_nt0_get_event(void *res)
111 {
112 ChscSeiNt0Res *nt0_res = (ChscSeiNt0Res *)res;
113 APConfigChgEvent *cfg_chg_event;
114
115 WITH_QEMU_LOCK_GUARD(&cfg_chg_events_lock) {
116 if (QTAILQ_EMPTY(&cfg_chg_events)) {
117 return EVENT_INFORMATION_NOT_STORED;
118 }
119
120 cfg_chg_event = QTAILQ_FIRST(&cfg_chg_events);
121 QTAILQ_REMOVE(&cfg_chg_events, cfg_chg_event, next);
122 }
123
124 memset(nt0_res, 0, sizeof(*nt0_res));
125 g_free(cfg_chg_event);
126 nt0_res->flags |= PENDING_EVENT_INFO_BITMASK;
127 nt0_res->length = sizeof(ChscSeiNt0Res);
128 nt0_res->code = NT0_RES_RESPONSE_CODE;
129 nt0_res->nt = NT0_RES_NT_DEFAULT;
130 nt0_res->rs = NT0_RES_RS_AP_CHANGE;
131 nt0_res->cc = NT0_RES_CC_AP_CHANGE;
132
133 return EVENT_INFORMATION_STORED;
134 }
135
ap_chsc_sei_nt0_have_event(void)136 bool ap_chsc_sei_nt0_have_event(void)
137 {
138 QEMU_LOCK_GUARD(&cfg_chg_events_lock);
139 return !QTAILQ_EMPTY(&cfg_chg_events);
140 }
141
vfio_ap_register_irq_notifier(VFIOAPDevice * vapdev,unsigned int irq,Error ** errp)142 static bool vfio_ap_register_irq_notifier(VFIOAPDevice *vapdev,
143 unsigned int irq, Error **errp)
144 {
145 int fd;
146 int ret;
147 IOHandler *fd_read;
148 EventNotifier *notifier;
149 struct vfio_irq_info irq_info;
150 VFIODevice *vdev = &vapdev->vdev;
151
152 switch (irq) {
153 case VFIO_AP_REQ_IRQ_INDEX:
154 notifier = &vapdev->req_notifier;
155 fd_read = vfio_ap_req_notifier_handler;
156 break;
157 case VFIO_AP_CFG_CHG_IRQ_INDEX:
158 notifier = &vapdev->cfg_notifier;
159 fd_read = vfio_ap_cfg_chg_notifier_handler;
160 break;
161 default:
162 error_setg(errp, "vfio: Unsupported device irq(%d)", irq);
163 return false;
164 }
165
166 if (vdev->num_irqs < irq + 1) {
167 error_setg(errp, "vfio: IRQ %u not available (number of irqs %u)",
168 irq, vdev->num_irqs);
169 return false;
170 }
171
172 ret = vfio_device_get_irq_info(vdev, irq, &irq_info);
173
174 if (ret < 0) {
175 error_setg_errno(errp, -ret, "vfio: Error getting irq info");
176 return false;
177 }
178
179 if (irq_info.count < 1) {
180 error_setg(errp, "vfio: Error getting irq info, count=0");
181 return false;
182 }
183
184 if (event_notifier_init(notifier, 0)) {
185 error_setg_errno(errp, errno,
186 "vfio: Unable to init event notifier for irq (%d)",
187 irq);
188 return false;
189 }
190
191 fd = event_notifier_get_fd(notifier);
192 qemu_set_fd_handler(fd, fd_read, NULL, vapdev);
193
194 if (!vfio_device_irq_set_signaling(vdev, irq, 0, VFIO_IRQ_SET_ACTION_TRIGGER, fd,
195 errp)) {
196 qemu_set_fd_handler(fd, NULL, NULL, vapdev);
197 event_notifier_cleanup(notifier);
198 }
199
200 return true;
201 }
202
vfio_ap_unregister_irq_notifier(VFIOAPDevice * vapdev,unsigned int irq)203 static void vfio_ap_unregister_irq_notifier(VFIOAPDevice *vapdev,
204 unsigned int irq)
205 {
206 Error *err = NULL;
207 EventNotifier *notifier;
208
209 switch (irq) {
210 case VFIO_AP_REQ_IRQ_INDEX:
211 notifier = &vapdev->req_notifier;
212 break;
213 case VFIO_AP_CFG_CHG_IRQ_INDEX:
214 notifier = &vapdev->cfg_notifier;
215 break;
216 default:
217 error_report("vfio: Unsupported device irq(%d)", irq);
218 return;
219 }
220
221 if (!vfio_device_irq_set_signaling(&vapdev->vdev, irq, 0,
222 VFIO_IRQ_SET_ACTION_TRIGGER, -1, &err)) {
223 warn_reportf_err(err, VFIO_MSG_PREFIX, vapdev->vdev.name);
224 }
225
226 qemu_set_fd_handler(event_notifier_get_fd(notifier),
227 NULL, NULL, vapdev);
228 event_notifier_cleanup(notifier);
229 }
230
vfio_ap_realize(DeviceState * dev,Error ** errp)231 static void vfio_ap_realize(DeviceState *dev, Error **errp)
232 {
233 ERRP_GUARD();
234 Error *err = NULL;
235 VFIOAPDevice *vapdev = VFIO_AP_DEVICE(dev);
236 VFIODevice *vbasedev = &vapdev->vdev;
237
238 if (!vfio_device_get_name(vbasedev, errp)) {
239 return;
240 }
241
242 if (!vfio_device_attach(vbasedev->name, vbasedev,
243 &address_space_memory, errp)) {
244 goto error;
245 }
246
247 if (!vfio_ap_register_irq_notifier(vapdev, VFIO_AP_REQ_IRQ_INDEX, &err)) {
248 /*
249 * Report this error, but do not make it a failing condition.
250 * Lack of this IRQ in the host does not prevent normal operation.
251 */
252 warn_report_err(err);
253 }
254
255 if (!vfio_ap_register_irq_notifier(vapdev, VFIO_AP_CFG_CHG_IRQ_INDEX, &err))
256 {
257 /*
258 * Report this error, but do not make it a failing condition.
259 * Lack of this IRQ in the host does not prevent normal operation.
260 */
261 warn_report_err(err);
262 }
263
264 return;
265
266 error:
267 error_prepend(errp, VFIO_MSG_PREFIX, vbasedev->name);
268 vfio_device_free_name(vbasedev);
269 }
270
vfio_ap_unrealize(DeviceState * dev)271 static void vfio_ap_unrealize(DeviceState *dev)
272 {
273 VFIOAPDevice *vapdev = VFIO_AP_DEVICE(dev);
274
275 vfio_ap_unregister_irq_notifier(vapdev, VFIO_AP_REQ_IRQ_INDEX);
276 vfio_ap_unregister_irq_notifier(vapdev, VFIO_AP_CFG_CHG_IRQ_INDEX);
277 vfio_device_detach(&vapdev->vdev);
278 vfio_device_free_name(&vapdev->vdev);
279 }
280
281 static const Property vfio_ap_properties[] = {
282 DEFINE_PROP_STRING("sysfsdev", VFIOAPDevice, vdev.sysfsdev),
283 #ifdef CONFIG_IOMMUFD
284 DEFINE_PROP_LINK("iommufd", VFIOAPDevice, vdev.iommufd,
285 TYPE_IOMMUFD_BACKEND, IOMMUFDBackend *),
286 #endif
287 };
288
vfio_ap_reset(DeviceState * dev)289 static void vfio_ap_reset(DeviceState *dev)
290 {
291 int ret;
292 VFIOAPDevice *vapdev = VFIO_AP_DEVICE(dev);
293
294 ret = ioctl(vapdev->vdev.fd, VFIO_DEVICE_RESET);
295 if (ret) {
296 error_report("%s: failed to reset %s device: %s", __func__,
297 vapdev->vdev.name, strerror(errno));
298 }
299 }
300
301 static const VMStateDescription vfio_ap_vmstate = {
302 .name = "vfio-ap",
303 .unmigratable = 1,
304 };
305
vfio_ap_instance_init(Object * obj)306 static void vfio_ap_instance_init(Object *obj)
307 {
308 VFIOAPDevice *vapdev = VFIO_AP_DEVICE(obj);
309 VFIODevice *vbasedev = &vapdev->vdev;
310
311 /*
312 * vfio-ap devices operate in a way compatible with discarding of
313 * memory in RAM blocks, as no pages are pinned in the host.
314 * This needs to be set before vfio_get_device() for vfio common to
315 * handle ram_block_discard_disable().
316 */
317 vfio_device_init(vbasedev, VFIO_DEVICE_TYPE_AP, &vfio_ap_ops,
318 DEVICE(vapdev), true);
319
320 /* AP device is mdev type device */
321 vbasedev->mdev = true;
322 }
323
324 #ifdef CONFIG_IOMMUFD
vfio_ap_set_fd(Object * obj,const char * str,Error ** errp)325 static void vfio_ap_set_fd(Object *obj, const char *str, Error **errp)
326 {
327 vfio_device_set_fd(&VFIO_AP_DEVICE(obj)->vdev, str, errp);
328 }
329 #endif
330
vfio_ap_class_init(ObjectClass * klass,const void * data)331 static void vfio_ap_class_init(ObjectClass *klass, const void *data)
332 {
333 DeviceClass *dc = DEVICE_CLASS(klass);
334
335 device_class_set_props(dc, vfio_ap_properties);
336 #ifdef CONFIG_IOMMUFD
337 object_class_property_add_str(klass, "fd", NULL, vfio_ap_set_fd);
338 #endif
339 dc->vmsd = &vfio_ap_vmstate;
340 dc->desc = "VFIO-based AP device assignment";
341 set_bit(DEVICE_CATEGORY_MISC, dc->categories);
342 dc->realize = vfio_ap_realize;
343 dc->unrealize = vfio_ap_unrealize;
344 dc->hotpluggable = true;
345 device_class_set_legacy_reset(dc, vfio_ap_reset);
346 dc->bus_type = TYPE_AP_BUS;
347
348 object_class_property_set_description(klass, /* 3.1 */
349 "sysfsdev",
350 "Host sysfs path of assigned device");
351 #ifdef CONFIG_IOMMUFD
352 object_class_property_set_description(klass, /* 9.0 */
353 "iommufd",
354 "Set host IOMMUFD backend device");
355 #endif
356 }
357
358 static const TypeInfo vfio_ap_info = {
359 .name = TYPE_VFIO_AP_DEVICE,
360 .parent = TYPE_AP_DEVICE,
361 .instance_size = sizeof(VFIOAPDevice),
362 .instance_init = vfio_ap_instance_init,
363 .class_init = vfio_ap_class_init,
364 };
365
vfio_ap_type_init(void)366 static void vfio_ap_type_init(void)
367 {
368 type_register_static(&vfio_ap_info);
369 }
370
371 type_init(vfio_ap_type_init)
372