Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
0002 /*
0003  * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
0004  * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
0005  */
0006 
0007 #include <linux/kernel.h>
0008 #include <linux/interrupt.h>
0009 #include <linux/hardirq.h>
0010 
0011 #include "rxe.h"
0012 
0013 int __rxe_do_task(struct rxe_task *task)
0014 
0015 {
0016     int ret;
0017 
0018     while ((ret = task->func(task->arg)) == 0)
0019         ;
0020 
0021     task->ret = ret;
0022 
0023     return ret;
0024 }
0025 
0026 /*
0027  * this locking is due to a potential race where
0028  * a second caller finds the task already running
0029  * but looks just after the last call to func
0030  */
0031 void rxe_do_task(struct tasklet_struct *t)
0032 {
0033     int cont;
0034     int ret;
0035     struct rxe_task *task = from_tasklet(task, t, tasklet);
0036     unsigned int iterations = RXE_MAX_ITERATIONS;
0037 
0038     spin_lock_bh(&task->state_lock);
0039     switch (task->state) {
0040     case TASK_STATE_START:
0041         task->state = TASK_STATE_BUSY;
0042         spin_unlock_bh(&task->state_lock);
0043         break;
0044 
0045     case TASK_STATE_BUSY:
0046         task->state = TASK_STATE_ARMED;
0047         fallthrough;
0048     case TASK_STATE_ARMED:
0049         spin_unlock_bh(&task->state_lock);
0050         return;
0051 
0052     default:
0053         spin_unlock_bh(&task->state_lock);
0054         pr_warn("%s failed with bad state %d\n", __func__, task->state);
0055         return;
0056     }
0057 
0058     do {
0059         cont = 0;
0060         ret = task->func(task->arg);
0061 
0062         spin_lock_bh(&task->state_lock);
0063         switch (task->state) {
0064         case TASK_STATE_BUSY:
0065             if (ret) {
0066                 task->state = TASK_STATE_START;
0067             } else if (iterations--) {
0068                 cont = 1;
0069             } else {
0070                 /* reschedule the tasklet and exit
0071                  * the loop to give up the cpu
0072                  */
0073                 tasklet_schedule(&task->tasklet);
0074                 task->state = TASK_STATE_START;
0075             }
0076             break;
0077 
0078         /* someone tried to run the task since the last time we called
0079          * func, so we will call one more time regardless of the
0080          * return value
0081          */
0082         case TASK_STATE_ARMED:
0083             task->state = TASK_STATE_BUSY;
0084             cont = 1;
0085             break;
0086 
0087         default:
0088             pr_warn("%s failed with bad state %d\n", __func__,
0089                 task->state);
0090         }
0091         spin_unlock_bh(&task->state_lock);
0092     } while (cont);
0093 
0094     task->ret = ret;
0095 }
0096 
0097 int rxe_init_task(void *obj, struct rxe_task *task,
0098           void *arg, int (*func)(void *), char *name)
0099 {
0100     task->obj   = obj;
0101     task->arg   = arg;
0102     task->func  = func;
0103     snprintf(task->name, sizeof(task->name), "%s", name);
0104     task->destroyed = false;
0105 
0106     tasklet_setup(&task->tasklet, rxe_do_task);
0107 
0108     task->state = TASK_STATE_START;
0109     spin_lock_init(&task->state_lock);
0110 
0111     return 0;
0112 }
0113 
0114 void rxe_cleanup_task(struct rxe_task *task)
0115 {
0116     bool idle;
0117 
0118     /*
0119      * Mark the task, then wait for it to finish. It might be
0120      * running in a non-tasklet (direct call) context.
0121      */
0122     task->destroyed = true;
0123 
0124     do {
0125         spin_lock_bh(&task->state_lock);
0126         idle = (task->state == TASK_STATE_START);
0127         spin_unlock_bh(&task->state_lock);
0128     } while (!idle);
0129 
0130     tasklet_kill(&task->tasklet);
0131 }
0132 
0133 void rxe_run_task(struct rxe_task *task, int sched)
0134 {
0135     if (task->destroyed)
0136         return;
0137 
0138     if (sched)
0139         tasklet_schedule(&task->tasklet);
0140     else
0141         rxe_do_task(&task->tasklet);
0142 }
0143 
0144 void rxe_disable_task(struct rxe_task *task)
0145 {
0146     tasklet_disable(&task->tasklet);
0147 }
0148 
0149 void rxe_enable_task(struct rxe_task *task)
0150 {
0151     tasklet_enable(&task->tasklet);
0152 }