openpic_kvm.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  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 "qemu/osdep.h"
  25. #include "qapi/error.h"
  26. #include "cpu.h"
  27. #include <sys/ioctl.h>
  28. #include "exec/address-spaces.h"
  29. #include "hw/ppc/openpic.h"
  30. #include "hw/ppc/openpic_kvm.h"
  31. #include "hw/pci/msi.h"
  32. #include "hw/qdev-properties.h"
  33. #include "hw/sysbus.h"
  34. #include "sysemu/kvm.h"
  35. #include "qemu/log.h"
  36. #include "qemu/module.h"
  37. #include "qom/object.h"
  38. #define GCR_RESET 0x80000000
  39. OBJECT_DECLARE_SIMPLE_TYPE(KVMOpenPICState, KVM_OPENPIC)
  40. struct KVMOpenPICState {
  41. /*< private >*/
  42. SysBusDevice parent_obj;
  43. /*< public >*/
  44. MemoryRegion mem;
  45. MemoryListener mem_listener;
  46. uint32_t fd;
  47. uint32_t model;
  48. hwaddr mapped;
  49. };
  50. static void kvm_openpic_set_irq(void *opaque, int n_IRQ, int level)
  51. {
  52. kvm_set_irq(kvm_state, n_IRQ, level);
  53. }
  54. static void kvm_openpic_write(void *opaque, hwaddr addr, uint64_t val,
  55. unsigned size)
  56. {
  57. KVMOpenPICState *opp = opaque;
  58. struct kvm_device_attr attr;
  59. uint32_t val32 = val;
  60. int ret;
  61. attr.group = KVM_DEV_MPIC_GRP_REGISTER;
  62. attr.attr = addr;
  63. attr.addr = (uint64_t)(unsigned long)&val32;
  64. ret = ioctl(opp->fd, KVM_SET_DEVICE_ATTR, &attr);
  65. if (ret < 0) {
  66. qemu_log_mask(LOG_UNIMP, "%s: %s %" PRIx64 "\n", __func__,
  67. strerror(errno), attr.attr);
  68. }
  69. }
  70. static void kvm_openpic_reset(DeviceState *d)
  71. {
  72. KVMOpenPICState *opp = KVM_OPENPIC(d);
  73. /* Trigger the GCR.RESET bit to reset the PIC */
  74. kvm_openpic_write(opp, 0x1020, GCR_RESET, sizeof(uint32_t));
  75. }
  76. static uint64_t kvm_openpic_read(void *opaque, hwaddr addr, unsigned size)
  77. {
  78. KVMOpenPICState *opp = opaque;
  79. struct kvm_device_attr attr;
  80. uint32_t val = 0xdeadbeef;
  81. int ret;
  82. attr.group = KVM_DEV_MPIC_GRP_REGISTER;
  83. attr.attr = addr;
  84. attr.addr = (uint64_t)(unsigned long)&val;
  85. ret = ioctl(opp->fd, KVM_GET_DEVICE_ATTR, &attr);
  86. if (ret < 0) {
  87. qemu_log_mask(LOG_UNIMP, "%s: %s %" PRIx64 "\n", __func__,
  88. strerror(errno), attr.attr);
  89. return 0;
  90. }
  91. return val;
  92. }
  93. static const MemoryRegionOps kvm_openpic_mem_ops = {
  94. .write = kvm_openpic_write,
  95. .read = kvm_openpic_read,
  96. .endianness = DEVICE_BIG_ENDIAN,
  97. .impl = {
  98. .min_access_size = 4,
  99. .max_access_size = 4,
  100. },
  101. };
  102. static void kvm_openpic_region_add(MemoryListener *listener,
  103. MemoryRegionSection *section)
  104. {
  105. KVMOpenPICState *opp = container_of(listener, KVMOpenPICState,
  106. mem_listener);
  107. struct kvm_device_attr attr;
  108. uint64_t reg_base;
  109. int ret;
  110. /* Ignore events on regions that are not us */
  111. if (section->mr != &opp->mem) {
  112. return;
  113. }
  114. if (opp->mapped) {
  115. /*
  116. * We can only map the MPIC once. Since we are already mapped,
  117. * the best we can do is ignore new maps.
  118. */
  119. return;
  120. }
  121. reg_base = section->offset_within_address_space;
  122. opp->mapped = reg_base;
  123. attr.group = KVM_DEV_MPIC_GRP_MISC;
  124. attr.attr = KVM_DEV_MPIC_BASE_ADDR;
  125. attr.addr = (uint64_t)(unsigned long)&reg_base;
  126. ret = ioctl(opp->fd, KVM_SET_DEVICE_ATTR, &attr);
  127. if (ret < 0) {
  128. fprintf(stderr, "%s: %s %" PRIx64 "\n", __func__,
  129. strerror(errno), reg_base);
  130. }
  131. }
  132. static void kvm_openpic_region_del(MemoryListener *listener,
  133. MemoryRegionSection *section)
  134. {
  135. KVMOpenPICState *opp = container_of(listener, KVMOpenPICState,
  136. mem_listener);
  137. struct kvm_device_attr attr;
  138. uint64_t reg_base = 0;
  139. int ret;
  140. /* Ignore events on regions that are not us */
  141. if (section->mr != &opp->mem) {
  142. return;
  143. }
  144. if (section->offset_within_address_space != opp->mapped) {
  145. /*
  146. * We can only map the MPIC once. This mapping was a secondary
  147. * one that we couldn't fulfill. Ignore it.
  148. */
  149. return;
  150. }
  151. opp->mapped = 0;
  152. attr.group = KVM_DEV_MPIC_GRP_MISC;
  153. attr.attr = KVM_DEV_MPIC_BASE_ADDR;
  154. attr.addr = (uint64_t)(unsigned long)&reg_base;
  155. ret = ioctl(opp->fd, KVM_SET_DEVICE_ATTR, &attr);
  156. if (ret < 0) {
  157. fprintf(stderr, "%s: %s %" PRIx64 "\n", __func__,
  158. strerror(errno), reg_base);
  159. }
  160. }
  161. static void kvm_openpic_init(Object *obj)
  162. {
  163. KVMOpenPICState *opp = KVM_OPENPIC(obj);
  164. memory_region_init_io(&opp->mem, OBJECT(opp), &kvm_openpic_mem_ops, opp,
  165. "kvm-openpic", 0x40000);
  166. }
  167. static void kvm_openpic_realize(DeviceState *dev, Error **errp)
  168. {
  169. SysBusDevice *d = SYS_BUS_DEVICE(dev);
  170. KVMOpenPICState *opp = KVM_OPENPIC(dev);
  171. KVMState *s = kvm_state;
  172. int kvm_openpic_model;
  173. struct kvm_create_device cd = {0};
  174. int ret, i;
  175. if (!kvm_check_extension(s, KVM_CAP_DEVICE_CTRL)) {
  176. error_setg(errp, "Kernel is lacking Device Control API");
  177. return;
  178. }
  179. switch (opp->model) {
  180. case OPENPIC_MODEL_FSL_MPIC_20:
  181. kvm_openpic_model = KVM_DEV_TYPE_FSL_MPIC_20;
  182. break;
  183. case OPENPIC_MODEL_FSL_MPIC_42:
  184. kvm_openpic_model = KVM_DEV_TYPE_FSL_MPIC_42;
  185. break;
  186. default:
  187. error_setg(errp, "Unsupported OpenPIC model %" PRIu32, opp->model);
  188. return;
  189. }
  190. cd.type = kvm_openpic_model;
  191. ret = kvm_vm_ioctl(s, KVM_CREATE_DEVICE, &cd);
  192. if (ret < 0) {
  193. error_setg(errp, "Can't create device %d: %s",
  194. cd.type, strerror(errno));
  195. return;
  196. }
  197. opp->fd = cd.fd;
  198. sysbus_init_mmio(d, &opp->mem);
  199. qdev_init_gpio_in(dev, kvm_openpic_set_irq, OPENPIC_MAX_IRQ);
  200. opp->mem_listener.region_add = kvm_openpic_region_add;
  201. opp->mem_listener.region_del = kvm_openpic_region_del;
  202. memory_listener_register(&opp->mem_listener, &address_space_memory);
  203. /* indicate pic capabilities */
  204. msi_nonbroken = true;
  205. kvm_kernel_irqchip = true;
  206. kvm_async_interrupts_allowed = true;
  207. /* set up irq routing */
  208. kvm_init_irq_routing(kvm_state);
  209. for (i = 0; i < 256; ++i) {
  210. kvm_irqchip_add_irq_route(kvm_state, i, 0, i);
  211. }
  212. kvm_msi_via_irqfd_allowed = true;
  213. kvm_gsi_routing_allowed = true;
  214. kvm_irqchip_commit_routes(s);
  215. }
  216. int kvm_openpic_connect_vcpu(DeviceState *d, CPUState *cs)
  217. {
  218. KVMOpenPICState *opp = KVM_OPENPIC(d);
  219. return kvm_vcpu_enable_cap(cs, KVM_CAP_IRQ_MPIC, 0, opp->fd,
  220. kvm_arch_vcpu_id(cs));
  221. }
  222. static Property kvm_openpic_properties[] = {
  223. DEFINE_PROP_UINT32("model", KVMOpenPICState, model,
  224. OPENPIC_MODEL_FSL_MPIC_20),
  225. DEFINE_PROP_END_OF_LIST(),
  226. };
  227. static void kvm_openpic_class_init(ObjectClass *oc, void *data)
  228. {
  229. DeviceClass *dc = DEVICE_CLASS(oc);
  230. dc->realize = kvm_openpic_realize;
  231. device_class_set_props(dc, kvm_openpic_properties);
  232. dc->reset = kvm_openpic_reset;
  233. set_bit(DEVICE_CATEGORY_MISC, dc->categories);
  234. }
  235. static const TypeInfo kvm_openpic_info = {
  236. .name = TYPE_KVM_OPENPIC,
  237. .parent = TYPE_SYS_BUS_DEVICE,
  238. .instance_size = sizeof(KVMOpenPICState),
  239. .instance_init = kvm_openpic_init,
  240. .class_init = kvm_openpic_class_init,
  241. };
  242. static void kvm_openpic_register_types(void)
  243. {
  244. type_register_static(&kvm_openpic_info);
  245. }
  246. type_init(kvm_openpic_register_types)