rxe_task.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
  2. /*
  3. * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
  4. * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
  5. */
  6. #include <linux/kernel.h>
  7. #include <linux/interrupt.h>
  8. #include <linux/hardirq.h>
  9. #include "rxe.h"
  10. int __rxe_do_task(struct rxe_task *task)
  11. {
  12. int ret;
  13. while ((ret = task->func(task->arg)) == 0)
  14. ;
  15. task->ret = ret;
  16. return ret;
  17. }
  18. /*
  19. * this locking is due to a potential race where
  20. * a second caller finds the task already running
  21. * but looks just after the last call to func
  22. */
  23. void rxe_do_task(struct tasklet_struct *t)
  24. {
  25. int cont;
  26. int ret;
  27. struct rxe_task *task = from_tasklet(task, t, tasklet);
  28. unsigned int iterations = RXE_MAX_ITERATIONS;
  29. spin_lock_bh(&task->state_lock);
  30. switch (task->state) {
  31. case TASK_STATE_START:
  32. task->state = TASK_STATE_BUSY;
  33. spin_unlock_bh(&task->state_lock);
  34. break;
  35. case TASK_STATE_BUSY:
  36. task->state = TASK_STATE_ARMED;
  37. fallthrough;
  38. case TASK_STATE_ARMED:
  39. spin_unlock_bh(&task->state_lock);
  40. return;
  41. default:
  42. spin_unlock_bh(&task->state_lock);
  43. pr_warn("%s failed with bad state %d\n", __func__, task->state);
  44. return;
  45. }
  46. do {
  47. cont = 0;
  48. ret = task->func(task->arg);
  49. spin_lock_bh(&task->state_lock);
  50. switch (task->state) {
  51. case TASK_STATE_BUSY:
  52. if (ret) {
  53. task->state = TASK_STATE_START;
  54. } else if (iterations--) {
  55. cont = 1;
  56. } else {
  57. /* reschedule the tasklet and exit
  58. * the loop to give up the cpu
  59. */
  60. tasklet_schedule(&task->tasklet);
  61. task->state = TASK_STATE_START;
  62. }
  63. break;
  64. /* someone tried to run the task since the last time we called
  65. * func, so we will call one more time regardless of the
  66. * return value
  67. */
  68. case TASK_STATE_ARMED:
  69. task->state = TASK_STATE_BUSY;
  70. cont = 1;
  71. break;
  72. default:
  73. pr_warn("%s failed with bad state %d\n", __func__,
  74. task->state);
  75. }
  76. spin_unlock_bh(&task->state_lock);
  77. } while (cont);
  78. task->ret = ret;
  79. }
  80. int rxe_init_task(struct rxe_task *task, void *arg, int (*func)(void *))
  81. {
  82. task->arg = arg;
  83. task->func = func;
  84. task->destroyed = false;
  85. tasklet_setup(&task->tasklet, rxe_do_task);
  86. task->state = TASK_STATE_START;
  87. spin_lock_init(&task->state_lock);
  88. return 0;
  89. }
  90. void rxe_cleanup_task(struct rxe_task *task)
  91. {
  92. bool idle;
  93. /*
  94. * Mark the task, then wait for it to finish. It might be
  95. * running in a non-tasklet (direct call) context.
  96. */
  97. task->destroyed = true;
  98. do {
  99. spin_lock_bh(&task->state_lock);
  100. idle = (task->state == TASK_STATE_START);
  101. spin_unlock_bh(&task->state_lock);
  102. } while (!idle);
  103. tasklet_kill(&task->tasklet);
  104. }
  105. void rxe_run_task(struct rxe_task *task)
  106. {
  107. if (task->destroyed)
  108. return;
  109. rxe_do_task(&task->tasklet);
  110. }
  111. void rxe_sched_task(struct rxe_task *task)
  112. {
  113. if (task->destroyed)
  114. return;
  115. tasklet_schedule(&task->tasklet);
  116. }
  117. void rxe_disable_task(struct rxe_task *task)
  118. {
  119. tasklet_disable(&task->tasklet);
  120. }
  121. void rxe_enable_task(struct rxe_task *task)
  122. {
  123. tasklet_enable(&task->tasklet);
  124. }