]>
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" | |
22 | #include "qemu/queue.h" | |
23 | #include "qemu/option.h" | |
24 | #include "qemu/config-file.h" | |
25 | #include "cpu.h" | |
26 | #include "kvm_s390x.h" | |
27 | #include "sysemu/sysemu.h" | |
28 | #include "hw/s390x/ap-bridge.h" | |
29 | #include "exec/address-spaces.h" | |
30 | ||
31 | #define VFIO_AP_DEVICE_TYPE "vfio-ap" | |
32 | ||
33 | typedef struct VFIOAPDevice { | |
34 | APDevice apdev; | |
35 | VFIODevice vdev; | |
36 | } VFIOAPDevice; | |
37 | ||
38 | #define VFIO_AP_DEVICE(obj) \ | |
39 | OBJECT_CHECK(VFIOAPDevice, (obj), VFIO_AP_DEVICE_TYPE) | |
40 | ||
41 | static void vfio_ap_compute_needs_reset(VFIODevice *vdev) | |
42 | { | |
43 | vdev->needs_reset = false; | |
44 | } | |
45 | ||
46 | /* | |
47 | * We don't need vfio_hot_reset_multi and vfio_eoi operations for | |
48 | * vfio-ap device now. | |
49 | */ | |
50 | struct VFIODeviceOps vfio_ap_ops = { | |
51 | .vfio_compute_needs_reset = vfio_ap_compute_needs_reset, | |
52 | }; | |
53 | ||
54 | static void vfio_ap_put_device(VFIOAPDevice *vapdev) | |
55 | { | |
56 | g_free(vapdev->vdev.name); | |
57 | vfio_put_base_device(&vapdev->vdev); | |
58 | } | |
59 | ||
60 | static VFIOGroup *vfio_ap_get_group(VFIOAPDevice *vapdev, Error **errp) | |
61 | { | |
62 | GError *gerror = NULL; | |
63 | char *symlink, *group_path; | |
64 | int groupid; | |
65 | ||
66 | symlink = g_strdup_printf("%s/iommu_group", vapdev->vdev.sysfsdev); | |
67 | group_path = g_file_read_link(symlink, &gerror); | |
68 | g_free(symlink); | |
69 | ||
70 | if (!group_path) { | |
71 | error_setg(errp, "%s: no iommu_group found for %s: %s", | |
72 | VFIO_AP_DEVICE_TYPE, vapdev->vdev.sysfsdev, gerror->message); | |
73 | return NULL; | |
74 | } | |
75 | ||
76 | if (sscanf(basename(group_path), "%d", &groupid) != 1) { | |
77 | error_setg(errp, "vfio: failed to read %s", group_path); | |
78 | g_free(group_path); | |
79 | return NULL; | |
80 | } | |
81 | ||
82 | g_free(group_path); | |
83 | ||
84 | return vfio_get_group(groupid, &address_space_memory, errp); | |
85 | } | |
86 | ||
87 | static void vfio_ap_realize(DeviceState *dev, Error **errp) | |
88 | { | |
89 | int ret; | |
90 | char *mdevid; | |
91 | Error *local_err = NULL; | |
92 | VFIOGroup *vfio_group; | |
93 | APDevice *apdev = AP_DEVICE(dev); | |
94 | VFIOAPDevice *vapdev = VFIO_AP_DEVICE(apdev); | |
95 | ||
96 | vfio_group = vfio_ap_get_group(vapdev, &local_err); | |
97 | if (!vfio_group) { | |
98 | goto out_err; | |
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 | ||
2fe2942c TK |
115 | ret = vfio_get_device(vfio_group, mdevid, &vapdev->vdev, &local_err); |
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); | |
125 | out_err: | |
126 | error_propagate(errp, local_err); | |
127 | } | |
128 | ||
129 | static void vfio_ap_unrealize(DeviceState *dev, Error **errp) | |
130 | { | |
131 | APDevice *apdev = AP_DEVICE(dev); | |
132 | VFIOAPDevice *vapdev = VFIO_AP_DEVICE(apdev); | |
133 | VFIOGroup *group = vapdev->vdev.group; | |
134 | ||
135 | vfio_ap_put_device(vapdev); | |
136 | vfio_put_group(group); | |
137 | } | |
138 | ||
139 | static Property vfio_ap_properties[] = { | |
140 | DEFINE_PROP_STRING("sysfsdev", VFIOAPDevice, vdev.sysfsdev), | |
141 | DEFINE_PROP_END_OF_LIST(), | |
142 | }; | |
143 | ||
144 | static void vfio_ap_reset(DeviceState *dev) | |
145 | { | |
146 | int ret; | |
147 | APDevice *apdev = AP_DEVICE(dev); | |
148 | VFIOAPDevice *vapdev = VFIO_AP_DEVICE(apdev); | |
149 | ||
150 | ret = ioctl(vapdev->vdev.fd, VFIO_DEVICE_RESET); | |
151 | if (ret) { | |
152 | error_report("%s: failed to reset %s device: %s", __func__, | |
ab17b1fc | 153 | vapdev->vdev.name, strerror(errno)); |
2fe2942c TK |
154 | } |
155 | } | |
156 | ||
157 | static const VMStateDescription vfio_ap_vmstate = { | |
158 | .name = VFIO_AP_DEVICE_TYPE, | |
159 | .unmigratable = 1, | |
160 | }; | |
161 | ||
162 | static void vfio_ap_class_init(ObjectClass *klass, void *data) | |
163 | { | |
164 | DeviceClass *dc = DEVICE_CLASS(klass); | |
165 | ||
166 | dc->props = vfio_ap_properties; | |
167 | dc->vmsd = &vfio_ap_vmstate; | |
168 | dc->desc = "VFIO-based AP device assignment"; | |
169 | set_bit(DEVICE_CATEGORY_MISC, dc->categories); | |
170 | dc->realize = vfio_ap_realize; | |
171 | dc->unrealize = vfio_ap_unrealize; | |
374b78e3 | 172 | dc->hotpluggable = true; |
2fe2942c TK |
173 | dc->reset = vfio_ap_reset; |
174 | dc->bus_type = TYPE_AP_BUS; | |
175 | } | |
176 | ||
177 | static const TypeInfo vfio_ap_info = { | |
178 | .name = VFIO_AP_DEVICE_TYPE, | |
179 | .parent = AP_DEVICE_TYPE, | |
180 | .instance_size = sizeof(VFIOAPDevice), | |
181 | .class_init = vfio_ap_class_init, | |
182 | }; | |
183 | ||
184 | static void vfio_ap_type_init(void) | |
185 | { | |
186 | type_register_static(&vfio_ap_info); | |
187 | } | |
188 | ||
189 | type_init(vfio_ap_type_init) |