openpic_kvm.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. /*
  2. * KVM in-kernel OpenPIC
  3. *
  4. * Copyright 2013 Freescale Semiconductor, Inc.
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. * THE SOFTWARE.
  23. */
  24. #include <sys/ioctl.h>
  25. #include "exec/address-spaces.h"
  26. #include "hw/hw.h"
  27. #include "hw/ppc/openpic.h"
  28. #include "hw/pci/msi.h"
  29. #include "hw/sysbus.h"
  30. #include "sysemu/kvm.h"
  31. #include "qemu/log.h"
  32. #define GCR_RESET 0x80000000
  33. #define KVM_OPENPIC(obj) \
  34. OBJECT_CHECK(KVMOpenPICState, (obj), TYPE_KVM_OPENPIC)
  35. typedef struct KVMOpenPICState {
  36. /*< private >*/
  37. SysBusDevice parent_obj;
  38. /*< public >*/
  39. MemoryRegion mem;
  40. MemoryListener mem_listener;
  41. uint32_t fd;
  42. uint32_t model;
  43. } KVMOpenPICState;
  44. static void kvm_openpic_set_irq(void *opaque, int n_IRQ, int level)
  45. {
  46. kvm_set_irq(kvm_state, n_IRQ, level);
  47. }
  48. static void kvm_openpic_write(void *opaque, hwaddr addr, uint64_t val,
  49. unsigned size)
  50. {
  51. KVMOpenPICState *opp = opaque;
  52. struct kvm_device_attr attr;
  53. uint32_t val32 = val;
  54. int ret;
  55. attr.group = KVM_DEV_MPIC_GRP_REGISTER;
  56. attr.attr = addr;
  57. attr.addr = (uint64_t)(unsigned long)&val32;
  58. ret = ioctl(opp->fd, KVM_SET_DEVICE_ATTR, &attr);
  59. if (ret < 0) {
  60. qemu_log_mask(LOG_UNIMP, "%s: %s %" PRIx64 "\n", __func__,
  61. strerror(errno), attr.attr);
  62. }
  63. }
  64. static void kvm_openpic_reset(DeviceState *d)
  65. {
  66. KVMOpenPICState *opp = KVM_OPENPIC(d);
  67. /* Trigger the GCR.RESET bit to reset the PIC */
  68. kvm_openpic_write(opp, 0x1020, GCR_RESET, sizeof(uint32_t));
  69. }
  70. static uint64_t kvm_openpic_read(void *opaque, hwaddr addr, unsigned size)
  71. {
  72. KVMOpenPICState *opp = opaque;
  73. struct kvm_device_attr attr;
  74. uint32_t val = 0xdeadbeef;
  75. int ret;
  76. attr.group = KVM_DEV_MPIC_GRP_REGISTER;
  77. attr.attr = addr;
  78. attr.addr = (uint64_t)(unsigned long)&val;
  79. ret = ioctl(opp->fd, KVM_GET_DEVICE_ATTR, &attr);
  80. if (ret < 0) {
  81. qemu_log_mask(LOG_UNIMP, "%s: %s %" PRIx64 "\n", __func__,
  82. strerror(errno), attr.attr);
  83. return 0;
  84. }
  85. return val;
  86. }
  87. static const MemoryRegionOps kvm_openpic_mem_ops = {
  88. .write = kvm_openpic_write,
  89. .read = kvm_openpic_read,
  90. .endianness = DEVICE_BIG_ENDIAN,
  91. .impl = {
  92. .min_access_size = 4,
  93. .max_access_size = 4,
  94. },
  95. };
  96. static void kvm_openpic_region_add(MemoryListener *listener,
  97. MemoryRegionSection *section)
  98. {
  99. KVMOpenPICState *opp = container_of(listener, KVMOpenPICState,
  100. mem_listener);
  101. struct kvm_device_attr attr;
  102. uint64_t reg_base;
  103. int ret;
  104. if (section->address_space != &address_space_memory) {
  105. abort();
  106. }
  107. /* Ignore events on regions that are not us */
  108. if (section->mr != &opp->mem) {
  109. return;
  110. }
  111. reg_base = section->offset_within_address_space;
  112. attr.group = KVM_DEV_MPIC_GRP_MISC;
  113. attr.attr = KVM_DEV_MPIC_BASE_ADDR;
  114. attr.addr = (uint64_t)(unsigned long)&reg_base;
  115. ret = ioctl(opp->fd, KVM_SET_DEVICE_ATTR, &attr);
  116. if (ret < 0) {
  117. fprintf(stderr, "%s: %s %" PRIx64 "\n", __func__,
  118. strerror(errno), reg_base);
  119. }
  120. }
  121. static void kvm_openpic_region_del(MemoryListener *listener,
  122. MemoryRegionSection *section)
  123. {
  124. KVMOpenPICState *opp = container_of(listener, KVMOpenPICState,
  125. mem_listener);
  126. struct kvm_device_attr attr;
  127. uint64_t reg_base = 0;
  128. int ret;
  129. /* Ignore events on regions that are not us */
  130. if (section->mr != &opp->mem) {
  131. return;
  132. }
  133. attr.group = KVM_DEV_MPIC_GRP_MISC;
  134. attr.attr = KVM_DEV_MPIC_BASE_ADDR;
  135. attr.addr = (uint64_t)(unsigned long)&reg_base;
  136. ret = ioctl(opp->fd, KVM_SET_DEVICE_ATTR, &attr);
  137. if (ret < 0) {
  138. fprintf(stderr, "%s: %s %" PRIx64 "\n", __func__,
  139. strerror(errno), reg_base);
  140. }
  141. }
  142. static void kvm_openpic_init(Object *obj)
  143. {
  144. KVMOpenPICState *opp = KVM_OPENPIC(obj);
  145. memory_region_init_io(&opp->mem, OBJECT(opp), &kvm_openpic_mem_ops, opp,
  146. "kvm-openpic", 0x40000);
  147. }
  148. static void kvm_openpic_realize(DeviceState *dev, Error **errp)
  149. {
  150. SysBusDevice *d = SYS_BUS_DEVICE(dev);
  151. KVMOpenPICState *opp = KVM_OPENPIC(dev);
  152. KVMState *s = kvm_state;
  153. int kvm_openpic_model;
  154. struct kvm_create_device cd = {0};
  155. int ret, i;
  156. if (!kvm_check_extension(s, KVM_CAP_DEVICE_CTRL)) {
  157. error_setg(errp, "Kernel is lacking Device Control API");
  158. return;
  159. }
  160. switch (opp->model) {
  161. case OPENPIC_MODEL_FSL_MPIC_20:
  162. kvm_openpic_model = KVM_DEV_TYPE_FSL_MPIC_20;
  163. break;
  164. case OPENPIC_MODEL_FSL_MPIC_42:
  165. kvm_openpic_model = KVM_DEV_TYPE_FSL_MPIC_42;
  166. break;
  167. default:
  168. error_setg(errp, "Unsupported OpenPIC model %" PRIu32, opp->model);
  169. return;
  170. }
  171. cd.type = kvm_openpic_model;
  172. ret = kvm_vm_ioctl(s, KVM_CREATE_DEVICE, &cd);
  173. if (ret < 0) {
  174. error_setg(errp, "Can't create device %d: %s",
  175. cd.type, strerror(errno));
  176. return;
  177. }
  178. opp->fd = cd.fd;
  179. sysbus_init_mmio(d, &opp->mem);
  180. qdev_init_gpio_in(dev, kvm_openpic_set_irq, OPENPIC_MAX_IRQ);
  181. opp->mem_listener.region_add = kvm_openpic_region_add;
  182. opp->mem_listener.region_del = kvm_openpic_region_del;
  183. memory_listener_register(&opp->mem_listener, &address_space_memory);
  184. /* indicate pic capabilities */
  185. msi_supported = true;
  186. kvm_kernel_irqchip = true;
  187. kvm_async_interrupts_allowed = true;
  188. /* set up irq routing */
  189. kvm_init_irq_routing(kvm_state);
  190. for (i = 0; i < 256; ++i) {
  191. kvm_irqchip_add_irq_route(kvm_state, i, 0, i);
  192. }
  193. kvm_irqfds_allowed = true;
  194. kvm_msi_via_irqfd_allowed = true;
  195. kvm_gsi_routing_allowed = true;
  196. kvm_irqchip_commit_routes(s);
  197. }
  198. int kvm_openpic_connect_vcpu(DeviceState *d, CPUState *cs)
  199. {
  200. KVMOpenPICState *opp = KVM_OPENPIC(d);
  201. return kvm_vcpu_enable_cap(cs, KVM_CAP_IRQ_MPIC, 0, opp->fd,
  202. kvm_arch_vcpu_id(cs));
  203. }
  204. static Property kvm_openpic_properties[] = {
  205. DEFINE_PROP_UINT32("model", KVMOpenPICState, model,
  206. OPENPIC_MODEL_FSL_MPIC_20),
  207. DEFINE_PROP_END_OF_LIST(),
  208. };
  209. static void kvm_openpic_class_init(ObjectClass *oc, void *data)
  210. {
  211. DeviceClass *dc = DEVICE_CLASS(oc);
  212. dc->realize = kvm_openpic_realize;
  213. dc->props = kvm_openpic_properties;
  214. dc->reset = kvm_openpic_reset;
  215. }
  216. static const TypeInfo kvm_openpic_info = {
  217. .name = TYPE_KVM_OPENPIC,
  218. .parent = TYPE_SYS_BUS_DEVICE,
  219. .instance_size = sizeof(KVMOpenPICState),
  220. .instance_init = kvm_openpic_init,
  221. .class_init = kvm_openpic_class_init,
  222. };
  223. static void kvm_openpic_register_types(void)
  224. {
  225. type_register_static(&kvm_openpic_info);
  226. }
  227. type_init(kvm_openpic_register_types)