0001
0002
0003
0004
0005
0006
0007 #include <linux/kernel.h>
0008 #include <linux/interrupt.h>
0009 #include <linux/hardirq.h>
0010
0011 #include "rxe.h"
0012
0013 int __rxe_do_task(struct rxe_task *task)
0014
0015 {
0016 int ret;
0017
0018 while ((ret = task->func(task->arg)) == 0)
0019 ;
0020
0021 task->ret = ret;
0022
0023 return ret;
0024 }
0025
0026
0027
0028
0029
0030
0031 void rxe_do_task(struct tasklet_struct *t)
0032 {
0033 int cont;
0034 int ret;
0035 struct rxe_task *task = from_tasklet(task, t, tasklet);
0036 unsigned int iterations = RXE_MAX_ITERATIONS;
0037
0038 spin_lock_bh(&task->state_lock);
0039 switch (task->state) {
0040 case TASK_STATE_START:
0041 task->state = TASK_STATE_BUSY;
0042 spin_unlock_bh(&task->state_lock);
0043 break;
0044
0045 case TASK_STATE_BUSY:
0046 task->state = TASK_STATE_ARMED;
0047 fallthrough;
0048 case TASK_STATE_ARMED:
0049 spin_unlock_bh(&task->state_lock);
0050 return;
0051
0052 default:
0053 spin_unlock_bh(&task->state_lock);
0054 pr_warn("%s failed with bad state %d\n", __func__, task->state);
0055 return;
0056 }
0057
0058 do {
0059 cont = 0;
0060 ret = task->func(task->arg);
0061
0062 spin_lock_bh(&task->state_lock);
0063 switch (task->state) {
0064 case TASK_STATE_BUSY:
0065 if (ret) {
0066 task->state = TASK_STATE_START;
0067 } else if (iterations--) {
0068 cont = 1;
0069 } else {
0070
0071
0072
0073 tasklet_schedule(&task->tasklet);
0074 task->state = TASK_STATE_START;
0075 }
0076 break;
0077
0078
0079
0080
0081
0082 case TASK_STATE_ARMED:
0083 task->state = TASK_STATE_BUSY;
0084 cont = 1;
0085 break;
0086
0087 default:
0088 pr_warn("%s failed with bad state %d\n", __func__,
0089 task->state);
0090 }
0091 spin_unlock_bh(&task->state_lock);
0092 } while (cont);
0093
0094 task->ret = ret;
0095 }
0096
0097 int rxe_init_task(void *obj, struct rxe_task *task,
0098 void *arg, int (*func)(void *), char *name)
0099 {
0100 task->obj = obj;
0101 task->arg = arg;
0102 task->func = func;
0103 snprintf(task->name, sizeof(task->name), "%s", name);
0104 task->destroyed = false;
0105
0106 tasklet_setup(&task->tasklet, rxe_do_task);
0107
0108 task->state = TASK_STATE_START;
0109 spin_lock_init(&task->state_lock);
0110
0111 return 0;
0112 }
0113
0114 void rxe_cleanup_task(struct rxe_task *task)
0115 {
0116 bool idle;
0117
0118
0119
0120
0121
0122 task->destroyed = true;
0123
0124 do {
0125 spin_lock_bh(&task->state_lock);
0126 idle = (task->state == TASK_STATE_START);
0127 spin_unlock_bh(&task->state_lock);
0128 } while (!idle);
0129
0130 tasklet_kill(&task->tasklet);
0131 }
0132
0133 void rxe_run_task(struct rxe_task *task, int sched)
0134 {
0135 if (task->destroyed)
0136 return;
0137
0138 if (sched)
0139 tasklet_schedule(&task->tasklet);
0140 else
0141 rxe_do_task(&task->tasklet);
0142 }
0143
0144 void rxe_disable_task(struct rxe_task *task)
0145 {
0146 tasklet_disable(&task->tasklet);
0147 }
0148
0149 void rxe_enable_task(struct rxe_task *task)
0150 {
0151 tasklet_enable(&task->tasklet);
0152 }