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