staging: visorchannelstub driver to provide channel support routines
authorKen Cox <jkc@redhat.com>
Tue, 4 Mar 2014 13:58:08 +0000 (07:58 -0600)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 5 Mar 2014 00:59:30 +0000 (16:59 -0800)
The visorchannelstub module provides support routines for storing and
retrieving data from a channel.

Signed-off-by: Ken Cox <jkc@redhat.com>
Cc: Ben Romer <sparmaintainer@unisys.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/staging/unisys/Kconfig
drivers/staging/unisys/Makefile
drivers/staging/unisys/channels/Kconfig [new file with mode: 0644]
drivers/staging/unisys/channels/Makefile [new file with mode: 0644]
drivers/staging/unisys/channels/channel.c [new file with mode: 0644]
drivers/staging/unisys/channels/chanstub.c [new file with mode: 0644]
drivers/staging/unisys/channels/chanstub.h [new file with mode: 0644]

index 14e1ea6803f81b9deee22b93dafcadffd14eaffc..c9a10bdf73cf8311cd5970c9163303076c084e4f 100644 (file)
@@ -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
index 4667f4485d50d5b720e2a06877d02183ada1dd7d..e637f30cf21aa05f96f0d02fc7562284d3439acd 100644 (file)
@@ -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 (file)
index 0000000..47a2353
--- /dev/null
@@ -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 (file)
index 0000000..e60b0ae
--- /dev/null
@@ -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 (file)
index 0000000..afe8cea
--- /dev/null
@@ -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 <linux/kernel.h>
+#ifdef CONFIG_MODVERSIONS
+#include <config/modversions.h>
+#endif
+#include <linux/module.h>
+#include <linux/init.h>                /* for module_init and module_exit */
+#include <linux/slab.h>                /* for memcpy */
+#include <linux/types.h>
+
+/* 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 (file)
index 0000000..37e207d
--- /dev/null
@@ -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 <linux/kernel.h>
+#ifdef CONFIG_MODVERSIONS
+#include <config/modversions.h>
+#endif
+#include <linux/module.h>
+#include <linux/init.h>                /* for module_init and module_exit */
+#include <linux/slab.h>                /* for memcpy */
+#include <linux/types.h>
+
+#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 (file)
index 0000000..dadd7cd
--- /dev/null
@@ -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