cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

rxe_task.c (2854B)


      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 */
      6
      7#include <linux/kernel.h>
      8#include <linux/interrupt.h>
      9#include <linux/hardirq.h>
     10
     11#include "rxe_task.h"
     12
     13int __rxe_do_task(struct rxe_task *task)
     14
     15{
     16	int ret;
     17
     18	while ((ret = task->func(task->arg)) == 0)
     19		;
     20
     21	task->ret = ret;
     22
     23	return ret;
     24}
     25
     26/*
     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
     30 */
     31void rxe_do_task(struct tasklet_struct *t)
     32{
     33	int cont;
     34	int ret;
     35	struct rxe_task *task = from_tasklet(task, t, tasklet);
     36
     37	spin_lock_bh(&task->state_lock);
     38	switch (task->state) {
     39	case TASK_STATE_START:
     40		task->state = TASK_STATE_BUSY;
     41		spin_unlock_bh(&task->state_lock);
     42		break;
     43
     44	case TASK_STATE_BUSY:
     45		task->state = TASK_STATE_ARMED;
     46		fallthrough;
     47	case TASK_STATE_ARMED:
     48		spin_unlock_bh(&task->state_lock);
     49		return;
     50
     51	default:
     52		spin_unlock_bh(&task->state_lock);
     53		pr_warn("%s failed with bad state %d\n", __func__, task->state);
     54		return;
     55	}
     56
     57	do {
     58		cont = 0;
     59		ret = task->func(task->arg);
     60
     61		spin_lock_bh(&task->state_lock);
     62		switch (task->state) {
     63		case TASK_STATE_BUSY:
     64			if (ret)
     65				task->state = TASK_STATE_START;
     66			else
     67				cont = 1;
     68			break;
     69
     70		/* soneone tried to run the task since the last time we called
     71		 * func, so we will call one more time regardless of the
     72		 * return value
     73		 */
     74		case TASK_STATE_ARMED:
     75			task->state = TASK_STATE_BUSY;
     76			cont = 1;
     77			break;
     78
     79		default:
     80			pr_warn("%s failed with bad state %d\n", __func__,
     81				task->state);
     82		}
     83		spin_unlock_bh(&task->state_lock);
     84	} while (cont);
     85
     86	task->ret = ret;
     87}
     88
     89int rxe_init_task(void *obj, struct rxe_task *task,
     90		  void *arg, int (*func)(void *), char *name)
     91{
     92	task->obj	= obj;
     93	task->arg	= arg;
     94	task->func	= func;
     95	snprintf(task->name, sizeof(task->name), "%s", name);
     96	task->destroyed	= false;
     97
     98	tasklet_setup(&task->tasklet, rxe_do_task);
     99
    100	task->state = TASK_STATE_START;
    101	spin_lock_init(&task->state_lock);
    102
    103	return 0;
    104}
    105
    106void rxe_cleanup_task(struct rxe_task *task)
    107{
    108	bool idle;
    109
    110	/*
    111	 * Mark the task, then wait for it to finish. It might be
    112	 * running in a non-tasklet (direct call) context.
    113	 */
    114	task->destroyed = true;
    115
    116	do {
    117		spin_lock_bh(&task->state_lock);
    118		idle = (task->state == TASK_STATE_START);
    119		spin_unlock_bh(&task->state_lock);
    120	} while (!idle);
    121
    122	tasklet_kill(&task->tasklet);
    123}
    124
    125void rxe_run_task(struct rxe_task *task, int sched)
    126{
    127	if (task->destroyed)
    128		return;
    129
    130	if (sched)
    131		tasklet_schedule(&task->tasklet);
    132	else
    133		rxe_do_task(&task->tasklet);
    134}
    135
    136void rxe_disable_task(struct rxe_task *task)
    137{
    138	tasklet_disable(&task->tasklet);
    139}
    140
    141void rxe_enable_task(struct rxe_task *task)
    142{
    143	tasklet_enable(&task->tasklet);
    144}