xref: /openbmc/qemu/hw/intc/s390_flic_kvm.c (revision 28ae3179fc52d2e4d870b635c4a412aab99759e7)
1  /*
2   * QEMU S390x KVM floating interrupt controller (flic)
3   *
4   * Copyright 2014 IBM Corp.
5   * Author(s): Jens Freimann <jfrei@linux.vnet.ibm.com>
6   *            Cornelia Huck <cornelia.huck@de.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 "kvm/kvm_s390x.h"
15  #include <sys/ioctl.h>
16  #include "qemu/error-report.h"
17  #include "qemu/module.h"
18  #include "qapi/error.h"
19  #include "sysemu/kvm.h"
20  #include "hw/s390x/s390_flic.h"
21  #include "hw/s390x/adapter.h"
22  #include "hw/s390x/css.h"
23  #include "migration/qemu-file-types.h"
24  #include "trace.h"
25  #include "qom/object.h"
26  
27  #define FLIC_SAVE_INITIAL_SIZE qemu_real_host_page_size()
28  #define FLIC_FAILED (-1UL)
29  #define FLIC_SAVEVM_VERSION 1
30  
31  struct KVMS390FLICState{
32      S390FLICState parent_obj;
33  
34      uint32_t fd;
35      bool clear_io_supported;
36  };
37  
s390_get_kvm_flic(S390FLICState * fs)38  static KVMS390FLICState *s390_get_kvm_flic(S390FLICState *fs)
39  {
40      static KVMS390FLICState *flic;
41  
42      if (!flic) {
43          /* we only have one flic device, so this is fine to cache */
44          flic = KVM_S390_FLIC(fs);
45      }
46      return flic;
47  }
48  
49  /**
50   * flic_get_all_irqs - store all pending irqs in buffer
51   * @buf: pointer to buffer which is passed to kernel
52   * @len: length of buffer
53   * @flic: pointer to flic device state
54   *
55   * Returns: -ENOMEM if buffer is too small,
56   * -EINVAL if attr.group is invalid,
57   * -EFAULT if copying to userspace failed,
58   * on success return number of stored interrupts
59   */
flic_get_all_irqs(KVMS390FLICState * flic,void * buf,int len)60  static int flic_get_all_irqs(KVMS390FLICState *flic,
61                               void *buf, int len)
62  {
63      struct kvm_device_attr attr = {
64          .group = KVM_DEV_FLIC_GET_ALL_IRQS,
65          .addr = (uint64_t) buf,
66          .attr = len,
67      };
68      int rc;
69  
70      rc = ioctl(flic->fd, KVM_GET_DEVICE_ATTR, &attr);
71  
72      return rc == -1 ? -errno : rc;
73  }
74  
flic_enable_pfault(KVMS390FLICState * flic)75  static void flic_enable_pfault(KVMS390FLICState *flic)
76  {
77      struct kvm_device_attr attr = {
78          .group = KVM_DEV_FLIC_APF_ENABLE,
79      };
80      int rc;
81  
82      rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
83  
84      if (rc) {
85          fprintf(stderr, "flic: couldn't enable pfault\n");
86      }
87  }
88  
flic_disable_wait_pfault(KVMS390FLICState * flic)89  static void flic_disable_wait_pfault(KVMS390FLICState *flic)
90  {
91      struct kvm_device_attr attr = {
92          .group = KVM_DEV_FLIC_APF_DISABLE_WAIT,
93      };
94      int rc;
95  
96      rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
97  
98      if (rc) {
99          fprintf(stderr, "flic: couldn't disable pfault\n");
100      }
101  }
102  
103  /** flic_enqueue_irqs - returns 0 on success
104   * @buf: pointer to buffer which is passed to kernel
105   * @len: length of buffer
106   * @flic: pointer to flic device state
107   *
108   * Returns: -EINVAL if attr.group is unknown
109   */
flic_enqueue_irqs(void * buf,uint64_t len,KVMS390FLICState * flic)110  static int flic_enqueue_irqs(void *buf, uint64_t len,
111                              KVMS390FLICState *flic)
112  {
113      int rc;
114      struct kvm_device_attr attr = {
115          .group = KVM_DEV_FLIC_ENQUEUE,
116          .addr = (uint64_t) buf,
117          .attr = len,
118      };
119  
120      rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
121  
122      return rc ? -errno : 0;
123  }
124  
kvm_s390_inject_flic(S390FLICState * fs,struct kvm_s390_irq * irq)125  static void kvm_s390_inject_flic(S390FLICState *fs, struct kvm_s390_irq *irq)
126  {
127      static bool use_flic = true;
128      int r;
129  
130      if (use_flic) {
131          r = flic_enqueue_irqs(irq, sizeof(*irq), s390_get_kvm_flic(fs));
132          if (r == -ENOSYS) {
133              use_flic = false;
134          }
135          if (!r) {
136              return;
137          }
138      }
139      /* fallback to legacy KVM IOCTL in case FLIC fails */
140      kvm_s390_floating_interrupt_legacy(irq);
141  }
142  
kvm_s390_inject_service(S390FLICState * fs,uint32_t parm)143  static void kvm_s390_inject_service(S390FLICState *fs, uint32_t parm)
144  {
145          struct kvm_s390_irq irq = {
146          .type = KVM_S390_INT_SERVICE,
147          .u.ext.ext_params = parm,
148      };
149  
150      kvm_s390_inject_flic(fs, &irq);
151  }
152  
kvm_s390_inject_io(S390FLICState * fs,uint16_t subchannel_id,uint16_t subchannel_nr,uint32_t io_int_parm,uint32_t io_int_word)153  static void kvm_s390_inject_io(S390FLICState *fs, uint16_t subchannel_id,
154                                 uint16_t subchannel_nr, uint32_t io_int_parm,
155                                 uint32_t io_int_word)
156  {
157      struct kvm_s390_irq irq = {
158          .u.io.subchannel_id = subchannel_id,
159          .u.io.subchannel_nr = subchannel_nr,
160          .u.io.io_int_parm = io_int_parm,
161          .u.io.io_int_word = io_int_word,
162      };
163  
164      if (io_int_word & IO_INT_WORD_AI) {
165          irq.type = KVM_S390_INT_IO(1, 0, 0, 0);
166      } else {
167          irq.type = KVM_S390_INT_IO(0, (subchannel_id & 0xff00) >> 8,
168                                        (subchannel_id & 0x0006),
169                                        subchannel_nr);
170      }
171      kvm_s390_inject_flic(fs, &irq);
172  }
173  
kvm_s390_inject_crw_mchk(S390FLICState * fs)174  static void kvm_s390_inject_crw_mchk(S390FLICState *fs)
175  {
176      struct kvm_s390_irq irq = {
177          .type = KVM_S390_MCHK,
178          .u.mchk.cr14 = CR14_CHANNEL_REPORT_SC,
179          .u.mchk.mcic = s390_build_validity_mcic() | MCIC_SC_CP,
180      };
181  
182      kvm_s390_inject_flic(fs, &irq);
183  }
184  
kvm_s390_clear_io_flic(S390FLICState * fs,uint16_t subchannel_id,uint16_t subchannel_nr)185  static int kvm_s390_clear_io_flic(S390FLICState *fs, uint16_t subchannel_id,
186                             uint16_t subchannel_nr)
187  {
188      KVMS390FLICState *flic = s390_get_kvm_flic(fs);
189      int rc;
190      uint32_t sid = subchannel_id << 16 | subchannel_nr;
191      struct kvm_device_attr attr = {
192          .group = KVM_DEV_FLIC_CLEAR_IO_IRQ,
193          .addr = (uint64_t) &sid,
194          .attr = sizeof(sid),
195      };
196      if (unlikely(!flic->clear_io_supported)) {
197          return -ENOSYS;
198      }
199      rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
200      return rc ? -errno : 0;
201  }
202  
kvm_s390_modify_ais_mode(S390FLICState * fs,uint8_t isc,uint16_t mode)203  static int kvm_s390_modify_ais_mode(S390FLICState *fs, uint8_t isc,
204                                      uint16_t mode)
205  {
206      KVMS390FLICState *flic = s390_get_kvm_flic(fs);
207      struct kvm_s390_ais_req req = {
208          .isc = isc,
209          .mode = mode,
210      };
211      struct kvm_device_attr attr = {
212          .group = KVM_DEV_FLIC_AISM,
213          .addr = (uint64_t)&req,
214      };
215  
216      if (!fs->ais_supported) {
217          return -ENOSYS;
218      }
219  
220      return ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr) ? -errno : 0;
221  }
222  
kvm_s390_inject_airq(S390FLICState * fs,uint8_t type,uint8_t isc,uint8_t flags)223  static int kvm_s390_inject_airq(S390FLICState *fs, uint8_t type,
224                                  uint8_t isc, uint8_t flags)
225  {
226      KVMS390FLICState *flic = s390_get_kvm_flic(fs);
227      uint32_t id = css_get_adapter_id(type, isc);
228      struct kvm_device_attr attr = {
229          .group = KVM_DEV_FLIC_AIRQ_INJECT,
230          .attr = id,
231      };
232  
233      if (!fs->ais_supported) {
234          return -ENOSYS;
235      }
236  
237      return ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr) ? -errno : 0;
238  }
239  
240  /**
241   * __get_all_irqs - store all pending irqs in buffer
242   * @flic: pointer to flic device state
243   * @buf: pointer to pointer to a buffer
244   * @len: length of buffer
245   *
246   * Returns: return value of flic_get_all_irqs
247   * Note: Retry and increase buffer size until flic_get_all_irqs
248   * either returns a value >= 0 or a negative error code.
249   * -ENOMEM is an exception, which means the buffer is too small
250   * and we should try again. Other negative error codes can be
251   * -EFAULT and -EINVAL which we ignore at this point
252   */
__get_all_irqs(KVMS390FLICState * flic,void ** buf,int len)253  static int __get_all_irqs(KVMS390FLICState *flic,
254                            void **buf, int len)
255  {
256      int r;
257  
258      do {
259          /* returns -ENOMEM if buffer is too small and number
260           * of queued interrupts on success */
261          r = flic_get_all_irqs(flic, *buf, len);
262          if (r >= 0) {
263              break;
264          }
265          len *= 2;
266          *buf = g_try_realloc(*buf, len);
267          if (!buf) {
268              return -ENOMEM;
269          }
270      } while (r == -ENOMEM && len <= KVM_S390_FLIC_MAX_BUFFER);
271  
272      return r;
273  }
274  
kvm_s390_register_io_adapter(S390FLICState * fs,uint32_t id,uint8_t isc,bool swap,bool is_maskable,uint8_t flags)275  static int kvm_s390_register_io_adapter(S390FLICState *fs, uint32_t id,
276                                          uint8_t isc, bool swap,
277                                          bool is_maskable, uint8_t flags)
278  {
279      struct kvm_s390_io_adapter adapter = {
280          .id = id,
281          .isc = isc,
282          .maskable = is_maskable,
283          .swap = swap,
284          .flags = flags,
285      };
286      KVMS390FLICState *flic = KVM_S390_FLIC(fs);
287      int r;
288      struct kvm_device_attr attr = {
289          .group = KVM_DEV_FLIC_ADAPTER_REGISTER,
290          .addr = (uint64_t)&adapter,
291      };
292  
293      if (!kvm_gsi_routing_enabled()) {
294          /* nothing to do */
295          return 0;
296      }
297  
298      r = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
299  
300      return r ? -errno : 0;
301  }
302  
kvm_s390_io_adapter_map(S390FLICState * fs,uint32_t id,uint64_t map_addr,bool do_map)303  static int kvm_s390_io_adapter_map(S390FLICState *fs, uint32_t id,
304                                     uint64_t map_addr, bool do_map)
305  {
306      struct kvm_s390_io_adapter_req req = {
307          .id = id,
308          .type = do_map ? KVM_S390_IO_ADAPTER_MAP : KVM_S390_IO_ADAPTER_UNMAP,
309          .addr = map_addr,
310      };
311      struct kvm_device_attr attr = {
312          .group = KVM_DEV_FLIC_ADAPTER_MODIFY,
313          .addr = (uint64_t)&req,
314      };
315      KVMS390FLICState *flic = s390_get_kvm_flic(fs);
316      int r;
317  
318      if (!kvm_gsi_routing_enabled()) {
319          /* nothing to do */
320          return 0;
321      }
322  
323      r = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
324      return r ? -errno : 0;
325  }
326  
kvm_irqchip_add_adapter_route(KVMState * s,AdapterInfo * adapter)327  static int kvm_irqchip_add_adapter_route(KVMState *s, AdapterInfo *adapter)
328  {
329      struct kvm_irq_routing_entry kroute = {};
330      int virq;
331  
332      if (!kvm_gsi_routing_enabled()) {
333          return -ENOSYS;
334      }
335  
336      virq = kvm_irqchip_get_virq(s);
337      if (virq < 0) {
338          return virq;
339      }
340  
341      kroute.gsi = virq;
342      kroute.type = KVM_IRQ_ROUTING_S390_ADAPTER;
343      kroute.flags = 0;
344      kroute.u.adapter.summary_addr = adapter->summary_addr;
345      kroute.u.adapter.ind_addr = adapter->ind_addr;
346      kroute.u.adapter.summary_offset = adapter->summary_offset;
347      kroute.u.adapter.ind_offset = adapter->ind_offset;
348      kroute.u.adapter.adapter_id = adapter->adapter_id;
349  
350      kvm_add_routing_entry(s, &kroute);
351  
352      return virq;
353  }
354  
kvm_s390_add_adapter_routes(S390FLICState * fs,AdapterRoutes * routes)355  static int kvm_s390_add_adapter_routes(S390FLICState *fs,
356                                         AdapterRoutes *routes)
357  {
358      int ret, i;
359      uint64_t ind_offset = routes->adapter.ind_offset;
360  
361      if (!kvm_gsi_routing_enabled()) {
362          return -ENOSYS;
363      }
364  
365      for (i = 0; i < routes->num_routes; i++) {
366          ret = kvm_irqchip_add_adapter_route(kvm_state, &routes->adapter);
367          if (ret < 0) {
368              goto out_undo;
369          }
370          routes->gsi[i] = ret;
371          routes->adapter.ind_offset++;
372      }
373      kvm_irqchip_commit_routes(kvm_state);
374  
375      /* Restore passed-in structure to original state. */
376      routes->adapter.ind_offset = ind_offset;
377      return 0;
378  out_undo:
379      while (--i >= 0) {
380          kvm_irqchip_release_virq(kvm_state, routes->gsi[i]);
381          routes->gsi[i] = -1;
382      }
383      routes->adapter.ind_offset = ind_offset;
384      return ret;
385  }
386  
kvm_s390_release_adapter_routes(S390FLICState * fs,AdapterRoutes * routes)387  static void kvm_s390_release_adapter_routes(S390FLICState *fs,
388                                              AdapterRoutes *routes)
389  {
390      int i;
391  
392      if (!kvm_gsi_routing_enabled()) {
393          return;
394      }
395  
396      for (i = 0; i < routes->num_routes; i++) {
397          if (routes->gsi[i] >= 0) {
398              kvm_irqchip_release_virq(kvm_state, routes->gsi[i]);
399              routes->gsi[i] = -1;
400          }
401      }
402  }
403  
404  /**
405   * kvm_flic_save - Save pending floating interrupts
406   * @f: QEMUFile containing migration state
407   * @opaque: pointer to flic device state
408   * @size: ignored
409   *
410   * Note: Pass buf and len to kernel. Start with one page and
411   * increase until buffer is sufficient or maximum size is
412   * reached
413   */
kvm_flic_save(QEMUFile * f,void * opaque,size_t size,const VMStateField * field,JSONWriter * vmdesc)414  static int kvm_flic_save(QEMUFile *f, void *opaque, size_t size,
415                           const VMStateField *field, JSONWriter *vmdesc)
416  {
417      KVMS390FLICState *flic = opaque;
418      int len = FLIC_SAVE_INITIAL_SIZE;
419      void *buf;
420      int count;
421      int r = 0;
422  
423      flic_disable_wait_pfault((struct KVMS390FLICState *) opaque);
424  
425      buf = g_try_malloc0(len);
426      if (!buf) {
427          /* Storing FLIC_FAILED into the count field here will cause the
428           * target system to fail when attempting to load irqs from the
429           * migration state */
430          error_report("flic: couldn't allocate memory");
431          qemu_put_be64(f, FLIC_FAILED);
432          return -ENOMEM;
433      }
434  
435      count = __get_all_irqs(flic, &buf, len);
436      if (count < 0) {
437          error_report("flic: couldn't retrieve irqs from kernel, rc %d",
438                       count);
439          /* Storing FLIC_FAILED into the count field here will cause the
440           * target system to fail when attempting to load irqs from the
441           * migration state */
442          qemu_put_be64(f, FLIC_FAILED);
443          r = count;
444      } else {
445          qemu_put_be64(f, count);
446          qemu_put_buffer(f, (uint8_t *) buf,
447                          count * sizeof(struct kvm_s390_irq));
448      }
449      g_free(buf);
450  
451      return r;
452  }
453  
454  /**
455   * kvm_flic_load - Load pending floating interrupts
456   * @f: QEMUFile containing migration state
457   * @opaque: pointer to flic device state
458   * @size: ignored
459   *
460   * Returns: value of flic_enqueue_irqs, -EINVAL on error
461   * Note: Do nothing when no interrupts where stored
462   * in QEMUFile
463   */
kvm_flic_load(QEMUFile * f,void * opaque,size_t size,const VMStateField * field)464  static int kvm_flic_load(QEMUFile *f, void *opaque, size_t size,
465                           const VMStateField *field)
466  {
467      uint64_t len = 0;
468      uint64_t count = 0;
469      void *buf = NULL;
470      int r = 0;
471  
472      flic_enable_pfault((struct KVMS390FLICState *) opaque);
473  
474      count = qemu_get_be64(f);
475      len = count * sizeof(struct kvm_s390_irq);
476      if (count == FLIC_FAILED) {
477          return -EINVAL;
478      }
479      if (count == 0) {
480          return 0;
481      }
482      buf = g_try_malloc0(len);
483      if (!buf) {
484          return -ENOMEM;
485      }
486  
487      if (qemu_get_buffer(f, (uint8_t *) buf, len) != len) {
488          r = -EINVAL;
489          goto out_free;
490      }
491      r = flic_enqueue_irqs(buf, len, (struct KVMS390FLICState *) opaque);
492  
493  out_free:
494      g_free(buf);
495      return r;
496  }
497  
498  typedef struct KVMS390FLICStateMigTmp {
499      KVMS390FLICState *parent;
500      uint8_t simm;
501      uint8_t nimm;
502  } KVMS390FLICStateMigTmp;
503  
kvm_flic_ais_pre_save(void * opaque)504  static int kvm_flic_ais_pre_save(void *opaque)
505  {
506      KVMS390FLICStateMigTmp *tmp = opaque;
507      KVMS390FLICState *flic = tmp->parent;
508      struct kvm_s390_ais_all ais;
509      struct kvm_device_attr attr = {
510          .group = KVM_DEV_FLIC_AISM_ALL,
511          .addr = (uint64_t)&ais,
512          .attr = sizeof(ais),
513      };
514  
515      if (ioctl(flic->fd, KVM_GET_DEVICE_ATTR, &attr)) {
516          error_report("Failed to retrieve kvm flic ais states");
517          return -EINVAL;
518      }
519  
520      tmp->simm = ais.simm;
521      tmp->nimm = ais.nimm;
522  
523      return 0;
524  }
525  
kvm_flic_ais_post_load(void * opaque,int version_id)526  static int kvm_flic_ais_post_load(void *opaque, int version_id)
527  {
528      KVMS390FLICStateMigTmp *tmp = opaque;
529      KVMS390FLICState *flic = tmp->parent;
530      struct kvm_s390_ais_all ais = {
531          .simm = tmp->simm,
532          .nimm = tmp->nimm,
533      };
534      struct kvm_device_attr attr = {
535          .group = KVM_DEV_FLIC_AISM_ALL,
536          .addr = (uint64_t)&ais,
537      };
538  
539      /* This can happen when the user mis-configures its guests in an
540       * incompatible fashion or without a CPU model. For example using
541       * qemu with -cpu host (which is not migration safe) and do a
542       * migration from a host that has AIS to a host that has no AIS.
543       * In that case the target system will reject the migration here.
544       */
545      if (!ais_needed(flic)) {
546          return -ENOSYS;
547      }
548  
549      return ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr) ? -errno : 0;
550  }
551  
552  static const VMStateDescription kvm_s390_flic_ais_tmp = {
553      .name = "s390-flic-ais-tmp",
554      .pre_save = kvm_flic_ais_pre_save,
555      .post_load = kvm_flic_ais_post_load,
556      .fields = (const VMStateField[]) {
557          VMSTATE_UINT8(simm, KVMS390FLICStateMigTmp),
558          VMSTATE_UINT8(nimm, KVMS390FLICStateMigTmp),
559          VMSTATE_END_OF_LIST()
560      }
561  };
562  
563  static const VMStateDescription kvm_s390_flic_vmstate_ais = {
564      .name = "s390-flic/ais",
565      .version_id = 1,
566      .minimum_version_id = 1,
567      .needed = ais_needed,
568      .fields = (const VMStateField[]) {
569          VMSTATE_WITH_TMP(KVMS390FLICState, KVMS390FLICStateMigTmp,
570                           kvm_s390_flic_ais_tmp),
571          VMSTATE_END_OF_LIST()
572      }
573  };
574  
575  static const VMStateDescription kvm_s390_flic_vmstate = {
576      /* should have been like kvm-s390-flic,
577       * can't change without breaking compat */
578      .name = "s390-flic",
579      .version_id = FLIC_SAVEVM_VERSION,
580      .minimum_version_id = FLIC_SAVEVM_VERSION,
581      .fields = (const VMStateField[]) {
582          {
583              .name = "irqs",
584              .info = &(const VMStateInfo) {
585                  .name = "irqs",
586                  .get = kvm_flic_load,
587                  .put = kvm_flic_save,
588              },
589              .flags = VMS_SINGLE,
590          },
591          VMSTATE_END_OF_LIST()
592      },
593      .subsections = (const VMStateDescription * const []) {
594          &kvm_s390_flic_vmstate_ais,
595          NULL
596      }
597  };
598  
599  struct KVMS390FLICStateClass {
600      S390FLICStateClass parent_class;
601      DeviceRealize parent_realize;
602  };
603  typedef struct KVMS390FLICStateClass KVMS390FLICStateClass;
604  
DECLARE_CLASS_CHECKERS(KVMS390FLICStateClass,KVM_S390_FLIC,TYPE_KVM_S390_FLIC)605  DECLARE_CLASS_CHECKERS(KVMS390FLICStateClass, KVM_S390_FLIC,
606                         TYPE_KVM_S390_FLIC)
607  
608  
609  static void kvm_s390_flic_realize(DeviceState *dev, Error **errp)
610  {
611      KVMS390FLICState *flic_state = KVM_S390_FLIC(dev);
612      struct kvm_create_device cd = {0};
613      struct kvm_device_attr test_attr = {0};
614      int ret;
615      Error *err = NULL;
616  
617      KVM_S390_FLIC_GET_CLASS(dev)->parent_realize(dev, &err);
618      if (err) {
619          error_propagate(errp, err);
620          return;
621      }
622      flic_state->fd = -1;
623  
624      cd.type = KVM_DEV_TYPE_FLIC;
625      ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd);
626      if (ret < 0) {
627          error_setg_errno(errp, errno, "Creating the KVM device failed");
628          trace_flic_create_device(errno);
629          return;
630      }
631      flic_state->fd = cd.fd;
632  
633      /* Check clear_io_irq support */
634      test_attr.group = KVM_DEV_FLIC_CLEAR_IO_IRQ;
635      flic_state->clear_io_supported = !ioctl(flic_state->fd,
636                                              KVM_HAS_DEVICE_ATTR, test_attr);
637  }
638  
kvm_s390_flic_reset(DeviceState * dev)639  static void kvm_s390_flic_reset(DeviceState *dev)
640  {
641      KVMS390FLICState *flic = KVM_S390_FLIC(dev);
642      S390FLICState *fs = S390_FLIC_COMMON(dev);
643      struct kvm_device_attr attr = {
644          .group = KVM_DEV_FLIC_CLEAR_IRQS,
645      };
646      int rc = 0;
647      uint8_t isc;
648  
649      if (flic->fd == -1) {
650          return;
651      }
652  
653      flic_disable_wait_pfault(flic);
654  
655      if (fs->ais_supported) {
656          for (isc = 0; isc <= MAX_ISC; isc++) {
657              rc = kvm_s390_modify_ais_mode(fs, isc, SIC_IRQ_MODE_ALL);
658              if (rc) {
659                  error_report("Failed to reset ais mode for isc %d: %s",
660                               isc, strerror(-rc));
661              }
662          }
663      }
664  
665      rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
666      if (rc) {
667          trace_flic_reset_failed(errno);
668      }
669  
670      flic_enable_pfault(flic);
671  }
672  
kvm_s390_flic_class_init(ObjectClass * oc,void * data)673  static void kvm_s390_flic_class_init(ObjectClass *oc, void *data)
674  {
675      DeviceClass *dc = DEVICE_CLASS(oc);
676      S390FLICStateClass *fsc = S390_FLIC_COMMON_CLASS(oc);
677      KVMS390FLICStateClass *kfsc = KVM_S390_FLIC_CLASS(oc);
678  
679      device_class_set_parent_realize(dc, kvm_s390_flic_realize,
680                                      &kfsc->parent_realize);
681      dc->vmsd = &kvm_s390_flic_vmstate;
682      device_class_set_legacy_reset(dc, kvm_s390_flic_reset);
683      fsc->register_io_adapter = kvm_s390_register_io_adapter;
684      fsc->io_adapter_map = kvm_s390_io_adapter_map;
685      fsc->add_adapter_routes = kvm_s390_add_adapter_routes;
686      fsc->release_adapter_routes = kvm_s390_release_adapter_routes;
687      fsc->clear_io_irq = kvm_s390_clear_io_flic;
688      fsc->modify_ais_mode = kvm_s390_modify_ais_mode;
689      fsc->inject_airq = kvm_s390_inject_airq;
690      fsc->inject_service = kvm_s390_inject_service;
691      fsc->inject_io = kvm_s390_inject_io;
692      fsc->inject_crw_mchk = kvm_s390_inject_crw_mchk;
693  }
694  
695  static const TypeInfo kvm_s390_flic_info = {
696      .name          = TYPE_KVM_S390_FLIC,
697      .parent        = TYPE_S390_FLIC_COMMON,
698      .instance_size = sizeof(KVMS390FLICState),
699      .class_size    = sizeof(KVMS390FLICStateClass),
700      .class_init    = kvm_s390_flic_class_init,
701  };
702  
kvm_s390_flic_register_types(void)703  static void kvm_s390_flic_register_types(void)
704  {
705      type_register_static(&kvm_s390_flic_info);
706  }
707  
708  type_init(kvm_s390_flic_register_types)
709