[patch V2 2/8] staging: visorchannel module

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The visorchannel module is a support library that abstracts reading
and writing a channel in memory.

Signed-off-by: Ken Cox <jkc@xxxxxxxxxx>
Cc: Ben Romer <sparmaintainer@xxxxxxxxxx>

Index: upstream-staging/drivers/staging/unisys/Kconfig
===================================================================
--- upstream-staging.orig/drivers/staging/unisys/Kconfig
+++ upstream-staging/drivers/staging/unisys/Kconfig
@@ -10,5 +10,6 @@ menuconfig UNISYSSPAR
 if UNISYSSPAR
 
 source "drivers/staging/unisys/visorutil/Kconfig"
+source "drivers/staging/unisys/visorchannel/Kconfig"
 
 endif # UNISYSSPAR
Index: upstream-staging/drivers/staging/unisys/Makefile
===================================================================
--- upstream-staging.orig/drivers/staging/unisys/Makefile
+++ upstream-staging/drivers/staging/unisys/Makefile
@@ -2,4 +2,5 @@
 # Makefile for Unisys SPAR drivers
 #
 obj-$(CONFIG_UNISYS_VISORUTIL)		+= visorutil/
+obj-$(CONFIG_UNISYS_VISORCHANNEL)	+= visorchannel/
 
Index: upstream-staging/drivers/staging/unisys/common-spar/include/channels/channel.h
===================================================================
--- /dev/null
+++ upstream-staging/drivers/staging/unisys/common-spar/include/channels/channel.h
@@ -0,0 +1,645 @@
+/* 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 __CHANNEL_H__
+#define __CHANNEL_H__
+
+/*
+* Whenever this file is changed a corresponding change must be made in
+* the Console/ServicePart/visordiag_early/supervisor_channel.h file
+* which is needed for Linux kernel compiles. These two files must be
+* in sync.
+*/
+
+/* define the following to prevent include nesting in kernel header
+ * files of similar abreviated content
+ */
+#define __SUPERVISOR_CHANNEL_H__
+
+#include "commontypes.h"
+
+#define SIGNATURE_16(A, B) ((A) | (B<<8))
+#define SIGNATURE_32(A, B, C, D) \
+	(SIGNATURE_16(A, B) | (SIGNATURE_16(C, D) << 16))
+#define SIGNATURE_64(A, B, C, D, E, F, G, H) \
+	(SIGNATURE_32(A, B, C, D) | ((U64)(SIGNATURE_32(E, F, G, H)) << 32))
+
+#ifndef lengthof
+#define lengthof(TYPE, MEMBER) (sizeof(((TYPE *)0)->MEMBER))
+#endif
+#ifndef COVERQ
+#define COVERQ(v, d)  (((v)+(d)-1) / (d))
+#endif
+#ifndef COVER
+#define COVER(v, d)   ((d)*COVERQ(v, d))
+#endif
+
+#ifndef GUID0
+#define GUID0 {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0} }
+#endif
+
+/*  The C language is inconsistent with respect to where it allows literal
+ *  constants, especially literal constant structs.  Literal constant structs
+ *  are allowed for initialization only, whereas other types of literal
+ *  constants are allowed anywhere.  We get around this inconsistency by
+ *  declaring a "static const" variable for each GUID.  This variable can be
+ *  used in expressions where the literal constant would not be allowed.
+ */
+static const GUID Guid0 = GUID0;
+
+#define ULTRA_CHANNEL_PROTOCOL_SIGNATURE  SIGNATURE_32('E', 'C', 'N', 'L')
+
+typedef enum {
+	CHANNELSRV_UNINITIALIZED = 0,	/* channel is in an undefined state */
+	CHANNELSRV_READY = 1	/* channel has been initialized by server */
+} CHANNEL_SERVERSTATE;
+
+typedef enum {
+	CHANNELCLI_DETACHED = 0,
+	CHANNELCLI_DISABLED = 1,	/* client can see channel but is NOT
+					 * allowed to use it unless given TBD
+					 * explicit request (should actually be
+					 * < DETACHED) */
+	CHANNELCLI_ATTACHING = 2,	/* legacy EFI client request
+					 * for EFI server to attach */
+	CHANNELCLI_ATTACHED = 3,	/* idle, but client may want
+					 * to use channel any time */
+	CHANNELCLI_BUSY = 4,	/* client either wants to use or is
+				 * using channel */
+	CHANNELCLI_OWNED = 5	/* "no worries" state - client can
+				 * access channel anytime */
+} CHANNEL_CLIENTSTATE;
+static inline const U8 *
+ULTRA_CHANNELCLI_STRING(U32 v)
+{
+	switch (v) {
+	case CHANNELCLI_DETACHED:
+		return (const U8 *) ("DETACHED");
+	case CHANNELCLI_DISABLED:
+		return (const U8 *) ("DISABLED");
+	case CHANNELCLI_ATTACHING:
+		return (const U8 *) ("ATTACHING");
+	case CHANNELCLI_ATTACHED:
+		return (const U8 *) ("ATTACHED");
+	case CHANNELCLI_BUSY:
+		return (const U8 *) ("BUSY");
+	case CHANNELCLI_OWNED:
+		return (const U8 *) ("OWNED");
+	default:
+		break;
+	}
+	return (const U8 *) ("?");
+}
+
+#define ULTRA_CHANNELSRV_IS_READY(x)     ((x) == CHANNELSRV_READY)
+#define ULTRA_CHANNEL_SERVER_READY(pChannel) \
+	(ULTRA_CHANNELSRV_IS_READY((pChannel)->SrvState))
+
+#define ULTRA_VALID_CHANNELCLI_TRANSITION(o, n)				\
+	(((((o) == CHANNELCLI_DETACHED) && ((n) == CHANNELCLI_DISABLED)) || \
+	  (((o) == CHANNELCLI_ATTACHING) && ((n) == CHANNELCLI_DISABLED)) || \
+	  (((o) == CHANNELCLI_ATTACHED) && ((n) == CHANNELCLI_DISABLED)) || \
+	  (((o) == CHANNELCLI_ATTACHING) && ((n) == CHANNELCLI_DETACHED)) || \
+	  (((o) == CHANNELCLI_ATTACHED) && ((n) == CHANNELCLI_DETACHED)) || \
+	  (((o) == CHANNELCLI_DETACHED) && ((n) == CHANNELCLI_ATTACHING)) || \
+	  (((o) == CHANNELCLI_ATTACHING) && ((n) == CHANNELCLI_ATTACHED)) || \
+	  (((o) == CHANNELCLI_DETACHED) && ((n) == CHANNELCLI_ATTACHED)) || \
+	  (((o) == CHANNELCLI_BUSY) && ((n) == CHANNELCLI_ATTACHED)) ||	\
+	  (((o) == CHANNELCLI_ATTACHED) && ((n) == CHANNELCLI_BUSY)) ||	\
+	  (((o) == CHANNELCLI_DETACHED) && ((n) == CHANNELCLI_OWNED)) || \
+	  (((o) == CHANNELCLI_DISABLED) && ((n) == CHANNELCLI_OWNED)) || \
+	  (((o) == CHANNELCLI_ATTACHING) && ((n) == CHANNELCLI_OWNED)) || \
+	  (((o) == CHANNELCLI_ATTACHED) && ((n) == CHANNELCLI_OWNED)) || \
+	  (((o) == CHANNELCLI_BUSY) && ((n) == CHANNELCLI_OWNED)) || (0)) \
+	 ? (1) : (0))
+
+#define ULTRA_CHANNEL_CLIENT_CHK_TRANSITION(old, new, chanId, logCtx,	\
+					    file, line)			\
+	do {								\
+		if (!ULTRA_VALID_CHANNELCLI_TRANSITION(old, new))	\
+			UltraLogEvent(logCtx,				\
+				      CHANNELSTATE_DIAG_EVENTID_TRANSITERR, \
+				      CHANNELSTATE_DIAG_SEVERITY, \
+				      CHANNELSTATE_DIAG_SUBSYS,		\
+				      __func__, __LINE__,		\
+				      "%s Channel StateTransition INVALID! (%s) %s(%d)-->%s(%d) @%s:%d\n", \
+				      chanId, "CliState<x>",		\
+				      ULTRA_CHANNELCLI_STRING(old),	\
+				      old,				\
+				      ULTRA_CHANNELCLI_STRING(new),	\
+				      new,				\
+				      PathName_Last_N_Nodes((U8 *)file, 4), \
+				      line);				\
+	} while (0)
+
+#define ULTRA_CHANNEL_CLIENT_TRANSITION(pChan, chanId, field, \
+					newstate, logCtx)		\
+	do {								\
+		ULTRA_CHANNEL_CLIENT_CHK_TRANSITION(			\
+			(((CHANNEL_HEADER *)(pChan))->field), newstate, \
+			chanId, logCtx, __FILE__, __LINE__);		\
+		UltraLogEvent(logCtx, CHANNELSTATE_DIAG_EVENTID_TRANSITOK, \
+			CHANNELSTATE_DIAG_SEVERITY, \
+			      CHANNELSTATE_DIAG_SUBSYS,			\
+			      __func__, __LINE__,			\
+			      "%s Channel StateTransition (%s) %s(%d)-->%s(%d) @%s:%d\n", \
+			      chanId, #field,				\
+			      ULTRA_CHANNELCLI_STRING(((CHANNEL_HEADER *) \
+						       (pChan))->field), \
+			      ((CHANNEL_HEADER *)(pChan))->field,	\
+			      ULTRA_CHANNELCLI_STRING(newstate),	\
+			      newstate,					\
+			      PathName_Last_N_Nodes(__FILE__, 4), __LINE__); \
+		((CHANNEL_HEADER *)(pChan))->field = newstate;		\
+		MEMORYBARRIER;						\
+	} while (0)
+
+#define ULTRA_CHANNEL_CLIENT_ACQUIRE_OS(pChan, chanId, logCtx)	\
+	ULTRA_channel_client_acquire_os(pChan, chanId, logCtx,		\
+					(char *)__FILE__, __LINE__,	\
+					(char *)__func__)
+#define ULTRA_CHANNEL_CLIENT_RELEASE_OS(pChan, chanId, logCtx)	\
+	ULTRA_channel_client_release_os(pChan, chanId, logCtx,	\
+		(char *)__FILE__, __LINE__, (char *)__func__)
+
+/* Values for ULTRA_CHANNEL_PROTOCOL.CliErrorBoot: */
+/* throttling invalid boot channel statetransition error due to client
+ * disabled */
+#define ULTRA_CLIERRORBOOT_THROTTLEMSG_DISABLED    0x01
+
+/* throttling invalid boot channel statetransition error due to client
+ * not attached */
+#define ULTRA_CLIERRORBOOT_THROTTLEMSG_NOTATTACHED 0x02
+
+/* throttling invalid boot channel statetransition error due to busy channel */
+#define ULTRA_CLIERRORBOOT_THROTTLEMSG_BUSY        0x04
+
+/* Values for ULTRA_CHANNEL_PROTOCOL.CliErrorOS: */
+/* throttling invalid guest OS channel statetransition error due to
+ * client disabled */
+#define ULTRA_CLIERROROS_THROTTLEMSG_DISABLED      0x01
+
+/* throttling invalid guest OS channel statetransition error due to
+ * client not attached */
+#define ULTRA_CLIERROROS_THROTTLEMSG_NOTATTACHED   0x02
+
+/* throttling invalid guest OS channel statetransition error due to
+ * busy channel */
+#define ULTRA_CLIERROROS_THROTTLEMSG_BUSY          0x04
+
+/* Values for ULTRA_CHANNEL_PROTOCOL.Features: This define exists so
+* that windows guest can look at the FeatureFlags in the io channel,
+* and configure the windows driver to use interrupts or not based on
+* this setting.  This flag is set in uislib after the
+* ULTRA_VHBA_init_channel is called.  All feature bits for all
+* channels should be defined here.  The io channel feature bits are
+* defined right here */
+#define ULTRA_IO_DRIVER_ENABLES_INTS (0x1ULL << 1)
+#define ULTRA_IO_CHANNEL_IS_POLLING (0x1ULL << 3)
+#define ULTRA_IO_IOVM_IS_OK_WITH_DRIVER_DISABLING_INTS (0x1ULL << 4)
+#define ULTRA_IO_DRIVER_DISABLES_INTS (0x1ULL << 5)
+#define ULTRA_IO_DRIVER_SUPPORTS_ENHANCED_RCVBUF_CHECKING (0x1ULL << 6)
+
+#pragma pack(push, 1)		/* both GCC and VC now allow this pragma */
+/* Common Channel Header */
+typedef struct _CHANNEL_HEADER {
+	U64 Signature;		/* Signature */
+	U32 LegacyState;	/* DEPRECATED - being replaced by */
+	/* /              SrvState, CliStateBoot, and CliStateOS below */
+	U32 HeaderSize;		/* sizeof(CHANNEL_HEADER) */
+	U64 Size;		/* Total size of this channel in bytes */
+	U64 Features;		/* Flags to modify behavior */
+	GUID Type;		/* Channel type: data, bus, control, etc. */
+	U64 PartitionHandle;	/* ID of guest partition */
+	U64 Handle;		/* Device number of this channel in client */
+	U64 oChannelSpace;	/* Offset in bytes to channel specific area */
+	U32 VersionId;		/* CHANNEL_HEADER Version ID */
+	U32 PartitionIndex;	/* Index of guest partition */
+	GUID ZoneGuid;		/* Guid of Channel's zone */
+	U32 oClientString;	/* offset from channel header to
+				 * nul-terminated ClientString (0 if
+				 * ClientString not present) */
+	U32 CliStateBoot;	/* CHANNEL_CLIENTSTATE of pre-boot
+				 * EFI client of this channel */
+	U32 CmdStateCli;	/* CHANNEL_COMMANDSTATE (overloaded in
+				 * Windows drivers, see ServerStateUp,
+				 * ServerStateDown, etc) */
+	U32 CliStateOS;		/* CHANNEL_CLIENTSTATE of Guest OS
+				 * client of this channel */
+	U32 ChannelCharacteristics;	/* CHANNEL_CHARACTERISTIC_<xxx> */
+	U32 CmdStateSrv;	/* CHANNEL_COMMANDSTATE (overloaded in
+				 * Windows drivers, see ServerStateUp,
+				 * ServerStateDown, etc) */
+	U32 SrvState;		/* CHANNEL_SERVERSTATE */
+	U8 CliErrorBoot;	/* bits to indicate err states for
+				 * boot clients, so err messages can
+				 * be throttled */
+	U8 CliErrorOS;		/* bits to indicate err states for OS
+				 * clients, so err messages can be
+				 * throttled */
+	U8 Filler[1];		/* Pad out to 128 byte cacheline */
+	/* Please add all new single-byte values below here */
+	U8 RecoverChannel;
+} CHANNEL_HEADER, *pCHANNEL_HEADER, ULTRA_CHANNEL_PROTOCOL;
+
+#define ULTRA_CHANNEL_ENABLE_INTS (0x1ULL << 0)
+
+/* Subheader for the Signal Type variation of the Common Channel */
+typedef struct _SIGNAL_QUEUE_HEADER {
+	/* 1st cache line */
+	U32 VersionId;		/* SIGNAL_QUEUE_HEADER Version ID */
+	U32 Type;		/* Queue type: storage, network */
+	U64 Size;		/* Total size of this queue in bytes */
+	U64 oSignalBase;	/* Offset to signal queue area */
+	U64 FeatureFlags;	/* Flags to modify behavior */
+	U64 NumSignalsSent;	/* Total # of signals placed in this queue */
+	U64 NumOverflows;	/* Total # of inserts failed due to
+				 * full queue */
+	U32 SignalSize;		/* Total size of a signal for this queue */
+	U32 MaxSignalSlots;	/* Max # of slots in queue, 1 slot is
+				 * always empty */
+	U32 MaxSignals;		/* Max # of signals in queue
+				 * (MaxSignalSlots-1) */
+	U32 Head;		/* Queue head signal # */
+	/* 2nd cache line */
+	U64 NumSignalsReceived;	/* Total # of signals removed from this queue */
+	U32 Tail;		/* Queue tail signal # (on separate
+				 * cache line) */
+	U32 Reserved1;		/* Reserved field */
+	U64 Reserved2;		/* Resrved field */
+	U64 ClientQueue;
+	U64 NumInterruptsReceived;	/* Total # of Interrupts received.  This
+					 * is incremented by the ISR in the
+					 * guest windows driver */
+	U64 NumEmptyCnt;	/* Number of times that SignalRemove
+				 * is called and returned Empty
+				 * Status. */
+	U32 ErrorFlags;		/* Error bits set during SignalReinit
+				 * to denote trouble with client's
+				 * fields */
+	U8 Filler[12];		/* Pad out to 64 byte cacheline */
+} SIGNAL_QUEUE_HEADER, *pSIGNAL_QUEUE_HEADER;
+
+#pragma pack(pop)
+
+#define SignalInit(chan, QHDRFLD, QDATAFLD, QDATATYPE, ver, typ)	\
+	do {								\
+		MEMSET(&chan->QHDRFLD, 0, sizeof(chan->QHDRFLD));	\
+		chan->QHDRFLD.VersionId = ver;				\
+		chan->QHDRFLD.Type = typ;				\
+		chan->QHDRFLD.Size = sizeof(chan->QDATAFLD);		\
+		chan->QHDRFLD.SignalSize = sizeof(QDATATYPE);		\
+		chan->QHDRFLD.oSignalBase = (UINTN)(chan->QDATAFLD)-	\
+			(UINTN)(&chan->QHDRFLD);			\
+		chan->QHDRFLD.MaxSignalSlots =				\
+			sizeof(chan->QDATAFLD)/sizeof(QDATATYPE);	\
+		chan->QHDRFLD.MaxSignals = chan->QHDRFLD.MaxSignalSlots-1; \
+	} while (0)
+
+/* Generic function useful for validating any type of channel when it is
+ * received by the client that will be accessing the channel.
+ * Note that <logCtx> is only needed for callers in the EFI environment, and
+ * is used to pass the EFI_DIAG_CAPTURE_PROTOCOL needed to log messages.
+ */
+static inline int
+ULTRA_check_channel_client(void *pChannel,
+			   GUID expectedTypeGuid,
+			   char *channelName,
+			   U64 expectedMinBytes,
+			   U32 expectedVersionId,
+			   U64 expectedSignature,
+			   char *fileName, int lineNumber, void *logCtx)
+{
+	if (MEMCMP(&expectedTypeGuid, &Guid0, sizeof(GUID)) != 0)
+		/* caller wants us to verify type GUID */
+		if (MEMCMP(&(((CHANNEL_HEADER *) (pChannel))->Type),
+			   &expectedTypeGuid, sizeof(GUID)) != 0) {
+			CHANNEL_GUID_MISMATCH(expectedTypeGuid, channelName,
+					      "type", expectedTypeGuid,
+					      ((CHANNEL_HEADER *)
+					       (pChannel))->Type, fileName,
+					      lineNumber, logCtx);
+			return 0;
+		}
+	if (expectedMinBytes > 0)	/* caller wants us to verify
+					 * channel size */
+		if (((CHANNEL_HEADER *) (pChannel))->Size < expectedMinBytes) {
+			CHANNEL_U64_MISMATCH(expectedTypeGuid, channelName,
+					     "size", expectedMinBytes,
+					     ((CHANNEL_HEADER *)
+					      (pChannel))->Size, fileName,
+					     lineNumber, logCtx);
+			return 0;
+		}
+	if (expectedVersionId > 0)	/* caller wants us to verify
+					 * channel version */
+		if (((CHANNEL_HEADER *) (pChannel))->VersionId !=
+		    expectedVersionId) {
+			CHANNEL_U32_MISMATCH(expectedTypeGuid, channelName,
+					     "version", expectedVersionId,
+					     ((CHANNEL_HEADER *)
+					      (pChannel))->VersionId, fileName,
+					     lineNumber, logCtx);
+			return 0;
+		}
+	if (expectedSignature > 0)	/* caller wants us to verify
+					 * channel signature */
+		if (((CHANNEL_HEADER *) (pChannel))->Signature !=
+		    expectedSignature) {
+			CHANNEL_U64_MISMATCH(expectedTypeGuid, channelName,
+					     "signature", expectedSignature,
+					     ((CHANNEL_HEADER *)
+					      (pChannel))->Signature, fileName,
+					     lineNumber, logCtx);
+			return 0;
+		}
+	return 1;
+}
+
+/* Generic function useful for validating any type of channel when it is about
+ * to be initialized by the server of the channel.
+ * Note that <logCtx> is only needed for callers in the EFI environment, and
+ * is used to pass the EFI_DIAG_CAPTURE_PROTOCOL needed to log messages.
+ */
+static inline int
+ULTRA_check_channel_server(GUID typeGuid,
+			   char *channelName,
+			   U64 expectedMinBytes,
+			   U64 actualBytes,
+			   char *fileName, int lineNumber, void *logCtx)
+{
+	if (expectedMinBytes > 0)	/* caller wants us to verify
+					 * channel size */
+		if (actualBytes < expectedMinBytes) {
+			CHANNEL_U64_MISMATCH(typeGuid, channelName, "size",
+					     expectedMinBytes, actualBytes,
+					     fileName, lineNumber, logCtx);
+			return 0;
+		}
+	return 1;
+}
+
+/* Given a file pathname <s> (with '/' or '\' separating directory nodes),
+ * returns a pointer to the beginning of a node within that pathname such
+ * that the number of nodes from that pointer to the end of the string is
+ * NOT more than <n>.  Note that if the pathname has less than <n> nodes
+ * in it, the return pointer will be to the beginning of the string.
+ */
+static inline U8 *
+PathName_Last_N_Nodes(U8 *s, unsigned int n)
+{
+	U8 *p = s;
+	unsigned int node_count = 0;
+	while (*p != '\0') {
+		if ((*p == '/') || (*p == '\\'))
+			node_count++;
+		p++;
+	}
+	if (node_count <= n)
+		return s;
+	while (n > 0) {
+		p--;
+		if (p == s)
+			break;	/* should never happen, unless someone
+				 * is changing the string while we are
+				 * looking at it!! */
+		if ((*p == '/') || (*p == '\\'))
+			n--;
+	}
+	return p + 1;
+}
+
+static inline int
+ULTRA_channel_client_acquire_os(void *pChannel, U8 *chanId, void *logCtx,
+				char *file, int line, char *func)
+{
+	CHANNEL_HEADER *pChan = (CHANNEL_HEADER *) (pChannel);
+
+	if (pChan->CliStateOS == CHANNELCLI_DISABLED) {
+		if ((pChan->
+		     CliErrorOS & ULTRA_CLIERROROS_THROTTLEMSG_DISABLED) == 0) {
+			/* we are NOT throttling this message */
+			pChan->CliErrorOS |=
+				ULTRA_CLIERROROS_THROTTLEMSG_DISABLED;
+			/* throttle until acquire successful */
+
+			UltraLogEvent(logCtx,
+				      CHANNELSTATE_DIAG_EVENTID_TRANSITERR,
+				      CHANNELSTATE_DIAG_SEVERITY,
+				      CHANNELSTATE_DIAG_SUBSYS, func, line,
+				      "%s Channel StateTransition INVALID! - acquire failed because OS client DISABLED @%s:%d\n",
+				      chanId, PathName_Last_N_Nodes(
+					      (U8 *) file, 4), line);
+		}
+		return 0;
+	}
+	if ((pChan->CliStateOS != CHANNELCLI_OWNED)
+	    && (pChan->CliStateBoot == CHANNELCLI_DISABLED)) {
+		/* Our competitor is DISABLED, so we can transition to OWNED */
+		UltraLogEvent(logCtx, CHANNELSTATE_DIAG_EVENTID_TRANSITOK,
+			      CHANNELSTATE_DIAG_SEVERITY,
+			      CHANNELSTATE_DIAG_SUBSYS, func, line,
+			      "%s Channel StateTransition (%s) %s(%d)-->%s(%d) @%s:%d\n",
+			      chanId, "CliStateOS",
+			      ULTRA_CHANNELCLI_STRING(pChan->CliStateOS),
+			      pChan->CliStateOS,
+			      ULTRA_CHANNELCLI_STRING(CHANNELCLI_OWNED),
+			      CHANNELCLI_OWNED,
+			      PathName_Last_N_Nodes((U8 *) file, 4), line);
+		pChan->CliStateOS = CHANNELCLI_OWNED;
+		MEMORYBARRIER;
+	}
+	if (pChan->CliStateOS == CHANNELCLI_OWNED) {
+		if (pChan->CliErrorOS != 0) {
+			/* we are in an error msg throttling state;
+			 * come out of it */
+			UltraLogEvent(logCtx,
+				      CHANNELSTATE_DIAG_EVENTID_TRANSITOK,
+				      CHANNELSTATE_DIAG_SEVERITY,
+				      CHANNELSTATE_DIAG_SUBSYS, func, line,
+				      "%s Channel OS client acquire now successful @%s:%d\n",
+				      chanId, PathName_Last_N_Nodes((U8 *) file,
+								    4), line);
+			pChan->CliErrorOS = 0;
+		}
+		return 1;
+	}
+
+	/* We have to do it the "hard way".  We transition to BUSY,
+	* and can use the channel iff our competitor has not also
+	* transitioned to BUSY. */
+	if (pChan->CliStateOS != CHANNELCLI_ATTACHED) {
+		if ((pChan->
+		     CliErrorOS & ULTRA_CLIERROROS_THROTTLEMSG_NOTATTACHED) ==
+		    0) {
+			/* we are NOT throttling this message */
+			pChan->CliErrorOS |=
+				ULTRA_CLIERROROS_THROTTLEMSG_NOTATTACHED;
+			/* throttle until acquire successful */
+			UltraLogEvent(logCtx,
+				      CHANNELSTATE_DIAG_EVENTID_TRANSITERR,
+				      CHANNELSTATE_DIAG_SEVERITY,
+				      CHANNELSTATE_DIAG_SUBSYS, func, line,
+				      "%s Channel StateTransition INVALID! - acquire failed because OS client NOT ATTACHED (state=%s(%d)) @%s:%d\n",
+				      chanId,
+				      ULTRA_CHANNELCLI_STRING(pChan->CliStateOS),
+				      pChan->CliStateOS,
+				      PathName_Last_N_Nodes((U8 *) file, 4),
+				      line);
+		}
+		return 0;
+	}
+	pChan->CliStateOS = CHANNELCLI_BUSY;
+	MEMORYBARRIER;
+	if (pChan->CliStateBoot == CHANNELCLI_BUSY) {
+		if ((pChan->CliErrorOS & ULTRA_CLIERROROS_THROTTLEMSG_BUSY) ==
+		    0) {
+			/* we are NOT throttling this message */
+			pChan->CliErrorOS |= ULTRA_CLIERROROS_THROTTLEMSG_BUSY;
+			/* throttle until acquire successful */
+			UltraLogEvent(logCtx,
+				      CHANNELSTATE_DIAG_EVENTID_TRANSITBUSY,
+				      CHANNELSTATE_DIAG_SEVERITY,
+				      CHANNELSTATE_DIAG_SUBSYS, func, line,
+				      "%s Channel StateTransition failed - host OS acquire failed because boot BUSY @%s:%d\n",
+				      chanId, PathName_Last_N_Nodes((U8 *) file,
+								    4), line);
+		}
+		pChan->CliStateOS = CHANNELCLI_ATTACHED;	/* reset busy */
+		MEMORYBARRIER;
+		return 0;
+	}
+	if (pChan->CliErrorOS != 0) {
+		/* we are in an error msg throttling state; come out of it */
+		UltraLogEvent(logCtx, CHANNELSTATE_DIAG_EVENTID_TRANSITOK,
+			      CHANNELSTATE_DIAG_SEVERITY,
+			      CHANNELSTATE_DIAG_SUBSYS, func, line,
+			      "%s Channel OS client acquire now successful @%s:%d\n",
+			      chanId, PathName_Last_N_Nodes((U8 *) file, 4),
+			      line);
+		pChan->CliErrorOS = 0;
+	}
+	return 1;
+}
+
+static inline void
+ULTRA_channel_client_release_os(void *pChannel, U8 *chanId, void *logCtx,
+				char *file, int line, char *func)
+{
+	CHANNEL_HEADER *pChan = (CHANNEL_HEADER *) (pChannel);
+	if (pChan->CliErrorOS != 0) {
+		/* we are in an error msg throttling state; come out of it */
+		UltraLogEvent(logCtx, CHANNELSTATE_DIAG_EVENTID_TRANSITOK,
+			      CHANNELSTATE_DIAG_SEVERITY,
+			      CHANNELSTATE_DIAG_SUBSYS, func, line,
+			      "%s Channel OS client error state cleared @%s:%d\n",
+			      chanId, PathName_Last_N_Nodes((U8 *) file, 4),
+			      line);
+		pChan->CliErrorOS = 0;
+	}
+	if (pChan->CliStateOS == CHANNELCLI_OWNED)
+		return;
+	if (pChan->CliStateOS != CHANNELCLI_BUSY) {
+		UltraLogEvent(logCtx, CHANNELSTATE_DIAG_EVENTID_TRANSITERR,
+			      CHANNELSTATE_DIAG_SEVERITY,
+			      CHANNELSTATE_DIAG_SUBSYS, func, line,
+			      "%s Channel StateTransition INVALID! - release failed because OS client NOT BUSY (state=%s(%d)) @%s:%d\n",
+			      chanId,
+			      ULTRA_CHANNELCLI_STRING(pChan->CliStateOS),
+			      pChan->CliStateOS,
+			      PathName_Last_N_Nodes((U8 *) file, 4), line);
+		/* return; */
+	}
+	pChan->CliStateOS = CHANNELCLI_ATTACHED;	/* release busy */
+}
+
+/*
+* 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);
+
+/*
+* 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);
+
+/*
+* 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);
+
+/*
+* 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);
+
+#endif
Index: upstream-staging/drivers/staging/unisys/common-spar/include/version.h
===================================================================
--- /dev/null
+++ upstream-staging/drivers/staging/unisys/common-spar/include/version.h
@@ -0,0 +1,46 @@
+/* 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.
+ */
+
+/* version.h */
+
+/*  Common version/release info needed by all components goes here.
+ *  (This file must compile cleanly in all environments.)
+ *  Ultimately, this will be combined with defines generated dynamically as
+ *  part of the sysgen, and some of the defines below may in fact end up
+ *  being replaced with dynamically generated ones.
+ */
+#ifndef __VERSION_H__
+#define __VERSION_H__
+
+#define SPARVER1 "1"
+#define SPARVER2 "0"
+#define SPARVER3 "0"
+#define SPARVER4 "0"
+
+#define  VERSION        SPARVER1 "." SPARVER2 "." SPARVER3 "." SPARVER4
+#define  VERSIONDATE    __DATE__
+
+/* Here are various version forms needed in Windows environments.
+ */
+#define VISOR_PRODUCTVERSION      SPARVERCOMMA
+#define VISOR_PRODUCTVERSION_STR  SPARVER1 "." SPARVER2 "." SPARVER3 "." \
+	SPARVER4
+#define VISOR_OBJECTVERSION_STR   SPARVER1 "," SPARVER2 "," SPARVER3 "," \
+	SPARVER4
+
+#define  COPYRIGHT      "Unisys Corporation"
+#define  COPYRIGHTDATE  "2010 - 2013"
+
+#endif
Index: upstream-staging/drivers/staging/unisys/include/commontypes.h
===================================================================
--- /dev/null
+++ upstream-staging/drivers/staging/unisys/include/commontypes.h
@@ -0,0 +1,166 @@
+/* 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 _COMMONTYPES_H_
+#define _COMMONTYPES_H_
+
+/* define the following to prevent include nesting in kernel header files of
+ * similar abreviated content */
+#define _SUPERVISOR_COMMONTYPES_H_
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#include <linux/version.h>
+#else
+#include <stdint.h>
+#include <syslog.h>
+#endif
+
+#define U8  uint8_t
+#define U16 uint16_t
+#define U32 uint32_t
+#define U64 uint64_t
+#define S8  int8_t
+#define S16 int16_t
+#define S32 int32_t
+#define S64 int64_t
+
+#ifdef __KERNEL__
+
+#ifdef CONFIG_X86_32
+#define UINTN U32
+#else
+#define UINTN U64
+#endif
+
+#else
+
+#include <stdint.h>
+#if __WORDSIZE == 32
+#define UINTN U32
+#elif __WORDSIZE == 64
+#define UINTN U64
+#else
+#error Unsupported __WORDSIZE
+#endif
+
+#endif
+
+typedef struct {
+	U32 data1;
+	U16 data2;
+	U16 data3;
+	U8 data4[8];
+} __attribute__ ((__packed__)) GUID;
+
+#ifndef GUID0
+#define GUID0 {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0} }
+#endif
+typedef U64 GUEST_PHYSICAL_ADDRESS;
+
+#define MEMSET(ptr, val, len) memset(ptr, val, len)
+#define MEMCMP(m1, m2, len) memcmp(m1, m2, len)
+#define STRLEN(s) ((UINTN)strlen((const char *)s))
+#define STRCPY(d, s) (strcpy((char *)d, (const char *)s))
+
+#define INLINE inline
+#define OFFSETOF offsetof
+
+#ifdef __KERNEL__
+#define MEMORYBARRIER mb()
+#define MEMCPY(dest, src, len) memcpy(dest, src, len)
+
+#define CHANNEL_GUID_MISMATCH(chType, chName, field, expected, actual, fil, \
+			      lin, logCtx)				\
+	do {								\
+		char s1[50], s2[50], s3[50];				\
+		pr_err("Channel mismatch on channel=%s(%s) field=%s expected=%s actual=%s @%s:%d\n", \
+		       chName, GUID_format2(&chType, s1), field,	\
+		       GUID_format2(&expected, s2), GUID_format2(&actual, s3), \
+		       fil, lin);					\
+	} while (0)
+#define CHANNEL_U32_MISMATCH(chType, chName, field, expected, actual, fil, \
+			     lin, logCtx)				\
+	do {								\
+		char s1[50];						\
+		pr_err("Channel mismatch on channel=%s(%s) field=%s expected=0x%-8.8lx actual=0x%-8.8lx @%s:%d\n", \
+		       chName, GUID_format2(&chType, s1), field,	\
+		       (unsigned long)expected, (unsigned long)actual,	\
+		       fil, lin);					\
+	} while (0)
+
+#define CHANNEL_U64_MISMATCH(chType, chName, field, expected, actual, fil, \
+			     lin, logCtx)				\
+	do {								\
+		char s1[50];						\
+		pr_err("Channel mismatch on channel=%s(%s) field=%s expected=0x%-8.8Lx actual=0x%-8.8Lx @%s:%d\n", \
+		       chName, GUID_format2(&chType, s1), field,	\
+		       (unsigned long long)expected,			\
+		       (unsigned long long)actual,			\
+		       fil, lin);					\
+	} while (0)
+
+#define UltraLogEvent(logCtx, EventId, Severity, SubsystemMask, pFunctionName, \
+		      LineNumber, Str, args...)				\
+	pr_info(Str, ## args)
+
+#else
+#define MEMCPY(dest, src, len) memcpy(dest, src, len)
+
+#define MEMORYBARRIER mb()
+
+#define CHANNEL_GUID_MISMATCH(chType, chName, field, expected, actual, fil, \
+			      lin, logCtx)				\
+	do {								\
+		char s1[50], s2[50], s3[50];				\
+		syslog(LOG_USER | LOG_ERR,				\
+		       "Channel mismatch on channel=%s(%s) field=%s expected=%s actual=%s @%s:%d", \
+		       chName, GUID_format2(&chType, s1), field,	\
+		       GUID_format2(&expected, s2), GUID_format2(&actual, s3), \
+		       fil, lin);					\
+	} while (0)
+
+#define CHANNEL_U32_MISMATCH(chType, chName, field, expected, actual, fil, \
+			     lin, logCtx)				\
+	do {								\
+		char s1[50];						\
+		syslog(LOG_USER | LOG_ERR,				\
+		       "Channel mismatch on channel=%s(%s) field=%s expected=0x%-8.8lx actual=0x%-8.8lx @%s:%d", \
+		       chName, GUID_format2(&chType, s1), field,	\
+		       (unsigned long)expected, (unsigned long)actual,	\
+		       fil, lin);					\
+	} while (0)
+
+#define CHANNEL_U64_MISMATCH(chType, chName, field, expected, actual, fil, \
+			     lin, logCtx)				\
+	do {								\
+		char s1[50];						\
+		syslog(LOG_USER | LOG_ERR,				\
+		       "Channel mismatch on channel=%s(%s) field=%s expected=0x%-8.8Lx actual=0x%-8.8Lx @%s:%d", \
+		       chName, GUID_format2(&chType, s1), field,	\
+		       (unsigned long long)expected,			\
+		       (unsigned long long)actual,			\
+		       fil, lin);					\
+	} while (0)
+
+#define UltraLogEvent(logCtx, EventId, Severity, SubsystemMask, pFunctionName, \
+		      LineNumber, Str, args...)				\
+	syslog(LOG_USER | LOG_INFO, Str, ## args)
+#endif
+
+#define VolatileBarrier() MEMORYBARRIER
+
+#endif
+#include "guidutils.h"
Index: upstream-staging/drivers/staging/unisys/include/guidutils.h
===================================================================
--- /dev/null
+++ upstream-staging/drivers/staging/unisys/include/guidutils.h
@@ -0,0 +1,203 @@
+/* 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.
+ */
+
+/* guidutils.h
+ *
+ * These are GUID manipulation inlines that can be used from either
+ * kernel-mode or user-mode.
+ *
+ */
+#ifndef __GUIDUTILS_H__
+#define __GUIDUTILS_H__
+
+#ifdef __KERNEL__
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#define GUID_STRTOUL kstrtoul
+#else
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define GUID_STRTOUL strtoul
+#endif
+
+static inline char *
+GUID_format1(const GUID *guid, char *s)
+{
+	sprintf(s, "{%-8.8lx-%-4.4x-%-4.4x-%-2.2x%-2.2x%-2.2x%-2.2x%-2.2x%-2.2x%-2.2x%-2.2x}",
+		(ulong) guid->data1,
+		guid->data2,
+		guid->data3,
+		guid->data4[0],
+		guid->data4[1],
+		guid->data4[2],
+		guid->data4[3],
+		guid->data4[4], guid->data4[5], guid->data4[6], guid->data4[7]);
+	return s;
+}
+
+/** Format a GUID in Microsoft's 'what in the world were they thinking'
+ *  format.
+ */
+static inline char *
+GUID_format2(const GUID *guid, char *s)
+{
+	sprintf(s, "{%-8.8lx-%-4.4x-%-4.4x-%-2.2x%-2.2x-%-2.2x%-2.2x%-2.2x%-2.2x%-2.2x%-2.2x}",
+		(ulong) guid->data1,
+		guid->data2,
+		guid->data3,
+		guid->data4[0],
+		guid->data4[1],
+		guid->data4[2],
+		guid->data4[3],
+		guid->data4[4], guid->data4[5], guid->data4[6], guid->data4[7]);
+	return s;
+}
+
+/**
+ * Like GUID_format2 but without the curly braces and the
+ * hex digits in upper case
+ */
+static inline char *
+GUID_format3(const GUID *guid, char *s)
+{
+	sprintf(s, "%-8.8lX-%-4.4X-%-4.4X-%-2.2X%-2.2X-%-2.2X%-2.2X%-2.2X%-2.2X%-2.2X%-2.2X",
+		(ulong) guid->data1,
+		guid->data2,
+		guid->data3,
+		guid->data4[0],
+		guid->data4[1],
+		guid->data4[2],
+		guid->data4[3],
+		guid->data4[4], guid->data4[5], guid->data4[6], guid->data4[7]);
+	return s;
+}
+
+/** Parse a guid string in any of these forms:
+ *      {11111111-2222-3333-4455-66778899aabb}
+ *      {11111111-2222-3333-445566778899aabb}
+ *      11111111-2222-3333-4455-66778899aabb
+ *      11111111-2222-3333-445566778899aabb
+ */
+static inline GUID
+GUID_scan(U8 *p)
+{
+	GUID guid = GUID0;
+	U8 x[33];
+	int count = 0;
+	int c, i = 0;
+	U8 cdata1[9];
+	U8 cdata2[5];
+	U8 cdata3[5];
+	U8 cdata4[3];
+	int dashcount = 0;
+	int brace = 0;
+	unsigned long uldata;
+
+	if (!p)
+		return guid;
+	if (*p == '{') {
+		p++;
+		brace = 1;
+	}
+	while (count < 32) {
+		if (*p == '}')
+			return guid;
+		if (*p == '\0')
+			return guid;
+		c = toupper(*p);
+		p++;
+		if (c == '-') {
+			switch (dashcount) {
+			case 0:
+				if (i != 8)
+					return guid;
+				break;
+			case 1:
+				if (i != 4)
+					return guid;
+				break;
+			case 2:
+				if (i != 4)
+					return guid;
+				break;
+			case 3:
+				if (i != 4)
+					return guid;
+				break;
+			default:
+				return guid;
+			}
+			dashcount++;
+			i = 0;
+			continue;
+		}
+		if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F'))
+			i++;
+		else
+			return guid;
+		x[count++] = c;
+	}
+	x[count] = '\0';
+	if (brace) {
+		if (*p == '}')
+			p++;
+		else
+			return guid;
+	}
+	if (dashcount == 3 || dashcount == 4)
+		;
+	else
+		return guid;
+	memset(cdata1, 0, sizeof(cdata1));
+	memset(cdata2, 0, sizeof(cdata2));
+	memset(cdata3, 0, sizeof(cdata3));
+	memset(cdata4, 0, sizeof(cdata4));
+	memcpy(cdata1, x + 0, 8);
+	memcpy(cdata2, x + 8, 4);
+	memcpy(cdata3, x + 12, 4);
+
+	if (GUID_STRTOUL((char *) cdata1, 16, &uldata) == 0)
+		guid.data1 = (U32)uldata;
+	if (GUID_STRTOUL((char *) cdata2, 16, &uldata) == 0)
+		guid.data2 = (U16)uldata;
+	if (GUID_STRTOUL((char *) cdata3, 16, &uldata) == 0)
+		guid.data3 = (U16)uldata;
+
+	for (i = 0; i < 8; i++) {
+		memcpy(cdata4, x + 16 + (i * 2), 2);
+		if (GUID_STRTOUL((char *) cdata4, 16, &uldata) == 0)
+			guid.data4[i] = (U8) uldata;
+	}
+
+	return guid;
+}
+
+static inline char *
+GUID_sanitize(char *inputGuidStr, char *outputGuidStr)
+{
+	GUID g;
+	GUID guid0 = GUID0;
+	*outputGuidStr = '\0';
+	g = GUID_scan((U8 *) inputGuidStr);
+	if (memcmp(&g, &guid0, sizeof(GUID)) == 0)
+		return outputGuidStr;	/* bad GUID format */
+	return GUID_format1(&g, outputGuidStr);
+}
+
+#endif
Index: upstream-staging/drivers/staging/unisys/visorchannel/Kconfig
===================================================================
--- /dev/null
+++ upstream-staging/drivers/staging/unisys/visorchannel/Kconfig
@@ -0,0 +1,10 @@
+#
+# Unisys visorchannel configuration
+#
+
+config UNISYS_VISORCHANNEL
+	tristate "Unisys visorchannel driver"
+	depends on UNISYSSPAR && UNISYS_VISORUTIL
+	---help---
+	If you say Y here, you will enable the Unisys visorchannel driver.
+
Index: upstream-staging/drivers/staging/unisys/visorchannel/Makefile
===================================================================
--- /dev/null
+++ upstream-staging/drivers/staging/unisys/visorchannel/Makefile
@@ -0,0 +1,14 @@
+#
+# Makefile for Unisys visorchannel
+#
+
+obj-$(CONFIG_UNISYS_VISORCHANNEL)	+= visorchannel.o
+
+visorchannel-y := visorchannel_main.o visorchannel_funcs.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 += -Idrivers/staging/unisys/visorutil
+ccflags-y += -DCONFIG_SPAR_GUEST -DGUESTDRIVERBUILD -DNOAUTOVERSION
+
Index: upstream-staging/drivers/staging/unisys/visorchannel/globals.h
===================================================================
--- /dev/null
+++ upstream-staging/drivers/staging/unisys/visorchannel/globals.h
@@ -0,0 +1,29 @@
+/* globals.h
+ *
+ * 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 __VISORCHANNEL_GLOBALS_H__
+#define __VISORCHANNEL_GLOBALS_H__
+
+#include "uniklog.h"
+#include "timskmod.h"
+#include "memregion.h"
+#include "version.h"
+
+#define MYDRVNAME "visorchannel"
+
+
+#endif
Index: upstream-staging/drivers/staging/unisys/visorchannel/visorchannel.h
===================================================================
--- /dev/null
+++ upstream-staging/drivers/staging/unisys/visorchannel/visorchannel.h
@@ -0,0 +1,106 @@
+/* visorchannel.h
+ *
+ * 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 __VISORCHANNEL_H__
+#define __VISORCHANNEL_H__
+
+#include "commontypes.h"
+#include "memregion.h"
+#include "channel.h"
+#ifndef HOSTADDRESS
+#define HOSTADDRESS U64
+#endif
+#ifndef BOOL
+#define BOOL int
+#endif
+
+/* VISORCHANNEL is an opaque structure to users.
+ * Fields are declared only in the implementation .c files.
+ */
+typedef struct VISORCHANNEL_Tag VISORCHANNEL;
+
+/* Note that for visorchannel_create() and visorchannel_create_overlapped(),
+ * <channelBytes> and <guid> arguments may be 0 if we are a channel CLIENT.
+ * In this case, the values can simply be read from the channel header.
+ */
+VISORCHANNEL *visorchannel_create(HOSTADDRESS physaddr,
+				  ulong channelBytes, GUID guid);
+VISORCHANNEL *visorchannel_create_overlapped(ulong channelBytes,
+					     VISORCHANNEL *parent, ulong off,
+					     GUID guid);
+VISORCHANNEL *visorchannel_create_with_lock(HOSTADDRESS physaddr,
+					    ulong channelBytes, GUID guid);
+VISORCHANNEL *visorchannel_create_overlapped_with_lock(ulong channelBytes,
+						       VISORCHANNEL *parent,
+						       ulong off, GUID guid);
+void visorchannel_destroy(VISORCHANNEL *channel);
+int visorchannel_read(VISORCHANNEL *channel, ulong offset,
+		      void *local, ulong nbytes);
+int visorchannel_write(VISORCHANNEL *channel, ulong offset,
+		       void *local, ulong nbytes);
+int visorchannel_clear(VISORCHANNEL *channel, ulong offset,
+		       U8 ch, ulong nbytes);
+BOOL visorchannel_signalremove(VISORCHANNEL *channel, U32 queue, void *msg);
+BOOL visorchannel_signalinsert(VISORCHANNEL *channel, U32 queue, void *msg);
+int visorchannel_signalqueue_slots_avail(VISORCHANNEL *channel, U32 queue);
+int visorchannel_signalqueue_max_slots(VISORCHANNEL *channel, U32 queue);
+
+HOSTADDRESS visorchannel_get_physaddr(VISORCHANNEL *channel);
+ulong visorchannel_get_nbytes(VISORCHANNEL *channel);
+char *visorchannel_id(VISORCHANNEL *channel, char *s);
+char *visorchannel_zoneid(VISORCHANNEL *channel, char *s);
+U64 visorchannel_get_clientpartition(VISORCHANNEL *channel);
+GUID visorchannel_get_GUID(VISORCHANNEL *channel);
+MEMREGION *visorchannel_get_memregion(VISORCHANNEL *channel);
+char *visorchannel_GUID_id(GUID *guid, char *s);
+void visorchannel_debug(VISORCHANNEL *channel, int nQueues,
+			struct seq_file *seq, U32 off);
+void visorchannel_dump_section(VISORCHANNEL *chan, char *s,
+			       int off, int len, struct seq_file *seq);
+void *visorchannel_get_header(VISORCHANNEL *channel);
+
+#define	VISORCHANNEL_CHANGE_SERVER_STATE(chan, chanId, newstate)	\
+	do {								\
+		U8 *p = (U8 *)visorchannel_get_header(chan);		\
+		if (p) {						\
+			ULTRA_CHANNEL_SERVER_TRANSITION(p, chanId, SrvState, \
+							newstate, logCtx); \
+			visorchannel_write				\
+				(chan,					\
+				 offsetof(ULTRA_CHANNEL_PROTOCOL, SrvState), \
+				 p +					\
+				 offsetof(ULTRA_CHANNEL_PROTOCOL, SrvState), \
+				 sizeof(U32));				\
+		}							\
+	} while (0)
+
+#define	VISORCHANNEL_CHANGE_CLIENT_STATE(chan, chanId, newstate)	\
+	do {								\
+		U8 *p = (U8 *)visorchannel_get_header(chan);		\
+		if (p) {						\
+			ULTRA_CHANNEL_CLIENT_TRANSITION(p, chanId, CliStateOS, \
+							newstate, logCtx); \
+			visorchannel_write				\
+				(chan,					\
+				 offsetof(ULTRA_CHANNEL_PROTOCOL, CliStateOS), \
+				 p +					\
+				 offsetof(ULTRA_CHANNEL_PROTOCOL, CliStateOS), \
+				 sizeof(U32));				\
+		}							\
+	} while (0)
+
+#endif
Index: upstream-staging/drivers/staging/unisys/visorchannel/visorchannel_funcs.c
===================================================================
--- /dev/null
+++ upstream-staging/drivers/staging/unisys/visorchannel/visorchannel_funcs.c
@@ -0,0 +1,765 @@
+/* visorchannel_funcs.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.
+ */
+
+/*
+ *  This provides Supervisor channel communication primitives, which are
+ *  independent of the mechanism used to access the channel data.  All channel
+ *  data is accessed using the memregion abstraction.  (memregion has both
+ *  a CM2 implementation and a direct memory implementation.)
+ */
+
+#include "globals.h"
+#include "visorchannel.h"
+#include "guidutils.h"
+
+#define MYDRVNAME "visorchannel"
+
+struct VISORCHANNEL_Tag {
+	MEMREGION *memregion;	/* from memregion_create() */
+	CHANNEL_HEADER chan_hdr;
+	GUID guid;
+	ulong size;
+	BOOL needs_lock;
+	spinlock_t insert_lock;
+	spinlock_t remove_lock;
+
+	struct {
+		SIGNAL_QUEUE_HEADER req_queue;
+		SIGNAL_QUEUE_HEADER rsp_queue;
+		SIGNAL_QUEUE_HEADER event_queue;
+		SIGNAL_QUEUE_HEADER ack_queue;
+	} safe_uis_queue;
+};
+
+/* Creates the VISORCHANNEL abstraction for a data area in memory, but does
+ * NOT modify this data area.
+ */
+static VISORCHANNEL *
+visorchannel_create_guts(HOSTADDRESS physaddr, ulong channelBytes,
+			 VISORCHANNEL *parent, ulong off, GUID guid,
+			 BOOL needs_lock)
+{
+	VISORCHANNEL *p = NULL;
+	void *rc = NULL;
+
+	p = kmalloc(sizeof(VISORCHANNEL), GFP_KERNEL|__GFP_NORETRY);
+	if (p == NULL)
+		FAIL("allocation failed", 0);
+	p->memregion = NULL;
+	p->needs_lock = needs_lock;
+	spin_lock_init(&p->insert_lock);
+	spin_lock_init(&p->remove_lock);
+
+	/* prepare chan_hdr (abstraction to read/write channel memory) */
+	if (parent == NULL)
+		p->memregion =
+		    memregion_create(physaddr, sizeof(CHANNEL_HEADER));
+	else
+		p->memregion =
+		    memregion_create_overlapped
+		    (parent->memregion, off, sizeof(CHANNEL_HEADER));
+	if (p->memregion == NULL)
+		FAIL("memregion_create failed", 0);
+	if (memregion_read(p->memregion, 0, &p->chan_hdr,
+			   sizeof(CHANNEL_HEADER)) < 0)
+		FAIL("memregion_read failed", 0);
+	if (channelBytes == 0)
+		/* we had better be a CLIENT of this channel */
+		channelBytes = (ulong) p->chan_hdr.Size;
+	if (STRUCTSEQUAL(guid, Guid0))
+		/* we had better be a CLIENT of this channel */
+		guid = p->chan_hdr.Type;
+	if (memregion_resize(p->memregion, channelBytes) < 0)
+		FAIL("memregion_resize failed", 0);
+	p->size = channelBytes;
+	p->guid = guid;
+
+	RETPTR(p);
+
+Away:
+
+	if (rc == NULL) {
+		if (p != NULL) {
+			visorchannel_destroy(p);
+			p = NULL;
+		}
+	}
+	return rc;
+}
+
+VISORCHANNEL *
+visorchannel_create(HOSTADDRESS physaddr, ulong channelBytes, GUID guid)
+{
+	return visorchannel_create_guts(physaddr, channelBytes, NULL, 0, guid,
+					FALSE);
+}
+EXPORT_SYMBOL_GPL(visorchannel_create);
+
+VISORCHANNEL *
+visorchannel_create_with_lock(HOSTADDRESS physaddr, ulong channelBytes,
+			      GUID guid)
+{
+	return visorchannel_create_guts(physaddr, channelBytes, NULL, 0, guid,
+					TRUE);
+}
+EXPORT_SYMBOL_GPL(visorchannel_create_with_lock);
+
+VISORCHANNEL *
+visorchannel_create_overlapped(ulong channelBytes,
+			       VISORCHANNEL *parent, ulong off, GUID guid)
+{
+	return visorchannel_create_guts(0, channelBytes, parent, off, guid,
+					FALSE);
+}
+EXPORT_SYMBOL_GPL(visorchannel_create_overlapped);
+
+VISORCHANNEL *
+visorchannel_create_overlapped_with_lock(ulong channelBytes,
+					 VISORCHANNEL *parent, ulong off,
+					 GUID guid)
+{
+	return visorchannel_create_guts(0, channelBytes, parent, off, guid,
+					TRUE);
+}
+EXPORT_SYMBOL_GPL(visorchannel_create_overlapped_with_lock);
+
+void
+visorchannel_destroy(VISORCHANNEL *channel)
+{
+	if (channel == NULL)
+		return;
+	if (channel->memregion != NULL) {
+		memregion_destroy(channel->memregion);
+		channel->memregion = NULL;
+	}
+	kfree(channel);
+}
+EXPORT_SYMBOL_GPL(visorchannel_destroy);
+
+HOSTADDRESS
+visorchannel_get_physaddr(VISORCHANNEL *channel)
+{
+	return memregion_get_physaddr(channel->memregion);
+}
+EXPORT_SYMBOL_GPL(visorchannel_get_physaddr);
+
+ulong
+visorchannel_get_nbytes(VISORCHANNEL *channel)
+{
+	return channel->size;
+}
+EXPORT_SYMBOL_GPL(visorchannel_get_nbytes);
+
+char *
+visorchannel_GUID_id(GUID *guid, char *s)
+{
+	return GUID_format1(guid, s);
+}
+EXPORT_SYMBOL_GPL(visorchannel_GUID_id);
+
+char *
+visorchannel_id(VISORCHANNEL *channel, char *s)
+{
+	return visorchannel_GUID_id(&channel->guid, s);
+}
+EXPORT_SYMBOL_GPL(visorchannel_id);
+
+char *
+visorchannel_zoneid(VISORCHANNEL *channel, char *s)
+{
+	return visorchannel_GUID_id(&channel->chan_hdr.ZoneGuid, s);
+}
+EXPORT_SYMBOL_GPL(visorchannel_zoneid);
+
+HOSTADDRESS
+visorchannel_get_clientpartition(VISORCHANNEL *channel)
+{
+	return channel->chan_hdr.PartitionHandle;
+}
+EXPORT_SYMBOL_GPL(visorchannel_get_clientpartition);
+
+GUID
+visorchannel_get_GUID(VISORCHANNEL *channel)
+{
+	return channel->guid;
+}
+EXPORT_SYMBOL_GPL(visorchannel_get_GUID);
+
+MEMREGION *
+visorchannel_get_memregion(VISORCHANNEL *channel)
+{
+	return channel->memregion;
+}
+EXPORT_SYMBOL_GPL(visorchannel_get_memregion);
+
+pSIGNAL_QUEUE_HEADER
+visorchannel_get_safe_queue(VISORCHANNEL *pchannel, U32 queue)
+{
+	switch (queue) {
+	case 0:
+		return &pchannel->safe_uis_queue.req_queue;
+	case 1:
+		return &pchannel->safe_uis_queue.rsp_queue;
+	case 2:
+		return &pchannel->safe_uis_queue.event_queue;
+	case 3:
+		return &pchannel->safe_uis_queue.ack_queue;
+	default:
+		ERRDRV("Invalid queue value %d\n", queue);
+		return NULL;
+	}
+}				/* end visorchannel_get_safe_queue */
+
+int
+visorchannel_read(VISORCHANNEL *channel, ulong offset,
+		  void *local, ulong nbytes)
+{
+	int rc = memregion_read(channel->memregion, offset, local, nbytes);
+	if ((rc >= 0) && (offset == 0) && (nbytes >= sizeof(CHANNEL_HEADER)))
+		memcpy(&channel->chan_hdr, local, sizeof(CHANNEL_HEADER));
+	return rc;
+}
+EXPORT_SYMBOL_GPL(visorchannel_read);
+
+int
+visorchannel_write(VISORCHANNEL *channel, ulong offset,
+		   void *local, ulong nbytes)
+{
+	if (offset == 0 && nbytes >= sizeof(CHANNEL_HEADER))
+		memcpy(&channel->chan_hdr, local, sizeof(CHANNEL_HEADER));
+	return memregion_write(channel->memregion, offset, local, nbytes);
+}
+EXPORT_SYMBOL_GPL(visorchannel_write);
+
+int
+visorchannel_clear(VISORCHANNEL *channel, ulong offset, U8 ch, ulong nbytes)
+{
+	int rc = -1;
+	int bufsize = 65536;
+	int written = 0;
+	U8 *buf = vmalloc(bufsize);
+
+	if (buf == NULL) {
+		ERRDRV("%s failed memory allocation", __func__);
+		RETINT(-1);
+	}
+	memset(buf, ch, bufsize);
+	while (nbytes > 0) {
+		ulong thisbytes = bufsize;
+		int x = -1;
+		if (nbytes < thisbytes)
+			thisbytes = nbytes;
+		x = memregion_write(channel->memregion, offset + written,
+				    buf, thisbytes);
+		if (x < 0)
+			RETINT(x);
+		written += thisbytes;
+		nbytes -= thisbytes;
+	}
+	RETINT(0);
+
+Away:
+	if (buf != NULL) {
+		vfree(buf);
+		buf = NULL;
+	}
+	return rc;
+}
+EXPORT_SYMBOL_GPL(visorchannel_clear);
+
+void *
+visorchannel_get_header(VISORCHANNEL *channel)
+{
+	return (void *) &(channel->chan_hdr);
+}
+EXPORT_SYMBOL_GPL(visorchannel_get_header);
+
+/** Return offset of a specific SIGNAL_QUEUE_HEADER from the beginning of a
+ *  channel header
+ */
+#define SIG_QUEUE_OFFSET(chan_hdr, q) \
+	((chan_hdr)->oChannelSpace + ((q) * sizeof(SIGNAL_QUEUE_HEADER)))
+
+/** Return offset of a specific queue entry (data) from the beginning of a
+ *  channel header
+ */
+#define SIG_DATA_OFFSET(chan_hdr, q, sig_hdr, slot) \
+	(SIG_QUEUE_OFFSET(chan_hdr, q) + (sig_hdr)->oSignalBase + \
+	    ((slot) * (sig_hdr)->SignalSize))
+
+/** Write the contents of a specific field within a SIGNAL_QUEUE_HEADER back
+ *  into host memory
+ */
+#define SIG_WRITE_FIELD(channel, queue, sig_hdr, FIELD)                \
+	(memregion_write(channel->memregion,                        \
+			 SIG_QUEUE_OFFSET(&channel->chan_hdr, queue)+\
+			   offsetof(SIGNAL_QUEUE_HEADER, FIELD),     \
+			 &((sig_hdr)->FIELD),                       \
+			 sizeof((sig_hdr)->FIELD)) >= 0)
+
+static BOOL
+sig_read_header(VISORCHANNEL *channel, U32 queue,
+		SIGNAL_QUEUE_HEADER *sig_hdr)
+{
+	BOOL rc = FALSE;
+
+	if (channel->chan_hdr.oChannelSpace < sizeof(CHANNEL_HEADER))
+		FAIL("oChannelSpace too small", FALSE);
+
+	/* Read the appropriate SIGNAL_QUEUE_HEADER into local memory. */
+
+	if (memregion_read(channel->memregion,
+			   SIG_QUEUE_OFFSET(&channel->chan_hdr, queue),
+			   sig_hdr, sizeof(SIGNAL_QUEUE_HEADER)) < 0) {
+		ERRDRV("queue=%d SIG_QUEUE_OFFSET=%d",
+		       queue, (int)SIG_QUEUE_OFFSET(&channel->chan_hdr, queue));
+		FAIL("memregion_read of signal queue failed", FALSE);
+	}
+	RETBOOL(TRUE);
+Away:
+	return rc;
+}
+
+static BOOL
+sig_do_data(VISORCHANNEL *channel, U32 queue,
+	    SIGNAL_QUEUE_HEADER *sig_hdr, U32 slot, void *data, BOOL is_write)
+{
+	BOOL rc = FALSE;
+	int signal_data_offset = SIG_DATA_OFFSET(&channel->chan_hdr, queue,
+						 sig_hdr, slot);
+	if (is_write) {
+		if (memregion_write(channel->memregion, signal_data_offset,
+				    data, sig_hdr->SignalSize) < 0)
+			FAIL("memregion_write of signal data failed", FALSE);
+	} else {
+		if (memregion_read(channel->memregion, signal_data_offset,
+				   data, sig_hdr->SignalSize) < 0)
+			FAIL("memregion_read of signal data failed", FALSE);
+	}
+	RETBOOL(TRUE);
+Away:
+	return rc;
+}
+
+static inline BOOL
+sig_read_data(VISORCHANNEL *channel, U32 queue,
+	      SIGNAL_QUEUE_HEADER *sig_hdr, U32 slot, void *data)
+{
+	return sig_do_data(channel, queue, sig_hdr, slot, data, FALSE);
+}
+
+static inline BOOL
+sig_write_data(VISORCHANNEL *channel, U32 queue,
+	       SIGNAL_QUEUE_HEADER *sig_hdr, U32 slot, void *data)
+{
+	return sig_do_data(channel, queue, sig_hdr, slot, data, TRUE);
+}
+
+static inline unsigned char
+safe_sig_queue_validate(pSIGNAL_QUEUE_HEADER psafe_sqh,
+			pSIGNAL_QUEUE_HEADER punsafe_sqh,
+			U32 *phead, U32 *ptail)
+{
+	if ((*phead >= psafe_sqh->MaxSignalSlots)
+	    || (*ptail >= psafe_sqh->MaxSignalSlots)) {
+		/* Choose 0 or max, maybe based on current tail value */
+		*phead = 0;
+		*ptail = 0;
+
+		/* Sync with client as necessary */
+		punsafe_sqh->Head = *phead;
+		punsafe_sqh->Tail = *ptail;
+
+		ERRDRV("safe_sig_queue_validate: head = 0x%x, tail = 0x%x, MaxSlots = 0x%x",
+		     *phead, *ptail, psafe_sqh->MaxSignalSlots);
+		return 0;
+	}
+	return 1;
+}				/* end safe_sig_queue_validate */
+
+BOOL
+visorchannel_signalremove(VISORCHANNEL *channel, U32 queue, void *msg)
+{
+	BOOL rc = FALSE;
+	SIGNAL_QUEUE_HEADER sig_hdr;
+
+	if (channel->needs_lock)
+		spin_lock(&channel->remove_lock);
+
+	if (!sig_read_header(channel, queue, &sig_hdr))
+		RETBOOL(FALSE);
+	if (sig_hdr.Head == sig_hdr.Tail)
+		RETBOOL(FALSE);	/* no signals to remove */
+	sig_hdr.Tail = (sig_hdr.Tail + 1) % sig_hdr.MaxSignalSlots;
+	if (!sig_read_data(channel, queue, &sig_hdr, sig_hdr.Tail, msg))
+		FAIL("sig_read_data failed", FALSE);
+	sig_hdr.NumSignalsReceived++;
+
+	/* For each data field in SIGNAL_QUEUE_HEADER that was modified,
+	 * update host memory.
+	 */
+	MEMORYBARRIER;
+	if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, Tail))
+		FAIL("memregion_write of Tail failed", FALSE);
+	if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, NumSignalsReceived))
+		FAIL("memregion_write of NumSignalsReceived failed", FALSE);
+
+	RETBOOL(TRUE);
+
+Away:
+	if (channel->needs_lock)
+		spin_unlock(&channel->remove_lock);
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(visorchannel_signalremove);
+
+BOOL
+visorchannel_safesignalremove(VISORCHANNEL *channel, U32 queue, void *msg)
+{
+	BOOL rc = FALSE;
+	SIGNAL_QUEUE_HEADER *psafe_sqh, unsafe_sqh;
+	int stat;
+
+	if (channel->needs_lock)
+		spin_lock(&channel->remove_lock);
+
+	if (!sig_read_header(channel, queue, &unsafe_sqh))
+		RETBOOL(FALSE);
+
+	psafe_sqh = visorchannel_get_safe_queue(channel, queue);
+	if (psafe_sqh == NULL) {
+		ERRDRV("safesignalremove: get_safe_queue failed\n");
+		RETBOOL(FALSE);
+	}
+
+	stat =
+	    safe_sig_queue_validate(psafe_sqh, &unsafe_sqh, &unsafe_sqh.Head,
+				    &unsafe_sqh.Tail);
+	if (stat == 0) {
+		ERRDRV("safe_signal_remove: safe_sig_queue_validate failed, queue = %d",
+		     queue);
+		RETBOOL(FALSE);
+	}
+
+	if (unsafe_sqh.Head == unsafe_sqh.Tail)
+		RETBOOL(FALSE);	/* no signals to remove */
+	unsafe_sqh.Tail = (unsafe_sqh.Tail + 1) % psafe_sqh->MaxSignalSlots;
+	if (!sig_read_data(channel, queue, psafe_sqh, unsafe_sqh.Tail, msg))
+		FAIL("sig_read_data failed", FALSE);
+	unsafe_sqh.NumSignalsReceived++;
+
+	/* For each data field in SIGNAL_QUEUE_HEADER that was modified,
+	 * update host memory.
+	 */
+	MEMORYBARRIER;
+	if (!SIG_WRITE_FIELD(channel, queue, &unsafe_sqh, Tail))
+		FAIL("memregion_write of Tail failed", FALSE);
+	if (!SIG_WRITE_FIELD(channel, queue, &unsafe_sqh, NumSignalsReceived))
+		FAIL("memregion_write of NumSignalsReceived failed", FALSE);
+
+	RETBOOL(TRUE);
+
+Away:
+	if (channel->needs_lock)
+		spin_unlock(&channel->remove_lock);
+
+	return rc;
+}				/* end visorchannel_safesignalremove */
+
+BOOL
+visorchannel_signalinsert(VISORCHANNEL *channel, U32 queue, void *msg)
+{
+	BOOL rc = FALSE;
+	SIGNAL_QUEUE_HEADER sig_hdr;
+
+	if (channel->needs_lock)
+		spin_lock(&channel->insert_lock);
+
+	if (!sig_read_header(channel, queue, &sig_hdr))
+		RETBOOL(FALSE);
+
+	sig_hdr.Head = ((sig_hdr.Head + 1) % sig_hdr.MaxSignalSlots);
+	if (sig_hdr.Head == sig_hdr.Tail) {
+#if 0
+		ERRDRV("visorchannel queue #%d overflow (max slots=%d)",
+		       queue, sig_hdr.MaxSignalSlots);
+#endif
+		sig_hdr.NumOverflows++;
+		if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, NumOverflows))
+			FAIL("memregion_write of NumOverflows failed", FALSE);
+		RETBOOL(FALSE);
+	}
+
+	if (!sig_write_data(channel, queue, &sig_hdr, sig_hdr.Head, msg))
+		FAIL("sig_write_data failed", FALSE);
+	sig_hdr.NumSignalsSent++;
+
+	/* For each data field in SIGNAL_QUEUE_HEADER that was modified,
+	 * update host memory.
+	 */
+	MEMORYBARRIER;
+	if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, Head))
+		FAIL("memregion_write of Head failed", FALSE);
+	if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, NumSignalsSent))
+		FAIL("memregion_write of NumSignalsSent failed", FALSE);
+
+	RETBOOL(TRUE);
+
+Away:
+	if (channel->needs_lock)
+		spin_unlock(&channel->insert_lock);
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(visorchannel_signalinsert);
+
+
+int
+visorchannel_signalqueue_slots_avail(VISORCHANNEL *channel, U32 queue)
+{
+	SIGNAL_QUEUE_HEADER sig_hdr;
+	U32 slots_avail, slots_used;
+	U32 head, tail;
+
+	if (!sig_read_header(channel, queue, &sig_hdr))
+		return 0;
+	head = sig_hdr.Head;
+	tail = sig_hdr.Tail;
+	if (head < tail)
+		head = head + sig_hdr.MaxSignalSlots;
+	slots_used = (head - tail);
+	slots_avail = sig_hdr.MaxSignals - slots_used;
+	return (int) slots_avail;
+}
+EXPORT_SYMBOL_GPL(visorchannel_signalqueue_slots_avail);
+
+int
+visorchannel_signalqueue_max_slots(VISORCHANNEL *channel, U32 queue)
+{
+	SIGNAL_QUEUE_HEADER sig_hdr;
+	if (!sig_read_header(channel, queue, &sig_hdr))
+		return 0;
+	return (int) sig_hdr.MaxSignals;
+}
+EXPORT_SYMBOL_GPL(visorchannel_signalqueue_max_slots);
+
+BOOL
+visorchannel_safesignalinsert(VISORCHANNEL *channel, U32 queue, void *msg)
+{
+	BOOL rc = FALSE;
+	SIGNAL_QUEUE_HEADER *psafe_sqh, unsafe_sqh;
+	int stat;
+
+	if (channel->needs_lock)
+		spin_lock(&channel->insert_lock);
+
+	if (!sig_read_header(channel, queue, &unsafe_sqh))
+		RETBOOL(FALSE);
+
+	psafe_sqh = visorchannel_get_safe_queue(channel, queue);
+	if (psafe_sqh == NULL) {
+		ERRDRV("safesignalinsert: get_safe_queue failed\n");
+		RETBOOL(FALSE);
+	}
+
+	unsafe_sqh.Head = ((unsafe_sqh.Head + 1) % psafe_sqh->MaxSignalSlots);
+
+	stat =
+	    safe_sig_queue_validate(psafe_sqh, &unsafe_sqh, &unsafe_sqh.Head,
+				    &unsafe_sqh.Tail);
+	if (stat == 0) {
+		ERRDRV("safe_signal_insert: safe_sig_queue_validate failed, queue = %d",
+		     queue);
+		RETBOOL(FALSE);
+	}
+
+	if (unsafe_sqh.Head == unsafe_sqh.Tail) {
+#if 0
+		ERRDRV("visorchannel queue #%d overflow (max slots=%d)",
+		       queue, psafe_sqh->MaxSignalSlots);
+#endif
+		unsafe_sqh.NumOverflows++;
+		if (!SIG_WRITE_FIELD(channel, queue, &unsafe_sqh, NumOverflows))
+			FAIL("memregion_write of NumOverflows failed", FALSE);
+		RETBOOL(FALSE);
+	}
+
+	if (!sig_write_data(channel, queue, psafe_sqh, unsafe_sqh.Head, msg))
+		FAIL("sig_write_data failed", FALSE);
+	unsafe_sqh.NumSignalsSent++;
+
+	/* For each data field in SIGNAL_QUEUE_HEADER that was modified,
+	 * update host memory.
+	 */
+	MEMORYBARRIER;
+	if (!SIG_WRITE_FIELD(channel, queue, &unsafe_sqh, Head))
+		FAIL("memregion_write of Head failed", FALSE);
+	if (!SIG_WRITE_FIELD(channel, queue, &unsafe_sqh, NumSignalsSent))
+		FAIL("memregion_write of NumSignalsSent failed", FALSE);
+
+	RETBOOL(TRUE);
+
+Away:
+	if (channel->needs_lock)
+		spin_unlock(&channel->insert_lock);
+
+	return rc;
+}				/* end visorchannel_safesignalinsert */
+
+static void
+sigqueue_debug(SIGNAL_QUEUE_HEADER *q, int which, struct seq_file *seq)
+{
+	seq_printf(seq, "Signal Queue #%d\n", which);
+	seq_printf(seq, "   VersionId          = %lu\n", (ulong) q->VersionId);
+	seq_printf(seq, "   Type               = %lu\n", (ulong) q->Type);
+	seq_printf(seq, "   oSignalBase        = %llu\n",
+		   (long long) q->oSignalBase);
+	seq_printf(seq, "   SignalSize         = %lu\n", (ulong) q->SignalSize);
+	seq_printf(seq, "   MaxSignalSlots     = %lu\n",
+		   (ulong) q->MaxSignalSlots);
+	seq_printf(seq, "   MaxSignals         = %lu\n", (ulong) q->MaxSignals);
+	seq_printf(seq, "   FeatureFlags       = %-16.16Lx\n",
+		   (long long) q->FeatureFlags);
+	seq_printf(seq, "   NumSignalsSent     = %llu\n",
+		   (long long) q->NumSignalsSent);
+	seq_printf(seq, "   NumSignalsReceived = %llu\n",
+		   (long long) q->NumSignalsReceived);
+	seq_printf(seq, "   NumOverflows       = %llu\n",
+		   (long long) q->NumOverflows);
+	seq_printf(seq, "   Head               = %lu\n", (ulong) q->Head);
+	seq_printf(seq, "   Tail               = %lu\n", (ulong) q->Tail);
+}
+
+void
+visorchannel_debug(VISORCHANNEL *channel, int nQueues,
+		   struct seq_file *seq, U32 off)
+{
+	HOSTADDRESS addr = 0;
+	ulong nbytes = 0, nbytes_region = 0;
+	MEMREGION *memregion = NULL;
+	CHANNEL_HEADER hdr;
+	CHANNEL_HEADER *phdr = &hdr;
+	char s[99];
+	int i = 0;
+	int errcode = 0;
+
+	if (channel == NULL) {
+		ERRDRV("%s no channel", __func__);
+		return;
+	}
+	memregion = channel->memregion;
+	if (memregion == NULL) {
+		ERRDRV("%s no memregion", __func__);
+		return;
+	}
+	addr = memregion_get_physaddr(memregion);
+	nbytes_region = memregion_get_nbytes(memregion);
+	errcode = visorchannel_read(channel, off,
+				    phdr, sizeof(CHANNEL_HEADER));
+	if (errcode < 0) {
+		seq_printf(seq,
+			   "Read of channel header failed with errcode=%d)\n",
+			   errcode);
+		if (off == 0) {
+			phdr = &channel->chan_hdr;
+			seq_puts(seq, "(following data may be stale)\n");
+		} else
+			return;
+	}
+	nbytes = (ulong) (phdr->Size);
+	seq_printf(seq, "--- Begin channel @0x%-16.16Lx for 0x%lx bytes (region=0x%lx bytes) ---\n",
+		   addr + off, nbytes, nbytes_region);
+	seq_printf(seq, "Type            = %s\n", GUID_format2(&phdr->Type, s));
+	seq_printf(seq, "ZoneGuid        = %s\n",
+		   GUID_format2(&phdr->ZoneGuid, s));
+	seq_printf(seq, "Signature       = 0x%-16.16Lx\n",
+		   (long long) phdr->Signature);
+	seq_printf(seq, "LegacyState     = %lu\n", (ulong) phdr->LegacyState);
+	seq_printf(seq, "SrvState        = %lu\n", (ulong) phdr->SrvState);
+	seq_printf(seq, "CliStateBoot    = %lu\n", (ulong) phdr->CliStateBoot);
+	seq_printf(seq, "CliStateOS      = %lu\n", (ulong) phdr->CliStateOS);
+	seq_printf(seq, "HeaderSize      = %lu\n", (ulong) phdr->HeaderSize);
+	seq_printf(seq, "Size            = %llu\n", (long long) phdr->Size);
+	seq_printf(seq, "Features        = 0x%-16.16llx\n",
+		   (long long) phdr->Features);
+	seq_printf(seq, "PartitionHandle = 0x%-16.16llx\n",
+		   (long long) phdr->PartitionHandle);
+	seq_printf(seq, "Handle          = 0x%-16.16llx\n",
+		   (long long) phdr->Handle);
+	seq_printf(seq, "VersionId       = %lu\n", (ulong) phdr->VersionId);
+	seq_printf(seq, "oChannelSpace   = %llu\n",
+		   (long long) phdr->oChannelSpace);
+	if ((phdr->oChannelSpace == 0) || (errcode < 0))
+		;
+	else
+		for (i = 0; i < nQueues; i++) {
+			SIGNAL_QUEUE_HEADER q;
+			errcode = visorchannel_read(channel,
+						    off + phdr->oChannelSpace +
+						    (i * sizeof(q)),
+						    &q, sizeof(q));
+			if (errcode < 0) {
+				seq_printf(seq,
+					   "failed to read signal queue #%d from channel @0x%-16.16Lx errcode=%d\n",
+					   i, addr, errcode);
+				continue;
+			}
+			sigqueue_debug(&q, i, seq);
+		}
+	seq_printf(seq, "--- End   channel @0x%-16.16Lx for 0x%lx bytes ---\n",
+		   addr + off, nbytes);
+}
+EXPORT_SYMBOL_GPL(visorchannel_debug);
+
+void
+visorchannel_dump_section(VISORCHANNEL *chan, char *s,
+			  int off, int len, struct seq_file *seq)
+{
+	char *buf = NULL, *fmtbuf = NULL;
+	int fmtbufsize = 0;
+	int i = 0;
+	int errcode = 0;
+
+	fmtbufsize = 100 * COVQ(len, 16);
+	buf = kmalloc(len, GFP_KERNEL|__GFP_NORETRY);
+	fmtbuf = kmalloc(fmtbufsize, GFP_KERNEL|__GFP_NORETRY);
+	if (buf == NULL || fmtbuf == NULL)
+		goto Away;
+
+	errcode = visorchannel_read(chan, off, buf, len);
+	if (errcode < 0) {
+		ERRDRV("%s failed to read %s from channel errcode=%d",
+		       s, __func__, errcode);
+		goto Away;
+	}
+	seq_printf(seq, "channel %s:\n", s);
+	hexDumpToBuffer(fmtbuf, fmtbufsize, "  ", buf, len, 16);
+	for (i = 0; fmtbuf[i] != '\0'; i++)
+		seq_printf(seq, "%c", fmtbuf[i]);
+
+Away:
+	if (buf != NULL) {
+		kfree(buf);
+		buf = NULL;
+	}
+	if (fmtbuf != NULL) {
+		kfree(fmtbuf);
+		fmtbuf = NULL;
+	}
+}
+EXPORT_SYMBOL_GPL(visorchannel_dump_section);
Index: upstream-staging/drivers/staging/unisys/visorchannel/visorchannel_main.c
===================================================================
--- /dev/null
+++ upstream-staging/drivers/staging/unisys/visorchannel/visorchannel_main.c
@@ -0,0 +1,49 @@
+/* visorchannel_main.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.
+ */
+
+/*
+ *  This is a module "wrapper" around visorchannel_funcs.
+ */
+
+#include "globals.h"
+#include "channel.h"
+#include "visorchannel.h"
+#include "guidutils.h"
+
+#define MYDRVNAME "visorchannel"
+
+static int __init
+visorchannel_init(void)
+{
+	INFODRV("driver version %s loaded", VERSION);
+	return 0;
+}
+
+static void
+visorchannel_exit(void)
+{
+	INFODRV("driver unloaded");
+}
+
+module_init(visorchannel_init);
+module_exit(visorchannel_exit);
+
+MODULE_AUTHOR("Unisys");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Supervisor channel driver for service partition: ver "
+		   VERSION);
+MODULE_VERSION(VERSION);

_______________________________________________
devel mailing list
devel@xxxxxxxxxxxxxxxxxxxxxx
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

[Index of Archives]     [Linux Driver Backports]     [DMA Engine]     [Linux GPIO]     [Linux SPI]     [Video for Linux]     [Linux USB Devel]     [Linux Coverity]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux