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
15 * - Redistributions of source code must retain the above
16 * copyright notice, this list of conditions and the following
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
34 #include <linux/kernel.h>
35 #include <linux/interrupt.h>
36 #include <linux/hardirq.h>
40 int __rxe_do_task(struct rxe_task
*task
)
45 while ((ret
= task
->func(task
->arg
)) == 0)
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
)
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
);
73 task
->state
= TASK_STATE_ARMED
;
75 case TASK_STATE_ARMED
:
76 spin_unlock_irqrestore(&task
->state_lock
, flags
);
80 spin_unlock_irqrestore(&task
->state_lock
, flags
);
81 pr_warn("%s failed with bad state %d\n", __func__
, task
->state
);
87 ret
= task
->func(task
->arg
);
89 spin_lock_irqsave(&task
->state_lock
, flags
);
90 switch (task
->state
) {
93 task
->state
= TASK_STATE_START
;
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
102 case TASK_STATE_ARMED
:
103 task
->state
= TASK_STATE_BUSY
;
108 pr_warn("%s failed with bad state %d\n", __func__
,
111 spin_unlock_irqrestore(&task
->state_lock
, flags
);
117 int rxe_init_task(void *obj
, struct rxe_task
*task
,
118 void *arg
, int (*func
)(void *), char *name
)
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
);
134 void rxe_cleanup_task(struct rxe_task
*task
)
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;
146 spin_lock_irqsave(&task
->state_lock
, flags
);
147 idle
= (task
->state
== TASK_STATE_START
);
148 spin_unlock_irqrestore(&task
->state_lock
, flags
);
151 tasklet_kill(&task
->tasklet
);
154 void rxe_run_task(struct rxe_task
*task
, int sched
)
160 tasklet_schedule(&task
->tasklet
);
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
);