summaryrefslogtreecommitdiffstats
path: root/src/lib/occlib
diff options
context:
space:
mode:
authorWilliam Bryan <wilbryan@us.ibm.com>2015-08-03 12:38:58 -0500
committerWilliam A. Bryan <wilbryan@us.ibm.com>2015-08-03 15:32:27 -0500
commit420e6d248cc6d2b3c39bc3970e3bb6747b3bddc3 (patch)
treec9f6691eddba39193e39aa769367e1267fb9fc86 /src/lib/occlib
parentadade8c8ef30ed519322674c762d95663009c5d4 (diff)
downloadtalos-occ-420e6d248cc6d2b3c39bc3970e3bb6747b3bddc3.tar.gz
talos-occ-420e6d248cc6d2b3c39bc3970e3bb6747b3bddc3.zip
new ssx and lib files
Change-Id: I2328b1e86d59e3788910687d762fb70ec680058f Reviewed-on: http://gfw160.aus.stglabs.ibm.com:8080/gerrit/19503 Reviewed-by: William A. Bryan <wilbryan@us.ibm.com> Tested-by: William A. Bryan <wilbryan@us.ibm.com>
Diffstat (limited to 'src/lib/occlib')
-rw-r--r--src/lib/occlib/Makefile57
-rw-r--r--src/lib/occlib/README.txt1
-rw-r--r--src/lib/occlib/ipc_api.h519
-rw-r--r--src/lib/occlib/ipc_async_cmd.h49
-rw-r--r--src/lib/occlib/ipc_core.c484
-rw-r--r--src/lib/occlib/ipc_init.c153
-rw-r--r--src/lib/occlib/ipc_macros.h197
-rw-r--r--src/lib/occlib/ipc_msgq.c108
-rw-r--r--src/lib/occlib/ipc_ping.c96
-rw-r--r--src/lib/occlib/ipc_ping.h53
-rw-r--r--src/lib/occlib/ipc_structs.h226
-rw-r--r--src/lib/occlib/liboccfiles.mk53
-rw-r--r--src/lib/occlib/occhw_scom_cmd.h93
-rw-r--r--src/lib/occlib/occhw_shared_data.h93
-rw-r--r--src/lib/occlib/occhw_xir_dump.c60
-rw-r--r--src/lib/occlib/occhw_xir_dump.h70
16 files changed, 2312 insertions, 0 deletions
diff --git a/src/lib/occlib/Makefile b/src/lib/occlib/Makefile
new file mode 100644
index 0000000..9f86413
--- /dev/null
+++ b/src/lib/occlib/Makefile
@@ -0,0 +1,57 @@
+# IBM_PROLOG_BEGIN_TAG
+# This is an automatically generated prolog.
+#
+# $Source: src/lib/occlib/Makefile $
+#
+# OpenPOWER OnChipController Project
+#
+# Contributors Listed Below - COPYRIGHT 2015
+# [+] International Business Machines Corp.
+#
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+#
+# IBM_PROLOG_END_TAG
+# This Makefile currently builds a single archive, 'libocc.a', from
+# various library source files.
+#
+# part of the complete application build.
+#
+
+#all generated files from this makefile will end up in obj/$(IMAGE_NAME)/occ
+export SUB_OBJDIR = /occlib
+
+include img_defs.mk
+include liboccfiles.mk
+
+OBJS := $(addprefix $(OBJDIR)/, $(LIBOCC_OBJECTS))
+
+libocc.a: local
+ $(AR) crs $(OBJDIR)/libocc.a $(OBJDIR)/*.o
+
+.PHONY: clean
+
+local: $(OBJS)
+
+$(OBJS) $(OBJS:.o=.d): | $(OBJDIR)
+
+$(OBJDIR):
+ mkdir -p $(OBJDIR)
+
+clean:
+ rm -fr $(OBJDIR)
+
+ifneq ($(MAKECMDGOALS),clean)
+include $(OBJS:.o=.d)
+endif
+
diff --git a/src/lib/occlib/README.txt b/src/lib/occlib/README.txt
new file mode 100644
index 0000000..2f3667f
--- /dev/null
+++ b/src/lib/occlib/README.txt
@@ -0,0 +1 @@
+This directory contains all code that is common for all processors in the OCC complex (405 + 4 GPE's)
diff --git a/src/lib/occlib/ipc_api.h b/src/lib/occlib/ipc_api.h
new file mode 100644
index 0000000..e4756f5
--- /dev/null
+++ b/src/lib/occlib/ipc_api.h
@@ -0,0 +1,519 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/occlib/ipc_api.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __IPC_API_H__
+#define __IPC_API_H__
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2015
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file ipc_api.h
+/// \brief Common header for Interprocessor Communications API
+///
+#include "ipc_structs.h"
+
+#ifndef __ASSEMBLER__
+///////////////////////////////////////////////////////////////////////////////
+/// Initialize an IPC command message
+///
+/// \param msg A pointer to the command message
+///
+/// \param func_id A user-defined function ID that is known to both the sender
+/// and receiver of a command message. (Defined in \a ipc_func_ids.h)
+///
+/// \param resp_callback A user-defined function that should be called when
+/// the message is returned as a response to the command. This must be set
+/// to 0 if no callback function should be called.
+///
+/// \param callback_arg A pointer to user-defined data that will be passed in
+/// to the callback function when it is called. This should be set to 0 if
+/// no data needs to be passed.
+///
+/// This function (or \a ipc_init_msgq_msg) must be called on a message at
+/// least once before it is sent via the \a ipc_send_msg interface.
+///
+/// There are two types of function ID's. Function ID's that only work on a
+/// single processor are called \e single-target ID's. These function
+/// ID's have the target ID embedded as part of the ID. FUnction ID's
+/// that are supported on multiple processors are called \e multi-target ID's.
+/// Command messages associated with multi-target function ID's must go through
+/// the extra step of setting the target ID by calling the \a ipc_set_cmd_target
+/// interface on the command message.
+///
+/// If a callback function is provided, that callback function should cause
+/// (directly or indirectly) the \ipc_free_msg interface to be called once it
+/// is known that it is safe for the message to be reused (sent as a command
+/// again).
+///
+void ipc_init_msg(ipc_msg_t* msg,
+ uint32_t func_id,
+ ipc_msg_handler_t resp_callback,
+ void* callback_arg);
+
+//Use these to statically initialize an IPC message
+#define IPC_MSG_INIT(_func_id, _resp_callback, _callback_arg) \
+{\
+ {.node = KERN_DEQUE_ELEMENT_INIT()}, \
+ .func_id.word32 = _func_id, \
+ .ipc_rc = IPC_RC_SUCCESS, \
+ .resp_callback = _resp_callback, \
+ .callback_arg = _callback_arg \
+}
+
+#define IPC_MSG_CREATE(msg_name, _func_id, _resp_callback, _callback_arg) \
+ipc_msg_t msg_name = IPC_MSG_INIT(_func_id, _resp_callback, _callback_arg)
+
+///////////////////////////////////////////////////////////////////////////////
+/// Free up a message to be reused.
+///
+/// \param msg a pointer to a message.
+///
+/// This interface should be called on a message when it is known that it is
+/// safe to reuse the message. Normally, this would be one of the last things
+/// performed in the response callback function for a command, but it may also
+/// be called when it is known that a peer has stopped functioning.
+///
+static inline void ipc_free_msg(ipc_msg_t* msg)
+{
+ msg->func_id.active_flag = 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// Set the target ID for a multi-target command message.
+///
+/// \param cmd A pointer to an initialized command message.
+///
+/// \param target_id The target ID of the processor the command is intended
+/// for.
+///
+/// The following return codes are possible:
+///
+/// \retval IPC_RC_SUCCESS The command's target ID was updated.
+///
+/// \retval IPC_RC_INVALID_FUNC_ID The function ID associated with this
+/// command is not a valid mult-target function ID.
+///
+int ipc_set_cmd_target(ipc_msg_t* cmd, uint32_t target_id);
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// Send a message as a command
+///
+/// \param cmd A pointer to an initialized command message
+///
+/// It is expected that at some point prior to calling this function the
+/// message was initialized with a call to \a ipc_init_msg or
+/// \a ipc_init_msgq_msg.
+///
+/// Once a message has been sent it is not safe to send again until it has been
+/// sent back to the sender as a response.
+///
+/// The following return codes are possible:
+///
+/// \retval IPC_RC_SUCCESS The message was successfully placed on the target's
+/// receive buffer.
+///
+/// \retval IPC_RC_SELF_BLOCKED The call was made prior to calling
+/// \a ipc_enable.
+///
+/// \retval IPC_RC_INVALID_FUNC_ID The command was initialized with an invalid
+/// function ID.
+///
+/// \retval IPC_RC_MSG_ACTIVE The message is currently in use.
+///
+/// \retval IPC_RC_INVALID_TARGET_ID The message was initialized with an
+/// invalid target ID. This can happen if a multi-target command has not had
+/// its target set via the \a ipc_set_cmd_target function at least one time.
+///
+/// \retval IPC_RC_BUFFER_FULL The command could not be sent because the target's
+/// receive buffer is full.
+///
+/// \retval IPC_RC_TARGET_BLOCKED The command could not be sent because the
+/// target is blocking any new messages.
+///
+int ipc_send_cmd(ipc_msg_t* cmd);
+
+
+////////////////////////////////////////////////////////////////////////////////
+/// Send a command message back to the sender as a response message with status.
+///
+/// \param rsp A pointer to a message that was recieved as a command message.
+///
+/// \param ipc_rc This should be either \a IPC_RC_SUCCESS if the command was
+/// successful or \a IPC_RC_CMD_FAILED if the command failed. If
+/// command-specific return codes are needed, they should be returned as
+/// command-specific fields instead of returning them here so that there
+/// is no risk of overlapping return codes.
+///
+/// It is expected that at some point prior to calling this function the
+/// message was initialized with a call to \a ipc_init_msg or
+/// \a ipc_init_msgq_msg.
+///
+/// Once a message has been sent it is not safe to send again until it has been
+/// sent back to the sender as a response.
+///
+/// The following return codes are possible:
+///
+/// \retval IPC_RC_SUCCESS The message was successfully placed on the target's
+/// receive buffer.
+///
+/// \retval IPC_RC_MSG_NOT_ACTIVE The message is not from an active command.
+///
+/// \retval IPC_RC_INVALID_TARGET_ID The target id for the sender is invalid.
+/// This likely means that the message has been corrupted.
+///
+/// \retval IPC_RC_BUFFER_FULL The response could not be sent because the target's
+/// recieve buffer is full.
+///
+/// \retval IPC_RC_TARGET_BLOCKED The response could not be sent because the
+/// target is blocking any new messages.
+///
+int ipc_send_rsp(ipc_msg_t* rsp, uint32_t return_code);
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// Retrieves the IPC return code embedded in the response message.
+///
+/// \param rsp A pointer to a response message.
+///
+/// The embedded IPC return code is how the remote processor communicates
+/// IPC internal failures to the local processor. It can also be used by
+/// non-IPC code on the remote processor to signal success or failure when it
+/// sends the response message via the \a ipc_send_rsp interface.
+///
+/// The IPC return code should always be checked to verify that a command
+/// message was processed successfully.
+///
+/// The following return codes are possible:
+///
+/// \retval IPC_RC_SUCCESS The message was successfully processed.
+///
+/// \retval IPC_RC_CMD_FAILED The command was processed on the remote end but
+/// did not complete successfully.
+///
+/// \retval IPC_RC_CMD_NOT_SUPPORTED The function ID for the command is valid
+/// but the remote end does not have support for that function ID.
+///
+/// \retval IPC_RC_INVALID_FUNC_ID The function ID for the command is invalid.
+///
+static inline int ipc_get_rc(ipc_msg_t* rsp)
+{
+ return rsp->ipc_rc;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// Retrieve the IPC function ID for a message
+///
+/// \param msg A pointer to an IPC message
+///
+/// This interface should be used to extract the IPC function ID of a message.
+///
+/// The IPC function ID is returned.
+///
+static inline int ipc_get_funcid(ipc_msg_t* msg)
+{
+ int func_id = msg->func_id.word32;
+
+ //Multi-target function ID's always have the target ID set to
+ //so that if the caller doesn't set it to a proper target id it will
+ //flag an error.
+ if(func_id & IPC_FLAG_MT)
+ {
+ func_id |= IPC_TARGET_MASK;
+ }
+
+ //Clear the active and response flags in case they are set along
+ //with the sender ID.
+ func_id &= ~(IPC_FLAG_ACTIVE | IPC_FLAG_RESPONSE | IPC_SENDER_MASK);
+
+ return func_id;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// Determine if a message is a response or a command
+///
+/// \param msg A pointer to an IPC message
+///
+/// This function should be used to determine if a message is a response or a
+/// command. The function will return a non-zero value if the message is a
+/// response and 0 otherwise.
+///
+static inline int ipc_is_a_response(ipc_msg_t* msg)
+{
+ return msg->func_id.response_flag;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// Determine if a message is free to be re-used
+///
+/// \param msg A pointer to an IPC message
+///
+/// This function should be used to determine if a message is free to re-use.
+/// The function will return a non-zero value if the message is free and
+/// 0 otherwise.
+///
+static inline int ipc_is_free(ipc_msg_t* msg)
+{
+ return !msg->func_id.active_flag;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// Retrieve the sender ID of a message.
+///
+/// \param msg A pointer to an IPC message
+///
+/// This function should be used to retrieve the sender ID of a message. It
+/// returns the sender ID.
+///
+static inline int ipc_sender_id(ipc_msg_t* msg)
+{
+ return msg->func_id.sender_id;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// Retrieve the target ID of a message.
+///
+/// \param msg A pointer to an IPC message
+///
+/// This function should be used to retrieve the target ID of a message. It
+/// returns the target ID.
+///
+static inline int ipc_target_id(ipc_msg_t* msg)
+{
+ return msg->func_id.target_id;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// Initializes IPC control structures.
+///
+/// Clears the IPC buffers for this processor and places them in a state
+/// where new messages are blocked. Also initializes the IPC handler table
+/// for this processor if STATIC_IPC_TABLES has not been defined.
+///
+/// This function always returns \a IPC_RC_SUCCESS
+///
+int ipc_init(void);
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// Enables IPC communications.
+///
+/// Unmasks the IPC interrupt for this processor and places the circular
+/// buffers in a state where they can recieve messages.
+///
+/// This function must be called before using the \a ipc_send_cmd function or
+/// it will return \a IPC_RC_SELF_BLOCKED.
+///
+/// The function always returns \a IPC_RC_SUCCESS.
+///
+int ipc_enable(void);
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// Disable recieving new IPC commands for a processor.
+///
+/// \param target_id The target ID of the processor to disable receiving new
+/// IPC commands on.
+///
+/// This interface should be used by a processor that knows it is about to go
+/// down or by a processor that knows that one of its peers has halted.
+///
+/// Calling this function on a processor will cause other processors to get
+/// a return code of \a IPC_RC_TARGET_BLOCKED with subsequent calls to
+/// \a ipc_send_cmd. Calling this function on one's self (using a target ID of
+/// OCCHW_INST_ID_SELF) will cause subsequent calls to \a ipc_send_cmd to
+/// return \a IPC_RC_SELF_BLOCKED.
+///
+/// Possible return codes for this function are:
+///
+/// \retval IPC_RC_SUCCESS The target processor was successfully disabled.
+///
+/// \retval IPC_RC_INVALID_TARGET_ID The target ID is invalid.
+///
+int ipc_disable(uint32_t target_id);
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// Associates an IPC function ID with a handler function
+///
+/// \param func_id A user-defined function ID that is known to both the sender
+/// and receiver of a command message. (Defined in \a ipc_func_ids.h)
+///
+/// \param handler A pointer to the function that handles command messages that
+/// have been initialized with \a func_id.
+///
+/// \param callback_arg A pointer to data that is passed as an argument to the
+/// handler function when it is called.
+///
+/// This function should be used to link an IPC function ID with a function.
+/// Once this has been done, if the local processor recieves a command message
+/// with an IPC function ID that matches \a func_id then it will call the
+/// handler function that was specified by \a handler.
+///
+/// NOTE: All handler functions will be called from an interrupt context.
+///
+/// Possible return codes are:
+///
+/// \retval IPC_RC_SUCCESS The operation completed successfully.
+///
+/// \retval IPC_RC_INVALID_TARGET_ID The function ID is a single-target
+/// function ID that does not target this processor.
+///
+/// \retval IPC_RC_INVALID_FUNC_ID The function ID is not a valid IPC function
+/// ID.
+///
+/// \retval IPC_RC_INVALID_ARG The handler parameter must be a non-zero value.
+///
+int ipc_set_handler(uint32_t func_id,
+ ipc_msg_handler_t handler,
+ void* callback_arg);
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// Initialize an IPC message queue.
+///
+/// \param msgq A pointer to a message queue.
+///
+/// All message queues must be initialized one time prior to use with other
+/// interfaces.
+///
+void ipc_init_msgq(ipc_msgq_t* msgq);
+
+//Use this to statically initialize an IPC message queue
+#define IPC_MSGQ_CREATE(msgq) \
+ipc_msgq_t msgq = \
+{\
+ .msg_head = KERN_DEQUE_SENTINEL_INIT(&msgq.msg_head),\
+ .msg_sem = KERN_SEMAPHORE_INITIALIZATION(0, 0)\
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// Initialize an IPC message and associate it with an IPC message queue
+///
+/// \param msg A pointer to an IPC message.
+///
+/// \param func_id A user-defined function ID that is known to both the sender
+/// and receiver of the command message. (Defined in \a ipc_func_ids.h)
+///
+/// \param msgq A pointer to an initialized IPC message queue.
+///
+/// This interface should be used in place of \a ipc_init_msg when the caller
+/// wishes to have the command response placed on the specified IPC message
+/// queue. This allows a thread to block (via the \a ipc_msq_recv interface)
+/// on the message queue until a response to a command has arrived.
+///
+/// \note An IPC message queue can be associated with more than one IPC
+/// message.
+///
+/// See \a ipc_init_msg for more information.
+///
+void ipc_init_msgq_msg(ipc_msg_t* msg, uint32_t func_id, ipc_msgq_t* msgq);
+
+//Use this to statically create an initialized IPC message queue message
+#define IPC_MSGQ_MSG_CREATE(msg_name, func_id, msgq) \
+ IPC_MSG_CREATE(msg_name, func_id, ipc_msgq_handler, msgq)
+
+///////////////////////////////////////////////////////////////////////////////
+/// Wait (with timeout) for an IPC message on an IPC message queue.
+///
+/// \param msg A pointer to an IPC message pointer.
+///
+/// \param msgq A pointer to an initialized IPC message queue.
+///
+/// \param timeout The time to wait for the next IPC message to arrive.
+///
+/// This interface can be used in a thread context to block while waiting for
+/// the next message (command or response) to arrive on an IPC message queue.
+///
+/// For an IPC command message to be placed on an IPC message queue, the
+/// function ID for the command must first be associated with the message queue
+/// by making a call to \a ipc_register_msgq.
+///
+/// For an IPC response message to be placed on an IPC message queue, the
+/// message must be initialized via the \a ipc_init_msgq_msg interface.
+///
+/// If \a ipc_msgq_recv returns a value of \a IPC_RC_SUCCESS then \a msg is
+/// guaranteed to point to a new message. Otherwise, an IPC message was not
+/// retrieved from the message queue and \a msg will be set to 0.
+///
+/// Possible return codes for this function are:
+///
+/// \retval IPC_RC_SUCCESS A new IPC message was received and \a msg has been
+/// set to point to the new message.
+///
+/// \retval IPC_RC_TIMEOUT No new messages were recieved within the timeout
+/// period and \msg was set to 0.
+///
+/// \retval IPC_RC_NO_MSG This should never happen, but if it does it indicates
+/// an internal failure occurred.
+///
+int ipc_msgq_recv(ipc_msg_t** msg, ipc_msgq_t* msgq, KERN_INTERVAL timeout);
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// Associate an IPC message queue with an IPC function ID
+///
+/// \param func_id A user-defined function ID that is known to both the sender
+/// and receiver of a command message. (Defined in \a ipc_func_ids.h)
+///
+/// \param msgq A pointer to an initialized IPC message queue.
+///
+/// This interface associates an IPC function ID with an IPC message queue so
+/// that when the calling processor recieves a command with the specified
+/// function ID the message will be place on the message queue and a thread
+/// that is blocked waiting for a message on the queue (using the
+/// \a ipc_msgq_recv interface) will be woken up and given the message.
+///
+/// This function should be called in place of the \a ipc_set_handler
+/// interface.
+///
+/// NOTE: Multiple function ID's can be associated with a single queue.
+///
+/// Possible return codes are:
+///
+/// \retval IPC_RC_SUCCESS The operation completed successfully.
+///
+/// \retval IPC_RC_INVALID_TARGET_ID The function ID is a single-target
+/// function ID that does not target this processor.
+///
+/// \retval IPC_RC_INVALID_FUNC_ID The function ID is not a valid IPC function
+/// ID.
+///
+int ipc_register_msgq(uint32_t func_id, ipc_msgq_t* msgq);
+
+///////////////////////////////////////////////////////////////////////////////
+/// Internal function that places an IPC message on an IPC message queue
+///
+void ipc_msgq_handler(ipc_msg_t* msg, void* arg);
+
+///////////////////////////////////////////////////////////////////////////////
+/// The default IPC command handler simply sends a response with the IPC return
+/// code set to IPC_RC_CMD_NOT_SUPPORTED
+///
+void ipc_default_handler(ipc_msg_t* msg, void* arg);
+
+#endif /*__ASSEMBLER__*/
+#endif /* __IPC_API_H__ */
diff --git a/src/lib/occlib/ipc_async_cmd.h b/src/lib/occlib/ipc_async_cmd.h
new file mode 100644
index 0000000..db09e9e
--- /dev/null
+++ b/src/lib/occlib/ipc_async_cmd.h
@@ -0,0 +1,49 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/occlib/ipc_async_cmd.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __IPC_ASYNC_CMD_H__
+#define __IPC_ASYNC_CMD_H__
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2015
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file ipc_async_cmd.h
+/// \brief This header is shared between the 405 and GPE's that need to
+/// support IPC command messages that are sent from the occhw_async_gpe.c
+/// code.
+///
+
+#include "ipc_api.h"
+
+#ifndef __ASSEMBLER__
+
+typedef struct {
+ ipc_msg_t cmd;
+ void* cmd_data;
+}ipc_async_cmd_t;
+
+#endif /*__ASSEMBLER__*/
+#endif /*__IPC_ASYNC_CMD_H__*/
diff --git a/src/lib/occlib/ipc_core.c b/src/lib/occlib/ipc_core.c
new file mode 100644
index 0000000..342f024
--- /dev/null
+++ b/src/lib/occlib/ipc_core.c
@@ -0,0 +1,484 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/occlib/ipc_core.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2015
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file ipc_core.c
+/// \brief Implementation of core IPC (InterProcessor Communication) routines
+
+#include "kernel.h"
+#include "ipc_api.h"
+#include "occhw_shared_data.h"
+
+/// If G_ipc_enabled is zero then calls to ipc_send_cmd() will return
+/// IPC_RC_SELF_BLOCKED.
+uint8_t G_ipc_enabled = 0;
+
+#ifndef STATIC_IPC_TABLES
+ipc_func_table_entry_t G_ipc_mt_handlers[IPC_MT_MAX_FUNCTIONS];
+ipc_func_table_entry_t G_ipc_st_handlers[IPC_ST_MAX_FUNCTIONS];
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+/// Helper function used by ipc_send_cmd and ipc_send_rsp to send a message
+///
+int ipc_send_msg(ipc_msg_t* msg, uint32_t target_id)
+{
+ ipc_target_t* target_cbufs;
+ uint8_t* read_count;
+ uint8_t* write_count;
+ ipc_msg_t** msgs;
+ KERN_MACHINE_CONTEXT ctx;
+ int rc = IPC_RC_SUCCESS;
+ uint8_t num_entries;
+
+ do
+ {
+ // Check for invalid target ID
+ if(target_id > OCCHW_INST_ID_MAX)
+ {
+ rc = IPC_RC_INVALID_TARGET_ID;
+ break;
+ }
+
+ target_cbufs = &OSD_PTR->ipc_data.targets[target_id];
+ msgs = &target_cbufs->cbufs[OCCHW_INST_ID_SELF][0];
+ read_count = &target_cbufs->counts.reads.counts8[OCCHW_INST_ID_SELF];
+ write_count = &target_cbufs->counts.writes.counts8[OCCHW_INST_ID_SELF];
+
+ //Prevent other threads on this processor from updating the cbuf
+ KERN_CRITICAL_SECTION_ENTER(KERN_CRITICAL, &ctx);
+
+ //Determine the number of entries in the buffer
+ num_entries = *write_count - *read_count;
+
+ //If the cbuf isn't full, then add the message and raise an interrupt
+ if(num_entries < IPC_CBUF_SIZE)
+ {
+ // Mark the message as being active
+ msg->func_id.active_flag = 1;
+
+ msgs[*write_count % IPC_CBUF_SIZE] = msg;
+ (*write_count)++;
+
+ //raise the IPC interrupt on the target
+ KERN_IRQ_STATUS_SET(IPC_GET_IRQ(target_id), 1);
+ }
+ else
+ {
+ //Check if cbuf is just full or is blocked
+ if(num_entries == IPC_CBUF_SIZE)
+ {
+ rc = IPC_RC_BUFFER_FULL;
+ }
+ else
+ {
+ rc = IPC_RC_TARGET_BLOCKED;
+ }
+ }
+ KERN_CRITICAL_SECTION_EXIT(&ctx);
+ }while(0);
+ return rc;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// Send a message as a command
+///
+int ipc_send_cmd(ipc_msg_t* cmd)
+{
+ int rc;
+ do
+ {
+ //don't allow sending new commands if IPC is disabled
+ if(!G_ipc_enabled)
+ {
+ rc = IPC_RC_SELF_BLOCKED;
+ break;
+ }
+
+ //don't send a command if the valid flag is not set
+ if(!cmd->func_id.valid_flag)
+ {
+ rc = IPC_RC_INVALID_FUNC_ID;
+ break;
+ }
+
+ //don't send a command if the active flag is set
+ if(cmd->func_id.active_flag)
+ {
+ rc = IPC_RC_MSG_ACTIVE;
+ break;
+ }
+
+ cmd->func_id.response_flag = 0;
+
+ //Set the sender ID here. Remote side uses this for sending responses.
+ cmd->func_id.sender_id = OCCHW_INST_ID_SELF;
+
+ cmd->ipc_rc = 0;
+
+ //place the message on the target's circular buffer
+ rc = ipc_send_msg(cmd, cmd->func_id.target_id);
+
+ cmd->ipc_rc = rc;
+ }while(0);
+ return rc;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// Send a command message back to the sender as a response message with status.
+///
+int ipc_send_rsp(ipc_msg_t* rsp, uint32_t ipc_rc)
+{
+ int rc;
+ if(rsp->func_id.active_flag)
+ {
+ rsp->func_id.response_flag = 1;
+ rsp->ipc_rc = ipc_rc;
+ rc = ipc_send_msg(rsp, rsp->func_id.sender_id);
+ }
+ else
+ {
+ rc = IPC_RC_MSG_NOT_ACTIVE;
+ }
+ return rc;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// Default IPC handler that is called when no IPC handler has been
+/// installed for the IPC function that is being requested.
+void ipc_default_handler(ipc_msg_t* msg, void* arg)
+{
+ //Return code is ignored. If failure occurs in sending
+ //the response then the sender of the command should eventually
+ //time out waiting for a response or the sender may be incapacitated.
+ ipc_send_rsp(msg, IPC_RC_CMD_NOT_SUPPORTED);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// Set the target ID for a multi-target command message.
+///
+int ipc_set_cmd_target(ipc_msg_t* cmd, uint32_t target_id)
+{
+ int rc = IPC_RC_SUCCESS;
+ do
+ {
+ //verify that this is a muti-target function
+ if(!cmd->func_id.multi_target_flag)
+ {
+ rc = IPC_RC_INVALID_FUNC_ID;
+ break;
+ }
+ else
+ {
+ cmd->func_id.target_id = target_id;
+ }
+ }while(0);
+
+ return rc;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// Processes an incoming message (response or command) after it has been
+/// removed from the circular buffer.
+/// This function is for internal use only!
+///
+void ipc_process_msg(ipc_msg_t* msg)
+{
+ uint32_t table_index;
+ uint32_t table_limit;
+ ipc_func_table_entry_t *func_table;
+
+ do
+ {
+ // If this is a response message, call the response callback function
+ if(msg->func_id.response_flag)
+ {
+ if(msg->resp_callback)
+ {
+ msg->resp_callback(msg, msg->callback_arg);
+ }
+ else
+ {
+ //normally, the resp_callback function would call this function
+ //to notify users of the message that it is free to be re-used.
+ //Since there is no callback for this message we call it here.
+ ipc_free_msg(msg);
+ }
+
+ break;
+ }
+
+ // extract the function table index
+ table_index = msg->func_id.table_index;
+
+ //setup for multi-target commands
+ if(msg->func_id.multi_target_flag)
+ {
+ table_limit = IPC_MT_NUM_FUNCIDS;
+ func_table = G_ipc_mt_handlers;
+ }
+ //setup for single-target commands
+ else
+ {
+ table_limit = IPC_ST_NUM_FUNCIDS;
+ func_table = G_ipc_st_handlers;
+ }
+
+ //Common command handling code
+ if(table_index < table_limit)
+ {
+ func_table[table_index].handler(msg, func_table[table_index].arg);
+ }
+ else
+ {
+ //drop errors if this fails. If target was waiting for a response
+ //it should eventually time out and log the message as FFDC.
+ ipc_send_rsp(msg, IPC_RC_INVALID_FUNC_ID);
+ }
+ }while(0);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// Removes messages from the circular buffer for the processor associated with
+/// sender_id and processes them one at a time.
+/// This function is for internal use only!
+///
+void ipc_process_cbuf(uint32_t sender_id)
+{
+ ipc_target_t *my_cbufs = &OSD_PTR->ipc_data.targets[OCCHW_INST_ID_SELF];
+ uint8_t *read_count = &my_cbufs->counts.reads.counts8[sender_id];
+ uint8_t *write_count = &my_cbufs->counts.writes.counts8[sender_id];
+ ipc_msg_t **msg_ptrs = &my_cbufs->cbufs[sender_id][0];
+ ipc_msg_t *cur_msg;
+
+
+ while(*read_count != *write_count)
+ {
+ // extract the message pointer
+ cur_msg = msg_ptrs[*read_count % IPC_CBUF_SIZE];
+
+ // increment the read count
+ (*read_count)++;
+
+ ipc_process_msg(cur_msg);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// The IPC interrupt handler. Finds which circular buffers have messages
+/// and processes them.
+///
+#ifdef __SSX__
+KERN_IRQ_HANDLER(ipc_irq_handler_full)
+#else
+KERN_IRQ_HANDLER(ipc_irq_handler)
+#endif
+{
+ ipc_counts_t xored_counts;
+ ipc_target_t *my_cbufs;
+ uint32_t sender_id;
+
+ // Processors could be sending us new packets while we're
+ // processing this interrupt. We need to mask all new
+ // IPI interrupts until we are done processing so that we don't
+ // end up processing an interrupt that was already handled.
+ KERN_IRQ_DISABLE(IPC_GET_IRQ(OCCHW_INST_ID_SELF));
+
+ // Clear the interrupt bit in the OISR before we check for
+ // status. Checking status and then clearing the OISR bit
+ // can lead to a race condition where we loose an interrupt.
+ KERN_IRQ_STATUS_CLEAR(IPC_GET_IRQ(OCCHW_INST_ID_SELF));
+
+ my_cbufs = &OSD_PTR->ipc_data.targets[OCCHW_INST_ID_SELF];
+
+ // Make sure we get the most recent write counts from SRAM
+ // dcbf(&my_cbufs->counts.writes.counts64);
+
+ // Use XOR to find the buffers that aren't empty (read count != write count)
+ xored_counts.counts64 = my_cbufs->counts.reads.counts64 ^
+ my_cbufs->counts.writes.counts64;
+
+ while(1)
+ {
+ // Use cntlzw to find the first buffer that isn't empty
+ sender_id = cntlz64(xored_counts.counts64) / IPC_CBUF_COUNT_BITS;
+
+
+ // If all buffers are empty then we're done
+ if(sender_id > OCCHW_INST_ID_MAX)
+ {
+ break;
+ }
+
+ // Mark the buffer as empty in our local snapshot
+ xored_counts.counts8[sender_id] = 0;
+
+ // Process all new messages in the buffer
+ ipc_process_cbuf(sender_id);
+ }
+
+ // Unmask the irq before returning
+ KERN_IRQ_ENABLE(IPC_GET_IRQ(OCCHW_INST_ID_SELF));
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// This macro creates an assembly function named ipc_irq_handler which handles
+/// saving/restoring the context that is required for calling a C
+/// function.
+///
+/// NOTE: This is only needed for SSX. PK only supports full interrupts.
+///
+#ifdef __SSX__
+KERN_IRQ_FAST2FULL(ipc_irq_handler, ipc_irq_handler_full);
+#endif
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// Initialize IPC control structures.
+///
+int ipc_init(void)
+{
+ //prevent new messages from coming in.
+ ipc_disable(OCCHW_INST_ID_SELF);
+
+#ifndef STATIC_IPC_TABLES
+ int i;
+ for(i = 0; i < IPC_MT_MAX_FUNCTIONS; i++)
+ {
+ G_ipc_mt_handlers[i].handler = ipc_default_handler;
+ G_ipc_mt_handlers[i].arg = 0;
+ }
+ for(i = 0; i < IPC_ST_MAX_FUNCTIONS; i++)
+ {
+ G_ipc_st_handlers[i].handler = ipc_default_handler;
+ G_ipc_st_handlers[i].arg = 0;
+ }
+#endif
+ return IPC_RC_SUCCESS;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// Enables IPC communications.
+///
+int ipc_enable(void)
+{
+ int rc;
+ ipc_target_t* my_cbufs;
+
+ do
+ {
+ // Install the IPI interrupt handler for this processor
+ rc = KERN_IRQ_HANDLER_SET(IPC_GET_IRQ(OCCHW_INST_ID_SELF),
+ ipc_irq_handler,
+ 0,
+ KERN_CRITICAL);
+
+ if(rc)
+ {
+ break;
+ }
+
+ my_cbufs = &OSD_PTR->ipc_data.targets[OCCHW_INST_ID_SELF];
+
+ //Any messages that were placed on the cbufs before this point
+ //are dropped. Clear any interrupts that might have been raised
+ //before this point.
+ KERN_IRQ_STATUS_CLEAR(IPC_GET_IRQ(OCCHW_INST_ID_SELF));
+
+ // Clear and open up all receive buffers for this processor
+ // by setting the read counts equal to the write counts
+ my_cbufs->counts.reads.counts64 = my_cbufs->counts.writes.counts64;
+
+ // Unmask the IPI interrupt for this processor
+ KERN_IRQ_ENABLE(IPC_GET_IRQ(OCCHW_INST_ID_SELF));
+
+ //Allow us to send out new commands
+ G_ipc_enabled = 1;
+
+ }while(0);
+
+ return rc;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// Disable recieving new IPC commands for a processor.
+///
+int ipc_disable(uint32_t target_id)
+{
+ int i;
+ int rc = IPC_RC_SUCCESS;
+ ipc_target_t* target_cbufs;
+ KERN_MACHINE_CONTEXT ctx;
+
+ do
+ {
+ // Check for invalid target ID
+ if(target_id > OCCHW_INST_ID_MAX)
+ {
+ rc = IPC_RC_INVALID_TARGET_ID;
+ break;
+ }
+
+ // Prevent us from sending out new commands
+ if(target_id == OCCHW_INST_ID_SELF)
+ {
+ G_ipc_enabled = 0;
+ }
+
+ //disable interrupts to prevent the IPC interrupt handler or other threads
+ //on this instance from interrupting us and changing the read count or
+ //interrupt mask bits under our feet.
+ KERN_CRITICAL_SECTION_ENTER(KERN_CRITICAL, &ctx);
+
+ //mask off the IPC interrupt for the target (this is mostly for the case
+ //where we are diabling IPC for ourselves).
+ KERN_IRQ_DISABLE(IPC_GET_IRQ(target_id));
+
+ target_cbufs = &OSD_PTR->ipc_data.targets[target_id];
+
+ // Make each cbuf appear to be more than full. This signals to
+ // senders that the buffer is not just full, but blocked. When
+ // the sender sees this it knows not to place more messages on the cbuf.
+ // NOTE: we are updating the read register, which is allowed if the cbuf
+ // is owned by the instance this code is running on OR if the instance
+ // is known to be halted.
+ for(i = 0; i <= OCCHW_INST_ID_MAX; i++)
+ {
+ target_cbufs->counts.reads.counts8[i] =
+ target_cbufs->counts.writes.counts8[i] - (IPC_CBUF_SIZE * 2);
+ }
+
+ KERN_CRITICAL_SECTION_EXIT(&ctx);
+
+ }while(0);
+ return rc;
+}
+
diff --git a/src/lib/occlib/ipc_init.c b/src/lib/occlib/ipc_init.c
new file mode 100644
index 0000000..4d732b7
--- /dev/null
+++ b/src/lib/occlib/ipc_init.c
@@ -0,0 +1,153 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/occlib/ipc_init.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2015
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file ipc_init.c
+/// \brief Implementation of IPC (InterProcessor Communication) routines for
+/// Setting up the IPC function tables, messages and message queues.
+///
+/// NOTE: The functions that these interfaces peform can all be done statically.
+/// This code will not be included in an image if none of the functions are
+/// referenced.
+
+#include "ipc_api.h"
+#include "ipc_ping.h"
+
+///////////////////////////////////////////////////////////////////////////////
+/// Associate an IPC function ID with a handler function
+///
+int ipc_set_handler(uint32_t function_id,
+ ipc_msg_handler_t handler,
+ void* callback_arg)
+{
+ ipc_func_table_entry_t *func_table;
+ uint32_t table_limit;
+ int rc = IPC_RC_SUCCESS;
+ ipc_func_id_t func_id = {{0}};
+
+ do
+ {
+ func_id.word32 = function_id;
+
+ //setup for multi-target commands
+ if(func_id.multi_target_flag)
+ {
+ table_limit = IPC_MT_NUM_FUNCIDS;
+ func_table = G_ipc_mt_handlers;
+ }
+ //setup for single-target commands
+ else
+ {
+ //make sure the function id targets this processor
+ if(func_id.target_id != OCCHW_INST_ID_SELF)
+ {
+ rc = IPC_RC_INVALID_TARGET_ID;
+ break;
+ }
+ table_limit = IPC_ST_NUM_FUNCIDS;
+ func_table = G_ipc_st_handlers;
+ }
+
+ //make sure the function id is valid
+ if((func_id.table_index >= table_limit) || !func_id.valid_flag)
+ {
+ rc = IPC_RC_INVALID_FUNC_ID;
+ break;
+ }
+
+ if(!handler)
+ {
+ rc = IPC_RC_INVALID_ARG;
+ break;
+ }
+
+ func_table[func_id.table_index].handler = handler;
+ func_table[func_id.table_index].arg = callback_arg;
+ }while(0);
+ return rc;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// Initialize an IPC command message
+///
+void ipc_init_msg(ipc_msg_t* msg,
+ uint32_t func_id,
+ ipc_msg_handler_t resp_callback,
+ void* callback_arg)
+{
+ KERN_DEQUE_ELEMENT_CREATE(&msg->node);
+ msg->func_id.word32 = func_id;
+ msg->ipc_rc = IPC_RC_SUCCESS;
+ msg->resp_callback = resp_callback;
+ msg->callback_arg = callback_arg;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// Initialize an IPC message queue.
+///
+void ipc_init_msgq(ipc_msgq_t* msgq)
+{
+ KERN_DEQUE_SENTINEL_CREATE(&msgq->msg_head);
+
+ //set the initial count to 0 with no max count
+ KERN_SEMAPHORE_CREATE(&msgq->msg_sem, 0, 0);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// Initialize an IPC message and associate it with an IPC message queue
+///
+void ipc_init_msgq_msg(ipc_msg_t* msg, uint32_t func_id, ipc_msgq_t* msgq)
+{
+ ipc_init_msg(msg, func_id, ipc_msgq_handler, msgq);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// Initialize an IPC ping command message
+///
+#ifdef IPC_ENABLE_PING
+int ipc_ping_cmd_init(ipc_ping_cmd_t* ping_cmd)
+{
+ int rc;
+
+ do
+ {
+ //initialize the message
+ ipc_init_msg(&ping_cmd->msg, IPC_MT_PING, ipc_ping_response, 0);
+
+ //initialize the semaphore count to 0 and set the max count to 1
+ rc = KERN_SEMAPHORE_CREATE(&ping_cmd->sem, 0, 1);
+ if(rc)
+ {
+ break;
+ }
+ }while(0);
+ return rc;
+}
+#endif /*IPC_ENABLE_PING*/
diff --git a/src/lib/occlib/ipc_macros.h b/src/lib/occlib/ipc_macros.h
new file mode 100644
index 0000000..c95bff6
--- /dev/null
+++ b/src/lib/occlib/ipc_macros.h
@@ -0,0 +1,197 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/occlib/ipc_macros.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __IPC_MACROS_H__
+#define __IPC_MACROS_H__
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2015
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file ipc_macros.h
+/// \brief Contains macros related to the Interprocessor Communications (IPC)
+/// API.
+///
+
+///////////////////////////////////////////////////////////////////////////////
+/// Retrieves the IRQ number for the specified OCC processor instance
+///
+#define IPC_GET_IRQ(instance_id) (OCCHW_IRQ_IPI0_HI_PRIORITY + instance_id)
+
+///////////////////////////////////////////////////////////////////////////////
+/// Marks the start of the IPC function ID table
+///
+#define IPC_FUNCIDS_TABLE_START \
+ typedef enum \
+{
+
+///////////////////////////////////////////////////////////////////////////////
+/// Marks the end of the IPC function ID table
+///
+#define IPC_FUNCIDS_TABLE_END \
+} ipc_func_enum_t;
+
+///////////////////////////////////////////////////////////////////////////////
+/// Marks the start of the IPC multi-target function IDs within the IPC
+/// function ID table.
+///
+#define IPC_FUNCIDS_MT_START \
+ IPC_MT_START = (int)((IPC_TARGET_MASK | IPC_FLAG_MT | IPC_FLAG_VALID | (((uint32_t)((uint8_t)OCCHW_INST_ID_SELF)) << 16)) - 1),
+
+///////////////////////////////////////////////////////////////////////////////
+/// Marks the end of the IPC multi-target function IDs within the IPC function
+/// ID table.
+///
+#define IPC_FUNCIDS_MT_END \
+ IPC_MT_END,
+
+#define IPC_CONCAT_INST(name, inst) name ## inst
+
+///////////////////////////////////////////////////////////////////////////////
+/// Marks the start of the IPC single-target function IDs within the IPC
+/// ID table.
+///
+/// \param target_id The instance ID of the processor that the following
+/// function IDs will target.
+///
+/// Each processor has it's own set of single-target function IDs. Messages
+/// that are initialized with these function ID's can only be sent to the
+/// processor specified by \a target_id.
+///
+#define IPC_FUNCIDS_ST_START(target_id) \
+ IPC_CONCAT_INST(IPC_ST_START_, target_id) = \
+ (int)(((((uint32_t)target_id) << 24) | IPC_FLAG_VALID ) - 1),
+
+///////////////////////////////////////////////////////////////////////////////
+/// Marks the end of the IPC single-target function IDs for the specified
+/// target ID, \a target_id.
+///
+#define IPC_FUNCIDS_ST_END(target_id) \
+ IPC_CONCAT_INST(IPC_ST_END_, target_id),
+
+///////////////////////////////////////////////////////////////////////////////
+/// Create an IPC function ID.
+///
+/// \param The name of the IPC function ID
+///
+/// This macro should only be used inside the IPC function ID table. Under
+/// the covers, an enum with a name of \a name is created.
+///
+#define IPC_FUNC_ID(name) \
+ name,
+
+///////////////////////////////////////////////////////////////////////////////
+#define IPC_MT_NUM_FUNCIDS \
+ ((IPC_MT_END - IPC_MT_START) - 1)
+
+///////////////////////////////////////////////////////////////////////////////
+#define IPC_ST_TARGET_NUM_FUNCIDS(target_id) \
+ ((IPC_CONCAT_INST(IPC_ST_END_, target_id) - IPC_CONCAT_INST(IPC_ST_START_, target_id)) - 1)
+
+///////////////////////////////////////////////////////////////////////////////
+#define IPC_ST_NUM_FUNCIDS IPC_ST_TARGET_NUM_FUNCIDS(OCCHW_INST_ID_SELF)
+
+///////////////////////////////////////////////////////////////////////////////
+/// Macros for statically initializing the IPC function tables
+#ifdef STATIC_IPC_TABLES
+
+#define IPC_MT_FUNC_TABLE_START \
+ ipc_func_table_entry_t G_ipc_mt_handlers[IPC_MT_MAX_FUNCTIONS] = \
+{
+
+#define IPC_ST_FUNC_TABLE_START \
+ ipc_func_table_entry_t G_ipc_st_handlers[IPC_ST_MAX_FUNCTIONS] = \
+{
+
+#define IPC_HANDLER(func, arg) \
+ {func, arg},
+
+#define IPC_HANDLER_DEFAULT \
+ {ipc_default_handler, 0},
+
+#define IPC_MSGQ_HANDLER(msgq_ptr) \
+ {ipc_msgq_handler, msgq_ptr},
+
+#define IPC_MT_FUNC_TABLE_END \
+};
+
+#define IPC_ST_FUNC_TABLE_END \
+};
+
+#else
+
+#define IPC_MT_FUNC_TABLE_START
+
+#define IPC_ST_FUNC_TABLE_START
+
+#define IPC_HANDLER(func, arg)
+
+#define IPC_HANDLER_DEFAULT
+
+#define IPC_MSGQ_HANDLER(msgq_ptr)
+
+#define IPC_MT_FUNC_TABLE_END
+
+#define IPC_ST_FUNC_TABLE_END
+
+#endif /*STATIC_IPC_TABLES*/
+
+///////////////////////////////////////////////////////////////////////////////
+/// Convenience macro for defering handling of a command or
+/// response in a noncritical interrupt context. This was
+/// specifically added for ipc functions that need to call
+/// ssx functions on the 405. (ssx functions can not be called
+/// inside a critical interrupt context).
+#ifdef __SSX__
+#define IPC_DEFER_TO_NONCRITICAL(ipc_msg) \
+{ \
+ ssx_deque_push_back(&G_ipc_deferred_queue, &ipc_msg->node); \
+ ssx_irq_status_set(OCCHW_IRQ_ASYNC_IPI, 1); \
+}
+
+#else
+#define IPC_DEFER_TO_NONCRITICAL(ipc_msg)
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+/// Determine if an IPC function ID is a multi-target ID
+///////////////////////////////////////////////////////////////////////////////
+#define IPC_FUNCID_IS_MT(funcid) (IPC_FLAG_MT & (funcid))
+
+///////////////////////////////////////////////////////////////////////////////
+/// Set the target ID of a multi-target function ID
+/// Sets the target to be invalid if it's not a multi-target function id
+///////////////////////////////////////////////////////////////////////////////
+#define IPC_SET_MT_TARGET(funcid, targetid) \
+(((funcid) & IPC_FLAG_MT)? \
+ (((targetid) << IPC_TARGET_SHIFT) | ((funcid) & ~(IPC_TARGET_MASK))): \
+ (IPC_TARGET_MASK | (funcid)))
+
+///////////////////////////////////////////////////////////////////////////////
+/// Retrieve the target ID from an IPC function id
+///////////////////////////////////////////////////////////////////////////////
+#define IPC_GET_TARGET_ID(funcid) (((uint32_t)(funcid)) >> IPC_TARGET_SHIFT)
+
+#endif /*__IPC_MACROS_H__*/
diff --git a/src/lib/occlib/ipc_msgq.c b/src/lib/occlib/ipc_msgq.c
new file mode 100644
index 0000000..8048b72
--- /dev/null
+++ b/src/lib/occlib/ipc_msgq.c
@@ -0,0 +1,108 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/occlib/ipc_msgq.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2015
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file ipc_msgq.c
+/// \brief Implementation of IPC (InterProcessor Communication) routines that
+/// involve using message queues (primarily in a thread context).
+
+#include "ipc_api.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// Handles msgq messages (commands and responses) by placing them on a message
+// queue and then posting the message queue semaphore.
+// This function is for internal use only!
+void ipc_msgq_handler(ipc_msg_t* msg, void* arg)
+{
+ ipc_msgq_t *msgq = (ipc_msgq_t*)arg;
+
+ //NOTE: this is hard coded to 0 on PPE
+ if(KERN_CONTEXT_CRITICAL_INTERRUPT())
+ {
+ //NOTE: this is a no-op on PPE
+ IPC_DEFER_TO_NONCRITICAL(msg);
+ }
+ else
+ {
+ KERN_DEQUE_PUSH_BACK(&msgq->msg_head, &msg->node);
+ KERN_SEMAPHORE_POST(&msgq->msg_sem);
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// Wait (with timeout) for an IPC message on an IPC message queue.
+///
+int ipc_msgq_recv(ipc_msg_t** msg, ipc_msgq_t* msgq, KERN_INTERVAL timeout)
+{
+ int rc;
+ ipc_msg_t *popped_msg = 0;
+ KERN_MACHINE_CONTEXT ctx;
+
+ rc = KERN_SEMAPHORE_PEND(&msgq->msg_sem, timeout);
+ if(rc)
+ {
+ if(rc == -KERN_SEMAPHORE_PEND_TIMED_OUT ||
+ rc == -KERN_SEMAPHORE_PEND_NO_WAIT)
+ {
+ rc = IPC_RC_TIMEOUT;
+ }
+ }
+ else
+ {
+ //The queue is also modified in the IPC interrupt context so
+ //we need to make sure interrupts are disabled while we modify it.
+ KERN_CRITICAL_SECTION_ENTER(KERN_CRITICAL, &ctx);
+ popped_msg = (ipc_msg_t*)KERN_DEQUE_POP_FRONT(&msgq->msg_head);
+ KERN_CRITICAL_SECTION_EXIT(&ctx);
+
+ if(popped_msg)
+ {
+ rc = IPC_RC_SUCCESS;
+ }
+ else
+ {
+ rc = IPC_RC_NO_MSG;
+ }
+ }
+ *msg = popped_msg;
+ return rc;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// Associate a message queue with a function ID (commands recieved with the
+/// specified function id will be placed on the message queue).
+///
+int ipc_register_msgq(uint32_t func_id, ipc_msgq_t* msgq)
+{
+ return ipc_set_handler(func_id, ipc_msgq_handler, msgq);
+}
+
+
+
diff --git a/src/lib/occlib/ipc_ping.c b/src/lib/occlib/ipc_ping.c
new file mode 100644
index 0000000..f295c99
--- /dev/null
+++ b/src/lib/occlib/ipc_ping.c
@@ -0,0 +1,96 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/occlib/ipc_ping.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#include "ipc_ping.h"
+
+#ifdef IPC_ENABLE_PING
+//server side ping message handler
+void ipc_ping_handler(ipc_msg_t* cmd, void* arg)
+{
+ //NOTE: this will run in a critical interrupt when sent to the 405
+ //ignore return codes
+ ipc_send_rsp(cmd, IPC_RC_SUCCESS);
+}
+
+//Note: This runs in a critical interrupt on the 405 but SSX functions
+// can not be called from a critical interrupt. Instead, it must be
+// deferred to a non-critical handler.
+void ipc_ping_response(ipc_msg_t* rsp, void* arg)
+{
+ ipc_ping_cmd_t *ping_cmd = (ipc_ping_cmd_t*)rsp;
+
+ if(KERN_CONTEXT_CRITICAL_INTERRUPT())
+ {
+ //NOTE: this is a no-op on PPE
+ IPC_DEFER_TO_NONCRITICAL(rsp);
+ }
+ else
+ {
+ KERN_SEMAPHORE_POST(&ping_cmd->sem);
+ ipc_free_msg(&ping_cmd->msg);
+ }
+
+}
+
+
+//Command that can be run in a thread context to ping another target
+//The message is allocated on the stack
+int ipc_ping(ipc_ping_cmd_t* ping_cmd, uint32_t target_id)
+{
+ int rc;
+
+ do
+ {
+ //set the target (since this is a multi-target command)
+ rc = ipc_set_cmd_target(&ping_cmd->msg, target_id);
+ if(rc)
+ {
+ break;
+ }
+
+ //send the command
+ rc = ipc_send_cmd(&ping_cmd->msg);
+ if(rc)
+ {
+ break;
+ }
+
+ //assume that if we timed out then the target must have gone down.
+ rc = KERN_SEMAPHORE_PEND(&ping_cmd->sem, KERN_SECONDS(1));
+ if(rc)
+ {
+ if(rc == -KERN_SEMAPHORE_PEND_TIMED_OUT)
+ {
+ rc = IPC_RC_TIMEOUT;
+ }
+ break;
+ }
+
+ //response message was received. Now return the ipc_rc
+ rc = ipc_get_rc(&ping_cmd->msg);
+
+ }while(0);
+ return rc;
+}
+#endif /*IPC_ENABLE_PING*/
diff --git a/src/lib/occlib/ipc_ping.h b/src/lib/occlib/ipc_ping.h
new file mode 100644
index 0000000..0b315ee
--- /dev/null
+++ b/src/lib/occlib/ipc_ping.h
@@ -0,0 +1,53 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/occlib/ipc_ping.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#include "ipc_api.h"
+
+typedef struct
+{
+ ipc_msg_t msg;
+ KERN_SEMAPHORE sem;
+}ipc_ping_cmd_t;
+
+#ifdef IPC_ENABLE_PING
+//server side ping message handler
+void ipc_ping_handler(ipc_msg_t* cmd, void* arg);
+
+//Initialize a ping command.
+int ipc_ping_cmd_init(ipc_ping_cmd_t* ping_cmd);
+
+//function for handling the ping response on the local processor
+void ipc_ping_response(ipc_msg_t* rsp, void* arg);
+
+//Statically initialize a ping command
+#define IPC_PING_CMD_CREATE(name) \
+ipc_ping_cmd_t name = \
+{\
+ .msg = IPC_MSG_INIT(IPC_MT_PING, ipc_ping_response, 0), \
+ .sem = KERN_SEMAPHORE_INITIALIZATION(0, 1) \
+}
+
+//blocking command that can be run in a thread context to ping another target
+int ipc_ping(ipc_ping_cmd_t* ping_cmd, uint32_t target_id);
+#endif /*IPC_ENABLE_PING*/
diff --git a/src/lib/occlib/ipc_structs.h b/src/lib/occlib/ipc_structs.h
new file mode 100644
index 0000000..5f1c90b
--- /dev/null
+++ b/src/lib/occlib/ipc_structs.h
@@ -0,0 +1,226 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/occlib/ipc_structs.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __IPC_STRUCTS_H__
+#define __IPC_STRUCTS_H__
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2015
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file ipc_structs.h
+/// \brief Common header for Interprocessor Communication structures in the
+/// OCC complex
+///
+#include "kernel.h" //kernel wrapper macros
+#include "occhw_common.h"
+#include "ipc_macros.h"
+
+
+#ifndef IPC_CBUF_SIZE
+#define IPC_CBUF_SIZE 8 //number of messages must be a power of 2
+#endif
+
+//the maximum number of multi-target functions (common functions)
+//This can be overriden in a global header that's included by all occ images
+//so that it is the same across all processors.
+#ifndef IPC_MT_MAX_FUNCTIONS
+#define IPC_MT_MAX_FUNCTIONS 8
+#endif
+
+//the maximum number of single-target functions (processor-specific functions)
+//This can be overridden in a local header file and does not need to be the
+//same across all processors.
+#ifndef IPC_ST_MAX_FUNCTIONS
+#define IPC_ST_MAX_FUNCTIONS 16
+#endif
+
+/// IPC return codes
+#define IPC_RC_SUCCESS 0
+#define IPC_RC_CMD_FAILED 0x00472000
+#define IPC_RC_BUFFER_FULL 0x00472001
+#define IPC_RC_SELF_BLOCKED 0x00472002
+#define IPC_RC_TARGET_BLOCKED 0x00472003
+#define IPC_RC_MSG_ACTIVE 0x00472004
+#define IPC_RC_INVALID_FUNC_ID 0x00472005
+#define IPC_RC_CMD_NOT_SUPPORTED 0x00472006
+#define IPC_RC_INVALID_TARGET_ID 0x00472007
+#define IPC_RC_INVALID_ARG 0x00472008
+#define IPC_RC_MSG_NOT_ACTIVE 0x00472009
+#define IPC_RC_NO_MSG 0x0047200a
+#define IPC_RC_TIMEOUT 0x0047200b
+
+/// IPC Message Flags
+#define IPC_FLAG_MT 0x00000100
+#define IPC_FLAG_RESPONSE 0x00000200
+#define IPC_FLAG_VALID 0x00000400
+#define IPC_FLAG_ACTIVE 0x00000800
+
+// Function ID field masks
+#define IPC_TARGET_MASK 0xff000000
+#define IPC_SENDER_MASK 0x00ff0000
+#define IPC_FLAGS_MASK 0x0000ff00
+#define IPC_INDEX_MASK 0x000000ff
+
+#define IPC_TARGET_SHIFT 24
+
+#define IPC_CBUF_COUNT_BYTES 1
+#define IPC_CBUF_COUNT_BITS 8
+
+#ifndef __ASSEMBLER__
+
+// If an occ application does not wish to use IPC then it should not
+// define the GLOBAL_CFG_USE_IPC macro. This allows IPC to compile
+// without errors.
+#ifdef GLOBAL_CFG_USE_IPC
+#include "ipc_func_ids.h"
+#else
+IPC_FUNCIDS_TABLE_START
+ IPC_FUNCIDS_MT_START
+ IPC_FUNCIDS_MT_END
+ IPC_FUNCIDS_ST_START(OCCHW_INST_ID_GPE0)
+ IPC_FUNCIDS_ST_END(OCCHW_INST_ID_GPE0)
+ IPC_FUNCIDS_ST_START(OCCHW_INST_ID_GPE1)
+ IPC_FUNCIDS_ST_END(OCCHW_INST_ID_GPE1)
+ IPC_FUNCIDS_ST_START(OCCHW_INST_ID_GPE2)
+ IPC_FUNCIDS_ST_END(OCCHW_INST_ID_GPE2)
+ IPC_FUNCIDS_ST_START(OCCHW_INST_ID_GPE3)
+ IPC_FUNCIDS_ST_END(OCCHW_INST_ID_GPE3)
+ IPC_FUNCIDS_ST_START(OCCHW_INST_ID_PPC)
+ IPC_FUNCIDS_ST_END(OCCHW_INST_ID_PPC)
+IPC_FUNCIDS_TABLE_END
+#endif /*GLOBAL_CFG_USE_IPC*/
+
+//Statically check that the function tables are large enough
+KERN_STATIC_ASSERT(IPC_MT_NUM_FUNCIDS <= IPC_MT_MAX_FUNCTIONS);
+KERN_STATIC_ASSERT(IPC_ST_NUM_FUNCIDS <= IPC_ST_MAX_FUNCTIONS);
+
+#ifdef __SSX__
+extern KERN_DEQUE G_ipc_deferred_queue;
+#endif
+
+struct ipc_msg;
+typedef struct ipc_msg ipc_msg_t;
+
+typedef union
+{
+ uint64_t counts64;
+ uint8_t counts8[sizeof(uint64_t) / IPC_CBUF_COUNT_BYTES];
+} ipc_counts_t;
+
+/// Circular buffer read and write counts are grouped together by target_id
+/// so that an interrupt hander can quickly tell which buffer requires
+/// service. Each counter is 1 byte.
+///
+/// Note: index 0 (or most significant byte) is for GPE0
+typedef struct
+{
+ ipc_counts_t reads;
+ ipc_counts_t writes;
+}ipc_rwcounts_t;
+
+typedef struct
+{
+ ipc_rwcounts_t counts;
+ ipc_msg_t* cbufs[OCCHW_MAX_INSTANCES][IPC_CBUF_SIZE];
+ uint8_t pad[16];
+}ipc_target_t; //size is 6 x 32 = 192 bytes
+
+/// All of the shared data for IPC is contained in this structure
+typedef struct
+{
+ ipc_target_t targets[OCCHW_MAX_INSTANCES]; //880 bytes
+}ipc_shared_data_t;
+
+//prototype for ipc handlers and callback functions
+typedef void (*ipc_msg_handler_t)(ipc_msg_t*, void *);
+
+//function table entry
+typedef struct
+{
+ ipc_msg_handler_t handler;
+ void* arg;
+}ipc_func_table_entry_t;
+
+extern ipc_func_table_entry_t G_ipc_mt_handlers[IPC_MT_MAX_FUNCTIONS];
+
+extern ipc_func_table_entry_t G_ipc_st_handlers[IPC_ST_MAX_FUNCTIONS];
+
+typedef union
+{
+ struct
+ {
+ uint32_t target_id: 8;
+ uint32_t sender_id: 8;
+ uint32_t reserved: 4;
+ uint32_t active_flag: 1;
+ uint32_t valid_flag: 1;
+ uint32_t response_flag: 1;
+ uint32_t multi_target_flag: 1;
+ uint32_t table_index: 8;
+ };
+ uint32_t word32;
+}ipc_func_id_t;
+
+#define IPC_MSG_DEQUEUE_SZ 8 //expected size of a deque structure
+struct ipc_msg
+{
+ // but this file is shared by both, so use a void* type
+ // instead.
+ union
+ {
+ KERN_DEQUE node;
+ uint8_t pad[IPC_MSG_DEQUEUE_SZ];
+ };
+
+ //function ID of the function that the sender wants executed
+ volatile ipc_func_id_t func_id;
+
+ //The IPC return code
+ volatile uint32_t ipc_rc;
+
+ //function to call if this is a response message
+ ipc_msg_handler_t resp_callback;
+
+ //Argument passed into the callback function
+ void *callback_arg;
+};
+
+//Do a static check on the size of KERN_DEQUE. IPC_MSG_DEQUE_SZ must be <= sizeof(KERN_DEQUE).
+//If the compiler fails here then you probably need to update the value of IPC_MSG_DEQUEUE_SZ.
+//NOTE: this is needed because ipc_msg_t is used in both PK and SSX environments and there is
+// no guarantee that the size of a deque will be the same in both environments.
+KERN_STATIC_ASSERT(sizeof(KERN_DEQUE) <= IPC_MSG_DEQUEUE_SZ);
+
+//A message queue that threads can block on while they wait for new messages.
+typedef struct
+{
+ KERN_DEQUE msg_head;
+ KERN_SEMAPHORE msg_sem; //posted whenever a new message is queued
+}ipc_msgq_t;
+
+#endif /*__ASSEMBLER__*/
+
+#endif /* __IPC_STRUCTS_H__ */
diff --git a/src/lib/occlib/liboccfiles.mk b/src/lib/occlib/liboccfiles.mk
new file mode 100644
index 0000000..7b3c80a
--- /dev/null
+++ b/src/lib/occlib/liboccfiles.mk
@@ -0,0 +1,53 @@
+# IBM_PROLOG_BEGIN_TAG
+# This is an automatically generated prolog.
+#
+# $Source: src/lib/occlib/liboccfiles.mk $
+#
+# OpenPOWER OnChipController Project
+#
+# Contributors Listed Below - COPYRIGHT 2015
+# [+] International Business Machines Corp.
+#
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+#
+# IBM_PROLOG_END_TAG
+# @file liboccfiles.mk
+#
+# @brief mk for libocc.a object files
+#
+# @page ChangeLogs Change Logs
+# @section liboccfiles.mk
+# @verbatim
+#
+#
+# Change Log ******************************************************************
+# Flag Defect/Feature User Date Description
+# ------ -------------- ---------- ------------ -----------
+#
+# @endverbatim
+#
+##########################################################################
+# INCLUDES
+##########################################################################
+
+C-SOURCES = \
+ ipc_core.c \
+ ipc_init.c \
+ ipc_msgq.c \
+ ipc_ping.c \
+ occhw_xir_dump.c
+
+S-SOURCES =
+
+LIBOCC_OBJECTS = $(C-SOURCES:.c=.o) $(S-SOURCES:.S=.o)
diff --git a/src/lib/occlib/occhw_scom_cmd.h b/src/lib/occlib/occhw_scom_cmd.h
new file mode 100644
index 0000000..c6051f5
--- /dev/null
+++ b/src/lib/occlib/occhw_scom_cmd.h
@@ -0,0 +1,93 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/occlib/occhw_scom_cmd.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __OCCHW_SCOM_CMD_H__
+#define __OCCHW_SCOM_CMD_H__
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2015
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file occhw_scom_cmd.h
+/// \brief Defines the shared scom command control block
+///
+/// This file contains definitions that are used by both ppc405 and GPE
+/// instances inside the OCC.
+
+// The most significant bit of scom addresses is always 0, so we use this
+// bit to tell the SCOM proxy server (GPE) whether a getscom or putscom is
+// needed.
+#define OCCHW_SCOM_READ_MASK 0x80000000
+
+// This is a status value that the ppc405 will write to the status
+// word prior to starting a new request. This value can be used to
+// detect that the GPE has not yet written status for the request.
+// Note: The GPE simply copies it's MSR value to the status field
+// when it completes. This value is not a valid MSR value.
+#define OCCHW_SCOM_PENDING 0x0000EF00
+
+// Define the structure offsets for use in assembly code on the GPE
+#define OCCHW_SCOM_STATUS_OFFSET 0
+#define OCCHW_SCOM_ADDR_OFFSET 4
+#define OCCHW_SCOM_DATA_OFFSET 8
+
+#ifndef __ASSEMBLER__
+typedef union
+{
+ uint32_t status32;
+ struct
+ {
+ uint32_t rsvd0 : 1;
+ uint32_t mask : 7;
+ uint32_t is0 : 1;
+ uint32_t sibrc : 3;
+ uint32_t lp : 1;
+ uint32_t we : 1;
+ uint32_t is1 : 1;
+ uint32_t uie : 1;
+ uint32_t ee : 1;
+ uint32_t rsvd1 : 2;
+ uint32_t me : 1;
+ uint32_t rsvd2 : 3;
+ uint32_t ipe : 1;
+ uint32_t sibrca : 8;
+ };
+}occhw_scom_status_t;
+
+typedef struct
+{
+ //MSR is saved here
+ volatile occhw_scom_status_t scom_status;
+
+ //msg is used to communicate read/!write
+ volatile uint32_t scom_addr;
+
+ //data for putscom or from getscom
+ volatile uint64_t scom_data;
+} occhw_scom_cmd_t;
+
+#endif /*__ASSEMBLER__*/
+
+#endif /* __OCCHW_SCOM_CMD_H__ */
diff --git a/src/lib/occlib/occhw_shared_data.h b/src/lib/occlib/occhw_shared_data.h
new file mode 100644
index 0000000..643691a
--- /dev/null
+++ b/src/lib/occlib/occhw_shared_data.h
@@ -0,0 +1,93 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/occlib/occhw_shared_data.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __OCCHW_OSD_H__
+#define __OCCHW_OSD_H__
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2015
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file occhw_osd.h
+/// \brief Common header for shared data within the OCC complex
+///
+
+#include "kernel.h"
+#include "ipc_structs.h"
+#include "occhw_scom_cmd.h"
+
+/// Hardcoded address for the location of the OCC shared data segment
+/// This is placed in the non-cacheable aliased region of SRAM space
+#ifndef OSD_ADDR
+#define OSD_ADDR 0xf7f00000
+#endif
+
+/// Total space of the OCC shared data segment
+#define OSD_TOTAL_SHARED_DATA_BYTES 4096
+
+/// Reserve space for IPC data in case it needs to grow
+#define OSD_IPC_RESERVED_BYTES 2048
+
+/// Reserve space for Debug
+#define OSD_DEBUG_RESERVED_BYTES 512
+
+#define OSD_GPE_SCOM_ADDR (OSD_ADDR + OSD_IPC_RESERVED_BYTES + OSD_DEBUG_RESERVED_BYTES)
+
+#define OSD_GPE_SCOM_RESERVED_BYTES 32
+
+#ifndef __ASSEMBLER__
+typedef union
+{
+ struct
+ {
+ union
+ {
+ ipc_shared_data_t ipc_data; //880 bytes
+ uint8_t ipc_reserved[OSD_IPC_RESERVED_BYTES];
+ };
+ union
+ {
+ //debug_shared_data_t debug_data;
+ uint8_t debug_reserved[OSD_DEBUG_RESERVED_BYTES];
+ };
+ union
+ {
+ occhw_scom_cmd_t scom_cmd;
+ uint8_t gpe_scom_reserved[OSD_GPE_SCOM_RESERVED_BYTES];
+ };
+
+ };
+ uint8_t total_reserved[OSD_TOTAL_SHARED_DATA_BYTES];
+} occhw_osd_t;
+
+// Fail to compile if ipc_shared_data exceeds the reserved space
+KERN_STATIC_ASSERT((sizeof(ipc_shared_data_t) <= OSD_IPC_RESERVED_BYTES));
+
+/// Hardcoded pointer for the location of the OCC shared data segment
+#define OSD_PTR ((occhw_osd_t*) OSD_ADDR)
+
+#endif /*__ASSEMBLER__*/
+
+#endif /* __OCCHW_OSD_H__ */
diff --git a/src/lib/occlib/occhw_xir_dump.c b/src/lib/occlib/occhw_xir_dump.c
new file mode 100644
index 0000000..7ff2e4e
--- /dev/null
+++ b/src/lib/occlib/occhw_xir_dump.c
@@ -0,0 +1,60 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/occlib/occhw_xir_dump.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2015
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file occhw_xir_dump.c
+/// \brief Implementation of the occhw_xir_dump function
+#include "kernel.h"
+#include "occhw_common.h"
+#include "occhw_xir_dump.h"
+
+int32_t occhw_xir_dump(uint32_t inst_id, occhw_xir_dump_t* xir_dump)
+{
+ int rc;
+ do
+ {
+ if(!xir_dump)
+ {
+ rc = OCCHW_XIR_INVALID_POINTER;
+ break;
+ }
+
+ if(inst_id > OCCHW_INST_ID_MAX_GPE)
+ {
+ rc = OCCHW_XIR_INVALID_GPE;
+ break;
+ }
+
+ //TODO: dump the XIR regs once the addresses are available
+ rc = 0;
+
+ }while(0);
+
+ return rc;
+}
diff --git a/src/lib/occlib/occhw_xir_dump.h b/src/lib/occlib/occhw_xir_dump.h
new file mode 100644
index 0000000..85e52ad
--- /dev/null
+++ b/src/lib/occlib/occhw_xir_dump.h
@@ -0,0 +1,70 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/occlib/occhw_xir_dump.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __OCCHW_XIR_DUMP_H__
+#define __OCCHW_XIR_DUMP_H__
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2015
+// *! All Rights Reserved -- Property of IBM
+// *! *** IBM Confidential ***
+//-----------------------------------------------------------------------------
+
+/// \file occhw_xir_dump.h
+/// \brief header for the occhw_xir_dump function
+///
+
+#ifndef __ASSEMBLER__
+#include "stdint.h"
+
+/// Structure for dumping XIR data for a GPE
+typedef struct
+{
+ uint32_t xsr;
+ uint32_t sprg0;
+ uint32_t edr;
+ uint32_t ir;
+ uint32_t iar;
+ uint32_t sib_upper;
+ uint32_t sib_lower;
+} occhw_xir_dump_t;
+
+///////////////////////////////////////////////////////////////////////////////
+/// Dump the XIR registers for a GPE engine
+///
+/// \param inst_id The instance ID of the target GPE.
+///
+/// \param xir_dump Pointer to a occhw_xir_dump_t structure.
+///
+/// Possible return codes are:
+///
+/// \retval 0 XIR registers were successfully dumped
+///
+/// \retval OCCHW_XIR_INVALID_GPE \a inst_id is not for a valid GPE instance.
+///
+/// \retval OCCHW_XIR_INVALID_POINTER \a xir_dump is NULL
+///
+int32_t occhw_xir_dump(uint32_t inst_id, occhw_xir_dump_t* xir_dump);
+
+#endif /*__ASSEMBLER__*/
+#endif /*__OCCHW_XIR_DUMP_H__*/
OpenPOWER on IntegriCloud