qemu

Форк
0
/
ap.c 
276 строк · 7.4 Кб
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 CONFIG_DEVICES /* CONFIG_IOMMUFD */
15
#include <linux/vfio.h>
16
#include <sys/ioctl.h>
17
#include "qapi/error.h"
18
#include "hw/vfio/vfio-common.h"
19
#include "sysemu/iommufd.h"
20
#include "hw/s390x/ap-device.h"
21
#include "qemu/error-report.h"
22
#include "qemu/event_notifier.h"
23
#include "qemu/main-loop.h"
24
#include "qemu/module.h"
25
#include "qemu/option.h"
26
#include "qemu/config-file.h"
27
#include "kvm/kvm_s390x.h"
28
#include "migration/vmstate.h"
29
#include "hw/qdev-properties.h"
30
#include "hw/s390x/ap-bridge.h"
31
#include "exec/address-spaces.h"
32
#include "qom/object.h"
33

34
#define TYPE_VFIO_AP_DEVICE      "vfio-ap"
35

36
struct VFIOAPDevice {
37
    APDevice apdev;
38
    VFIODevice vdev;
39
    EventNotifier req_notifier;
40
};
41

42
OBJECT_DECLARE_SIMPLE_TYPE(VFIOAPDevice, VFIO_AP_DEVICE)
43

44
static void vfio_ap_compute_needs_reset(VFIODevice *vdev)
45
{
46
    vdev->needs_reset = false;
47
}
48

49
/*
50
 * We don't need vfio_hot_reset_multi and vfio_eoi operations for
51
 * vfio-ap device now.
52
 */
53
struct VFIODeviceOps vfio_ap_ops = {
54
    .vfio_compute_needs_reset = vfio_ap_compute_needs_reset,
55
};
56

57
static void vfio_ap_req_notifier_handler(void *opaque)
58
{
59
    VFIOAPDevice *vapdev = opaque;
60
    Error *err = NULL;
61

62
    if (!event_notifier_test_and_clear(&vapdev->req_notifier)) {
63
        return;
64
    }
65

66
    qdev_unplug(DEVICE(vapdev), &err);
67

68
    if (err) {
69
        warn_reportf_err(err, VFIO_MSG_PREFIX, vapdev->vdev.name);
70
    }
71
}
72

73
static bool vfio_ap_register_irq_notifier(VFIOAPDevice *vapdev,
74
                                          unsigned int irq, Error **errp)
75
{
76
    int fd;
77
    size_t argsz;
78
    IOHandler *fd_read;
79
    EventNotifier *notifier;
80
    g_autofree struct vfio_irq_info *irq_info = NULL;
81
    VFIODevice *vdev = &vapdev->vdev;
82

83
    switch (irq) {
84
    case VFIO_AP_REQ_IRQ_INDEX:
85
        notifier = &vapdev->req_notifier;
86
        fd_read = vfio_ap_req_notifier_handler;
87
        break;
88
    default:
89
        error_setg(errp, "vfio: Unsupported device irq(%d)", irq);
90
        return false;
91
    }
92

93
    if (vdev->num_irqs < irq + 1) {
94
        error_setg(errp, "vfio: IRQ %u not available (number of irqs %u)",
95
                   irq, vdev->num_irqs);
96
        return false;
97
    }
98

99
    argsz = sizeof(*irq_info);
100
    irq_info = g_malloc0(argsz);
101
    irq_info->index = irq;
102
    irq_info->argsz = argsz;
103

104
    if (ioctl(vdev->fd, VFIO_DEVICE_GET_IRQ_INFO,
105
              irq_info) < 0 || irq_info->count < 1) {
106
        error_setg_errno(errp, errno, "vfio: Error getting irq info");
107
        return false;
108
    }
109

110
    if (event_notifier_init(notifier, 0)) {
111
        error_setg_errno(errp, errno,
112
                         "vfio: Unable to init event notifier for irq (%d)",
113
                         irq);
114
        return false;
115
    }
116

117
    fd = event_notifier_get_fd(notifier);
118
    qemu_set_fd_handler(fd, fd_read, NULL, vapdev);
119

120
    if (!vfio_set_irq_signaling(vdev, irq, 0, VFIO_IRQ_SET_ACTION_TRIGGER, fd,
121
                                errp)) {
122
        qemu_set_fd_handler(fd, NULL, NULL, vapdev);
123
        event_notifier_cleanup(notifier);
124
    }
125

126
    return true;
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
    ERRP_GUARD();
157
    Error *err = NULL;
158
    VFIOAPDevice *vapdev = VFIO_AP_DEVICE(dev);
159
    VFIODevice *vbasedev = &vapdev->vdev;
160

161
    if (!vfio_device_get_name(vbasedev, errp)) {
162
        return;
163
    }
164

165
    if (!vfio_attach_device(vbasedev->name, vbasedev,
166
                            &address_space_memory, errp)) {
167
        goto error;
168
    }
169

170
    if (!vfio_ap_register_irq_notifier(vapdev, VFIO_AP_REQ_IRQ_INDEX, &err)) {
171
        /*
172
         * Report this error, but do not make it a failing condition.
173
         * Lack of this IRQ in the host does not prevent normal operation.
174
         */
175
        warn_report_err(err);
176
    }
177

178
    return;
179

180
error:
181
    error_prepend(errp, VFIO_MSG_PREFIX, vbasedev->name);
182
    g_free(vbasedev->name);
183
}
184

185
static void vfio_ap_unrealize(DeviceState *dev)
186
{
187
    VFIOAPDevice *vapdev = VFIO_AP_DEVICE(dev);
188

189
    vfio_ap_unregister_irq_notifier(vapdev, VFIO_AP_REQ_IRQ_INDEX);
190
    vfio_detach_device(&vapdev->vdev);
191
    g_free(vapdev->vdev.name);
192
}
193

194
static Property vfio_ap_properties[] = {
195
    DEFINE_PROP_STRING("sysfsdev", VFIOAPDevice, vdev.sysfsdev),
196
#ifdef CONFIG_IOMMUFD
197
    DEFINE_PROP_LINK("iommufd", VFIOAPDevice, vdev.iommufd,
198
                     TYPE_IOMMUFD_BACKEND, IOMMUFDBackend *),
199
#endif
200
    DEFINE_PROP_END_OF_LIST(),
201
};
202

203
static void vfio_ap_reset(DeviceState *dev)
204
{
205
    int ret;
206
    VFIOAPDevice *vapdev = VFIO_AP_DEVICE(dev);
207

208
    ret = ioctl(vapdev->vdev.fd, VFIO_DEVICE_RESET);
209
    if (ret) {
210
        error_report("%s: failed to reset %s device: %s", __func__,
211
                     vapdev->vdev.name, strerror(errno));
212
    }
213
}
214

215
static const VMStateDescription vfio_ap_vmstate = {
216
    .name = "vfio-ap",
217
    .unmigratable = 1,
218
};
219

220
static void vfio_ap_instance_init(Object *obj)
221
{
222
    VFIOAPDevice *vapdev = VFIO_AP_DEVICE(obj);
223
    VFIODevice *vbasedev = &vapdev->vdev;
224

225
    /*
226
     * vfio-ap devices operate in a way compatible with discarding of
227
     * memory in RAM blocks, as no pages are pinned in the host.
228
     * This needs to be set before vfio_get_device() for vfio common to
229
     * handle ram_block_discard_disable().
230
     */
231
    vfio_device_init(vbasedev, VFIO_DEVICE_TYPE_AP, &vfio_ap_ops,
232
                     DEVICE(vapdev), true);
233

234
    /* AP device is mdev type device */
235
    vbasedev->mdev = true;
236
}
237

238
#ifdef CONFIG_IOMMUFD
239
static void vfio_ap_set_fd(Object *obj, const char *str, Error **errp)
240
{
241
    vfio_device_set_fd(&VFIO_AP_DEVICE(obj)->vdev, str, errp);
242
}
243
#endif
244

245
static void vfio_ap_class_init(ObjectClass *klass, void *data)
246
{
247
    DeviceClass *dc = DEVICE_CLASS(klass);
248

249
    device_class_set_props(dc, vfio_ap_properties);
250
#ifdef CONFIG_IOMMUFD
251
    object_class_property_add_str(klass, "fd", NULL, vfio_ap_set_fd);
252
#endif
253
    dc->vmsd = &vfio_ap_vmstate;
254
    dc->desc = "VFIO-based AP device assignment";
255
    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
256
    dc->realize = vfio_ap_realize;
257
    dc->unrealize = vfio_ap_unrealize;
258
    dc->hotpluggable = true;
259
    dc->reset = vfio_ap_reset;
260
    dc->bus_type = TYPE_AP_BUS;
261
}
262

263
static const TypeInfo vfio_ap_info = {
264
    .name = TYPE_VFIO_AP_DEVICE,
265
    .parent = TYPE_AP_DEVICE,
266
    .instance_size = sizeof(VFIOAPDevice),
267
    .instance_init = vfio_ap_instance_init,
268
    .class_init = vfio_ap_class_init,
269
};
270

271
static void vfio_ap_type_init(void)
272
{
273
    type_register_static(&vfio_ap_info);
274
}
275

276
type_init(vfio_ap_type_init)
277

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.