gzvm_irqfd.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (c) 2023 MediaTek Inc.
  4. */
  5. #include <linux/eventfd.h>
  6. #include <linux/syscalls.h>
  7. #include <linux/gzvm_drv.h>
  8. #include "gzvm_common.h"
  9. struct gzvm_irq_ack_notifier {
  10. struct hlist_node link;
  11. unsigned int gsi;
  12. void (*irq_acked)(struct gzvm_irq_ack_notifier *ian);
  13. };
  14. /**
  15. * struct gzvm_kernel_irqfd: gzvm kernel irqfd descriptor.
  16. * @gzvm: Pointer to struct gzvm.
  17. * @wait: Wait queue entry.
  18. * @gsi: Used for level IRQ fast-path.
  19. * @eventfd: Used for setup/shutdown.
  20. * @list: struct list_head.
  21. * @pt: struct poll_table_struct.
  22. * @shutdown: struct work_struct.
  23. */
  24. struct gzvm_kernel_irqfd {
  25. struct gzvm *gzvm;
  26. wait_queue_entry_t wait;
  27. int gsi;
  28. struct eventfd_ctx *eventfd;
  29. struct list_head list;
  30. poll_table pt;
  31. struct work_struct shutdown;
  32. };
  33. static struct workqueue_struct *irqfd_cleanup_wq;
  34. /**
  35. * irqfd_set_irq(): irqfd to inject virtual interrupt.
  36. * @gzvm: Pointer to gzvm.
  37. * @irq: This is spi interrupt number (starts from 0 instead of 32).
  38. * @level: irq triggered level.
  39. */
  40. static void irqfd_set_irq(struct gzvm *gzvm, u32 irq, int level)
  41. {
  42. if (level)
  43. gzvm_irqchip_inject_irq(gzvm, 0, irq, level);
  44. }
  45. /**
  46. * irqfd_shutdown() - Race-free decouple logic (ordering is critical).
  47. * @work: Pointer to work_struct.
  48. */
  49. static void irqfd_shutdown(struct work_struct *work)
  50. {
  51. struct gzvm_kernel_irqfd *irqfd =
  52. container_of(work, struct gzvm_kernel_irqfd, shutdown);
  53. struct gzvm *gzvm = irqfd->gzvm;
  54. u64 cnt;
  55. /* Make sure irqfd has been initialized in assign path. */
  56. synchronize_srcu(&gzvm->irq_srcu);
  57. /*
  58. * Synchronize with the wait-queue and unhook ourselves to prevent
  59. * further events.
  60. */
  61. eventfd_ctx_remove_wait_queue(irqfd->eventfd, &irqfd->wait, &cnt);
  62. /*
  63. * It is now safe to release the object's resources
  64. */
  65. eventfd_ctx_put(irqfd->eventfd);
  66. kfree(irqfd);
  67. }
  68. /**
  69. * irqfd_is_active() - Assumes gzvm->irqfds.lock is held.
  70. * @irqfd: Pointer to gzvm_kernel_irqfd.
  71. *
  72. * Return:
  73. * * true - irqfd is active.
  74. */
  75. static bool irqfd_is_active(struct gzvm_kernel_irqfd *irqfd)
  76. {
  77. return list_empty(&irqfd->list) ? false : true;
  78. }
  79. /**
  80. * irqfd_deactivate() - Mark the irqfd as inactive and schedule it for removal.
  81. * assumes gzvm->irqfds.lock is held.
  82. * @irqfd: Pointer to gzvm_kernel_irqfd.
  83. */
  84. static void irqfd_deactivate(struct gzvm_kernel_irqfd *irqfd)
  85. {
  86. if (!irqfd_is_active(irqfd))
  87. return;
  88. list_del_init(&irqfd->list);
  89. queue_work(irqfd_cleanup_wq, &irqfd->shutdown);
  90. }
  91. /**
  92. * irqfd_wakeup() - Callback of irqfd wait queue, would be woken by writing to
  93. * irqfd to do virtual interrupt injection.
  94. * @wait: Pointer to wait_queue_entry_t.
  95. * @mode: Unused.
  96. * @sync: Unused.
  97. * @key: Get flags about Epoll events.
  98. *
  99. * Return:
  100. * * 0 - Success
  101. */
  102. static int irqfd_wakeup(wait_queue_entry_t *wait, unsigned int mode, int sync,
  103. void *key)
  104. {
  105. struct gzvm_kernel_irqfd *irqfd =
  106. container_of(wait, struct gzvm_kernel_irqfd, wait);
  107. __poll_t flags = key_to_poll(key);
  108. struct gzvm *gzvm = irqfd->gzvm;
  109. if (flags & EPOLLIN) {
  110. u64 cnt;
  111. eventfd_ctx_do_read(irqfd->eventfd, &cnt);
  112. /* gzvm's irq injection is not blocked, don't need workq */
  113. irqfd_set_irq(gzvm, irqfd->gsi, 1);
  114. }
  115. if (flags & EPOLLHUP) {
  116. /* The eventfd is closing, detach from GZVM */
  117. unsigned long iflags;
  118. spin_lock_irqsave(&gzvm->irqfds.lock, iflags);
  119. /*
  120. * Do more check if someone deactivated the irqfd before
  121. * we could acquire the irqfds.lock.
  122. */
  123. if (irqfd_is_active(irqfd))
  124. irqfd_deactivate(irqfd);
  125. spin_unlock_irqrestore(&gzvm->irqfds.lock, iflags);
  126. }
  127. return 0;
  128. }
  129. static void irqfd_ptable_queue_proc(struct file *file, wait_queue_head_t *wqh,
  130. poll_table *pt)
  131. {
  132. struct gzvm_kernel_irqfd *irqfd =
  133. container_of(pt, struct gzvm_kernel_irqfd, pt);
  134. add_wait_queue_priority(wqh, &irqfd->wait);
  135. }
  136. static int gzvm_irqfd_assign(struct gzvm *gzvm, struct gzvm_irqfd *args)
  137. {
  138. struct gzvm_kernel_irqfd *irqfd, *tmp;
  139. struct fd f;
  140. struct eventfd_ctx *eventfd = NULL;
  141. int ret;
  142. int idx;
  143. irqfd = kzalloc(sizeof(*irqfd), GFP_KERNEL_ACCOUNT);
  144. if (!irqfd)
  145. return -ENOMEM;
  146. irqfd->gzvm = gzvm;
  147. irqfd->gsi = args->gsi;
  148. INIT_LIST_HEAD(&irqfd->list);
  149. INIT_WORK(&irqfd->shutdown, irqfd_shutdown);
  150. f = fdget(args->fd);
  151. if (!f.file) {
  152. ret = -EBADF;
  153. goto out;
  154. }
  155. eventfd = eventfd_ctx_fileget(f.file);
  156. if (IS_ERR(eventfd)) {
  157. ret = PTR_ERR(eventfd);
  158. goto fail;
  159. }
  160. irqfd->eventfd = eventfd;
  161. /*
  162. * Install our own custom wake-up handling so we are notified via
  163. * a callback whenever someone signals the underlying eventfd
  164. */
  165. init_waitqueue_func_entry(&irqfd->wait, irqfd_wakeup);
  166. init_poll_funcptr(&irqfd->pt, irqfd_ptable_queue_proc);
  167. spin_lock_irq(&gzvm->irqfds.lock);
  168. ret = 0;
  169. list_for_each_entry(tmp, &gzvm->irqfds.items, list) {
  170. if (irqfd->eventfd != tmp->eventfd)
  171. continue;
  172. /* This fd is used for another irq already. */
  173. pr_err("already used: gsi=%d fd=%d\n", args->gsi, args->fd);
  174. ret = -EBUSY;
  175. spin_unlock_irq(&gzvm->irqfds.lock);
  176. goto fail;
  177. }
  178. idx = srcu_read_lock(&gzvm->irq_srcu);
  179. list_add_tail(&irqfd->list, &gzvm->irqfds.items);
  180. spin_unlock_irq(&gzvm->irqfds.lock);
  181. vfs_poll(f.file, &irqfd->pt);
  182. srcu_read_unlock(&gzvm->irq_srcu, idx);
  183. /*
  184. * do not drop the file until the irqfd is fully initialized, otherwise
  185. * we might race against the EPOLLHUP
  186. */
  187. fdput(f);
  188. return 0;
  189. fail:
  190. if (eventfd && !IS_ERR(eventfd))
  191. eventfd_ctx_put(eventfd);
  192. fdput(f);
  193. out:
  194. kfree(irqfd);
  195. return ret;
  196. }
  197. static void gzvm_notify_acked_gsi(struct gzvm *gzvm, int gsi)
  198. {
  199. struct gzvm_irq_ack_notifier *gian;
  200. hlist_for_each_entry_srcu(gian, &gzvm->irq_ack_notifier_list,
  201. link, srcu_read_lock_held(&gzvm->irq_srcu))
  202. if (gian->gsi == gsi)
  203. gian->irq_acked(gian);
  204. }
  205. void gzvm_notify_acked_irq(struct gzvm *gzvm, unsigned int gsi)
  206. {
  207. int idx;
  208. idx = srcu_read_lock(&gzvm->irq_srcu);
  209. gzvm_notify_acked_gsi(gzvm, gsi);
  210. srcu_read_unlock(&gzvm->irq_srcu, idx);
  211. }
  212. /**
  213. * gzvm_irqfd_deassign() - Shutdown any irqfd's that match fd+gsi.
  214. * @gzvm: Pointer to gzvm.
  215. * @args: Pointer to gzvm_irqfd.
  216. *
  217. * Return:
  218. * * 0 - Success.
  219. * * Negative value - Failure.
  220. */
  221. static int gzvm_irqfd_deassign(struct gzvm *gzvm, struct gzvm_irqfd *args)
  222. {
  223. struct gzvm_kernel_irqfd *irqfd, *tmp;
  224. struct eventfd_ctx *eventfd;
  225. eventfd = eventfd_ctx_fdget(args->fd);
  226. if (IS_ERR(eventfd))
  227. return PTR_ERR(eventfd);
  228. spin_lock_irq(&gzvm->irqfds.lock);
  229. list_for_each_entry_safe(irqfd, tmp, &gzvm->irqfds.items, list) {
  230. if (irqfd->eventfd == eventfd && irqfd->gsi == args->gsi)
  231. irqfd_deactivate(irqfd);
  232. }
  233. spin_unlock_irq(&gzvm->irqfds.lock);
  234. eventfd_ctx_put(eventfd);
  235. /*
  236. * Block until we know all outstanding shutdown jobs have completed
  237. * so that we guarantee there will not be any more interrupts on this
  238. * gsi once this deassign function returns.
  239. */
  240. flush_workqueue(irqfd_cleanup_wq);
  241. return 0;
  242. }
  243. int gzvm_irqfd(struct gzvm *gzvm, struct gzvm_irqfd *args)
  244. {
  245. for (int i = 0; i < ARRAY_SIZE(args->pad); i++) {
  246. if (args->pad[i])
  247. return -EINVAL;
  248. }
  249. if (args->flags &
  250. ~(GZVM_IRQFD_FLAG_DEASSIGN | GZVM_IRQFD_FLAG_RESAMPLE))
  251. return -EINVAL;
  252. if (args->flags & GZVM_IRQFD_FLAG_DEASSIGN)
  253. return gzvm_irqfd_deassign(gzvm, args);
  254. return gzvm_irqfd_assign(gzvm, args);
  255. }
  256. /**
  257. * gzvm_vm_irqfd_init() - Initialize irqfd data structure per VM
  258. *
  259. * @gzvm: Pointer to struct gzvm.
  260. *
  261. * Return:
  262. * * 0 - Success.
  263. * * Negative - Failure.
  264. */
  265. int gzvm_vm_irqfd_init(struct gzvm *gzvm)
  266. {
  267. mutex_init(&gzvm->irq_lock);
  268. spin_lock_init(&gzvm->irqfds.lock);
  269. INIT_LIST_HEAD(&gzvm->irqfds.items);
  270. if (init_srcu_struct(&gzvm->irq_srcu))
  271. return -EINVAL;
  272. INIT_HLIST_HEAD(&gzvm->irq_ack_notifier_list);
  273. return 0;
  274. }
  275. /**
  276. * gzvm_vm_irqfd_release() - This function is called as the gzvm VM fd is being
  277. * released. Shutdown all irqfds that still remain open.
  278. * @gzvm: Pointer to gzvm.
  279. */
  280. void gzvm_vm_irqfd_release(struct gzvm *gzvm)
  281. {
  282. struct gzvm_kernel_irqfd *irqfd, *tmp;
  283. spin_lock_irq(&gzvm->irqfds.lock);
  284. list_for_each_entry_safe(irqfd, tmp, &gzvm->irqfds.items, list)
  285. irqfd_deactivate(irqfd);
  286. spin_unlock_irq(&gzvm->irqfds.lock);
  287. /*
  288. * Block until we know all outstanding shutdown jobs have completed.
  289. */
  290. flush_workqueue(irqfd_cleanup_wq);
  291. }
  292. /**
  293. * gzvm_drv_irqfd_init() - Erase flushing work items when a VM exits.
  294. *
  295. * Return:
  296. * * 0 - Success.
  297. * * Negative - Failure.
  298. *
  299. * Create a host-wide workqueue for issuing deferred shutdown requests
  300. * aggregated from all vm* instances. We need our own isolated
  301. * queue to ease flushing work items when a VM exits.
  302. */
  303. int gzvm_drv_irqfd_init(void)
  304. {
  305. irqfd_cleanup_wq = alloc_workqueue("gzvm-irqfd-cleanup", 0, 0);
  306. if (!irqfd_cleanup_wq)
  307. return -ENOMEM;
  308. return 0;
  309. }
  310. void gzvm_drv_irqfd_exit(void)
  311. {
  312. destroy_workqueue(irqfd_cleanup_wq);
  313. }