loongarch_ipi.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. /* SPDX-License-Identifier: GPL-2.0-or-later */
  2. /*
  3. * LoongArch ipi interrupt support
  4. *
  5. * Copyright (C) 2021 Loongson Technology Corporation Limited
  6. */
  7. #include "qemu/osdep.h"
  8. #include "hw/sysbus.h"
  9. #include "hw/intc/loongarch_ipi.h"
  10. #include "hw/irq.h"
  11. #include "qapi/error.h"
  12. #include "qemu/log.h"
  13. #include "exec/address-spaces.h"
  14. #include "hw/loongarch/virt.h"
  15. #include "migration/vmstate.h"
  16. #include "target/loongarch/internals.h"
  17. #include "trace.h"
  18. static uint64_t loongarch_ipi_readl(void *opaque, hwaddr addr, unsigned size)
  19. {
  20. IPICore *s = opaque;
  21. uint64_t ret = 0;
  22. int index = 0;
  23. addr &= 0xff;
  24. switch (addr) {
  25. case CORE_STATUS_OFF:
  26. ret = s->status;
  27. break;
  28. case CORE_EN_OFF:
  29. ret = s->en;
  30. break;
  31. case CORE_SET_OFF:
  32. ret = 0;
  33. break;
  34. case CORE_CLEAR_OFF:
  35. ret = 0;
  36. break;
  37. case CORE_BUF_20 ... CORE_BUF_38 + 4:
  38. index = (addr - CORE_BUF_20) >> 2;
  39. ret = s->buf[index];
  40. break;
  41. default:
  42. qemu_log_mask(LOG_UNIMP, "invalid read: %x", (uint32_t)addr);
  43. break;
  44. }
  45. trace_loongarch_ipi_read(size, (uint64_t)addr, ret);
  46. return ret;
  47. }
  48. static void send_ipi_data(CPULoongArchState *env, target_ulong val, target_ulong addr)
  49. {
  50. int i, mask = 0, data = 0;
  51. /*
  52. * bit 27-30 is mask for byte writing,
  53. * if the mask is 0, we need not to do anything.
  54. */
  55. if ((val >> 27) & 0xf) {
  56. data = address_space_ldl(&env->address_space_iocsr, addr,
  57. MEMTXATTRS_UNSPECIFIED, NULL);
  58. for (i = 0; i < 4; i++) {
  59. /* get mask for byte writing */
  60. if (val & (0x1 << (27 + i))) {
  61. mask |= 0xff << (i * 8);
  62. }
  63. }
  64. }
  65. data &= mask;
  66. data |= (val >> 32) & ~mask;
  67. address_space_stl(&env->address_space_iocsr, addr,
  68. data, MEMTXATTRS_UNSPECIFIED, NULL);
  69. }
  70. static void ipi_send(uint64_t val)
  71. {
  72. int cpuid, data;
  73. CPULoongArchState *env;
  74. CPUState *cs;
  75. LoongArchCPU *cpu;
  76. cpuid = (val >> 16) & 0x3ff;
  77. /* IPI status vector */
  78. data = 1 << (val & 0x1f);
  79. cs = qemu_get_cpu(cpuid);
  80. cpu = LOONGARCH_CPU(cs);
  81. env = &cpu->env;
  82. address_space_stl(&env->address_space_iocsr, 0x1008,
  83. data, MEMTXATTRS_UNSPECIFIED, NULL);
  84. }
  85. static void mail_send(uint64_t val)
  86. {
  87. int cpuid;
  88. hwaddr addr;
  89. CPULoongArchState *env;
  90. CPUState *cs;
  91. LoongArchCPU *cpu;
  92. cpuid = (val >> 16) & 0x3ff;
  93. addr = 0x1020 + (val & 0x1c);
  94. cs = qemu_get_cpu(cpuid);
  95. cpu = LOONGARCH_CPU(cs);
  96. env = &cpu->env;
  97. send_ipi_data(env, val, addr);
  98. }
  99. static void any_send(uint64_t val)
  100. {
  101. int cpuid;
  102. hwaddr addr;
  103. CPULoongArchState *env;
  104. cpuid = (val >> 16) & 0x3ff;
  105. addr = val & 0xffff;
  106. CPUState *cs = qemu_get_cpu(cpuid);
  107. LoongArchCPU *cpu = LOONGARCH_CPU(cs);
  108. env = &cpu->env;
  109. send_ipi_data(env, val, addr);
  110. }
  111. static void loongarch_ipi_writel(void *opaque, hwaddr addr, uint64_t val,
  112. unsigned size)
  113. {
  114. IPICore *s = opaque;
  115. int index = 0;
  116. addr &= 0xff;
  117. trace_loongarch_ipi_write(size, (uint64_t)addr, val);
  118. switch (addr) {
  119. case CORE_STATUS_OFF:
  120. qemu_log_mask(LOG_GUEST_ERROR, "can not be written");
  121. break;
  122. case CORE_EN_OFF:
  123. s->en = val;
  124. break;
  125. case CORE_SET_OFF:
  126. s->status |= val;
  127. if (s->status != 0 && (s->status & s->en) != 0) {
  128. qemu_irq_raise(s->irq);
  129. }
  130. break;
  131. case CORE_CLEAR_OFF:
  132. s->status &= ~val;
  133. if (s->status == 0 && s->en != 0) {
  134. qemu_irq_lower(s->irq);
  135. }
  136. break;
  137. case CORE_BUF_20 ... CORE_BUF_38 + 4:
  138. index = (addr - CORE_BUF_20) >> 2;
  139. s->buf[index] = val;
  140. break;
  141. case IOCSR_IPI_SEND:
  142. ipi_send(val);
  143. break;
  144. default:
  145. qemu_log_mask(LOG_UNIMP, "invalid write: %x", (uint32_t)addr);
  146. break;
  147. }
  148. }
  149. static const MemoryRegionOps loongarch_ipi_ops = {
  150. .read = loongarch_ipi_readl,
  151. .write = loongarch_ipi_writel,
  152. .impl.min_access_size = 4,
  153. .impl.max_access_size = 4,
  154. .valid.min_access_size = 4,
  155. .valid.max_access_size = 8,
  156. .endianness = DEVICE_LITTLE_ENDIAN,
  157. };
  158. /* mail send and any send only support writeq */
  159. static void loongarch_ipi_writeq(void *opaque, hwaddr addr, uint64_t val,
  160. unsigned size)
  161. {
  162. addr &= 0xfff;
  163. switch (addr) {
  164. case MAIL_SEND_OFFSET:
  165. mail_send(val);
  166. break;
  167. case ANY_SEND_OFFSET:
  168. any_send(val);
  169. break;
  170. default:
  171. break;
  172. }
  173. }
  174. static const MemoryRegionOps loongarch_ipi64_ops = {
  175. .write = loongarch_ipi_writeq,
  176. .impl.min_access_size = 8,
  177. .impl.max_access_size = 8,
  178. .valid.min_access_size = 8,
  179. .valid.max_access_size = 8,
  180. .endianness = DEVICE_LITTLE_ENDIAN,
  181. };
  182. static void loongarch_ipi_init(Object *obj)
  183. {
  184. int cpu;
  185. LoongArchMachineState *lams;
  186. LoongArchIPI *s = LOONGARCH_IPI(obj);
  187. SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
  188. Object *machine = qdev_get_machine();
  189. ObjectClass *mc = object_get_class(machine);
  190. /* 'lams' should be initialized */
  191. if (!strcmp(MACHINE_CLASS(mc)->name, "none")) {
  192. return;
  193. }
  194. lams = LOONGARCH_MACHINE(machine);
  195. for (cpu = 0; cpu < MAX_IPI_CORE_NUM; cpu++) {
  196. memory_region_init_io(&s->ipi_iocsr_mem[cpu], obj, &loongarch_ipi_ops,
  197. &lams->ipi_core[cpu], "loongarch_ipi_iocsr", 0x48);
  198. sysbus_init_mmio(sbd, &s->ipi_iocsr_mem[cpu]);
  199. memory_region_init_io(&s->ipi64_iocsr_mem[cpu], obj, &loongarch_ipi64_ops,
  200. &lams->ipi_core[cpu], "loongarch_ipi64_iocsr", 0x118);
  201. sysbus_init_mmio(sbd, &s->ipi64_iocsr_mem[cpu]);
  202. qdev_init_gpio_out(DEVICE(obj), &lams->ipi_core[cpu].irq, 1);
  203. }
  204. }
  205. static const VMStateDescription vmstate_ipi_core = {
  206. .name = "ipi-single",
  207. .version_id = 0,
  208. .minimum_version_id = 0,
  209. .fields = (VMStateField[]) {
  210. VMSTATE_UINT32(status, IPICore),
  211. VMSTATE_UINT32(en, IPICore),
  212. VMSTATE_UINT32(set, IPICore),
  213. VMSTATE_UINT32(clear, IPICore),
  214. VMSTATE_UINT32_ARRAY(buf, IPICore, MAX_IPI_MBX_NUM * 2),
  215. VMSTATE_END_OF_LIST()
  216. }
  217. };
  218. static const VMStateDescription vmstate_loongarch_ipi = {
  219. .name = TYPE_LOONGARCH_IPI,
  220. .version_id = 0,
  221. .minimum_version_id = 0,
  222. .fields = (VMStateField[]) {
  223. VMSTATE_STRUCT_ARRAY(ipi_core, LoongArchMachineState,
  224. MAX_IPI_CORE_NUM, 0,
  225. vmstate_ipi_core, IPICore),
  226. VMSTATE_END_OF_LIST()
  227. }
  228. };
  229. static void loongarch_ipi_class_init(ObjectClass *klass, void *data)
  230. {
  231. DeviceClass *dc = DEVICE_CLASS(klass);
  232. dc->vmsd = &vmstate_loongarch_ipi;
  233. }
  234. static const TypeInfo loongarch_ipi_info = {
  235. .name = TYPE_LOONGARCH_IPI,
  236. .parent = TYPE_SYS_BUS_DEVICE,
  237. .instance_size = sizeof(LoongArchIPI),
  238. .instance_init = loongarch_ipi_init,
  239. .class_init = loongarch_ipi_class_init,
  240. };
  241. static void loongarch_ipi_register_types(void)
  242. {
  243. type_register_static(&loongarch_ipi_info);
  244. }
  245. type_init(loongarch_ipi_register_types)