]>
Commit | Line | Data |
---|---|---|
2fe2942c TK |
1 | /* |
2 | * VFIO based AP matrix device assignment | |
3 | * | |
4 | * Copyright 2018 IBM Corp. | |
5 | * Author(s): Tony Krowiak <[email protected]> | |
6 | * Halil Pasic <[email protected]> | |
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 | ||
b7d89466 | 13 | #include "qemu/osdep.h" |
2fe2942c TK |
14 | #include <linux/vfio.h> |
15 | #include <sys/ioctl.h> | |
2fe2942c TK |
16 | #include "qapi/error.h" |
17 | #include "hw/sysbus.h" | |
18 | #include "hw/vfio/vfio.h" | |
19 | #include "hw/vfio/vfio-common.h" | |
20 | #include "hw/s390x/ap-device.h" | |
21 | #include "qemu/error-report.h" | |
0b8fa32f | 22 | #include "qemu/module.h" |
2fe2942c TK |
23 | #include "qemu/option.h" |
24 | #include "qemu/config-file.h" | |
25 | #include "cpu.h" | |
26 | #include "kvm_s390x.h" | |
d6454270 | 27 | #include "migration/vmstate.h" |
a27bd6c7 | 28 | #include "hw/qdev-properties.h" |
2fe2942c TK |
29 | #include "hw/s390x/ap-bridge.h" |
30 | #include "exec/address-spaces.h" | |
31 | ||
32 | #define VFIO_AP_DEVICE_TYPE "vfio-ap" | |
33 | ||
34 | typedef struct VFIOAPDevice { | |
35 | APDevice apdev; | |
36 | VFIODevice vdev; | |
37 | } VFIOAPDevice; | |
38 | ||
39 | #define VFIO_AP_DEVICE(obj) \ | |
40 | OBJECT_CHECK(VFIOAPDevice, (obj), VFIO_AP_DEVICE_TYPE) | |
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_put_device(VFIOAPDevice *vapdev) | |
56 | { | |
57 | g_free(vapdev->vdev.name); | |
58 | vfio_put_base_device(&vapdev->vdev); | |
59 | } | |
60 | ||
61 | static VFIOGroup *vfio_ap_get_group(VFIOAPDevice *vapdev, Error **errp) | |
62 | { | |
63 | GError *gerror = NULL; | |
64 | char *symlink, *group_path; | |
65 | int groupid; | |
66 | ||
67 | symlink = g_strdup_printf("%s/iommu_group", vapdev->vdev.sysfsdev); | |
68 | group_path = g_file_read_link(symlink, &gerror); | |
69 | g_free(symlink); | |
70 | ||
71 | if (!group_path) { | |
72 | error_setg(errp, "%s: no iommu_group found for %s: %s", | |
73 | VFIO_AP_DEVICE_TYPE, vapdev->vdev.sysfsdev, gerror->message); | |
74 | return NULL; | |
75 | } | |
76 | ||
77 | if (sscanf(basename(group_path), "%d", &groupid) != 1) { | |
78 | error_setg(errp, "vfio: failed to read %s", group_path); | |
79 | g_free(group_path); | |
80 | return NULL; | |
81 | } | |
82 | ||
83 | g_free(group_path); | |
84 | ||
85 | return vfio_get_group(groupid, &address_space_memory, errp); | |
86 | } | |
87 | ||
88 | static void vfio_ap_realize(DeviceState *dev, Error **errp) | |
89 | { | |
90 | int ret; | |
91 | char *mdevid; | |
2fe2942c TK |
92 | VFIOGroup *vfio_group; |
93 | APDevice *apdev = AP_DEVICE(dev); | |
94 | VFIOAPDevice *vapdev = VFIO_AP_DEVICE(apdev); | |
95 | ||
b5e45b0f | 96 | vfio_group = vfio_ap_get_group(vapdev, errp); |
2fe2942c | 97 | if (!vfio_group) { |
b5e45b0f | 98 | return; |
2fe2942c TK |
99 | } |
100 | ||
101 | vapdev->vdev.ops = &vfio_ap_ops; | |
102 | vapdev->vdev.type = VFIO_DEVICE_TYPE_AP; | |
103 | mdevid = basename(vapdev->vdev.sysfsdev); | |
104 | vapdev->vdev.name = g_strdup_printf("%s", mdevid); | |
105 | vapdev->vdev.dev = dev; | |
106 | ||
1883e8fc CH |
107 | /* |
108 | * vfio-ap devices operate in a way compatible with | |
109 | * memory ballooning, as no pages are pinned in the host. | |
110 | * This needs to be set before vfio_get_device() for vfio common to | |
111 | * handle the balloon inhibitor. | |
112 | */ | |
113 | vapdev->vdev.balloon_allowed = true; | |
114 | ||
b5e45b0f | 115 | ret = vfio_get_device(vfio_group, mdevid, &vapdev->vdev, errp); |
2fe2942c TK |
116 | if (ret) { |
117 | goto out_get_dev_err; | |
118 | } | |
119 | ||
120 | return; | |
121 | ||
122 | out_get_dev_err: | |
123 | vfio_ap_put_device(vapdev); | |
124 | vfio_put_group(vfio_group); | |
2fe2942c TK |
125 | } |
126 | ||
b69c3c21 | 127 | static void vfio_ap_unrealize(DeviceState *dev) |
2fe2942c TK |
128 | { |
129 | APDevice *apdev = AP_DEVICE(dev); | |
130 | VFIOAPDevice *vapdev = VFIO_AP_DEVICE(apdev); | |
131 | VFIOGroup *group = vapdev->vdev.group; | |
132 | ||
133 | vfio_ap_put_device(vapdev); | |
134 | vfio_put_group(group); | |
135 | } | |
136 | ||
137 | static Property vfio_ap_properties[] = { | |
138 | DEFINE_PROP_STRING("sysfsdev", VFIOAPDevice, vdev.sysfsdev), | |
139 | DEFINE_PROP_END_OF_LIST(), | |
140 | }; | |
141 | ||
142 | static void vfio_ap_reset(DeviceState *dev) | |
143 | { | |
144 | int ret; | |
145 | APDevice *apdev = AP_DEVICE(dev); | |
146 | VFIOAPDevice *vapdev = VFIO_AP_DEVICE(apdev); | |
147 | ||
148 | ret = ioctl(vapdev->vdev.fd, VFIO_DEVICE_RESET); | |
149 | if (ret) { | |
150 | error_report("%s: failed to reset %s device: %s", __func__, | |
ab17b1fc | 151 | vapdev->vdev.name, strerror(errno)); |
2fe2942c TK |
152 | } |
153 | } | |
154 | ||
155 | static const VMStateDescription vfio_ap_vmstate = { | |
da56e330 | 156 | .name = "vfio-ap", |
2fe2942c TK |
157 | .unmigratable = 1, |
158 | }; | |
159 | ||
160 | static void vfio_ap_class_init(ObjectClass *klass, void *data) | |
161 | { | |
162 | DeviceClass *dc = DEVICE_CLASS(klass); | |
163 | ||
4f67d30b | 164 | device_class_set_props(dc, vfio_ap_properties); |
2fe2942c TK |
165 | dc->vmsd = &vfio_ap_vmstate; |
166 | dc->desc = "VFIO-based AP device assignment"; | |
167 | set_bit(DEVICE_CATEGORY_MISC, dc->categories); | |
168 | dc->realize = vfio_ap_realize; | |
169 | dc->unrealize = vfio_ap_unrealize; | |
374b78e3 | 170 | dc->hotpluggable = true; |
2fe2942c TK |
171 | dc->reset = vfio_ap_reset; |
172 | dc->bus_type = TYPE_AP_BUS; | |
173 | } | |
174 | ||
175 | static const TypeInfo vfio_ap_info = { | |
176 | .name = VFIO_AP_DEVICE_TYPE, | |
177 | .parent = AP_DEVICE_TYPE, | |
178 | .instance_size = sizeof(VFIOAPDevice), | |
179 | .class_init = vfio_ap_class_init, | |
180 | }; | |
181 | ||
182 | static void vfio_ap_type_init(void) | |
183 | { | |
184 | type_register_static(&vfio_ap_info); | |
185 | } | |
186 | ||
187 | type_init(vfio_ap_type_init) |