loongson_ipi_common.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. /* SPDX-License-Identifier: GPL-2.0-or-later */
  2. /*
  3. * Loongson IPI interrupt common 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/loongson_ipi_common.h"
  10. #include "hw/irq.h"
  11. #include "qemu/log.h"
  12. #include "migration/vmstate.h"
  13. #include "trace.h"
  14. MemTxResult loongson_ipi_core_readl(void *opaque, hwaddr addr, uint64_t *data,
  15. unsigned size, MemTxAttrs attrs)
  16. {
  17. IPICore *s = opaque;
  18. uint64_t ret = 0;
  19. int index = 0;
  20. addr &= 0xff;
  21. switch (addr) {
  22. case CORE_STATUS_OFF:
  23. ret = s->status;
  24. break;
  25. case CORE_EN_OFF:
  26. ret = s->en;
  27. break;
  28. case CORE_SET_OFF:
  29. ret = 0;
  30. break;
  31. case CORE_CLEAR_OFF:
  32. ret = 0;
  33. break;
  34. case CORE_BUF_20 ... CORE_BUF_38 + 4:
  35. index = (addr - CORE_BUF_20) >> 2;
  36. ret = s->buf[index];
  37. break;
  38. default:
  39. qemu_log_mask(LOG_UNIMP, "invalid read: %x", (uint32_t)addr);
  40. break;
  41. }
  42. trace_loongson_ipi_read(size, (uint64_t)addr, ret);
  43. *data = ret;
  44. return MEMTX_OK;
  45. }
  46. static MemTxResult loongson_ipi_iocsr_readl(void *opaque, hwaddr addr,
  47. uint64_t *data, unsigned size,
  48. MemTxAttrs attrs)
  49. {
  50. LoongsonIPICommonState *ipi = opaque;
  51. IPICore *s;
  52. if (attrs.requester_id >= ipi->num_cpu) {
  53. return MEMTX_DECODE_ERROR;
  54. }
  55. s = &ipi->cpu[attrs.requester_id];
  56. return loongson_ipi_core_readl(s, addr, data, size, attrs);
  57. }
  58. static MemTxResult send_ipi_data(LoongsonIPICommonState *ipi, CPUState *cpu,
  59. uint64_t val, hwaddr addr, MemTxAttrs attrs)
  60. {
  61. LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_GET_CLASS(ipi);
  62. int i, mask = 0, data = 0;
  63. AddressSpace *iocsr_as = licc->get_iocsr_as(cpu);
  64. if (!iocsr_as) {
  65. return MEMTX_DECODE_ERROR;
  66. }
  67. /*
  68. * bit 27-30 is mask for byte writing,
  69. * if the mask is 0, we need not to do anything.
  70. */
  71. if ((val >> 27) & 0xf) {
  72. data = address_space_ldl_le(iocsr_as, addr, attrs, NULL);
  73. for (i = 0; i < 4; i++) {
  74. /* get mask for byte writing */
  75. if (val & (0x1 << (27 + i))) {
  76. mask |= 0xff << (i * 8);
  77. }
  78. }
  79. }
  80. data &= mask;
  81. data |= (val >> 32) & ~mask;
  82. address_space_stl_le(iocsr_as, addr, data, attrs, NULL);
  83. return MEMTX_OK;
  84. }
  85. static MemTxResult mail_send(LoongsonIPICommonState *ipi,
  86. uint64_t val, MemTxAttrs attrs)
  87. {
  88. LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_GET_CLASS(ipi);
  89. uint32_t cpuid;
  90. hwaddr addr;
  91. CPUState *cs;
  92. int cpu, ret;
  93. cpuid = extract32(val, 16, 10);
  94. ret = licc->cpu_by_arch_id(ipi, cpuid, &cpu, &cs);
  95. if (ret != MEMTX_OK) {
  96. return MEMTX_DECODE_ERROR;
  97. }
  98. /* override requester_id */
  99. addr = SMP_IPI_MAILBOX + CORE_BUF_20 + (val & 0x1c);
  100. attrs.requester_id = cpu;
  101. return send_ipi_data(ipi, cs, val, addr, attrs);
  102. }
  103. static MemTxResult any_send(LoongsonIPICommonState *ipi,
  104. uint64_t val, MemTxAttrs attrs)
  105. {
  106. LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_GET_CLASS(ipi);
  107. uint32_t cpuid;
  108. hwaddr addr;
  109. CPUState *cs;
  110. int cpu, ret;
  111. cpuid = extract32(val, 16, 10);
  112. ret = licc->cpu_by_arch_id(ipi, cpuid, &cpu, &cs);
  113. if (ret != MEMTX_OK) {
  114. return MEMTX_DECODE_ERROR;
  115. }
  116. /* override requester_id */
  117. addr = val & 0xffff;
  118. attrs.requester_id = cpu;
  119. return send_ipi_data(ipi, cs, val, addr, attrs);
  120. }
  121. MemTxResult loongson_ipi_core_writel(void *opaque, hwaddr addr, uint64_t val,
  122. unsigned size, MemTxAttrs attrs)
  123. {
  124. IPICore *s = opaque;
  125. LoongsonIPICommonState *ipi = s->ipi;
  126. LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_GET_CLASS(ipi);
  127. int index = 0;
  128. uint32_t cpuid;
  129. uint8_t vector;
  130. CPUState *cs;
  131. int cpu, ret;
  132. addr &= 0xff;
  133. trace_loongson_ipi_write(size, (uint64_t)addr, val);
  134. switch (addr) {
  135. case CORE_STATUS_OFF:
  136. qemu_log_mask(LOG_GUEST_ERROR, "can not be written");
  137. break;
  138. case CORE_EN_OFF:
  139. s->en = val;
  140. break;
  141. case CORE_SET_OFF:
  142. s->status |= val;
  143. if (s->status != 0 && (s->status & s->en) != 0) {
  144. qemu_irq_raise(s->irq);
  145. }
  146. break;
  147. case CORE_CLEAR_OFF:
  148. s->status &= ~val;
  149. if (s->status == 0 && s->en != 0) {
  150. qemu_irq_lower(s->irq);
  151. }
  152. break;
  153. case CORE_BUF_20 ... CORE_BUF_38 + 4:
  154. index = (addr - CORE_BUF_20) >> 2;
  155. s->buf[index] = val;
  156. break;
  157. case IOCSR_IPI_SEND:
  158. cpuid = extract32(val, 16, 10);
  159. /* IPI status vector */
  160. vector = extract8(val, 0, 5);
  161. ret = licc->cpu_by_arch_id(ipi, cpuid, &cpu, &cs);
  162. if (ret != MEMTX_OK || cpu >= ipi->num_cpu) {
  163. return MEMTX_DECODE_ERROR;
  164. }
  165. loongson_ipi_core_writel(&ipi->cpu[cpu], CORE_SET_OFF,
  166. BIT(vector), 4, attrs);
  167. break;
  168. default:
  169. qemu_log_mask(LOG_UNIMP, "invalid write: %x", (uint32_t)addr);
  170. break;
  171. }
  172. return MEMTX_OK;
  173. }
  174. static MemTxResult loongson_ipi_iocsr_writel(void *opaque, hwaddr addr,
  175. uint64_t val, unsigned size,
  176. MemTxAttrs attrs)
  177. {
  178. LoongsonIPICommonState *ipi = opaque;
  179. IPICore *s;
  180. if (attrs.requester_id >= ipi->num_cpu) {
  181. return MEMTX_DECODE_ERROR;
  182. }
  183. s = &ipi->cpu[attrs.requester_id];
  184. return loongson_ipi_core_writel(s, addr, val, size, attrs);
  185. }
  186. static const MemoryRegionOps loongson_ipi_iocsr_ops = {
  187. .read_with_attrs = loongson_ipi_iocsr_readl,
  188. .write_with_attrs = loongson_ipi_iocsr_writel,
  189. .impl.min_access_size = 4,
  190. .impl.max_access_size = 4,
  191. .valid.min_access_size = 4,
  192. .valid.max_access_size = 8,
  193. .endianness = DEVICE_LITTLE_ENDIAN,
  194. };
  195. /* mail send and any send only support writeq */
  196. static MemTxResult loongson_ipi_writeq(void *opaque, hwaddr addr, uint64_t val,
  197. unsigned size, MemTxAttrs attrs)
  198. {
  199. LoongsonIPICommonState *ipi = opaque;
  200. MemTxResult ret = MEMTX_OK;
  201. addr &= 0xfff;
  202. switch (addr) {
  203. case MAIL_SEND_OFFSET:
  204. ret = mail_send(ipi, val, attrs);
  205. break;
  206. case ANY_SEND_OFFSET:
  207. ret = any_send(ipi, val, attrs);
  208. break;
  209. default:
  210. break;
  211. }
  212. return ret;
  213. }
  214. static const MemoryRegionOps loongson_ipi64_ops = {
  215. .write_with_attrs = loongson_ipi_writeq,
  216. .impl.min_access_size = 8,
  217. .impl.max_access_size = 8,
  218. .valid.min_access_size = 8,
  219. .valid.max_access_size = 8,
  220. .endianness = DEVICE_LITTLE_ENDIAN,
  221. };
  222. static void loongson_ipi_common_realize(DeviceState *dev, Error **errp)
  223. {
  224. LoongsonIPICommonState *s = LOONGSON_IPI_COMMON(dev);
  225. SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
  226. memory_region_init_io(&s->ipi_iocsr_mem, OBJECT(dev),
  227. &loongson_ipi_iocsr_ops,
  228. s, "loongson_ipi_iocsr", 0x48);
  229. /* loongson_ipi_iocsr performs re-entrant IO through ipi_send */
  230. s->ipi_iocsr_mem.disable_reentrancy_guard = true;
  231. sysbus_init_mmio(sbd, &s->ipi_iocsr_mem);
  232. memory_region_init_io(&s->ipi64_iocsr_mem, OBJECT(dev),
  233. &loongson_ipi64_ops,
  234. s, "loongson_ipi64_iocsr", 0x118);
  235. sysbus_init_mmio(sbd, &s->ipi64_iocsr_mem);
  236. }
  237. static void loongson_ipi_common_unrealize(DeviceState *dev)
  238. {
  239. LoongsonIPICommonState *s = LOONGSON_IPI_COMMON(dev);
  240. g_free(s->cpu);
  241. }
  242. static const VMStateDescription vmstate_ipi_core = {
  243. .name = "ipi-single",
  244. .version_id = 2,
  245. .minimum_version_id = 2,
  246. .fields = (const VMStateField[]) {
  247. VMSTATE_UINT32(status, IPICore),
  248. VMSTATE_UINT32(en, IPICore),
  249. VMSTATE_UINT32(set, IPICore),
  250. VMSTATE_UINT32(clear, IPICore),
  251. VMSTATE_UINT32_ARRAY(buf, IPICore, IPI_MBX_NUM * 2),
  252. VMSTATE_END_OF_LIST()
  253. }
  254. };
  255. static const VMStateDescription vmstate_loongson_ipi_common = {
  256. .name = "loongson_ipi",
  257. .version_id = 2,
  258. .minimum_version_id = 2,
  259. .fields = (const VMStateField[]) {
  260. VMSTATE_STRUCT_VARRAY_POINTER_UINT32(cpu, LoongsonIPICommonState,
  261. num_cpu, vmstate_ipi_core,
  262. IPICore),
  263. VMSTATE_END_OF_LIST()
  264. }
  265. };
  266. static void loongson_ipi_common_class_init(ObjectClass *klass, void *data)
  267. {
  268. DeviceClass *dc = DEVICE_CLASS(klass);
  269. LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_CLASS(klass);
  270. device_class_set_parent_realize(dc, loongson_ipi_common_realize,
  271. &licc->parent_realize);
  272. device_class_set_parent_unrealize(dc, loongson_ipi_common_unrealize,
  273. &licc->parent_unrealize);
  274. dc->vmsd = &vmstate_loongson_ipi_common;
  275. }
  276. static const TypeInfo loongarch_ipi_common_types[] = {
  277. {
  278. .name = TYPE_LOONGSON_IPI_COMMON,
  279. .parent = TYPE_SYS_BUS_DEVICE,
  280. .instance_size = sizeof(LoongsonIPICommonState),
  281. .class_size = sizeof(LoongsonIPICommonClass),
  282. .class_init = loongson_ipi_common_class_init,
  283. .abstract = true,
  284. }
  285. };
  286. DEFINE_TYPES(loongarch_ipi_common_types)