]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - drivers/infiniband/sw/rxe/rxe_task.c
Makefile: drop -D__CHECK_ENDIAN__ from cflags
[mirror_ubuntu-artful-kernel.git] / drivers / infiniband / sw / rxe / rxe_task.c
1 /*
2 * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
3 * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
4 *
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:
10 *
11 * Redistribution and use in source and binary forms, with or
12 * without modification, are permitted provided that the following
13 * conditions are met:
14 *
15 * - Redistributions of source code must retain the above
16 * copyright notice, this list of conditions and the following
17 * disclaimer.
18 *
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.
23 *
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.
32 */
33
34 #include <linux/kernel.h>
35 #include <linux/interrupt.h>
36 #include <linux/hardirq.h>
37
38 #include "rxe_task.h"
39
40 int __rxe_do_task(struct rxe_task *task)
41
42 {
43 int ret;
44
45 while ((ret = task->func(task->arg)) == 0)
46 ;
47
48 task->ret = ret;
49
50 return ret;
51 }
52
53 /*
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
57 */
58 void rxe_do_task(unsigned long data)
59 {
60 int cont;
61 int ret;
62 unsigned long flags;
63 struct rxe_task *task = (struct rxe_task *)data;
64
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;
71
72 case TASK_STATE_BUSY:
73 task->state = TASK_STATE_ARMED;
74 /* fall through to */
75 case TASK_STATE_ARMED:
76 spin_unlock_irqrestore(&task->state_lock, flags);
77 return;
78
79 default:
80 spin_unlock_irqrestore(&task->state_lock, flags);
81 pr_warn("bad state = %d in rxe_do_task\n", task->state);
82 return;
83 }
84
85 do {
86 cont = 0;
87 ret = task->func(task->arg);
88
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;
97
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
101 */
102 case TASK_STATE_ARMED:
103 task->state = TASK_STATE_BUSY;
104 cont = 1;
105 break;
106
107 default:
108 pr_warn("bad state = %d in rxe_do_task\n",
109 task->state);
110 }
111 spin_unlock_irqrestore(&task->state_lock, flags);
112 } while (cont);
113
114 task->ret = ret;
115 }
116
117 int rxe_init_task(void *obj, struct rxe_task *task,
118 void *arg, int (*func)(void *), char *name)
119 {
120 task->obj = obj;
121 task->arg = arg;
122 task->func = func;
123 snprintf(task->name, sizeof(task->name), "%s", name);
124
125 tasklet_init(&task->tasklet, rxe_do_task, (unsigned long)task);
126
127 task->state = TASK_STATE_START;
128 spin_lock_init(&task->state_lock);
129
130 return 0;
131 }
132
133 void rxe_cleanup_task(struct rxe_task *task)
134 {
135 tasklet_kill(&task->tasklet);
136 }
137
138 void rxe_run_task(struct rxe_task *task, int sched)
139 {
140 if (sched)
141 tasklet_schedule(&task->tasklet);
142 else
143 rxe_do_task((unsigned long)task);
144 }
145
146 void rxe_disable_task(struct rxe_task *task)
147 {
148 tasklet_disable(&task->tasklet);
149 }
150
151 void rxe_enable_task(struct rxe_task *task)
152 {
153 tasklet_enable(&task->tasklet);
154 }