s390_flic_kvm.c 19 KB

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