From 420e6d248cc6d2b3c39bc3970e3bb6747b3bddc3 Mon Sep 17 00:00:00 2001 From: William Bryan Date: Mon, 3 Aug 2015 12:38:58 -0500 Subject: new ssx and lib files Change-Id: I2328b1e86d59e3788910687d762fb70ec680058f Reviewed-on: http://gfw160.aus.stglabs.ibm.com:8080/gerrit/19503 Reviewed-by: William A. Bryan Tested-by: William A. Bryan --- src/lib/occlib/Makefile | 57 ++++ src/lib/occlib/README.txt | 1 + src/lib/occlib/ipc_api.h | 519 +++++++++++++++++++++++++++++++++++++ src/lib/occlib/ipc_async_cmd.h | 49 ++++ src/lib/occlib/ipc_core.c | 484 ++++++++++++++++++++++++++++++++++ src/lib/occlib/ipc_init.c | 153 +++++++++++ src/lib/occlib/ipc_macros.h | 197 ++++++++++++++ src/lib/occlib/ipc_msgq.c | 108 ++++++++ src/lib/occlib/ipc_ping.c | 96 +++++++ src/lib/occlib/ipc_ping.h | 53 ++++ src/lib/occlib/ipc_structs.h | 226 ++++++++++++++++ src/lib/occlib/liboccfiles.mk | 53 ++++ src/lib/occlib/occhw_scom_cmd.h | 93 +++++++ src/lib/occlib/occhw_shared_data.h | 93 +++++++ src/lib/occlib/occhw_xir_dump.c | 60 +++++ src/lib/occlib/occhw_xir_dump.h | 70 +++++ 16 files changed, 2312 insertions(+) create mode 100644 src/lib/occlib/Makefile create mode 100644 src/lib/occlib/README.txt create mode 100644 src/lib/occlib/ipc_api.h create mode 100644 src/lib/occlib/ipc_async_cmd.h create mode 100644 src/lib/occlib/ipc_core.c create mode 100644 src/lib/occlib/ipc_init.c create mode 100644 src/lib/occlib/ipc_macros.h create mode 100644 src/lib/occlib/ipc_msgq.c create mode 100644 src/lib/occlib/ipc_ping.c create mode 100644 src/lib/occlib/ipc_ping.h create mode 100644 src/lib/occlib/ipc_structs.h create mode 100644 src/lib/occlib/liboccfiles.mk create mode 100644 src/lib/occlib/occhw_scom_cmd.h create mode 100644 src/lib/occlib/occhw_shared_data.h create mode 100644 src/lib/occlib/occhw_xir_dump.c create mode 100644 src/lib/occlib/occhw_xir_dump.h (limited to 'src/lib/occlib') 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__*/ -- cgit v1.2.1