From: Ken Cox Date: Tue, 4 Mar 2014 13:58:08 +0000 (-0600) Subject: staging: visorchannelstub driver to provide channel support routines X-Git-Url: http://drtracing.org/?a=commitdiff_plain;h=7b2a2d8383d08793aac3f157fa3f38ea90c5d3c0;p=deliverable%2Flinux.git staging: visorchannelstub driver to provide channel support routines The visorchannelstub module provides support routines for storing and retrieving data from a channel. Signed-off-by: Ken Cox Cc: Ben Romer Signed-off-by: Greg Kroah-Hartman --- diff --git a/drivers/staging/unisys/Kconfig b/drivers/staging/unisys/Kconfig index 14e1ea6803f8..c9a10bdf73cf 100644 --- a/drivers/staging/unisys/Kconfig +++ b/drivers/staging/unisys/Kconfig @@ -12,5 +12,6 @@ if UNISYSSPAR source "drivers/staging/unisys/visorutil/Kconfig" source "drivers/staging/unisys/visorchannel/Kconfig" source "drivers/staging/unisys/visorchipset/Kconfig" +source "drivers/staging/unisys/channels/Kconfig" endif # UNISYSSPAR diff --git a/drivers/staging/unisys/Makefile b/drivers/staging/unisys/Makefile index 4667f4485d50..e637f30cf21a 100644 --- a/drivers/staging/unisys/Makefile +++ b/drivers/staging/unisys/Makefile @@ -4,4 +4,5 @@ obj-$(CONFIG_UNISYS_VISORUTIL) += visorutil/ obj-$(CONFIG_UNISYS_VISORCHANNEL) += visorchannel/ obj-$(CONFIG_UNISYS_VISORCHIPSET) += visorchipset/ +obj-$(CONFIG_UNISYS_CHANNELSTUB) += channels/ diff --git a/drivers/staging/unisys/channels/Kconfig b/drivers/staging/unisys/channels/Kconfig new file mode 100644 index 000000000000..47a235385567 --- /dev/null +++ b/drivers/staging/unisys/channels/Kconfig @@ -0,0 +1,10 @@ +# +# Unisys channels configuration +# + +config UNISYS_CHANNELSTUB + tristate "Unisys channelstub driver" + depends on UNISYSSPAR + ---help--- + If you say Y here, you will enable the Unisys channels driver. + diff --git a/drivers/staging/unisys/channels/Makefile b/drivers/staging/unisys/channels/Makefile new file mode 100644 index 000000000000..e60b0aef4dcd --- /dev/null +++ b/drivers/staging/unisys/channels/Makefile @@ -0,0 +1,13 @@ +# +# Makefile for Unisys channelstub +# + +obj-$(CONFIG_UNISYS_CHANNELSTUB) += visorchannelstub.o + +visorchannelstub-y := channel.o chanstub.o + +ccflags-y += -Idrivers/staging/unisys/include +ccflags-y += -Idrivers/staging/unisys/common-spar/include +ccflags-y += -Idrivers/staging/unisys/common-spar/include/channels +ccflags-y += -DCONFIG_SPAR_GUEST -DGUESTDRIVERBUILD -DNOAUTOVERSION + diff --git a/drivers/staging/unisys/channels/channel.c b/drivers/staging/unisys/channels/channel.c new file mode 100644 index 000000000000..afe8ceac2036 --- /dev/null +++ b/drivers/staging/unisys/channels/channel.c @@ -0,0 +1,307 @@ +/* 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. + */ + +#include +#ifdef CONFIG_MODVERSIONS +#include +#endif +#include +#include /* for module_init and module_exit */ +#include /* for memcpy */ +#include + +/* Implementation of exported functions for Supervisor channels */ +#include "channel.h" + +/* + * Routine Description: + * Tries to insert the prebuilt signal pointed to by pSignal into the nth + * Queue of the Channel pointed to by pChannel + * + * Parameters: + * pChannel: (IN) points to the IO Channel + * Queue: (IN) nth Queue of the IO Channel + * pSignal: (IN) pointer to the signal + * + * Assumptions: + * - pChannel, Queue and pSignal are valid. + * - If insertion fails due to a full queue, the caller will determine the + * retry policy (e.g. wait & try again, report an error, etc.). + * + * Return value: + * 1 if the insertion succeeds, 0 if the queue was full. + */ +unsigned char +SignalInsert(pCHANNEL_HEADER pChannel, U32 Queue, void *pSignal) +{ + void *psignal; + unsigned int head, tail; + pSIGNAL_QUEUE_HEADER pqhdr = + (pSIGNAL_QUEUE_HEADER) ((char *) pChannel + + pChannel->oChannelSpace) + Queue; + + /* capture current head and tail */ + head = pqhdr->Head; + tail = pqhdr->Tail; + + /* queue is full if (head + 1) % n equals tail */ + if (((head + 1) % pqhdr->MaxSignalSlots) == tail) { + pqhdr->NumOverflows++; + return 0; + } + + /* increment the head index */ + head = (head + 1) % pqhdr->MaxSignalSlots; + + /* copy signal to the head location from the area pointed to + * by pSignal + */ + psignal = + (char *) pqhdr + pqhdr->oSignalBase + (head * pqhdr->SignalSize); + MEMCPY(psignal, pSignal, pqhdr->SignalSize); + + VolatileBarrier(); + pqhdr->Head = head; + + pqhdr->NumSignalsSent++; + return 1; +} +EXPORT_SYMBOL_GPL(SignalInsert); + +/* + * Routine Description: + * Removes one signal from Channel pChannel's nth Queue at the + * time of the call and copies it into the memory pointed to by + * pSignal. + * + * Parameters: + * pChannel: (IN) points to the IO Channel + * Queue: (IN) nth Queue of the IO Channel + * pSignal: (IN) pointer to where the signals are to be copied + * + * Assumptions: + * - pChannel and Queue are valid. + * - pSignal points to a memory area large enough to hold queue's SignalSize + * + * Return value: + * 1 if the removal succeeds, 0 if the queue was empty. + */ +unsigned char +SignalRemove(pCHANNEL_HEADER pChannel, U32 Queue, void *pSignal) +{ + void *psource; + unsigned int head, tail; + pSIGNAL_QUEUE_HEADER pqhdr = + (pSIGNAL_QUEUE_HEADER) ((char *) pChannel + + pChannel->oChannelSpace) + Queue; + + /* capture current head and tail */ + head = pqhdr->Head; + tail = pqhdr->Tail; + + /* queue is empty if the head index equals the tail index */ + if (head == tail) { + pqhdr->NumEmptyCnt++; + return 0; + } + + /* advance past the 'empty' front slot */ + tail = (tail + 1) % pqhdr->MaxSignalSlots; + + /* copy signal from tail location to the area pointed to by pSignal */ + psource = + (char *) pqhdr + pqhdr->oSignalBase + (tail * pqhdr->SignalSize); + MEMCPY(pSignal, psource, pqhdr->SignalSize); + + VolatileBarrier(); + pqhdr->Tail = tail; + + pqhdr->NumSignalsReceived++; + return 1; +} +EXPORT_SYMBOL_GPL(SignalRemove); + +/* + * Routine Description: + * Removes all signals present in Channel pChannel's nth Queue at the + * time of the call and copies them into the memory pointed to by + * pSignal. Returns the # of signals copied as the value of the routine. + * + * Parameters: + * pChannel: (IN) points to the IO Channel + * Queue: (IN) nth Queue of the IO Channel + * pSignal: (IN) pointer to where the signals are to be copied + * + * Assumptions: + * - pChannel and Queue are valid. + * - pSignal points to a memory area large enough to hold Queue's MaxSignals + * # of signals, each of which is Queue's SignalSize. + * + * Return value: + * # of signals copied. + */ +unsigned int +SignalRemoveAll(pCHANNEL_HEADER pChannel, U32 Queue, void *pSignal) +{ + void *psource; + unsigned int head, tail, signalCount = 0; + pSIGNAL_QUEUE_HEADER pqhdr = + (pSIGNAL_QUEUE_HEADER) ((char *) pChannel + + pChannel->oChannelSpace) + Queue; + + /* capture current head and tail */ + head = pqhdr->Head; + tail = pqhdr->Tail; + + /* queue is empty if the head index equals the tail index */ + if (head == tail) + return 0; + + while (head != tail) { + /* advance past the 'empty' front slot */ + tail = (tail + 1) % pqhdr->MaxSignalSlots; + + /* copy signal from tail location to the area pointed + * to by pSignal + */ + psource = + (char *) pqhdr + pqhdr->oSignalBase + + (tail * pqhdr->SignalSize); + MEMCPY((char *) pSignal + (pqhdr->SignalSize * signalCount), + psource, pqhdr->SignalSize); + + VolatileBarrier(); + pqhdr->Tail = tail; + + signalCount++; + pqhdr->NumSignalsReceived++; + } + + return signalCount; +} + +/* + * Routine Description: + * Copies one signal from channel pChannel's nth Queue at the given position + * at the time of the call into the memory pointed to by pSignal. + * + * Parameters: + * pChannel: (IN) points to the IO Channel + * Queue: (IN) nth Queue of the IO Channel + * Position: (IN) nth entry in Queue of the IO Channel + * pSignal: (IN) pointer to where the signals are to be copied + * + * Assumptions: + * - pChannel and Queue are valid. + * - pSignal points to a memory area large enough to hold queue's SignalSize + * + * Return value: + * 1 if the copy succeeds, 0 if the queue was empty or Position was invalid. + */ +unsigned char +SignalPeek(pCHANNEL_HEADER pChannel, U32 Queue, U32 Position, void *pSignal) +{ + void *psignal; + unsigned int head, tail; + pSIGNAL_QUEUE_HEADER pqhdr = + (pSIGNAL_QUEUE_HEADER) ((char *) pChannel + + pChannel->oChannelSpace) + Queue; + + head = pqhdr->Head; + tail = pqhdr->Tail; + + /* check if Position is out of range or queue is empty */ + if (Position >= pqhdr->MaxSignalSlots || Position == tail + || head == tail) + return 0; + + /* check if Position is between tail and head */ + if (head > tail) { + if (Position > head || Position < tail) + return 0; + } else if ((Position > head) && (Position < tail)) + return 0; + + /* copy signal from Position location to the area pointed to + * by pSignal + */ + psignal = + (char *) pqhdr + pqhdr->oSignalBase + + (Position * pqhdr->SignalSize); + MEMCPY(pSignal, psignal, pqhdr->SignalSize); + + return 1; +} + +/* + * Routine Description: + * Determine whether a signal queue is empty. + * + * Parameters: + * pChannel: (IN) points to the IO Channel + * Queue: (IN) nth Queue of the IO Channel + * + * Return value: + * 1 if the signal queue is empty, 0 otherwise. + */ +unsigned char +SignalQueueIsEmpty(pCHANNEL_HEADER pChannel, U32 Queue) +{ + pSIGNAL_QUEUE_HEADER pqhdr = + (pSIGNAL_QUEUE_HEADER) ((char *) pChannel + + pChannel->oChannelSpace) + Queue; + return pqhdr->Head == pqhdr->Tail; +} +EXPORT_SYMBOL_GPL(SignalQueueIsEmpty); + +/* + * Routine Description: + * Determine whether a signal queue is empty. + * + * Parameters: + * pChannel: (IN) points to the IO Channel + * Queue: (IN) nth Queue of the IO Channel + * + * Return value: + * 1 if the signal queue has 1 element, 0 otherwise. + */ +unsigned char +SignalQueueHasOneElement(pCHANNEL_HEADER pChannel, U32 Queue) +{ + pSIGNAL_QUEUE_HEADER pqhdr = + (pSIGNAL_QUEUE_HEADER) ((char *) pChannel + + pChannel->oChannelSpace) + Queue; + return ((pqhdr->Tail + 1) % pqhdr->MaxSignalSlots) == pqhdr->Head; +} + +/* + * Routine Description: + * Determine whether a signal queue is full. + * + * Parameters: + * pChannel: (IN) points to the IO Channel + * Queue: (IN) nth Queue of the IO Channel + * + * Return value: + * 1 if the signal queue is full, 0 otherwise. + */ +unsigned char +SignalQueueIsFull(pCHANNEL_HEADER pChannel, U32 Queue) +{ + pSIGNAL_QUEUE_HEADER pqhdr = + (pSIGNAL_QUEUE_HEADER) ((char *) pChannel + + pChannel->oChannelSpace) + Queue; + return ((pqhdr->Head + 1) % pqhdr->MaxSignalSlots) == pqhdr->Tail; +} diff --git a/drivers/staging/unisys/channels/chanstub.c b/drivers/staging/unisys/channels/chanstub.c new file mode 100644 index 000000000000..37e207d19bdf --- /dev/null +++ b/drivers/staging/unisys/channels/chanstub.c @@ -0,0 +1,70 @@ +/* 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. + */ + +#define EXPORT_SYMTAB +#include +#ifdef CONFIG_MODVERSIONS +#include +#endif +#include +#include /* for module_init and module_exit */ +#include /* for memcpy */ +#include + +#include "channel.h" +#include "chanstub.h" +#include "version.h" + +__init int +channel_mod_init(void) +{ + return 0; +} + +__exit void +channel_mod_exit(void) +{ +} + +unsigned char +SignalInsert_withLock(pCHANNEL_HEADER pChannel, U32 Queue, + void *pSignal, spinlock_t *lock) +{ + unsigned char result; + unsigned long flags; + spin_lock_irqsave(lock, flags); + result = SignalInsert(pChannel, Queue, pSignal); + spin_unlock_irqrestore(lock, flags); + return result; +} + +unsigned char +SignalRemove_withLock(pCHANNEL_HEADER pChannel, U32 Queue, + void *pSignal, spinlock_t *lock) +{ + unsigned char result; + spin_lock(lock); + result = SignalRemove(pChannel, Queue, pSignal); + spin_unlock(lock); + return result; +} + +module_init(channel_mod_init); +module_exit(channel_mod_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Bryan Glaudel"); +MODULE_ALIAS("uischan"); + /* this is extracted during depmod and kept in modules.dep */ diff --git a/drivers/staging/unisys/channels/chanstub.h b/drivers/staging/unisys/channels/chanstub.h new file mode 100644 index 000000000000..dadd7cd31244 --- /dev/null +++ b/drivers/staging/unisys/channels/chanstub.h @@ -0,0 +1,23 @@ +/* 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. + */ + +#ifndef __CHANSTUB_H__ +#define __CHANSTUB_H__ +unsigned char SignalInsert_withLock(pCHANNEL_HEADER pChannel, U32 Queue, + void *pSignal, spinlock_t *lock); +unsigned char SignalRemove_withLock(pCHANNEL_HEADER pChannel, U32 Queue, + void *pSignal, spinlock_t *lock); + +#endif