net: cadence_gem: Make phy respond to broadcast
[qemu.git] / hw / intc / s390_flic.c
blobb2ef3e3f8e6994f6c6609b20e64162e455f45598
1 /*
2 * QEMU S390x KVM floating interrupt controller (flic)
4 * Copyright 2014 IBM Corp.
5 * Author(s): Jens Freimann <jfrei@linux.vnet.ibm.com>
7 * This work is licensed under the terms of the GNU GPL, version 2 or (at
8 * your option) any later version. See the COPYING file in the top-level
9 * directory.
12 #include <sys/ioctl.h>
13 #include "qemu/error-report.h"
14 #include "hw/sysbus.h"
15 #include "sysemu/kvm.h"
16 #include "migration/qemu-file.h"
17 #include "hw/s390x/s390_flic.h"
18 #include "trace.h"
20 #define FLIC_SAVE_INITIAL_SIZE getpagesize()
21 #define FLIC_FAILED (-1UL)
22 #define FLIC_SAVEVM_VERSION 1
24 void s390_flic_init(void)
26 DeviceState *dev;
27 int r;
29 if (kvm_enabled()) {
30 dev = qdev_create(NULL, "s390-flic");
31 object_property_add_child(qdev_get_machine(), "s390-flic",
32 OBJECT(dev), NULL);
33 r = qdev_init(dev);
34 if (r) {
35 error_report("flic: couldn't create qdev");
40 /**
41 * flic_get_all_irqs - store all pending irqs in buffer
42 * @buf: pointer to buffer which is passed to kernel
43 * @len: length of buffer
44 * @flic: pointer to flic device state
46 * Returns: -ENOMEM if buffer is too small,
47 * -EINVAL if attr.group is invalid,
48 * -EFAULT if copying to userspace failed,
49 * on success return number of stored interrupts
51 static int flic_get_all_irqs(KVMS390FLICState *flic,
52 void *buf, int len)
54 struct kvm_device_attr attr = {
55 .group = KVM_DEV_FLIC_GET_ALL_IRQS,
56 .addr = (uint64_t) buf,
57 .attr = len,
59 int rc;
61 rc = ioctl(flic->fd, KVM_GET_DEVICE_ATTR, &attr);
63 return rc == -1 ? -errno : rc;
66 static void flic_enable_pfault(KVMS390FLICState *flic)
68 struct kvm_device_attr attr = {
69 .group = KVM_DEV_FLIC_APF_ENABLE,
71 int rc;
73 rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
75 if (rc) {
76 fprintf(stderr, "flic: couldn't enable pfault\n");
80 static void flic_disable_wait_pfault(KVMS390FLICState *flic)
82 struct kvm_device_attr attr = {
83 .group = KVM_DEV_FLIC_APF_DISABLE_WAIT,
85 int rc;
87 rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
89 if (rc) {
90 fprintf(stderr, "flic: couldn't disable pfault\n");
94 /** flic_enqueue_irqs - returns 0 on success
95 * @buf: pointer to buffer which is passed to kernel
96 * @len: length of buffer
97 * @flic: pointer to flic device state
99 * Returns: -EINVAL if attr.group is unknown
101 static int flic_enqueue_irqs(void *buf, uint64_t len,
102 KVMS390FLICState *flic)
104 int rc;
105 struct kvm_device_attr attr = {
106 .group = KVM_DEV_FLIC_ENQUEUE,
107 .addr = (uint64_t) buf,
108 .attr = len,
111 rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
113 return rc ? -errno : 0;
117 * __get_all_irqs - store all pending irqs in buffer
118 * @flic: pointer to flic device state
119 * @buf: pointer to pointer to a buffer
120 * @len: length of buffer
122 * Returns: return value of flic_get_all_irqs
123 * Note: Retry and increase buffer size until flic_get_all_irqs
124 * either returns a value >= 0 or a negative error code.
125 * -ENOMEM is an exception, which means the buffer is too small
126 * and we should try again. Other negative error codes can be
127 * -EFAULT and -EINVAL which we ignore at this point
129 static int __get_all_irqs(KVMS390FLICState *flic,
130 void **buf, int len)
132 int r;
134 do {
135 /* returns -ENOMEM if buffer is too small and number
136 * of queued interrupts on success */
137 r = flic_get_all_irqs(flic, *buf, len);
138 if (r >= 0) {
139 break;
141 len *= 2;
142 *buf = g_try_realloc(*buf, len);
143 if (!buf) {
144 return -ENOMEM;
146 } while (r == -ENOMEM && len <= KVM_S390_FLIC_MAX_BUFFER);
148 return r;
152 * kvm_flic_save - Save pending floating interrupts
153 * @f: QEMUFile containing migration state
154 * @opaque: pointer to flic device state
156 * Note: Pass buf and len to kernel. Start with one page and
157 * increase until buffer is sufficient or maxium size is
158 * reached
160 static void kvm_flic_save(QEMUFile *f, void *opaque)
162 KVMS390FLICState *flic = opaque;
163 int len = FLIC_SAVE_INITIAL_SIZE;
164 void *buf;
165 int count;
167 flic_disable_wait_pfault((struct KVMS390FLICState *) opaque);
169 buf = g_try_malloc0(len);
170 if (!buf) {
171 /* Storing FLIC_FAILED into the count field here will cause the
172 * target system to fail when attempting to load irqs from the
173 * migration state */
174 error_report("flic: couldn't allocate memory");
175 qemu_put_be64(f, FLIC_FAILED);
176 return;
179 count = __get_all_irqs(flic, &buf, len);
180 if (count < 0) {
181 error_report("flic: couldn't retrieve irqs from kernel, rc %d",
182 count);
183 /* Storing FLIC_FAILED into the count field here will cause the
184 * target system to fail when attempting to load irqs from the
185 * migration state */
186 qemu_put_be64(f, FLIC_FAILED);
187 } else {
188 qemu_put_be64(f, count);
189 qemu_put_buffer(f, (uint8_t *) buf,
190 count * sizeof(struct kvm_s390_irq));
192 g_free(buf);
196 * kvm_flic_load - Load pending floating interrupts
197 * @f: QEMUFile containing migration state
198 * @opaque: pointer to flic device state
199 * @version_id: version id for migration
201 * Returns: value of flic_enqueue_irqs, -EINVAL on error
202 * Note: Do nothing when no interrupts where stored
203 * in QEMUFile
205 static int kvm_flic_load(QEMUFile *f, void *opaque, int version_id)
207 uint64_t len = 0;
208 uint64_t count = 0;
209 void *buf = NULL;
210 int r = 0;
212 if (version_id != FLIC_SAVEVM_VERSION) {
213 r = -EINVAL;
214 goto out;
217 flic_enable_pfault((struct KVMS390FLICState *) opaque);
219 count = qemu_get_be64(f);
220 len = count * sizeof(struct kvm_s390_irq);
221 if (count == FLIC_FAILED) {
222 r = -EINVAL;
223 goto out;
225 if (count == 0) {
226 r = 0;
227 goto out;
229 buf = g_try_malloc0(len);
230 if (!buf) {
231 r = -ENOMEM;
232 goto out;
235 if (qemu_get_buffer(f, (uint8_t *) buf, len) != len) {
236 r = -EINVAL;
237 goto out_free;
239 r = flic_enqueue_irqs(buf, len, (struct KVMS390FLICState *) opaque);
241 out_free:
242 g_free(buf);
243 out:
244 return r;
247 static void kvm_s390_flic_realize(DeviceState *dev, Error **errp)
249 KVMS390FLICState *flic_state = KVM_S390_FLIC(dev);
250 struct kvm_create_device cd = {0};
251 int ret;
253 flic_state->fd = -1;
254 if (!kvm_check_extension(kvm_state, KVM_CAP_DEVICE_CTRL)) {
255 trace_flic_no_device_api(errno);
256 return;
259 cd.type = KVM_DEV_TYPE_FLIC;
260 ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd);
261 if (ret < 0) {
262 trace_flic_create_device(errno);
263 return;
265 flic_state->fd = cd.fd;
267 /* Register savevm handler for floating interrupts */
268 register_savevm(NULL, "s390-flic", 0, 1, kvm_flic_save,
269 kvm_flic_load, (void *) flic_state);
272 static void kvm_s390_flic_unrealize(DeviceState *dev, Error **errp)
274 KVMS390FLICState *flic_state = KVM_S390_FLIC(dev);
276 unregister_savevm(DEVICE(flic_state), "s390-flic", flic_state);
279 static void kvm_s390_flic_reset(DeviceState *dev)
281 KVMS390FLICState *flic = KVM_S390_FLIC(dev);
282 struct kvm_device_attr attr = {
283 .group = KVM_DEV_FLIC_CLEAR_IRQS,
285 int rc = 0;
287 if (flic->fd == -1) {
288 return;
291 flic_disable_wait_pfault(flic);
293 rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
294 if (rc) {
295 trace_flic_reset_failed(errno);
298 flic_enable_pfault(flic);
301 static void kvm_s390_flic_class_init(ObjectClass *oc, void *data)
303 DeviceClass *dc = DEVICE_CLASS(oc);
305 dc->realize = kvm_s390_flic_realize;
306 dc->unrealize = kvm_s390_flic_unrealize;
307 dc->reset = kvm_s390_flic_reset;
310 static const TypeInfo kvm_s390_flic_info = {
311 .name = TYPE_KVM_S390_FLIC,
312 .parent = TYPE_SYS_BUS_DEVICE,
313 .instance_size = sizeof(KVMS390FLICState),
314 .class_init = kvm_s390_flic_class_init,
317 static void kvm_s390_flic_register_types(void)
319 type_register_static(&kvm_s390_flic_info);
322 type_init(kvm_s390_flic_register_types)