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