1
2
3
4
5
6
7#include <linux/kernel.h>
8#include <linux/interrupt.h>
9#include <linux/hardirq.h>
10
11#include "rxe_task.h"
12
13int __rxe_do_task(struct rxe_task *task)
14
15{
16 int ret;
17
18 while ((ret = task->func(task->arg)) == 0)
19 ;
20
21 task->ret = ret;
22
23 return ret;
24}
25
26
27
28
29
30
31void rxe_do_task(struct tasklet_struct *t)
32{
33 int cont;
34 int ret;
35 unsigned long flags;
36 struct rxe_task *task = from_tasklet(task, t, tasklet);
37
38 spin_lock_irqsave(&task->state_lock, flags);
39 switch (task->state) {
40 case TASK_STATE_START:
41 task->state = TASK_STATE_BUSY;
42 spin_unlock_irqrestore(&task->state_lock, flags);
43 break;
44
45 case TASK_STATE_BUSY:
46 task->state = TASK_STATE_ARMED;
47 fallthrough;
48 case TASK_STATE_ARMED:
49 spin_unlock_irqrestore(&task->state_lock, flags);
50 return;
51
52 default:
53 spin_unlock_irqrestore(&task->state_lock, flags);
54 pr_warn("%s failed with bad state %d\n", __func__, task->state);
55 return;
56 }
57
58 do {
59 cont = 0;
60 ret = task->func(task->arg);
61
62 spin_lock_irqsave(&task->state_lock, flags);
63 switch (task->state) {
64 case TASK_STATE_BUSY:
65 if (ret)
66 task->state = TASK_STATE_START;
67 else
68 cont = 1;
69 break;
70
71
72
73
74
75 case TASK_STATE_ARMED:
76 task->state = TASK_STATE_BUSY;
77 cont = 1;
78 break;
79
80 default:
81 pr_warn("%s failed with bad state %d\n", __func__,
82 task->state);
83 }
84 spin_unlock_irqrestore(&task->state_lock, flags);
85 } while (cont);
86
87 task->ret = ret;
88}
89
90int rxe_init_task(void *obj, struct rxe_task *task,
91 void *arg, int (*func)(void *), char *name)
92{
93 task->obj = obj;
94 task->arg = arg;
95 task->func = func;
96 snprintf(task->name, sizeof(task->name), "%s", name);
97 task->destroyed = false;
98
99 tasklet_setup(&task->tasklet, rxe_do_task);
100
101 task->state = TASK_STATE_START;
102 spin_lock_init(&task->state_lock);
103
104 return 0;
105}
106
107void rxe_cleanup_task(struct rxe_task *task)
108{
109 unsigned long flags;
110 bool idle;
111
112
113
114
115
116 task->destroyed = true;
117
118 do {
119 spin_lock_irqsave(&task->state_lock, flags);
120 idle = (task->state == TASK_STATE_START);
121 spin_unlock_irqrestore(&task->state_lock, flags);
122 } while (!idle);
123
124 tasklet_kill(&task->tasklet);
125}
126
127void rxe_run_task(struct rxe_task *task, int sched)
128{
129 if (task->destroyed)
130 return;
131
132 if (sched)
133 tasklet_schedule(&task->tasklet);
134 else
135 rxe_do_task(&task->tasklet);
136}
137
138void rxe_disable_task(struct rxe_task *task)
139{
140 tasklet_disable(&task->tasklet);
141}
142
143void rxe_enable_task(struct rxe_task *task)
144{
145 tasklet_enable(&task->tasklet);
146}
147