Linux 4.19.133
[linux/fpc-iii.git] / drivers / infiniband / sw / rxe / rxe_task.c
blob08f05ac5f5d526f94d48f5b68ae9512463c4bd15
1 /*
2 * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
3 * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
5 * This software is available to you under a choice of one of two
6 * licenses. You may choose to be licensed under the terms of the GNU
7 * General Public License (GPL) Version 2, available from the file
8 * COPYING in the main directory of this source tree, or the
9 * OpenIB.org BSD license below:
11 * Redistribution and use in source and binary forms, with or
12 * without modification, are permitted provided that the following
13 * conditions are met:
15 * - Redistributions of source code must retain the above
16 * copyright notice, this list of conditions and the following
17 * disclaimer.
19 * - Redistributions in binary form must reproduce the above
20 * copyright notice, this list of conditions and the following
21 * disclaimer in the documentation and/or other materials
22 * provided with the distribution.
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31 * SOFTWARE.
34 #include <linux/kernel.h>
35 #include <linux/interrupt.h>
36 #include <linux/hardirq.h>
38 #include "rxe_task.h"
40 int __rxe_do_task(struct rxe_task *task)
43 int ret;
45 while ((ret = task->func(task->arg)) == 0)
48 task->ret = ret;
50 return ret;
54 * this locking is due to a potential race where
55 * a second caller finds the task already running
56 * but looks just after the last call to func
58 void rxe_do_task(unsigned long data)
60 int cont;
61 int ret;
62 unsigned long flags;
63 struct rxe_task *task = (struct rxe_task *)data;
65 spin_lock_irqsave(&task->state_lock, flags);
66 switch (task->state) {
67 case TASK_STATE_START:
68 task->state = TASK_STATE_BUSY;
69 spin_unlock_irqrestore(&task->state_lock, flags);
70 break;
72 case TASK_STATE_BUSY:
73 task->state = TASK_STATE_ARMED;
74 /* fall through */
75 case TASK_STATE_ARMED:
76 spin_unlock_irqrestore(&task->state_lock, flags);
77 return;
79 default:
80 spin_unlock_irqrestore(&task->state_lock, flags);
81 pr_warn("%s failed with bad state %d\n", __func__, task->state);
82 return;
85 do {
86 cont = 0;
87 ret = task->func(task->arg);
89 spin_lock_irqsave(&task->state_lock, flags);
90 switch (task->state) {
91 case TASK_STATE_BUSY:
92 if (ret)
93 task->state = TASK_STATE_START;
94 else
95 cont = 1;
96 break;
98 /* soneone tried to run the task since the last time we called
99 * func, so we will call one more time regardless of the
100 * return value
102 case TASK_STATE_ARMED:
103 task->state = TASK_STATE_BUSY;
104 cont = 1;
105 break;
107 default:
108 pr_warn("%s failed with bad state %d\n", __func__,
109 task->state);
111 spin_unlock_irqrestore(&task->state_lock, flags);
112 } while (cont);
114 task->ret = ret;
117 int rxe_init_task(void *obj, struct rxe_task *task,
118 void *arg, int (*func)(void *), char *name)
120 task->obj = obj;
121 task->arg = arg;
122 task->func = func;
123 snprintf(task->name, sizeof(task->name), "%s", name);
124 task->destroyed = false;
126 tasklet_init(&task->tasklet, rxe_do_task, (unsigned long)task);
128 task->state = TASK_STATE_START;
129 spin_lock_init(&task->state_lock);
131 return 0;
134 void rxe_cleanup_task(struct rxe_task *task)
136 unsigned long flags;
137 bool idle;
140 * Mark the task, then wait for it to finish. It might be
141 * running in a non-tasklet (direct call) context.
143 task->destroyed = true;
145 do {
146 spin_lock_irqsave(&task->state_lock, flags);
147 idle = (task->state == TASK_STATE_START);
148 spin_unlock_irqrestore(&task->state_lock, flags);
149 } while (!idle);
151 tasklet_kill(&task->tasklet);
154 void rxe_run_task(struct rxe_task *task, int sched)
156 if (task->destroyed)
157 return;
159 if (sched)
160 tasklet_schedule(&task->tasklet);
161 else
162 rxe_do_task((unsigned long)task);
165 void rxe_disable_task(struct rxe_task *task)
167 tasklet_disable(&task->tasklet);
170 void rxe_enable_task(struct rxe_task *task)
172 tasklet_enable(&task->tasklet);