loongarch_ipi.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. /* SPDX-License-Identifier: GPL-2.0-or-later */
  2. /*
  3. * LoongArch IPI interrupt support
  4. *
  5. * Copyright (C) 2024 Loongson Technology Corporation Limited
  6. */
  7. #include "qemu/osdep.h"
  8. #include "qemu/error-report.h"
  9. #include "hw/boards.h"
  10. #include "qapi/error.h"
  11. #include "hw/intc/loongarch_ipi.h"
  12. #include "hw/qdev-properties.h"
  13. #include "target/loongarch/cpu.h"
  14. static AddressSpace *get_iocsr_as(CPUState *cpu)
  15. {
  16. return LOONGARCH_CPU(cpu)->env.address_space_iocsr;
  17. }
  18. static int loongarch_ipi_cmp(const void *a, const void *b)
  19. {
  20. IPICore *ipi_a = (IPICore *)a;
  21. IPICore *ipi_b = (IPICore *)b;
  22. return ipi_a->arch_id - ipi_b->arch_id;
  23. }
  24. static int loongarch_cpu_by_arch_id(LoongsonIPICommonState *lics,
  25. int64_t arch_id, int *index, CPUState **pcs)
  26. {
  27. IPICore ipi, *found;
  28. ipi.arch_id = arch_id;
  29. found = bsearch(&ipi, lics->cpu, lics->num_cpu, sizeof(IPICore),
  30. loongarch_ipi_cmp);
  31. if (found && found->cpu) {
  32. if (index) {
  33. *index = found - lics->cpu;
  34. }
  35. if (pcs) {
  36. *pcs = found->cpu;
  37. }
  38. return MEMTX_OK;
  39. }
  40. return MEMTX_ERROR;
  41. }
  42. static IPICore *loongarch_ipi_get_cpu(LoongsonIPICommonState *lics,
  43. DeviceState *dev)
  44. {
  45. CPUClass *k = CPU_GET_CLASS(dev);
  46. uint64_t arch_id = k->get_arch_id(CPU(dev));
  47. int i;
  48. for (i = 0; i < lics->num_cpu; i++) {
  49. if (lics->cpu[i].arch_id == arch_id) {
  50. return &lics->cpu[i];
  51. }
  52. }
  53. return NULL;
  54. }
  55. static void loongarch_ipi_realize(DeviceState *dev, Error **errp)
  56. {
  57. LoongsonIPICommonState *lics = LOONGSON_IPI_COMMON(dev);
  58. LoongarchIPIClass *lic = LOONGARCH_IPI_GET_CLASS(dev);
  59. MachineState *machine = MACHINE(qdev_get_machine());
  60. MachineClass *mc = MACHINE_GET_CLASS(machine);
  61. const CPUArchIdList *id_list;
  62. Error *local_err = NULL;
  63. int i;
  64. lic->parent_realize(dev, &local_err);
  65. if (local_err) {
  66. error_propagate(errp, local_err);
  67. return;
  68. }
  69. assert(mc->possible_cpu_arch_ids);
  70. id_list = mc->possible_cpu_arch_ids(machine);
  71. lics->num_cpu = id_list->len;
  72. lics->cpu = g_new0(IPICore, lics->num_cpu);
  73. for (i = 0; i < lics->num_cpu; i++) {
  74. lics->cpu[i].arch_id = id_list->cpus[i].arch_id;
  75. lics->cpu[i].cpu = CPU(id_list->cpus[i].cpu);
  76. lics->cpu[i].ipi = lics;
  77. qdev_init_gpio_out(dev, &lics->cpu[i].irq, 1);
  78. }
  79. }
  80. static void loongarch_ipi_cpu_plug(HotplugHandler *hotplug_dev,
  81. DeviceState *dev, Error **errp)
  82. {
  83. LoongsonIPICommonState *lics = LOONGSON_IPI_COMMON(hotplug_dev);
  84. Object *obj = OBJECT(dev);
  85. IPICore *core;
  86. int index;
  87. if (!object_dynamic_cast(obj, TYPE_LOONGARCH_CPU)) {
  88. warn_report("LoongArch extioi: Invalid %s device type",
  89. object_get_typename(obj));
  90. return;
  91. }
  92. core = loongarch_ipi_get_cpu(lics, dev);
  93. if (!core) {
  94. return;
  95. }
  96. core->cpu = CPU(dev);
  97. index = core - lics->cpu;
  98. /* connect ipi irq to cpu irq */
  99. qdev_connect_gpio_out(DEVICE(lics), index, qdev_get_gpio_in(dev, IRQ_IPI));
  100. }
  101. static void loongarch_ipi_cpu_unplug(HotplugHandler *hotplug_dev,
  102. DeviceState *dev, Error **errp)
  103. {
  104. LoongsonIPICommonState *lics = LOONGSON_IPI_COMMON(hotplug_dev);
  105. Object *obj = OBJECT(dev);
  106. IPICore *core;
  107. if (!object_dynamic_cast(obj, TYPE_LOONGARCH_CPU)) {
  108. warn_report("LoongArch extioi: Invalid %s device type",
  109. object_get_typename(obj));
  110. return;
  111. }
  112. core = loongarch_ipi_get_cpu(lics, dev);
  113. if (!core) {
  114. return;
  115. }
  116. core->cpu = NULL;
  117. }
  118. static void loongarch_ipi_class_init(ObjectClass *klass, void *data)
  119. {
  120. LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_CLASS(klass);
  121. HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
  122. LoongarchIPIClass *lic = LOONGARCH_IPI_CLASS(klass);
  123. DeviceClass *dc = DEVICE_CLASS(klass);
  124. device_class_set_parent_realize(dc, loongarch_ipi_realize,
  125. &lic->parent_realize);
  126. licc->get_iocsr_as = get_iocsr_as;
  127. licc->cpu_by_arch_id = loongarch_cpu_by_arch_id;
  128. hc->plug = loongarch_ipi_cpu_plug;
  129. hc->unplug = loongarch_ipi_cpu_unplug;
  130. }
  131. static const TypeInfo loongarch_ipi_types[] = {
  132. {
  133. .name = TYPE_LOONGARCH_IPI,
  134. .parent = TYPE_LOONGSON_IPI_COMMON,
  135. .instance_size = sizeof(LoongarchIPIState),
  136. .class_size = sizeof(LoongarchIPIClass),
  137. .class_init = loongarch_ipi_class_init,
  138. .interfaces = (InterfaceInfo[]) {
  139. { TYPE_HOTPLUG_HANDLER },
  140. { }
  141. },
  142. }
  143. };
  144. DEFINE_TYPES(loongarch_ipi_types)