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