diff options
Diffstat (limited to 'drivers/staging/unisys/common-spar/include/channels/channel.h')
-rw-r--r-- | drivers/staging/unisys/common-spar/include/channels/channel.h | 661 |
1 files changed, 661 insertions, 0 deletions
diff --git a/drivers/staging/unisys/common-spar/include/channels/channel.h b/drivers/staging/unisys/common-spar/include/channels/channel.h new file mode 100644 index 000000000000..aee204172b21 --- /dev/null +++ b/drivers/staging/unisys/common-spar/include/channels/channel.h @@ -0,0 +1,661 @@ +/* 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(readl(&(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, \ + newstate, logCtx) \ + do { \ + ULTRA_CHANNEL_CLIENT_CHK_TRANSITION( \ + readl(&(((CHANNEL_HEADER __iomem *) \ + (pChan))->CliStateOS)), \ + 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, "CliStateOS", \ + ULTRA_CHANNELCLI_STRING( \ + readl(&((CHANNEL_HEADER __iomem *) \ + (pChan))->CliStateOS)), \ + readl(&((CHANNEL_HEADER __iomem *) \ + (pChan))->CliStateOS), \ + ULTRA_CHANNELCLI_STRING(newstate), \ + newstate, \ + PathName_Last_N_Nodes(__FILE__, 4), __LINE__); \ + writel(newstate, &((CHANNEL_HEADER __iomem *) \ + (pChan))->CliStateOS); \ + 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 visor_signal_remove + * 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 __iomem *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_IO(&(((CHANNEL_HEADER __iomem *) (pChannel))->Type), + &expectedTypeGuid, sizeof(GUID)) != 0) { + CHANNEL_GUID_MISMATCH(expectedTypeGuid, channelName, + "type", expectedTypeGuid, + ((CHANNEL_HEADER __iomem *) + (pChannel))->Type, fileName, + lineNumber, logCtx); + return 0; + } + if (expectedMinBytes > 0) /* caller wants us to verify + * channel size */ + if (readq(&((CHANNEL_HEADER __iomem *) + (pChannel))->Size) < expectedMinBytes) { + CHANNEL_U64_MISMATCH(expectedTypeGuid, channelName, + "size", expectedMinBytes, + ((CHANNEL_HEADER __iomem *) + (pChannel))->Size, fileName, + lineNumber, logCtx); + return 0; + } + if (expectedVersionId > 0) /* caller wants us to verify + * channel version */ + if (readl(&((CHANNEL_HEADER __iomem *) (pChannel))->VersionId) + != expectedVersionId) { + CHANNEL_U32_MISMATCH(expectedTypeGuid, channelName, + "version", expectedVersionId, + ((CHANNEL_HEADER __iomem *) + (pChannel))->VersionId, fileName, + lineNumber, logCtx); + return 0; + } + if (expectedSignature > 0) /* caller wants us to verify + * channel signature */ + if (readq(&((CHANNEL_HEADER __iomem *) (pChannel))->Signature) + != expectedSignature) { + CHANNEL_U64_MISMATCH(expectedTypeGuid, channelName, + "signature", expectedSignature, + ((CHANNEL_HEADER __iomem *) + (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 __iomem *pChannel, U8 *chanId, + void *logCtx, char *file, int line, char *func) +{ + CHANNEL_HEADER __iomem *pChan = pChannel; + + if (readl(&pChan->CliStateOS) == CHANNELCLI_DISABLED) { + if ((readb(&pChan->CliErrorOS) + & ULTRA_CLIERROROS_THROTTLEMSG_DISABLED) == 0) { + /* we are NOT throttling this message */ + writeb(readb(&pChan->CliErrorOS) | + ULTRA_CLIERROROS_THROTTLEMSG_DISABLED, + &pChan->CliErrorOS); + /* 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 ((readl(&pChan->CliStateOS) != CHANNELCLI_OWNED) + && (readl(&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( + readl(&pChan->CliStateOS)), + readl(&pChan->CliStateOS), + ULTRA_CHANNELCLI_STRING(CHANNELCLI_OWNED), + CHANNELCLI_OWNED, + PathName_Last_N_Nodes((U8 *) file, 4), line); + writel(CHANNELCLI_OWNED, &pChan->CliStateOS); + MEMORYBARRIER; + } + if (readl(&pChan->CliStateOS) == CHANNELCLI_OWNED) { + if (readb(&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); + writeb(0, &pChan->CliErrorOS); + } + 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 (readl(&pChan->CliStateOS) != CHANNELCLI_ATTACHED) { + if ((readb(&pChan->CliErrorOS) + & ULTRA_CLIERROROS_THROTTLEMSG_NOTATTACHED) == 0) { + /* we are NOT throttling this message */ + writeb(readb(&pChan->CliErrorOS) | + ULTRA_CLIERROROS_THROTTLEMSG_NOTATTACHED, + &pChan->CliErrorOS); + /* 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( + readl(&pChan->CliStateOS)), + readl(&pChan->CliStateOS), + PathName_Last_N_Nodes((U8 *) file, 4), + line); + } + return 0; + } + writel(CHANNELCLI_BUSY, &pChan->CliStateOS); + MEMORYBARRIER; + if (readl(&pChan->CliStateBoot) == CHANNELCLI_BUSY) { + if ((readb(&pChan->CliErrorOS) + & ULTRA_CLIERROROS_THROTTLEMSG_BUSY) == 0) { + /* we are NOT throttling this message */ + writeb(readb(&pChan->CliErrorOS) | + ULTRA_CLIERROROS_THROTTLEMSG_BUSY, + &pChan->CliErrorOS); + /* 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); + } + /* reset busy */ + writel(CHANNELCLI_ATTACHED, &pChan->CliStateOS); + MEMORYBARRIER; + return 0; + } + if (readb(&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); + writeb(0, &pChan->CliErrorOS); + } + return 1; +} + +static inline void +ULTRA_channel_client_release_os(void __iomem *pChannel, U8 *chanId, + void *logCtx, char *file, int line, char *func) +{ + CHANNEL_HEADER __iomem *pChan = pChannel; + if (readb(&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); + writeb(0, &pChan->CliErrorOS); + } + if (readl(&pChan->CliStateOS) == CHANNELCLI_OWNED) + return; + if (readl(&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( + readl(&pChan->CliStateOS)), + readl(&pChan->CliStateOS), + PathName_Last_N_Nodes((U8 *) file, 4), line); + /* return; */ + } + writel(CHANNELCLI_ATTACHED, &pChan->CliStateOS); /* 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 visor_signal_insert(CHANNEL_HEADER __iomem *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 visor_signal_remove(CHANNEL_HEADER __iomem *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 visor_signalqueue_empty(CHANNEL_HEADER __iomem *pChannel, + U32 Queue); + +#endif |