vfio_platform_irq.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. /*
  2. * VFIO platform devices interrupt handling
  3. *
  4. * Copyright (C) 2013 - Virtual Open Systems
  5. * Author: Antonios Motakis <a.motakis@virtualopensystems.com>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License, version 2, as
  9. * published by the Free Software Foundation.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. */
  16. #include <linux/eventfd.h>
  17. #include <linux/interrupt.h>
  18. #include <linux/slab.h>
  19. #include <linux/types.h>
  20. #include <linux/vfio.h>
  21. #include <linux/irq.h>
  22. #include "vfio_platform_private.h"
  23. static void vfio_platform_mask(struct vfio_platform_irq *irq_ctx)
  24. {
  25. unsigned long flags;
  26. spin_lock_irqsave(&irq_ctx->lock, flags);
  27. if (!irq_ctx->masked) {
  28. disable_irq_nosync(irq_ctx->hwirq);
  29. irq_ctx->masked = true;
  30. }
  31. spin_unlock_irqrestore(&irq_ctx->lock, flags);
  32. }
  33. static int vfio_platform_mask_handler(void *opaque, void *unused)
  34. {
  35. struct vfio_platform_irq *irq_ctx = opaque;
  36. vfio_platform_mask(irq_ctx);
  37. return 0;
  38. }
  39. static int vfio_platform_set_irq_mask(struct vfio_platform_device *vdev,
  40. unsigned index, unsigned start,
  41. unsigned count, uint32_t flags,
  42. void *data)
  43. {
  44. if (start != 0 || count != 1)
  45. return -EINVAL;
  46. if (!(vdev->irqs[index].flags & VFIO_IRQ_INFO_MASKABLE))
  47. return -EINVAL;
  48. if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
  49. int32_t fd = *(int32_t *)data;
  50. if (fd >= 0)
  51. return vfio_virqfd_enable((void *) &vdev->irqs[index],
  52. vfio_platform_mask_handler,
  53. NULL, NULL,
  54. &vdev->irqs[index].mask, fd);
  55. vfio_virqfd_disable(&vdev->irqs[index].mask);
  56. return 0;
  57. }
  58. if (flags & VFIO_IRQ_SET_DATA_NONE) {
  59. vfio_platform_mask(&vdev->irqs[index]);
  60. } else if (flags & VFIO_IRQ_SET_DATA_BOOL) {
  61. uint8_t mask = *(uint8_t *)data;
  62. if (mask)
  63. vfio_platform_mask(&vdev->irqs[index]);
  64. }
  65. return 0;
  66. }
  67. static void vfio_platform_unmask(struct vfio_platform_irq *irq_ctx)
  68. {
  69. unsigned long flags;
  70. spin_lock_irqsave(&irq_ctx->lock, flags);
  71. if (irq_ctx->masked) {
  72. enable_irq(irq_ctx->hwirq);
  73. irq_ctx->masked = false;
  74. }
  75. spin_unlock_irqrestore(&irq_ctx->lock, flags);
  76. }
  77. static int vfio_platform_unmask_handler(void *opaque, void *unused)
  78. {
  79. struct vfio_platform_irq *irq_ctx = opaque;
  80. vfio_platform_unmask(irq_ctx);
  81. return 0;
  82. }
  83. static int vfio_platform_set_irq_unmask(struct vfio_platform_device *vdev,
  84. unsigned index, unsigned start,
  85. unsigned count, uint32_t flags,
  86. void *data)
  87. {
  88. if (start != 0 || count != 1)
  89. return -EINVAL;
  90. if (!(vdev->irqs[index].flags & VFIO_IRQ_INFO_MASKABLE))
  91. return -EINVAL;
  92. if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
  93. int32_t fd = *(int32_t *)data;
  94. if (fd >= 0)
  95. return vfio_virqfd_enable((void *) &vdev->irqs[index],
  96. vfio_platform_unmask_handler,
  97. NULL, NULL,
  98. &vdev->irqs[index].unmask,
  99. fd);
  100. vfio_virqfd_disable(&vdev->irqs[index].unmask);
  101. return 0;
  102. }
  103. if (flags & VFIO_IRQ_SET_DATA_NONE) {
  104. vfio_platform_unmask(&vdev->irqs[index]);
  105. } else if (flags & VFIO_IRQ_SET_DATA_BOOL) {
  106. uint8_t unmask = *(uint8_t *)data;
  107. if (unmask)
  108. vfio_platform_unmask(&vdev->irqs[index]);
  109. }
  110. return 0;
  111. }
  112. static irqreturn_t vfio_automasked_irq_handler(int irq, void *dev_id)
  113. {
  114. struct vfio_platform_irq *irq_ctx = dev_id;
  115. unsigned long flags;
  116. int ret = IRQ_NONE;
  117. spin_lock_irqsave(&irq_ctx->lock, flags);
  118. if (!irq_ctx->masked) {
  119. ret = IRQ_HANDLED;
  120. /* automask maskable interrupts */
  121. disable_irq_nosync(irq_ctx->hwirq);
  122. irq_ctx->masked = true;
  123. }
  124. spin_unlock_irqrestore(&irq_ctx->lock, flags);
  125. if (ret == IRQ_HANDLED)
  126. eventfd_signal(irq_ctx->trigger, 1);
  127. return ret;
  128. }
  129. static irqreturn_t vfio_irq_handler(int irq, void *dev_id)
  130. {
  131. struct vfio_platform_irq *irq_ctx = dev_id;
  132. eventfd_signal(irq_ctx->trigger, 1);
  133. return IRQ_HANDLED;
  134. }
  135. static int vfio_set_trigger(struct vfio_platform_device *vdev, int index,
  136. int fd, irq_handler_t handler)
  137. {
  138. struct vfio_platform_irq *irq = &vdev->irqs[index];
  139. struct eventfd_ctx *trigger;
  140. int ret;
  141. if (irq->trigger) {
  142. irq_clear_status_flags(irq->hwirq, IRQ_NOAUTOEN);
  143. free_irq(irq->hwirq, irq);
  144. kfree(irq->name);
  145. eventfd_ctx_put(irq->trigger);
  146. irq->trigger = NULL;
  147. }
  148. if (fd < 0) /* Disable only */
  149. return 0;
  150. irq->name = kasprintf(GFP_KERNEL, "vfio-irq[%d](%s)",
  151. irq->hwirq, vdev->name);
  152. if (!irq->name)
  153. return -ENOMEM;
  154. trigger = eventfd_ctx_fdget(fd);
  155. if (IS_ERR(trigger)) {
  156. kfree(irq->name);
  157. return PTR_ERR(trigger);
  158. }
  159. irq->trigger = trigger;
  160. irq_set_status_flags(irq->hwirq, IRQ_NOAUTOEN);
  161. ret = request_irq(irq->hwirq, handler, 0, irq->name, irq);
  162. if (ret) {
  163. kfree(irq->name);
  164. eventfd_ctx_put(trigger);
  165. irq->trigger = NULL;
  166. return ret;
  167. }
  168. if (!irq->masked)
  169. enable_irq(irq->hwirq);
  170. return 0;
  171. }
  172. static int vfio_platform_set_irq_trigger(struct vfio_platform_device *vdev,
  173. unsigned index, unsigned start,
  174. unsigned count, uint32_t flags,
  175. void *data)
  176. {
  177. struct vfio_platform_irq *irq = &vdev->irqs[index];
  178. irq_handler_t handler;
  179. if (vdev->irqs[index].flags & VFIO_IRQ_INFO_AUTOMASKED)
  180. handler = vfio_automasked_irq_handler;
  181. else
  182. handler = vfio_irq_handler;
  183. if (!count && (flags & VFIO_IRQ_SET_DATA_NONE))
  184. return vfio_set_trigger(vdev, index, -1, handler);
  185. if (start != 0 || count != 1)
  186. return -EINVAL;
  187. if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
  188. int32_t fd = *(int32_t *)data;
  189. return vfio_set_trigger(vdev, index, fd, handler);
  190. }
  191. if (flags & VFIO_IRQ_SET_DATA_NONE) {
  192. handler(irq->hwirq, irq);
  193. } else if (flags & VFIO_IRQ_SET_DATA_BOOL) {
  194. uint8_t trigger = *(uint8_t *)data;
  195. if (trigger)
  196. handler(irq->hwirq, irq);
  197. }
  198. return 0;
  199. }
  200. int vfio_platform_set_irqs_ioctl(struct vfio_platform_device *vdev,
  201. uint32_t flags, unsigned index, unsigned start,
  202. unsigned count, void *data)
  203. {
  204. int (*func)(struct vfio_platform_device *vdev, unsigned index,
  205. unsigned start, unsigned count, uint32_t flags,
  206. void *data) = NULL;
  207. switch (flags & VFIO_IRQ_SET_ACTION_TYPE_MASK) {
  208. case VFIO_IRQ_SET_ACTION_MASK:
  209. func = vfio_platform_set_irq_mask;
  210. break;
  211. case VFIO_IRQ_SET_ACTION_UNMASK:
  212. func = vfio_platform_set_irq_unmask;
  213. break;
  214. case VFIO_IRQ_SET_ACTION_TRIGGER:
  215. func = vfio_platform_set_irq_trigger;
  216. break;
  217. }
  218. if (!func)
  219. return -ENOTTY;
  220. return func(vdev, index, start, count, flags, data);
  221. }
  222. int vfio_platform_irq_init(struct vfio_platform_device *vdev)
  223. {
  224. int cnt = 0, i;
  225. while (vdev->get_irq(vdev, cnt) >= 0)
  226. cnt++;
  227. vdev->irqs = kcalloc(cnt, sizeof(struct vfio_platform_irq), GFP_KERNEL);
  228. if (!vdev->irqs)
  229. return -ENOMEM;
  230. for (i = 0; i < cnt; i++) {
  231. int hwirq = vdev->get_irq(vdev, i);
  232. if (hwirq < 0)
  233. goto err;
  234. spin_lock_init(&vdev->irqs[i].lock);
  235. vdev->irqs[i].flags = VFIO_IRQ_INFO_EVENTFD;
  236. if (irq_get_trigger_type(hwirq) & IRQ_TYPE_LEVEL_MASK)
  237. vdev->irqs[i].flags |= VFIO_IRQ_INFO_MASKABLE
  238. | VFIO_IRQ_INFO_AUTOMASKED;
  239. vdev->irqs[i].count = 1;
  240. vdev->irqs[i].hwirq = hwirq;
  241. vdev->irqs[i].masked = false;
  242. }
  243. vdev->num_irqs = cnt;
  244. return 0;
  245. err:
  246. kfree(vdev->irqs);
  247. return -EINVAL;
  248. }
  249. void vfio_platform_irq_cleanup(struct vfio_platform_device *vdev)
  250. {
  251. int i;
  252. for (i = 0; i < vdev->num_irqs; i++)
  253. vfio_set_trigger(vdev, i, -1, NULL);
  254. vdev->num_irqs = 0;
  255. kfree(vdev->irqs);
  256. }