WIP FPC-III support
[linux/fpc-iii.git] / drivers / infiniband / sw / rxe / rxe_task.c
blob6951fdcb31bf51f88b65be198a5d3397a0bd6408
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 */
7 #include <linux/kernel.h>
8 #include <linux/interrupt.h>
9 #include <linux/hardirq.h>
11 #include "rxe_task.h"
13 int __rxe_do_task(struct rxe_task *task)
16 int ret;
18 while ((ret = task->func(task->arg)) == 0)
21 task->ret = ret;
23 return ret;
27 * this locking is due to a potential race where
28 * a second caller finds the task already running
29 * but looks just after the last call to func
31 void rxe_do_task(struct tasklet_struct *t)
33 int cont;
34 int ret;
35 unsigned long flags;
36 struct rxe_task *task = from_tasklet(task, t, tasklet);
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;
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;
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;
58 do {
59 cont = 0;
60 ret = task->func(task->arg);
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;
71 /* soneone tried to run the task since the last time we called
72 * func, so we will call one more time regardless of the
73 * return value
75 case TASK_STATE_ARMED:
76 task->state = TASK_STATE_BUSY;
77 cont = 1;
78 break;
80 default:
81 pr_warn("%s failed with bad state %d\n", __func__,
82 task->state);
84 spin_unlock_irqrestore(&task->state_lock, flags);
85 } while (cont);
87 task->ret = ret;
90 int rxe_init_task(void *obj, struct rxe_task *task,
91 void *arg, int (*func)(void *), char *name)
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;
99 tasklet_setup(&task->tasklet, rxe_do_task);
101 task->state = TASK_STATE_START;
102 spin_lock_init(&task->state_lock);
104 return 0;
107 void rxe_cleanup_task(struct rxe_task *task)
109 unsigned long flags;
110 bool idle;
113 * Mark the task, then wait for it to finish. It might be
114 * running in a non-tasklet (direct call) context.
116 task->destroyed = true;
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);
124 tasklet_kill(&task->tasklet);
127 void rxe_run_task(struct rxe_task *task, int sched)
129 if (task->destroyed)
130 return;
132 if (sched)
133 tasklet_schedule(&task->tasklet);
134 else
135 rxe_do_task(&task->tasklet);
138 void rxe_disable_task(struct rxe_task *task)
140 tasklet_disable(&task->tasklet);
143 void rxe_enable_task(struct rxe_task *task)
145 tasklet_enable(&task->tasklet);