loongarch_extioi_common.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. /* SPDX-License-Identifier: GPL-2.0-or-later */
  2. /*
  3. * Loongson extioi interrupt controller emulation
  4. * Copyright (C) 2024 Loongson Technology Corporation Limited
  5. */
  6. #include "qemu/osdep.h"
  7. #include "qemu/error-report.h"
  8. #include "qemu/module.h"
  9. #include "qapi/error.h"
  10. #include "hw/qdev-properties.h"
  11. #include "hw/intc/loongarch_extioi_common.h"
  12. #include "migration/vmstate.h"
  13. #include "target/loongarch/cpu.h"
  14. static ExtIOICore *loongarch_extioi_get_cpu(LoongArchExtIOICommonState *s,
  15. DeviceState *dev)
  16. {
  17. CPUClass *k = CPU_GET_CLASS(dev);
  18. uint64_t arch_id = k->get_arch_id(CPU(dev));
  19. int i;
  20. for (i = 0; i < s->num_cpu; i++) {
  21. if (s->cpu[i].arch_id == arch_id) {
  22. return &s->cpu[i];
  23. }
  24. }
  25. return NULL;
  26. }
  27. static void loongarch_extioi_cpu_plug(HotplugHandler *hotplug_dev,
  28. DeviceState *dev, Error **errp)
  29. {
  30. LoongArchExtIOICommonState *s = LOONGARCH_EXTIOI_COMMON(hotplug_dev);
  31. Object *obj = OBJECT(dev);
  32. ExtIOICore *core;
  33. int pin, index;
  34. if (!object_dynamic_cast(obj, TYPE_LOONGARCH_CPU)) {
  35. warn_report("LoongArch extioi: Invalid %s device type",
  36. object_get_typename(obj));
  37. return;
  38. }
  39. core = loongarch_extioi_get_cpu(s, dev);
  40. if (!core) {
  41. return;
  42. }
  43. core->cpu = CPU(dev);
  44. index = core - s->cpu;
  45. /*
  46. * connect extioi irq to the cpu irq
  47. * cpu_pin[LS3A_INTC_IP + 2 : 2] <= intc_pin[LS3A_INTC_IP : 0]
  48. */
  49. for (pin = 0; pin < LS3A_INTC_IP; pin++) {
  50. qdev_connect_gpio_out(DEVICE(s), index * LS3A_INTC_IP + pin,
  51. qdev_get_gpio_in(dev, pin + 2));
  52. }
  53. }
  54. static void loongarch_extioi_cpu_unplug(HotplugHandler *hotplug_dev,
  55. DeviceState *dev, Error **errp)
  56. {
  57. LoongArchExtIOICommonState *s = LOONGARCH_EXTIOI_COMMON(hotplug_dev);
  58. Object *obj = OBJECT(dev);
  59. ExtIOICore *core;
  60. if (!object_dynamic_cast(obj, TYPE_LOONGARCH_CPU)) {
  61. warn_report("LoongArch extioi: Invalid %s device type",
  62. object_get_typename(obj));
  63. return;
  64. }
  65. core = loongarch_extioi_get_cpu(s, dev);
  66. if (!core) {
  67. return;
  68. }
  69. core->cpu = NULL;
  70. }
  71. static void loongarch_extioi_common_realize(DeviceState *dev, Error **errp)
  72. {
  73. LoongArchExtIOICommonState *s = (LoongArchExtIOICommonState *)dev;
  74. MachineState *machine = MACHINE(qdev_get_machine());
  75. MachineClass *mc = MACHINE_GET_CLASS(machine);
  76. const CPUArchIdList *id_list;
  77. int i, pin;
  78. assert(mc->possible_cpu_arch_ids);
  79. id_list = mc->possible_cpu_arch_ids(machine);
  80. s->num_cpu = id_list->len;
  81. s->cpu = g_new0(ExtIOICore, s->num_cpu);
  82. if (s->cpu == NULL) {
  83. error_setg(errp, "Memory allocation for ExtIOICore faile");
  84. return;
  85. }
  86. for (i = 0; i < s->num_cpu; i++) {
  87. s->cpu[i].arch_id = id_list->cpus[i].arch_id;
  88. s->cpu[i].cpu = CPU(id_list->cpus[i].cpu);
  89. for (pin = 0; pin < LS3A_INTC_IP; pin++) {
  90. qdev_init_gpio_out(dev, &s->cpu[i].parent_irq[pin], 1);
  91. }
  92. }
  93. }
  94. static int loongarch_extioi_common_pre_save(void *opaque)
  95. {
  96. LoongArchExtIOICommonState *s = (LoongArchExtIOICommonState *)opaque;
  97. LoongArchExtIOICommonClass *lecc = LOONGARCH_EXTIOI_COMMON_GET_CLASS(s);
  98. if (lecc->pre_save) {
  99. return lecc->pre_save(s);
  100. }
  101. return 0;
  102. }
  103. static int loongarch_extioi_common_post_load(void *opaque, int version_id)
  104. {
  105. LoongArchExtIOICommonState *s = (LoongArchExtIOICommonState *)opaque;
  106. LoongArchExtIOICommonClass *lecc = LOONGARCH_EXTIOI_COMMON_GET_CLASS(s);
  107. if (lecc->post_load) {
  108. return lecc->post_load(s, version_id);
  109. }
  110. return 0;
  111. }
  112. static const VMStateDescription vmstate_extioi_core = {
  113. .name = "extioi-core",
  114. .version_id = 1,
  115. .minimum_version_id = 1,
  116. .fields = (const VMStateField[]) {
  117. VMSTATE_UINT32_ARRAY(coreisr, ExtIOICore, EXTIOI_IRQS_GROUP_COUNT),
  118. VMSTATE_END_OF_LIST()
  119. }
  120. };
  121. static const VMStateDescription vmstate_loongarch_extioi = {
  122. .name = "loongarch.extioi",
  123. .version_id = 3,
  124. .minimum_version_id = 3,
  125. .pre_save = loongarch_extioi_common_pre_save,
  126. .post_load = loongarch_extioi_common_post_load,
  127. .fields = (const VMStateField[]) {
  128. VMSTATE_UINT32_ARRAY(bounce, LoongArchExtIOICommonState,
  129. EXTIOI_IRQS_GROUP_COUNT),
  130. VMSTATE_UINT32_ARRAY(nodetype, LoongArchExtIOICommonState,
  131. EXTIOI_IRQS_NODETYPE_COUNT / 2),
  132. VMSTATE_UINT32_ARRAY(enable, LoongArchExtIOICommonState,
  133. EXTIOI_IRQS / 32),
  134. VMSTATE_UINT32_ARRAY(isr, LoongArchExtIOICommonState,
  135. EXTIOI_IRQS / 32),
  136. VMSTATE_UINT32_ARRAY(ipmap, LoongArchExtIOICommonState,
  137. EXTIOI_IRQS_IPMAP_SIZE / 4),
  138. VMSTATE_UINT32_ARRAY(coremap, LoongArchExtIOICommonState,
  139. EXTIOI_IRQS / 4),
  140. VMSTATE_STRUCT_VARRAY_POINTER_UINT32(cpu, LoongArchExtIOICommonState,
  141. num_cpu, vmstate_extioi_core, ExtIOICore),
  142. VMSTATE_UINT32(features, LoongArchExtIOICommonState),
  143. VMSTATE_UINT32(status, LoongArchExtIOICommonState),
  144. VMSTATE_END_OF_LIST()
  145. }
  146. };
  147. static const Property extioi_properties[] = {
  148. DEFINE_PROP_BIT("has-virtualization-extension", LoongArchExtIOICommonState,
  149. features, EXTIOI_HAS_VIRT_EXTENSION, 0),
  150. };
  151. static void loongarch_extioi_common_class_init(ObjectClass *klass, void *data)
  152. {
  153. DeviceClass *dc = DEVICE_CLASS(klass);
  154. LoongArchExtIOICommonClass *lecc = LOONGARCH_EXTIOI_COMMON_CLASS(klass);
  155. HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
  156. device_class_set_parent_realize(dc, loongarch_extioi_common_realize,
  157. &lecc->parent_realize);
  158. device_class_set_props(dc, extioi_properties);
  159. dc->vmsd = &vmstate_loongarch_extioi;
  160. hc->plug = loongarch_extioi_cpu_plug;
  161. hc->unplug = loongarch_extioi_cpu_unplug;
  162. }
  163. static const TypeInfo loongarch_extioi_common_types[] = {
  164. {
  165. .name = TYPE_LOONGARCH_EXTIOI_COMMON,
  166. .parent = TYPE_SYS_BUS_DEVICE,
  167. .instance_size = sizeof(LoongArchExtIOICommonState),
  168. .class_size = sizeof(LoongArchExtIOICommonClass),
  169. .class_init = loongarch_extioi_common_class_init,
  170. .interfaces = (InterfaceInfo[]) {
  171. { TYPE_HOTPLUG_HANDLER },
  172. { }
  173. },
  174. .abstract = true,
  175. }
  176. };
  177. DEFINE_TYPES(loongarch_extioi_common_types)