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