diff options
Diffstat (limited to 'drivers/staging/unisys/uislib/uisqueue.c')
-rw-r--r-- | drivers/staging/unisys/uislib/uisqueue.c | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/drivers/staging/unisys/uislib/uisqueue.c b/drivers/staging/unisys/uislib/uisqueue.c new file mode 100644 index 000000000000..40598ff1f4f2 --- /dev/null +++ b/drivers/staging/unisys/uislib/uisqueue.c @@ -0,0 +1,160 @@ +/* uisqueue.c + * + * Copyright © 2010 - 2013 UNISYS CORPORATION + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + */ + +/* @ALL_INSPECTED */ +#include <linux/kernel.h> +#include <linux/module.h> + +#include "uisutils.h" + +#include "chanstub.h" + +/* this is shorter than using __FILE__ (full path name) in + * debug/info/error messages */ +#define CURRENT_FILE_PC UISLIB_PC_uisqueue_c +#define __MYFILE__ "uisqueue.c" + +#define CHECK_CACHE_ALIGN 0 + +/*****************************************************/ +/* Exported functions */ +/*****************************************************/ +unsigned long long +uisqueue_InterlockedOr(unsigned long long __iomem *Target, + unsigned long long Set) +{ + unsigned long long i; + unsigned long long j; + + j = readq(Target); + do { + i = j; + j = uislibcmpxchg64((__force unsigned long long *)Target, + i, i | Set, sizeof(*(Target))); + + } while (i != j); + + return j; +} +EXPORT_SYMBOL_GPL(uisqueue_InterlockedOr); + +unsigned long long +uisqueue_InterlockedAnd(unsigned long long __iomem *Target, + unsigned long long Set) +{ + unsigned long long i; + unsigned long long j; + + j = readq(Target); + do { + i = j; + j = uislibcmpxchg64((__force unsigned long long *)Target, + i, i & Set, sizeof(*(Target))); + + } while (i != j); + + return j; +} +EXPORT_SYMBOL_GPL(uisqueue_InterlockedAnd); + +static U8 +do_locked_client_insert(struct uisqueue_info *queueinfo, + unsigned int whichqueue, + void *pSignal, + spinlock_t *lock, + unsigned char issueInterruptIfEmpty, + U64 interruptHandle, U8 *channelId) +{ + unsigned long flags; + unsigned char queueWasEmpty; + unsigned int locked = 0; + unsigned int acquired = 0; + U8 rc = 0; + + spin_lock_irqsave(lock, flags); + locked = 1; + + if (!ULTRA_CHANNEL_CLIENT_ACQUIRE_OS(queueinfo->chan, channelId, NULL)) + goto Away; + + acquired = 1; + + queueWasEmpty = visor_signalqueue_empty(queueinfo->chan, whichqueue); + if (!visor_signal_insert(queueinfo->chan, whichqueue, pSignal)) + goto Away; + ULTRA_CHANNEL_CLIENT_RELEASE_OS(queueinfo->chan, channelId, NULL); + acquired = 0; + spin_unlock_irqrestore(lock, flags); + locked = 0; + + queueinfo->packets_sent++; + + rc = 1; +Away: + if (acquired) { + ULTRA_CHANNEL_CLIENT_RELEASE_OS(queueinfo->chan, channelId, + NULL); + acquired = 0; + } + if (locked) { + spin_unlock_irqrestore((spinlock_t *) lock, flags); + locked = 0; + } + + return rc; +} + +int +uisqueue_put_cmdrsp_with_lock_client(struct uisqueue_info *queueinfo, + struct uiscmdrsp *cmdrsp, + unsigned int whichqueue, + void *insertlock, + unsigned char issueInterruptIfEmpty, + U64 interruptHandle, + char oktowait, U8 *channelId) +{ + while (!do_locked_client_insert(queueinfo, whichqueue, cmdrsp, + (spinlock_t *) insertlock, + issueInterruptIfEmpty, + interruptHandle, channelId)) { + if (oktowait != OK_TO_WAIT) { + LOGERR("****FAILED visor_signal_insert failed; cannot wait; insert aborted\n"); + return 0; /* failed to queue */ + } + /* try again */ + LOGERR("****FAILED visor_signal_insert failed; waiting to try again\n"); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(msecs_to_jiffies(10)); + } + return 1; +} +EXPORT_SYMBOL_GPL(uisqueue_put_cmdrsp_with_lock_client); + +/* uisqueue_get_cmdrsp gets the cmdrsp entry at the head of the queue + * returns NULL if queue is empty */ +int +uisqueue_get_cmdrsp(struct uisqueue_info *queueinfo, + void *cmdrsp, unsigned int whichqueue) +{ + if (!visor_signal_remove(queueinfo->chan, whichqueue, cmdrsp)) + return 0; + + queueinfo->packets_received++; + + return 1; /* Success */ +} +EXPORT_SYMBOL_GPL(uisqueue_get_cmdrsp); |