xref: /qemu/hw/vfio/ap.c (revision 563ac3d18129a2770a285cc16c20ad50c8adc7c0)
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