loongson_ipi.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Loongson-3 Virtual IPI interrupt support.
  4. *
  5. * Copyright (C) 2019 Loongson Technologies, Inc. All rights reserved.
  6. *
  7. * Authors: Chen Zhu <[email protected]>
  8. * Authors: Huacai Chen <[email protected]>
  9. */
  10. #include <linux/kvm_host.h>
  11. #define IPI_BASE 0x3ff01000ULL
  12. #define CORE0_STATUS_OFF 0x000
  13. #define CORE0_EN_OFF 0x004
  14. #define CORE0_SET_OFF 0x008
  15. #define CORE0_CLEAR_OFF 0x00c
  16. #define CORE0_BUF_20 0x020
  17. #define CORE0_BUF_28 0x028
  18. #define CORE0_BUF_30 0x030
  19. #define CORE0_BUF_38 0x038
  20. #define CORE1_STATUS_OFF 0x100
  21. #define CORE1_EN_OFF 0x104
  22. #define CORE1_SET_OFF 0x108
  23. #define CORE1_CLEAR_OFF 0x10c
  24. #define CORE1_BUF_20 0x120
  25. #define CORE1_BUF_28 0x128
  26. #define CORE1_BUF_30 0x130
  27. #define CORE1_BUF_38 0x138
  28. #define CORE2_STATUS_OFF 0x200
  29. #define CORE2_EN_OFF 0x204
  30. #define CORE2_SET_OFF 0x208
  31. #define CORE2_CLEAR_OFF 0x20c
  32. #define CORE2_BUF_20 0x220
  33. #define CORE2_BUF_28 0x228
  34. #define CORE2_BUF_30 0x230
  35. #define CORE2_BUF_38 0x238
  36. #define CORE3_STATUS_OFF 0x300
  37. #define CORE3_EN_OFF 0x304
  38. #define CORE3_SET_OFF 0x308
  39. #define CORE3_CLEAR_OFF 0x30c
  40. #define CORE3_BUF_20 0x320
  41. #define CORE3_BUF_28 0x328
  42. #define CORE3_BUF_30 0x330
  43. #define CORE3_BUF_38 0x338
  44. static int loongson_vipi_read(struct loongson_kvm_ipi *ipi,
  45. gpa_t addr, int len, void *val)
  46. {
  47. uint32_t core = (addr >> 8) & 3;
  48. uint32_t node = (addr >> 44) & 3;
  49. uint32_t id = core + node * 4;
  50. uint64_t offset = addr & 0xff;
  51. void *pbuf;
  52. struct ipi_state *s = &(ipi->ipistate[id]);
  53. BUG_ON(offset & (len - 1));
  54. switch (offset) {
  55. case CORE0_STATUS_OFF:
  56. *(uint64_t *)val = s->status;
  57. break;
  58. case CORE0_EN_OFF:
  59. *(uint64_t *)val = s->en;
  60. break;
  61. case CORE0_SET_OFF:
  62. *(uint64_t *)val = 0;
  63. break;
  64. case CORE0_CLEAR_OFF:
  65. *(uint64_t *)val = 0;
  66. break;
  67. case CORE0_BUF_20 ... CORE0_BUF_38:
  68. pbuf = (void *)s->buf + (offset - 0x20);
  69. if (len == 8)
  70. *(uint64_t *)val = *(uint64_t *)pbuf;
  71. else /* Assume len == 4 */
  72. *(uint32_t *)val = *(uint32_t *)pbuf;
  73. break;
  74. default:
  75. pr_notice("%s with unknown addr %llx\n", __func__, addr);
  76. break;
  77. }
  78. return 0;
  79. }
  80. static int loongson_vipi_write(struct loongson_kvm_ipi *ipi,
  81. gpa_t addr, int len, const void *val)
  82. {
  83. uint32_t core = (addr >> 8) & 3;
  84. uint32_t node = (addr >> 44) & 3;
  85. uint32_t id = core + node * 4;
  86. uint64_t data, offset = addr & 0xff;
  87. void *pbuf;
  88. struct kvm *kvm = ipi->kvm;
  89. struct kvm_mips_interrupt irq;
  90. struct ipi_state *s = &(ipi->ipistate[id]);
  91. data = *(uint64_t *)val;
  92. BUG_ON(offset & (len - 1));
  93. switch (offset) {
  94. case CORE0_STATUS_OFF:
  95. break;
  96. case CORE0_EN_OFF:
  97. s->en = data;
  98. break;
  99. case CORE0_SET_OFF:
  100. s->status |= data;
  101. irq.cpu = id;
  102. irq.irq = 6;
  103. kvm_vcpu_ioctl_interrupt(kvm_get_vcpu(kvm, id), &irq);
  104. break;
  105. case CORE0_CLEAR_OFF:
  106. s->status &= ~data;
  107. if (!s->status) {
  108. irq.cpu = id;
  109. irq.irq = -6;
  110. kvm_vcpu_ioctl_interrupt(kvm_get_vcpu(kvm, id), &irq);
  111. }
  112. break;
  113. case CORE0_BUF_20 ... CORE0_BUF_38:
  114. pbuf = (void *)s->buf + (offset - 0x20);
  115. if (len == 8)
  116. *(uint64_t *)pbuf = (uint64_t)data;
  117. else /* Assume len == 4 */
  118. *(uint32_t *)pbuf = (uint32_t)data;
  119. break;
  120. default:
  121. pr_notice("%s with unknown addr %llx\n", __func__, addr);
  122. break;
  123. }
  124. return 0;
  125. }
  126. static int kvm_ipi_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
  127. gpa_t addr, int len, void *val)
  128. {
  129. unsigned long flags;
  130. struct loongson_kvm_ipi *ipi;
  131. struct ipi_io_device *ipi_device;
  132. ipi_device = container_of(dev, struct ipi_io_device, device);
  133. ipi = ipi_device->ipi;
  134. spin_lock_irqsave(&ipi->lock, flags);
  135. loongson_vipi_read(ipi, addr, len, val);
  136. spin_unlock_irqrestore(&ipi->lock, flags);
  137. return 0;
  138. }
  139. static int kvm_ipi_write(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
  140. gpa_t addr, int len, const void *val)
  141. {
  142. unsigned long flags;
  143. struct loongson_kvm_ipi *ipi;
  144. struct ipi_io_device *ipi_device;
  145. ipi_device = container_of(dev, struct ipi_io_device, device);
  146. ipi = ipi_device->ipi;
  147. spin_lock_irqsave(&ipi->lock, flags);
  148. loongson_vipi_write(ipi, addr, len, val);
  149. spin_unlock_irqrestore(&ipi->lock, flags);
  150. return 0;
  151. }
  152. static const struct kvm_io_device_ops kvm_ipi_ops = {
  153. .read = kvm_ipi_read,
  154. .write = kvm_ipi_write,
  155. };
  156. void kvm_init_loongson_ipi(struct kvm *kvm)
  157. {
  158. int i;
  159. unsigned long addr;
  160. struct loongson_kvm_ipi *s;
  161. struct kvm_io_device *device;
  162. s = &kvm->arch.ipi;
  163. s->kvm = kvm;
  164. spin_lock_init(&s->lock);
  165. /*
  166. * Initialize IPI device
  167. */
  168. for (i = 0; i < 4; i++) {
  169. device = &s->dev_ipi[i].device;
  170. kvm_iodevice_init(device, &kvm_ipi_ops);
  171. addr = (((unsigned long)i) << 44) + IPI_BASE;
  172. mutex_lock(&kvm->slots_lock);
  173. kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, addr, 0x400, device);
  174. mutex_unlock(&kvm->slots_lock);
  175. s->dev_ipi[i].ipi = s;
  176. s->dev_ipi[i].node_id = i;
  177. }
  178. }