diff options
Diffstat (limited to 'src/sbefw/core')
81 files changed, 17114 insertions, 0 deletions
diff --git a/src/sbefw/core/Makefile b/src/sbefw/core/Makefile new file mode 100644 index 00000000..3245d86e --- /dev/null +++ b/src/sbefw/core/Makefile @@ -0,0 +1,56 @@ +# IBM_PROLOG_BEGIN_TAG +# This is an automatically generated prolog. +# +# $Source: src/sbefw/core/Makefile $ +# +# OpenPOWER sbe Project +# +# Contributors Listed Below - COPYRIGHT 2016,2017 +# +# +# 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 +#export P2P_ENABLE = 1 + +export SUB_OBJDIR = /sbefw/core + +include img_defs.mk +include sbecorefiles.mk + +OBJS := $(addprefix $(OBJDIR)/, $(SBECORE_OBJECTS)) + +libsbecore.a: $(OBJS) + $(AR) crs $(OBJDIR)/libsbecore.a $(OBJDIR)/*.o + +.PHONY: clean sbecore +sbecore: $(OBJS) + +$(OBJS) $(OBJS:.o=.d): | $(OBJDIR) + +$(OBJDIR): + mkdir -p $(OBJDIR) + + +#clean the kernel directory first, then the application level clean +clean: + rm -fr $(OBJDIR) + +ifneq ($(MAKECMDGOALS),clean) +include $(OBJS:.o=.d) +endif + + + + + diff --git a/src/sbefw/core/MakefileSeeprom b/src/sbefw/core/MakefileSeeprom new file mode 100644 index 00000000..c2ecf874 --- /dev/null +++ b/src/sbefw/core/MakefileSeeprom @@ -0,0 +1,59 @@ +# IBM_PROLOG_BEGIN_TAG +# This is an automatically generated prolog. +# +# $Source: src/sbecore/Makefile $ +# +# OpenPOWER sbe Project +# +# Contributors Listed Below - COPYRIGHT 2016,2017 +# [+] 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 +#export P2P_ENABLE = 1 + +export SUB_OBJDIR = /sbefw/coreseeprom + +include img_defs.mk +include sbecoreseepromfiles.mk + +GCC-CFLAGS += -mlongcall +GCC-DEFS += -D__SBEFW_SEEPROM__=1 +OBJS := $(addprefix $(OBJDIR)/, $(SBECORESEEPROM_OBJECTS)) + +libsbecoreseeprom.a: $(OBJS) + $(AR) crs $(OBJDIR)/libsbecoreseeprom.a $(OBJDIR)/*.o + +.PHONY: clean sbecoreseeprom +sbecoreseeprom: $(OBJS) + +$(OBJS) $(OBJS:.o=.d): | $(OBJDIR) + +$(OBJDIR): + mkdir -p $(OBJDIR) + + +#clean the kernel directory first, then the application level clean +clean: + rm -fr $(OBJDIR) + +ifneq ($(MAKECMDGOALS),clean) +include $(OBJS:.o=.d) +endif + + + + + diff --git a/src/sbefw/core/assert.h b/src/sbefw/core/assert.h new file mode 100644 index 00000000..ad2824b7 --- /dev/null +++ b/src/sbefw/core/assert.h @@ -0,0 +1,49 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/assert.h $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* */ +/* */ +/* 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 assert.h + * + * @brief This file contains the assert macro for SBE + */ +#ifndef SBE_ASSERT_H +#define SBE_ASSERT_H +#include "sbetrace.H" +#include "sbeutil.H" + +//@TODO via RTC 129166 +//inject exception to halt SBE. Also see if we can use some +//PK kernel API. +#ifndef NDEBUG +#define assert(expr) \ + if( !(expr )) \ + { \ + SBE_ERROR("assertion failed: "#expr); \ + PK_PANIC(SBE::PANIC_ASSERT); \ + } \ + +#else +#define assert(expr) +#endif //NDEBUG + +#endif // SBE_ASSERT_H diff --git a/src/sbefw/core/pk_app_cfg.h b/src/sbefw/core/pk_app_cfg.h new file mode 100644 index 00000000..1e5557de --- /dev/null +++ b/src/sbefw/core/pk_app_cfg.h @@ -0,0 +1,143 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/pk_app_cfg.h $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2017 */ +/* */ +/* */ +/* 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: ppe/sbe/sbefw/pk_app_cfg.h + * + * @brief Application specific overrides go here. + * + */ + +#ifndef __PK_APP_CFG_H__ +#define __PK_APP_CFG_H__ + +#include "sbeirq.H" + +/* + * @brief Static configuration data for external interrupts: + * IRQ#, TYPE, POLARITY, ENABLE + * + */ +#define APPCFG_EXT_IRQS_CONFIG \ + SBE_IRQ_START0 STD_IRQ_TYPE_EDGE STD_IRQ_POLARITY_RISING STD_IRQ_MASKED \ + SBE_IRQ_START1 STD_IRQ_TYPE_EDGE STD_IRQ_POLARITY_RISING STD_IRQ_MASKED \ + SBE_IRQ_INTR0 STD_IRQ_TYPE_LEVEL STD_IRQ_POLARITY_RISING STD_IRQ_MASKED \ + SBE_IRQ_INTR1 STD_IRQ_TYPE_LEVEL STD_IRQ_POLARITY_RISING STD_IRQ_MASKED \ + SBE_IRQ_DRTM_REQ STD_IRQ_TYPE_LEVEL STD_IRQ_POLARITY_RISING STD_IRQ_MASKED \ + SBE_IRQ_SBEFIFO_RESET STD_IRQ_TYPE_LEVEL STD_IRQ_POLARITY_RISING STD_IRQ_MASKED \ + SBE_IRQ_SBEFIFO_DATA STD_IRQ_TYPE_LEVEL STD_IRQ_POLARITY_RISING STD_IRQ_MASKED \ + SBE_IRQ_HOST_PSU_INTR STD_IRQ_TYPE_LEVEL STD_IRQ_POLARITY_RISING STD_IRQ_MASKED \ + + +/* + * @brief This 64 bit mask specifies which of the interrupts are not to be used. + * + */ +#define APPCFG_IRQ_INVALID_MASK \ +(\ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_8) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_9) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_10) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_11) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_12) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_13) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_14) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_15) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_16) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_17) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_18) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_19) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_20) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_21) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_22) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_23) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_24) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_25) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_26) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_27) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_28) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_29) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_30) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_31) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_32) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_33) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_34) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_35) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_36) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_37) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_38) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_39) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_40) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_41) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_42) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_43) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_44) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_45) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_46) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_47) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_48) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_49) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_50) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_51) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_52) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_53) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_54) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_55) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_56) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_57) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_58) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_59) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_60) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_61) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_62) | \ + STD_IRQ_MASK64(SBE_IRQ_RESERVED_63)) + + +/* + * @brief Override the default behavior of the PK API error handling. + * Force PK to send the return code back to the application, + * instead of a kernel panic. + * + */ +#ifndef PK_ERROR_PANIC +#define PK_ERROR_PANIC 0 +#endif + +/* + * @brief Override the default behavior of idle timer trace. + * As SBE trace buffer is small, we do not want idle timer traces. + * + */ +#define PK_TRACE_TIMER_OUTPUT 0 + +#ifdef PPE42_MACHINE_CHECK_HANDLER +#undef PPE42_MACHINE_CHECK_HANDLER +#endif +#define PPE42_MACHINE_CHECK_HANDLER SBE_MACHINE_CHECK_HANDLER + +// Set the trace buffer size +#ifdef PK_TRACE_SZ +#undef PK_TRACE_SZ +#endif +#define PK_TRACE_SZ 512 +#endif /*__PK_APP_CFG_H__*/ diff --git a/src/sbefw/core/plugins/sbeUserDataParser.C b/src/sbefw/core/plugins/sbeUserDataParser.C new file mode 100644 index 00000000..d853a1a6 --- /dev/null +++ b/src/sbefw/core/plugins/sbeUserDataParser.C @@ -0,0 +1,297 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/plugins/sbeUserDataParser.C $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* */ +/* */ +/* 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 <sys/stat.h> +#include <errno.h> + +#include <cstdlib> +#include <cstring> +#include <sstream> + +#include <utilfile.H> +#include <utilmem.H> + +#include "sbeFFDCType.H" + +#define SBE_TEMP_DUMP_FILE "/tmp/trace_dump.bin" +#define SBE_TRACE_BIN "/tmp/sbe_trace.bin" +#define PPE2FSP_TOOL "ppe2fsp" +#define P9_XIP_TOOL "p9_xip_tool" +#define SBE_TRACE_CMD "fsp-trace -s" +#define SBE_TRACE_HEADLINE "SBE Traces" +#define SBE_ATTR_DUMP_HEADLINE "SBE Attributes Dump" +#define P9_XIP_ATTR_CMD "-ifs attrdump" +#define SBE_STRING_FILE "sbeStringFile" +std::string SBE_SEEPROM_BIN = "sbe_seeprom_DD1.bin"; + +#define SBE_PARSER_MAX_LOCAL_BUFFER 8192 + +#define SBE_PARSER_PRINT_DELIMITER {std::cout << \ +"*****************************************************************************"\ +<< std::endl;} +#define SBE_PARSER_PRINT_HEADING(x) { SBE_PARSER_PRINT_DELIMITER \ +std::cout << \ +" "x<< std::endl;\ +SBE_PARSER_PRINT_DELIMITER } + +std::string findSbeFile(const char *name) +{ +#ifdef CONTEXT_x86_nfp + //TODO via RTC:157433 + std::string tmp = getenv("bb"); + tmp += "obj/x86.nfp/sbei/sbfw/img/"; + std::string file = tmp + name; + + struct stat l_stat; + if(stat(file.c_str(), &l_stat) < 0) + { + //Can't find the file + } + + return file; +#endif +#ifdef CONTEXT_ppc + std::string tmp = getenv("PATH"); + tmp += ":/nfs:/maint"; + + char *path = strdup(tmp.c_str()); + char *dir = NULL; + + std::string file; + + struct stat l_stat; + + for(dir = strtok( path, ":" ); dir; dir = strtok(NULL, ":")) + { + file = file + dir + "/" + name; + + if(stat(file.c_str(), &l_stat) < 0) + { + // String file not found, go to next one + file.clear(); + } + else + { + // update where trexStringFile is + break; + } + } + + free(path); + path = NULL; //sm05c + + return file; +#endif +} + +void sbeParserSysCall(const char *cmd) +{ + FILE *stream; + char buffer[256]; + + stream = popen(cmd, "r" ); + if(stream) + { + while(!feof(stream)) + { + if(fgets(buffer, 256, stream) != NULL) + { + std::cout << buffer; + } + } + } + else + { + std::cout << "command failed :[" << cmd << "]" << std::endl; + std::cout << "errno [" << errno << "]" << std::endl; + } +} + +int parseSbeFFDC(ErrlUsrParser & i_parser, const void * i_pBuffer, + const uint32_t i_buflen) +{ + int l_rc = 0; + uint32_t fapiRc = 0; + sbeFFDCDataHeader_t l_pData = {0}; + char l_buffer[SBE_PARSER_MAX_LOCAL_BUFFER] = {0}; + char *l_pBuffer = (char*)i_pBuffer; + uint32_t l_buflen = i_buflen; + + do + { + if(i_pBuffer == NULL) + { + l_rc = -1; + break; + } + //seek l_mem to the binary blob of FFDC package + UtilMem l_mem(const_cast<void*>(i_pBuffer),i_buflen); + + // The data is a buffer of SBE FFDC data + i_parser.PrintHeading("SBE FFDC Parser"); + + if(l_buflen < sizeof(fapiRc)) + { + i_parser.PrintHexDump(l_pBuffer, l_buflen); + break; + } + l_buflen -= sizeof(fapiRc); + l_pBuffer += sizeof(fapiRc); + l_mem >> fapiRc; + i_parser.PrintNumber("FAPI RC ", "0x%08X", fapiRc); + + if(l_buflen < sizeof(l_pData)) + { + i_parser.PrintHexDump(l_pBuffer, l_buflen); + break; + } + l_buflen -= sizeof(l_pData); + l_pBuffer += sizeof(l_pData); + l_mem >> l_pData; + + i_parser.PrintNumber("Primary Status ", "0x%04X", + (uint16_t)l_pData.primaryStatus); + i_parser.PrintNumber("Secondary Status ", "0x%04X", + (uint16_t)l_pData.secondaryStatus); + i_parser.PrintNumber("FW Commit ID ", "0x%08X", + (uint32_t)l_pData.fwCommitID); + if(l_pData.ddLevel == SBE_FFDC_DD2) + { + SBE_SEEPROM_BIN = "sbe_seeprom_DD2.bin"; + } + //loop through the number of fields configured + uint32_t l_dumpFields = l_pData.dumpFields.get(); + while(l_dumpFields && !l_rc) + { + if(l_dumpFields & 0x0001) + { + if(l_buflen < sizeof(uint32_t)) + { + //Complete this loop and let the tools print as much data + //as possible but break from next loop + l_rc = -1; + } + sbeFFDCUserDataIdentifier_t l_ffdcUserDataId = {0}; + l_buflen -= sizeof(uint32_t); //l_ffdcUserDataId + l_pBuffer += sizeof(uint32_t); //l_ffdcUserDataId + + l_mem >> l_ffdcUserDataId; + + // TODO via RTC:158462 continue even for attribute dump + // Need to extend p9_xip_tool for partial attr dump handling + if((l_buflen < l_ffdcUserDataId.fieldLen) && + (l_ffdcUserDataId.fieldId != SBE_FFDC_TRACE_DUMP)) + { + i_parser.PrintHexDump(l_pBuffer, l_buflen); + break; + } + + l_buflen -= l_ffdcUserDataId.fieldLen; + l_pBuffer += l_ffdcUserDataId.fieldLen; + + l_mem.read(l_buffer, l_ffdcUserDataId.fieldLen); + std::ostringstream l_strFile; + //Generate temp dump file name + l_strFile << SBE_TEMP_DUMP_FILE; + + //Write dump into the temporary file + UtilFile l_fileObj(l_strFile.str().c_str()); + errlHndl_t l_errlHndl = l_fileObj.open("w"); + if ( l_errlHndl ) + { + std::cerr << "Error opening " + << l_strFile.str() << std::endl; + l_errlHndl->commit(HWSV_COMP_ID, ERRL_ACTION_REPORT); + delete l_errlHndl; + l_errlHndl = NULL; + i_parser.PrintHexDump(l_buffer, l_ffdcUserDataId.fieldLen); + return -1; + } + else + { + l_fileObj.write( l_buffer, l_ffdcUserDataId.fieldLen); + l_fileObj.Close(); + } + + //Specific handling + if(l_ffdcUserDataId.fieldId == SBE_FFDC_ATTR_DUMP) + { + SBE_PARSER_PRINT_HEADING(SBE_ATTR_DUMP_HEADLINE) + //command + std::ostringstream l_strCmd1; + // p9_xip_tool <sbe seeprom bin file> + // -ifs attrdump <attr dump file> 2>&1 + l_strCmd1 << findSbeFile(P9_XIP_TOOL) + << " " + << findSbeFile(SBE_SEEPROM_BIN.c_str()) + << " " + << P9_XIP_ATTR_CMD + << " " + << l_strFile.str().c_str() + << " " + << "2>&1"; + + //Call out the command + sbeParserSysCall( l_strCmd1.str().c_str() ); + } + else if(l_ffdcUserDataId.fieldId == SBE_FFDC_TRACE_DUMP) + { + SBE_PARSER_PRINT_HEADING(SBE_TRACE_HEADLINE) + //command + std::ostringstream l_strCmd1, l_strCmd2; + // ppe2fsp <trace dump file> <trace bin file> 2>&1 + l_strCmd1 << findSbeFile(PPE2FSP_TOOL) + << " " + << l_strFile.str().c_str() + << " " + << SBE_TRACE_BIN + << " " + << "2>&1"; + + // fsp-trace -s <sbe string file> <trace bin file> 2>&1 + l_strCmd2 << SBE_TRACE_CMD + << " " + << findSbeFile(SBE_STRING_FILE) + << " " + << SBE_TRACE_BIN + << " " + << "2>&1"; + + //Call out the commands + sbeParserSysCall( l_strCmd1.str().c_str() ); + sbeParserSysCall( l_strCmd2.str().c_str() ); + } + + //Delete the temp file + l_fileObj.Remove(); + } + l_dumpFields >>= 1; + if(l_rc != 0) + { + break; + } + } + } while(false); + + return l_rc; +} diff --git a/src/sbefw/core/pool.C b/src/sbefw/core/pool.C new file mode 100644 index 00000000..93c67bb4 --- /dev/null +++ b/src/sbefw/core/pool.C @@ -0,0 +1,65 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/pool.C $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2017 */ +/* */ +/* */ +/* 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 <stdint.h> +#include <sbetrace.H> +#include <stddef.h> +#include<pool.H> +#include "assert.h" + +namespace SBEVECTORPOOL +{ + +vectorMemPool_t g_pool[G_POOLSIZE]; + +vectorMemPool_t * allocMem() +{ + vectorMemPool_t *pool = NULL; + for( size_t idx = 0; idx < G_POOLSIZE; idx++ ) + { + if( 0 == g_pool[idx].refCount ) + { + pool = g_pool + idx; + g_pool[idx].refCount++; + break; + } + } + SBE_DEBUG(" Giving pool 0x%08X", pool); + return pool; +} + +void releaseMem( vectorMemPool_t * i_pool ) +{ + do + { + if ( NULL == i_pool ) break; + + // Assert here. This pool was not supposed to be in use. + assert( 0 != i_pool->refCount ) + SBE_DEBUG(" Releasing pool 0x%08X", i_pool); + i_pool->refCount--; + SBE_DEBUG(" In releaseMem() RefCount:%u", i_pool->refCount); + }while(0); +} + +} // namesspace SBEVECTORPOOL diff --git a/src/sbefw/core/pool.H b/src/sbefw/core/pool.H new file mode 100644 index 00000000..325a5aa6 --- /dev/null +++ b/src/sbefw/core/pool.H @@ -0,0 +1,58 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/pool.H $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* */ +/* */ +/* 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 SBE_VECTOR_POOL_H +#define SBE_VECTOR_POOL_H + +namespace SBEVECTORPOOL +{ + +// Size of a block for a vector +static const size_t G_BLOCKSIZE = 512; + +//Pool size +static const size_t G_POOLSIZE = 4; + +typedef struct +{ + size_t refCount; + uint8_t data[G_BLOCKSIZE] __attribute__ ((aligned (8))); +}vectorMemPool_t; + +/** + * @brief Returns memory pool block. + * + * @return Memory block if available, NULL otherwise. + */ +vectorMemPool_t * allocMem(); + +/** + * @brief Release memory pool block. + * + * @param[in] i_pool pool pointer. + */ +void releaseMem( vectorMemPool_t * i_pool ); + +} // namespace SBEVECTORPOOL +#endif //SBE_VECTOR_POOL_H diff --git a/src/sbefw/core/sbeFFDC.C b/src/sbefw/core/sbeFFDC.C new file mode 100644 index 00000000..affa9656 --- /dev/null +++ b/src/sbefw/core/sbeFFDC.C @@ -0,0 +1,274 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbeFFDC.C $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* */ +/* */ +/* 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 "sbefifo.H" +#include "sbetrace.H" +#include "sbe_sp_intf.H" +#include "sbeFifoMsgUtils.H" +#include "sberegaccess.H" +#include "sbeFFDC.H" +#include "sbe_build_info.H" +#include "sbeglobals.H" +#include "sbecmdcntrldmt.H" + +void SbeFFDCPackage::updateUserDataHeader(uint32_t i_fieldsConfig) +{ + //Update the user data header with dump fields configuration + iv_sbeFFDCDataHeader.dumpFields.set(i_fieldsConfig); + iv_sbeFFDCHeader.lenInWords = (sizeof(sbeResponseFfdc_t) + + sizeof(sbeFFDCDataHeader_t)) + /sizeof(uint32_t); + //Update the length in ffdc package header base on required fields + for(auto &sbeFFDCUserData:sbeFFDCUserDataArray) + { + if(sbeFFDCUserData.userDataId.fieldId & i_fieldsConfig) + { + iv_sbeFFDCHeader.lenInWords += + (sbeFFDCUserData.userDataId.fieldLen + + sizeof(sbeFFDCUserDataIdentifier_t)) + /sizeof(uint32_t); + } + } +} + +uint32_t SbeFFDCPackage::collectAsyncHwpFfdc (void) +{ + #define SBE_FUNC "collectAsyncHwpFfdc" + uint32_t l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + + switch (SBE_GLOBAL->asyncFfdcRC) + { + case fapi2::RC_CHECK_MASTER_STOP15_DEADMAN_TIMEOUT: + case fapi2::RC_CHECK_MASTER_STOP15_INVALID_STATE: + case fapi2::RC_BLOCK_WAKEUP_INTR_CHECK_FAIL: + SBE_INFO (SBE_FUNC "Collecting DMT Async FFDC for RC 0x%08x", + SBE_GLOBAL->asyncFfdcRC); + l_rc = sbeCollectDeadmanFfdc (); + break; + default: + SBE_INFO (SBE_FUNC"No specific Async FFDC to collect"); + break; + } + + return l_rc; + #undef SBE_FUNC +} + +uint32_t SbeFFDCPackage::sendOverFIFO(const sbeRespGenHdr_t &i_hdr, + const uint32_t i_fieldsConfig, + uint32_t &o_bytesSent, + const bool i_skipffdcBitCheck) +{ + #define SBE_FUNC "sendOverFIFO" + SBE_ENTER(SBE_FUNC); + uint32_t rc = SBE_SEC_OPERATION_SUCCESSFUL; + uint32_t length = 0; + + do + { + //reset sent bytes + o_bytesSent = 0; + + //check if SBE internal FFDC should be generated + if(!i_skipffdcBitCheck && + (SbeRegAccess::theSbeRegAccess().isSendInternalFFDCSet() + == false)) + { + SBE_INFO(SBE_FUNC" isSendInternalFFDCSet()=false, " + "not generating SBE InternalFFDC"); + rc = SBE_SEC_OPERATION_SUCCESSFUL; + break; + } + + // update the primary and secondary status + iv_sbeFFDCDataHeader.primaryStatus = i_hdr.primaryStatus; + iv_sbeFFDCDataHeader.secondaryStatus = i_hdr.secondaryStatus; + iv_sbeFFDCDataHeader.fwCommitID = SBE_COMMIT_ID; +#ifdef DD1 + iv_sbeFFDCDataHeader.ddLevel = SBE_FFDC_DD1; +#endif +#ifdef DD2 + iv_sbeFFDCDataHeader.ddLevel = SBE_FFDC_DD2; +#endif + // Set failed command information + // Sequence Id is 0 by default for Fifo interface + iv_sbeFFDCHeader.setCmdInfo(0, i_hdr.cmdClass, i_hdr.command); + //Update the user data header with dump fields configuration + updateUserDataHeader(i_fieldsConfig); + + //Send FFDC package header + length = sizeof(iv_sbeFFDCHeader) / sizeof(uint32_t); + rc = sbeDownFifoEnq_mult(length, + (uint32_t *)(&(iv_sbeFFDCHeader))); + if( rc!= SBE_SEC_OPERATION_SUCCESSFUL) + { + break; + } + o_bytesSent += length; + + //Send FFDC user data header + length = sizeof(iv_sbeFFDCDataHeader) / sizeof(uint32_t); + rc = sbeDownFifoEnq_mult(length, + (uint32_t *)(&(iv_sbeFFDCDataHeader))); + if( rc!= SBE_SEC_OPERATION_SUCCESSFUL) + { + break; + } + o_bytesSent += length; + + //Send FFDC user data blobs + for(auto &sbeFFDCUserData:sbeFFDCUserDataArray) + { + if(sbeFFDCUserData.userDataId.fieldId & i_fieldsConfig) + { + //Send User data identifer and length + length = sizeof(sbeFFDCUserDataIdentifier_t) / sizeof(uint32_t); + rc = sbeDownFifoEnq_mult(length, + (uint32_t*)&(sbeFFDCUserData.userDataId)); + if( rc!= SBE_SEC_OPERATION_SUCCESSFUL) + { + break; + } + o_bytesSent += length; + + //Send User data + length = sbeFFDCUserData.userDataId.fieldLen / sizeof(uint32_t); + rc = sbeDownFifoEnq_mult(length, + (uint32_t*)sbeFFDCUserData.userDataPtr); + if( rc!= SBE_SEC_OPERATION_SUCCESSFUL) + { + break; + } + o_bytesSent += length; + } + } + + SBE_INFO(SBE_FUNC "Number of words sent [%d]", o_bytesSent); + } while(false); + + SBE_EXIT(SBE_FUNC); + return rc; + #undef SBE_FUNC +} + +uint32_t SbeFFDCPackage::sendOverHostIntf(const sbeSbe2PsuRespHdr_t &i_hdr, + const uint32_t i_fieldsConfig, + sbeMemAccessInterface *i_pMemInterface, + uint32_t i_allocatedSize, + const bool i_skipffdcBitCheck) +{ + #define SBE_FUNC "sendOverHostIntf" + SBE_ENTER(SBE_FUNC); + uint32_t rc = SBE_SEC_OPERATION_SUCCESSFUL; + uint32_t length = 0; + bool isLastAccess = false; + fapi2::ReturnCode fapiRc = fapi2::FAPI2_RC_SUCCESS; + + do + { + //check if SBE internal FFDC should be generated + if(!i_skipffdcBitCheck && + (SbeRegAccess::theSbeRegAccess().isSendInternalFFDCSet() + == false)) + { + SBE_INFO(SBE_FUNC" isSendInternalFFDCSet()=false, " + "not generating SBE InternalFFDC"); + rc = SBE_SEC_OPERATION_SUCCESSFUL; + break; + } + + // update the primary and secondary status + iv_sbeFFDCDataHeader.primaryStatus = i_hdr.primStatus; + iv_sbeFFDCDataHeader.secondaryStatus = i_hdr.secStatus; + iv_sbeFFDCDataHeader.fwCommitID = SBE_COMMIT_ID; + // Set failed command information + iv_sbeFFDCHeader.setCmdInfo(i_hdr.seqID, i_hdr.cmdClass, i_hdr.command); + //Update the user data header with dump fields configuration + updateUserDataHeader(i_fieldsConfig); + + //Send FFDC package header + length = sizeof(iv_sbeFFDCHeader); + MEM_AVAILABLE_CHECK(i_allocatedSize, length, isLastAccess); + fapiRc = i_pMemInterface->accessWithBuffer(&iv_sbeFFDCHeader, length, + isLastAccess); + if(fapiRc != fapi2::FAPI2_RC_SUCCESS) + { + rc = SBE_SEC_GENERIC_FAILURE_IN_EXECUTION; + break; + } + + //Send FFDC user data header + length = sizeof(iv_sbeFFDCDataHeader); + MEM_AVAILABLE_CHECK(i_allocatedSize, length, isLastAccess); + fapiRc = i_pMemInterface->accessWithBuffer(&iv_sbeFFDCDataHeader, + length, + isLastAccess); + if(fapiRc != fapi2::FAPI2_RC_SUCCESS) + { + rc = SBE_SEC_GENERIC_FAILURE_IN_EXECUTION; + break; + } + + //Send FFDC user data blobs + for(auto &sbeFFDCUserData:sbeFFDCUserDataArray) + { + if(sbeFFDCUserData.userDataId.fieldId & i_fieldsConfig) + { + //Send User data identifer and length + length = sizeof(sbeFFDCUserDataIdentifier_t); + MEM_AVAILABLE_CHECK(i_allocatedSize, length, isLastAccess); + fapiRc = i_pMemInterface->accessWithBuffer( + &sbeFFDCUserData.userDataId, + length, + isLastAccess); + if(fapiRc != fapi2::FAPI2_RC_SUCCESS) + { + rc = SBE_SEC_GENERIC_FAILURE_IN_EXECUTION; + break; + } + + //Send User data + length = sbeFFDCUserData.userDataId.fieldLen; + MEM_AVAILABLE_CHECK(i_allocatedSize, length, isLastAccess); + isLastAccess = isLastAccess || + (&sbeFFDCUserData == + &sbeFFDCUserDataArray[NUM_USER_DATA_ELE-1]); + fapiRc = i_pMemInterface->accessWithBuffer( + sbeFFDCUserData.userDataPtr, + length, + isLastAccess); + if(fapiRc != fapi2::FAPI2_RC_SUCCESS) + { + rc = SBE_SEC_GENERIC_FAILURE_IN_EXECUTION; + break; + } + } + } + } while(false); + SBE_INFO(SBE_FUNC" [%d] bytes sent", + SBE_GLOBAL->hostFFDCAddr.size - i_allocatedSize); + + SBE_EXIT(SBE_FUNC); + return rc; + #undef SBE_FUNC +} diff --git a/src/sbefw/core/sbeFFDC.H b/src/sbefw/core/sbeFFDC.H new file mode 100644 index 00000000..2487a1f5 --- /dev/null +++ b/src/sbefw/core/sbeFFDC.H @@ -0,0 +1,148 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbeFFDC.H $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* */ +/* */ +/* 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 __SBE_FFDC_H +#define __SBE_FFDC_H + +#include "fapi2.H" +#include "plat_attributes.H" +#include "pk_trace.h" +#include "sbeFFDCType.H" +#include "sbeSpMsg.H" +#include "sbeHostUtils.H" +#include "sbeMemAccessInterface.H" + +//PIBMEM attribute dump +extern G_sbe_attrs_t G_sbe_attrs; + +//Configuration of user data blobs present in SBE FFDC +//Data is sent in the order defined here +//Definition - Identifier +// length of the blob +// pointer to the data +const sbeFFDCUserData_t sbeFFDCUserDataArray[] = + {{{SBE_FFDC_TRACE_DUMP, + sizeof(PkTraceBuffer)}, + (const void *)&g_pk_trace_buf, + }, + {{SBE_FFDC_ATTR_DUMP, + sizeof(G_sbe_attrs_t)}, + (const void *)&G_sbe_attrs, + }, + }; + +#define NUM_USER_DATA_ELE (sizeof(sbeFFDCUserDataArray)/sizeof(sbeFFDCUserData_t)) + +//SBE internal FFDC package class +class SbeFFDCPackage +{ +private: + //Disable copy constructor + SbeFFDCPackage(SbeFFDCPackage const &) = delete; + //Disable assignment operator + SbeFFDCPackage& operator=(SbeFFDCPackage const &) = delete; + + sbeResponseFfdc_t iv_sbeFFDCHeader; + //FFDC user data header + sbeFFDCDataHeader_t iv_sbeFFDCDataHeader; + + /* + * @bried updateUserDataHeader - method to update user data fields + * based on input config + * + * @param[in] i_fieldsConfig - input fields configuration + */ + void updateUserDataHeader(uint32_t i_fieldsConfig); + +public: + /*ctor + * + */ + SbeFFDCPackage() + { + //Making sure data is indeed aligned + static_assert((sizeof(G_sbe_attrs_t) % 4) == 0, + "G_sbe_attrs not 4byte aligned"); + static_assert((sizeof(PkTraceBuffer) % 4) == 0, + "g_pk_trace_buf not 4byte aligned"); + + iv_sbeFFDCHeader.fapiRc = fapi2::FAPI2_RC_PLAT_ERR_SEE_DATA; + + iv_sbeFFDCDataHeader.primaryStatus = SBE_PRI_OPERATION_SUCCESSFUL; + iv_sbeFFDCDataHeader.secondaryStatus = SBE_SEC_OPERATION_SUCCESSFUL; + + //length and dumpFields will be filled up depending on the fields + //to be sent in send APIs + iv_sbeFFDCDataHeader.dumpFields = {0}; + } + + /* + * @brief collectAsyncHwpFfdc - method to check and force collect + * HWP FFDC to SBE global FFDC region, + * asynchronous to the HWP execution + * @return - SBE secondary RC + */ + uint32_t collectAsyncHwpFfdc (void); + + /* + * @brief sendOverFIFO - method to pack and send SBE internal FFDC + * only if isSendInternalFFDCSet() is true + * over FIFO interface + * @param[in] i_hdr - Fifo response header + * @param[in] i_fieldsConfig - bitmap indicating the field + * to be sent in FFDC + * @param[out] o_bytesSent - number of bytes sent + * @param[in] i_skipffdcBitCheck - Boolean to indicate whether + * ffdc bit should be checked or not. + * By default it is false. + * + * @return - SBE secondary RC + */ + uint32_t sendOverFIFO(const sbeRespGenHdr_t &i_hdr, + const uint32_t i_fieldsConfig, + uint32_t &o_bytesSent, + const bool i_skipffdcBitCheck = false); + + /* @brief sendOverHostIntf - method to pack and send SBE internal FFDC + * only if isSendInternalFFDCSet() is true + * over HOST interface + * + * @param[in] i_hdr - Host response header + * @param[in] i_fieldsConfig - bitmap indicating the field + * to be sent in FFDC + * @param[in] i_pMemInterface - pointer to memory interface object + * @param[in] i_allocatedSize - size allocated for FFDC + * @param[in] i_skipffdcBitCheck - Boolean to indicate whether + * ffdc bit should be checked or not. + * By default it is false. + * + * @return - SBE secondary RC + */ + uint32_t sendOverHostIntf(const sbeSbe2PsuRespHdr_t &i_hdr, + const uint32_t i_fieldsConfig, + sbeMemAccessInterface *i_pMemInterface, + uint32_t i_allocatedSize, + const bool i_skipffdcBitCheck = false); +}; + +#endif //__SBE_FFDC_H diff --git a/src/sbefw/core/sbeFFDCType.H b/src/sbefw/core/sbeFFDCType.H new file mode 100644 index 00000000..b32f4d8e --- /dev/null +++ b/src/sbefw/core/sbeFFDCType.H @@ -0,0 +1,108 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbeFFDCType.H $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* */ +/* */ +/* 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 __SBE_FFDC_TYPE_H +#define __SBE_FFDC_TYPE_H + +//Bit mapped identifiers +#define SBE_FFDC_ATTR_DUMP 0x0001 +#define SBE_FFDC_TRACE_DUMP 0x0002 +#define SBE_FFDC_ALL_DUMP 0xFFFF + +enum SBE_FFDC_DD_LEVEL +{ + SBE_FFDC_DD1 = 0, + SBE_FFDC_DD2 = 1 +}; + +/* Structure indicating the contents of FFDC package + * value 'true' - field present;value 'false' - field not present + * bit_0 - attribute dump + * bit_1 - trace buffer dump + * bit 2-31 - reserved + */ +typedef struct +{ + uint32_t attrField:1; + uint32_t traceField:1; + uint32_t reserved:30; + /* @breif - set dump fields + * + * @param[in] - uint32_t value to be updated + */ + void set(uint32_t val) + { + if(val & SBE_FFDC_ATTR_DUMP) + { + attrField = true; + } + if(val & SBE_FFDC_TRACE_DUMP) + { + traceField = true; + } + } + /* @brief - get dump fields as uint32_t + * + * @return - uint32_t value + */ + uint32_t get() + { + uint32_t l_val = 0; + if(attrField) + { + l_val |= SBE_FFDC_ATTR_DUMP; + } + if(traceField) + { + l_val |= SBE_FFDC_TRACE_DUMP; + } + return l_val; + } +} sbeFFDCDumpFields_t; + +//Sturcture indicating the type of ffdc user data blob +//and its length in bytes +typedef struct +{ + uint32_t fieldId:16; + uint32_t fieldLen:16; +} sbeFFDCUserDataIdentifier_t; + +//Structure of ffdc user data blob +typedef struct +{ + sbeFFDCUserDataIdentifier_t userDataId; + const void *userDataPtr; +} sbeFFDCUserData_t; + +//keep it packed to 4byte boundary to avoid packing bytes +typedef struct +{ + uint32_t primaryStatus:16;//Chip Op Primary status + uint32_t secondaryStatus:16;//Chip Op Secondary status + uint32_t fwCommitID;// FW commit ID + uint32_t ddLevel;// DD level of the SBE + sbeFFDCDumpFields_t dumpFields;//bitmapped dumpFields +} sbeFFDCDataHeader_t; + +#endif //__SBE_FFDC_TYPE_H diff --git a/src/sbefw/core/sbeFifoMsgUtils.C b/src/sbefw/core/sbeFifoMsgUtils.C new file mode 100644 index 00000000..41d2ca20 --- /dev/null +++ b/src/sbefw/core/sbeFifoMsgUtils.C @@ -0,0 +1,401 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbeFifoMsgUtils.C $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2017 */ +/* */ +/* */ +/* 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: ppe/sbe/sbefw/sbeFifoMsgUtils.C + * + * @brief This file contains the SBE FIFO Access Common Utility Functions + * + */ + +#include "sbefifo.H" +#include "sbetrace.H" +#include "sbe_sp_intf.H" +#include "sbeFifoMsgUtils.H" +#include "sbeerrorcodes.H" +#include "plat_hw_access.H" +#include "assert.h" +#include "sbeFFDC.H" +#include "hwp_error_info.H" +#include "sbeglobals.H" + +// If we can not perform FIFO operation ( FIFO FULL while writing +// or EMPTY while reading ) we will sleep for FIFO_WAIT_SLEEP_TIME +// ms so that FIFO can be ready. +static const uint32_t FIFO_WAIT_SLEEP_TIME = 1; +// Write this data to send EOT to DS FIFO. The register to send EOT +// is 32 bit only. But our scom operations are 64 bit. So set a bit +// in higher word to trigger EOT. +static const uint64_t DOWNSTREAM_EOT_DATA = 0x100000000ull; + +using namespace fapi2; +inline uint32_t sbeBuildRespHeaderStatusWordGlobal (void) +{ + return ( (((uint32_t)SBE_GLOBAL->sbeCmdRespHdr.prim_status)<<16) | + (SBE_GLOBAL->sbeCmdRespHdr.sec_status) ); +} +////////////////////////////////////////////////////// +////////////////////////////////////////////////////// +uint32_t sbeUpFifoDeq_mult (uint32_t &io_len, + uint32_t *o_pData, + const bool i_isEotExpected, + const bool i_flush) +{ + #define SBE_FUNC " sbeUpFifoDeq_mult " + uint32_t l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + uint32_t l_len = 0; + + // If Caller didn't request flush operation + // and passed a non-zero valid length, we + // would expect a valid buffer + if ((!i_flush) && (io_len > 0)) + { + assert ( NULL != o_pData) + } + + do + { + sbeFifoEntry_t l_data = {0}; + + // Read Double word from the Upstream FIFO; + // The DW data represents the first 32 bits of data word entry + // followed by the status bits. + + // Bit 0-31 : Data + // Bit 32 : Data valid flag + // Bit 33 : EOT flag + // Bit 34-63 : Status (2-31) + // Valid : EOT + // 1 : 0 -> data=message + // 0 : 1 -> data=dummy_data of EOT operation + // 0 : 0 -> data=dummy_data + // 1 : 1 -> Not used + + l_rc = sbeUpFifoDeq ( reinterpret_cast<uint64_t*>(&l_data) ); + + if (l_rc) + { + // Error while dequeueing from upstream FIFO + SBE_ERROR(SBE_FUNC"sbeUpFifoDeq failed," + "l_rc=[0x%08X]", l_rc); + // @TODO RTC via : 132295 + // RC refactoring - reserve 3 bits in SBE RC for PCBPIB + l_rc = SBE_SEC_FIFO_ACCESS_FAILURE; + break; + } + + SBE_DEBUG(SBE_FUNC"sbeUpFifoDeq, " + "fifo_data:0x%08X, status:0x%08X", + l_data.fifo_data, l_data.status); + + // If FIFO reset is requested + if(l_data.statusOrReserved.req_upfifo_reset) + { + // @TODO via RTC : 126147 + // Review reset loop flow in here. + // Received a FIFO reset request + l_rc = SBE_FIFO_RESET_RECEIVED; + break; + } + + // if EOT flag is set, clear EOT and + // set the RC accordingly + if (l_data.statusOrReserved.eot_flag) + { + l_rc = sbeUpFifoAckEot(); + if (l_rc) + { + // Error while ack'ing EOT in upstream FIFO + SBE_ERROR(SBE_FUNC"sbeUpFifoAckEot failed," + "l_rc=[0x%08X]", l_rc); + + // Collect FFDC and save off the l_rc + l_rc = SBE_SEC_FIFO_ACCESS_FAILURE; + break; + } + + // Successfully Ack'ed the EOT in upstream FIFO + if ( ((!i_isEotExpected) || (l_len != io_len)) + && (!i_flush) ) + { + SBE_ERROR(SBE_FUNC" Actual length:0x%08X Expected len:0x%08X", + l_len, io_len ); + if (l_len < io_len) + { + // Unexpected EOT, got insufficient data + l_rc = SBE_SEC_UNEXPECTED_EOT_INSUFFICIENT_DATA ; + } + else + { + // Unexpected EOT, got excess data + l_rc = SBE_SEC_UNEXPECTED_EOT_EXCESS_DATA ; + } + } + break; + } + + // Check valid flag + if ( !l_data.statusOrReserved.valid_flag ) + { + if( l_data.statusOrReserved.parity_err ) + { + SBE_ERROR(SBE_FUNC"Parity error while reading FIFO." + " FIFO status: 0x%08X"); + l_rc = SBE_SEC_FIFO_PARITY_ERROR; + break; + } + // We can reach here because FIFO was empty. We can not trust + // empty flag because empty flag tells the status of FIFO after + // operation not at the time of operation + if( SBE::isSimicsRunning() ) + { + // sleep if simics is running. Otherwise simics becomes + // 99 % busy and fsp does not get a chance to do operation + // over FIFO. + pk_sleep(PK_MILLISECONDS(FIFO_WAIT_SLEEP_TIME)); + } + continue; + } + + if ((!i_flush) && (l_len < io_len)) + { + o_pData[l_len] = l_data.fifo_data; + } + + ++l_len; + + } while(i_flush || i_isEotExpected || (l_len < io_len)); + + // Return the length of entries dequeued. + io_len = l_len; + return l_rc; + + #undef SBE_FUNC +} + +////////////////////////////////////////////////////// +////////////////////////////////////////////////////// +uint32_t sbeDownFifoEnq_mult (uint32_t &io_len, + const uint32_t *i_pData) +{ + #define SBE_FUNC " sbeDownFifoEnq_mult " + uint32_t l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + uint32_t l_len = 0; + + do + { + sbeDownFifoStatusReg_t l_status = {0}; + + // Read the down stream FIFO status + l_rc = sbeDownFifoGetStatus (reinterpret_cast<uint64_t *>(&l_status)); + if (l_rc) + { + // Error while reading downstream FIFO status + SBE_ERROR(SBE_FUNC"sbeDownFifoGetStatus failed, " + "l_rc=[0x%08X]", l_rc); + l_rc = SBE_SEC_FIFO_ACCESS_FAILURE; + break; + } + + // Check if there was a FIFO reset request from SP + if (l_status.downfifo_status.req_upfifo_reset) + { + // @TODO via RTC : 126147 + // Review reset loop flow in here. + // Received an upstream FIFO reset request + SBE_ERROR(SBE_FUNC"Received reset request"); + l_rc = SBE_FIFO_RESET_RECEIVED; + break; + } + + // Check if downstream FIFO is full + if (l_status.downfifo_status.fifo_full) + { + // Downstream FIFO is full + if( SBE::isSimicsRunning() ) + { + // sleep if simics is running. Otherwise simics becomes + // 99 % busy and fsp does not get a chance to do operation + // over FIFO. + pk_sleep(PK_MILLISECONDS(FIFO_WAIT_SLEEP_TIME)); + } + continue; + } + + // PIB write data format: + // Bit 0 - 31 : Data + // Bit 32 - 63 : Unused + + sbeFifoEntry_t l_data = {0}; + + l_data.fifo_data = *(i_pData+l_len); + + SBE_DEBUG(SBE_FUNC"Downstream fifo data entry[0x%08X]", + l_data.fifo_data); + + // Write the data into the downstream FIFO + uint64_t * tp = reinterpret_cast<uint64_t*>(&l_data); + l_rc = sbeDownFifoEnq ( *tp ); + if (l_rc) + { + SBE_ERROR(SBE_FUNC"sbeDownFifoEnq failed, " + "l_rc[0x%08X]", l_rc); + // @TODO RTC via : 132295 + // RC refactoring - reserve 3 bits in SBE RC for PCBPIB + l_rc = SBE_SEC_FIFO_ACCESS_FAILURE; + break; + } + + ++l_len; + + } while(l_len<io_len); + + io_len = l_len; + return l_rc; + #undef SBE_FUNC +} + +//////////////////////////////////////////////////////// +//////////////////////////////////////////////////////// +uint32_t sbeDownFifoSignalEot (void) +{ + uint32_t l_rc = 0; + #define SBE_FUNC "sbeDownFifoSignalEot " + SBE_ENTER(SBE_FUNC); + sbeDownFifoStatusReg_t l_status = {0}; + do + { + // Read the down stream FIFO status + l_rc = sbeDownFifoGetStatus (reinterpret_cast<uint64_t *>(&l_status)); + if (l_rc) + { + // Error while reading downstream FIFO status + SBE_ERROR(SBE_FUNC"sbeDownFifoGetStatus failed, " + "l_rc=[0x%08X]", l_rc); + l_rc = SBE_SEC_FIFO_ACCESS_FAILURE; + break; + } + + // Check if downstream FIFO is full + if (l_status.downfifo_status.fifo_full) + { + if( SBE::isSimicsRunning() ) + { + // sleep if simics is running. Otherwise simics becomes + // 99 % busy and fsp does not get a chance to do operation + // over FIFO. + pk_sleep(PK_MILLISECONDS(FIFO_WAIT_SLEEP_TIME)); + } + continue; + } + l_rc = putscom_abs(SBE_DOWNSTREAM_FIFO_SIGNAL_EOT, DOWNSTREAM_EOT_DATA); + break; + } while(1); + + + SBE_EXIT(SBE_FUNC); + return l_rc; + #undef SBE_FUNC +} + + +uint32_t sbeDsSendRespHdr(const sbeRespGenHdr_t &i_hdr, + sbeResponseFfdc_t *i_ffdc ) +{ + #define SBE_FUNC "sbeDsSendRespHdr " + uint32_t rc = SBE_SEC_OPERATION_SUCCESSFUL; + do + { + uint32_t distance = 1; //initialise by 1 for entry count itself. + uint32_t len = sizeof( i_hdr )/sizeof(uint32_t); + // sbeDownFifoEnq_mult. + rc = sbeDownFifoEnq_mult ( len, ( uint32_t *) &i_hdr); + if (rc) + { + break; + } + distance += len; + + // If no ffdc , exit; + if( (i_ffdc != NULL) && (i_ffdc->getRc() != FAPI2_RC_SUCCESS)) + { + SBE_ERROR( SBE_FUNC" FAPI RC:0x%08X", i_ffdc->getRc()); + // making sure ffdc length is multiples of uint32_t + assert((g_FfdcData.ffdcLength % sizeof(uint32_t)) == 0); + uint32_t ffdcDataLenInWords = g_FfdcData.ffdcLength + / sizeof(uint32_t); + // Set failed command information + // Sequence Id is 0 by default for Fifo interface + i_ffdc->setCmdInfo(0, i_hdr.cmdClass, i_hdr.command); + // Add HWP specific ffdc data length + i_ffdc->lenInWords += ffdcDataLenInWords; + len = sizeof(sbeResponseFfdc_t)/sizeof(uint32_t); + rc = sbeDownFifoEnq_mult ( len, ( uint32_t *) i_ffdc); + if (rc) + { + break; + } + distance += len; + + // Send HWP ffdc data + rc = sbeDownFifoEnq_mult ( ffdcDataLenInWords, + ( uint32_t *) &g_FfdcData.ffdcData); + if (rc) + { + break; + } + distance += ffdcDataLenInWords; + } + + // If there is a SBE internal failure + if((i_hdr.primaryStatus != SBE_PRI_OPERATION_SUCCESSFUL) ||\ + (i_hdr.secondaryStatus != SBE_SEC_OPERATION_SUCCESSFUL)) + { + SBE_ERROR( SBE_FUNC" primaryStatus:0x%08X secondaryStatus:0x%08X", + (uint32_t)i_hdr.primaryStatus, + (uint32_t)i_hdr.secondaryStatus); + + //Add FFDC data as well. + //Generate all the fields of FFDC package + SbeFFDCPackage sbeFfdc; + rc = sbeFfdc.sendOverFIFO(i_hdr, + SBE_FFDC_ALL_DUMP, + len); + if (rc) + { + break; + } + distance += len; + } + + len = sizeof(distance)/sizeof(uint32_t); + rc = sbeDownFifoEnq_mult ( len, &distance); + if (rc) + { + break; + } + + }while(0); + return rc; + #undef SBE_FUNC +} diff --git a/src/sbefw/core/sbeFifoMsgUtils.H b/src/sbefw/core/sbeFifoMsgUtils.H new file mode 100644 index 00000000..214b65e5 --- /dev/null +++ b/src/sbefw/core/sbeFifoMsgUtils.H @@ -0,0 +1,149 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbeFifoMsgUtils.H $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* */ +/* */ +/* 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: ppe/sbe/sbefw/sbeFifoMsgUtils.H + * + * @brief This file contains the SBE FIFO Access Common Utility Functions + * + */ + +#ifndef __SBEFW_SBEFIFOMSGUTILS_H +#define __SBEFW_SBEFIFOMSGUTILS_H + +#include <stdint.h> +#include "sbeexeintf.H" + + +/**********************************************************************/ +// SBE Utilities +/**********************************************************************/ + +/** + * @brief sbeUpFifoDeq_mult : Dequeue multiple entries from upstream FIFO + * + * @param[in/out] io_len + * On input: Non-zero number of entries (excluding EOT) to dequeue. + * Ignored when i_flush == true. + * On output: Number of entries dequeued (excluding EOT). + * @param[out] o_pData Entries dequeued into the buffer + * @param[in] i_isEotExpected true / false + * true - Default case. + * Caller expects an EOT entry after io_len entries are + * dequeued. Accordingly, this function will attempt to dequeue + * the EOT entry after io_len entries are dequeued. + * false - Caller doesn't expect an EOT after io_len entries are + * dequeued. Accordingly, this function will not attempt to + * dequeue the EOT entry after io_len entries are dequeued. + * @param[in] i_flush true / false + * true - caller requested FIFO flush + * Usually caller marks this flag as true to handle error scenario. + * All entries written in the US fifo (until an EOT is encountered), + * would be dequeued and discarded (not processed). Note that io_len + * and i_isEotExpected inputs are ignored in this case. + * However, flag i_isEotExpected is always interpreted as true in + * case. + * false - Default good path. + * US Fifo entries will be dequeued and processed per inputs io_len + * and i_isEotExpected. + * + * @return Return Code SUCCESS or a secondary response code + * SBE_SEC_OPERATION_SUCCESSFUL + * SBE_SEC_FIFO_ACCESS_FAILURE + * SBE_SEC_UNEXPECTED_EOT_INSUFFICIENT_DATA + * SBE_SEC_UNEXPECTED_EOT_EXCESS_DATA + * SBE_FIFO_RESET_RECEIVED + * + */ +extern uint32_t sbeUpFifoDeq_mult (uint32_t &io_len, + uint32_t *o_pData, + const bool i_isEotExpected = true, + const bool i_flush = false); + + +/** + * @brief sbeDownFifoEnq_mult : Enqueue into downstream FIFO + * + * @param[in/out] io_len number of entries to enqueue as input, + * number of entries enqueued as output + * @param[in] i_pData buffer containting data to be enqueued + * + * @return Rc SUCCESS or a secondary response code + * SBE_SEC_OPERATION_SUCCESSFUL + * SBE_SEC_FIFO_ACCESS_FAILURE + * SBE_FIFO_RESET_RECEIVED + * + */ +extern uint32_t sbeDownFifoEnq_mult (uint32_t &io_len, + const uint32_t *i_pData) ; + +/** + * @brief sbeBuildRespHeaderStatusWordGlobal + * Builds the status header word from global variables + * + * @return Returns the status word in the response header + * + */ +extern inline uint32_t sbeBuildRespHeaderStatusWordGlobal (void); + +/** + * @brief sbeBuildRespHeaderStatusWordLocal + * Builds the status header word from passed in parameters + * + * @param[in] const uint16_t i_primStatus Primary Response Status Code + * @param[in] const uint16_t i_secStatus Secondary Response Status Code + * + * @return Returns the status word in the response header + * + */ +extern inline uint32_t sbeBuildRespHeaderStatusWordLocal ( + const uint16_t i_primStatus, + const uint16_t i_secStatus) +{ + return ( (((uint32_t)i_primStatus)<<16) | (i_secStatus) ); +} + +/** + * @brief sbeDownFifoSignalEot : Signal EOT in Downstream FIFO + * + * @return Rc from the underlying scom utility + * + * @note This is a blocking call. If FIFO is full, it will wait + * in loop ( sleep ) till the time there is some space in + * FIFO. + */ +uint32_t sbeDownFifoSignalEot (void); + +/** + * @brief sbeDsSendRespHdr : Send response header to DS FIFO + * - This also sends the FFDC if exist. + * + * @param[in] i_hdr Response Header + * @param[in] i_ffdc Pointer to FFDC object, if NULL FFDC package + * is not sent in the chip op response + * + * @return Rc from the underlying scom utility + */ +uint32_t sbeDsSendRespHdr(const sbeRespGenHdr_t &i_hdr, + sbeResponseFfdc_t *i_ffdc=NULL ); +#endif // __SBEFW_SBEFIFOMSGUTILS_H diff --git a/src/sbefw/core/sbeHostMsg.C b/src/sbefw/core/sbeHostMsg.C new file mode 100644 index 00000000..46ff5189 --- /dev/null +++ b/src/sbefw/core/sbeHostMsg.C @@ -0,0 +1,35 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbeHostMsg.C $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2017 */ +/* */ +/* */ +/* 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 "sbetrace.H" +#include "sbeHostMsg.H" +#include "sbeglobals.H" + +void sbeSbe2PsuRespHdr_t::init(void) +{ + primStatus = SBE_PRI_OPERATION_SUCCESSFUL; + secStatus = SBE_SEC_OPERATION_SUCCESSFUL; + seqID = SBE_GLOBAL->sbePsu2SbeCmdReqHdr.seqID; + cmdClass = SBE_GLOBAL->sbePsu2SbeCmdReqHdr.cmdClass; + command = SBE_GLOBAL->sbePsu2SbeCmdReqHdr.command; +} diff --git a/src/sbefw/core/sbeHostMsg.H b/src/sbefw/core/sbeHostMsg.H new file mode 100644 index 00000000..d6bd8576 --- /dev/null +++ b/src/sbefw/core/sbeHostMsg.H @@ -0,0 +1,184 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbeHostMsg.H $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* */ +/* */ +/* 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: ppe/sbe/sbefw/sbeHostMsg.H + * + * @brief This file contains the message structures for SBE Host + * communication. + * + */ + +#ifndef __SBEFW_SBEHOST_MSG_H +#define __SBEFW_SBEHOST_MSG_H + +#include <stdint.h> +#include "sbe_host_intf.H" +#include "sbe_sp_intf.H" +#include "sbe_link.H" + +/*****************************************************************/ +/* SBE->PSU request structures */ +/*****************************************************************/ + +/** + * @brief structure for Host->SBE command request format denoting + * mininum header (as of now, contained in mbx 0) + */ +typedef struct +{ + // mbxReg0 + uint64_t res:16; + uint64_t flags:16; + uint64_t seqID:16; + uint64_t cmdClass:8; + uint64_t command:8; + + /** + * @brief initialize the fields contained in PSU Mbx0 + * + */ + void init() + { + res = 0; + flags = 0; + seqID = 0; + cmdClass = SBE_PSU_CMD_CLASS_UNKNOWN; + command = SBE_PSU_CMD_UNKNOWN; + } +} sbePsu2SbeCmdReqHdr_t; + +/* @brief Address and size of memory allocated by Host + * for FFDC/pass through commands + */ +typedef struct +{ + uint32_t size; + uint64_t addr; +} sbeHostAddr_t; + +/* @brief Set FFDC Address message + */ +typedef struct +{ + uint64_t ffdcDataSize:32; + uint64_t passCmdDataSize:32; + uint64_t ffdcAddr; + uint64_t passCmdDataAddr; + + void getFFDCAddr(sbeHostAddr_t &i_hostFFDCAddr) + { + i_hostFFDCAddr.size = ffdcDataSize; + i_hostFFDCAddr.addr = ffdcAddr; + } + + void getPassThroughCmdAddr(sbeHostAddr_t &i_hostPassCmdAddr) + { + i_hostPassCmdAddr.size = passCmdDataSize; + i_hostPassCmdAddr.addr = passCmdDataAddr; + } +} sbeSetFFDCAddrReq_t; + +/* @brief Read SBE MEM structure + */ +typedef struct +{ + uint64_t offset:32; + uint64_t size:32; + uint64_t responseAddr; + + // validate request parameters + bool validateReq() + { + // On ppe reading 8 bytes is optimal. So offset + // should be multiple of 8. + uint32_t const OFFSET_ALLIGNMENT = 8; + // As we use PBA operation, size should be multiple + // of 128bytes. + uint32_t const SIZE_ALLIGNMENT = 128; + // There are 4 seeprom devices each of 64KB, + // aso there is 1 ecc byte per 8 bytes of data + uint32_t const MAX_SEEPROM_SIZE = ((65536 - (65536 % 9)) / 9) * 8 * 4; + + return ( !(( offset % OFFSET_ALLIGNMENT != 0) || + ( size % SIZE_ALLIGNMENT != 0 ) || + ( ( offset + size ) > MAX_SEEPROM_SIZE )) ); + } + // Return effective seeprom address + uint64_t * getEffectiveAddr() + { + return ( uint64_t *)( SBE_SEEPROM_BASE_ORIGIN + offset ); + } +} sbeReadMemReq_t; + +/*****************************************************************/ +/* SBE->PSU response structures */ +/*****************************************************************/ + +/** + * @brief SBE->Host Generic response structure + * + */ +typedef struct +{ + uint64_t mbxReg4; + uint64_t mbxReg5; + uint64_t mbxReg6; + uint64_t mbxReg7; +} sbeSbe2PsuGenericResp_t ; + +/** + * @brief Structure for SBE->Host response header contained in + * mbx4 register + * + */ +typedef struct +{ + // mbxReg 4 + uint64_t primStatus:16; + uint64_t secStatus:16; + uint64_t seqID:16; + uint64_t cmdClass:8; + uint64_t command:8; + + /** + * @brief set the primary and secondary status + * + * @param[in] i_prim Primary status + * @param[in] i_sec Secondary status + * + */ + void setStatus(const uint16_t i_prim, const uint16_t i_sec) + { + primStatus = i_prim; + secStatus = i_sec; + } + + /** + * @brief initialize the response fields contained in PSU Mbx3 + * + */ + void init(); +} sbeSbe2PsuRespHdr_t; + +#endif // __SBEFW_SBEHOST_MSG_H diff --git a/src/sbefw/core/sbeHostUtils.C b/src/sbefw/core/sbeHostUtils.C new file mode 100644 index 00000000..ea0605a3 --- /dev/null +++ b/src/sbefw/core/sbeHostUtils.C @@ -0,0 +1,323 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbeHostUtils.C $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* */ +/* */ +/* 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: ppe/sbe/sbefw/sbeHostUtils.C + * + * @brief This file contains the PSU Access Utility Functions + * + */ + +#include "sbetrace.H" +#include "sbe_sp_intf.H" +#include "sbeHostUtils.H" +#include "sbeHostMsg.H" +#include "sbe_host_intf.H" +#include "sbeerrorcodes.H" +#include "assert.h" +#include "fapi2.H" +#include "sbeglobals.H" +#include "sbeMemAccessInterface.H" +#include "sbeFFDC.H" +#include "hwp_error_info.H" +#include "sberegaccess.H" + +/////////////////////////////////////////////////////////////////// +// PSU->SBE register access utilities +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////// +uint32_t sbeReadPsu2SbeMbxReg (uint32_t i_addr, + const uint8_t i_count, + uint64_t *o_pData, + bool i_isFinalRead) +{ + #define SBE_FUNC " sbeReadPsu2SbeMbxReg " + SBE_DEBUG(SBE_FUNC"i_count[0x%02X], i_addr=[0x%08X]", i_count, i_addr); + + uint32_t l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + uint8_t l_count = 0; + + assert((i_count >0 ) && (NULL != o_pData)) + assert( (SBE_HOST_PSU_MBOX_REG0 <= i_addr) && + (SBE_HOST_PSU_MBOX_REG3 >= (i_addr + i_count - 1)) ) + + while (l_count < i_count) + { + l_rc = getscom_abs ( i_addr, + reinterpret_cast<uint64_t*>(&o_pData[l_count]) ); + + if (l_rc) + { + // Error while reading from PSU->SBE mbx register + SBE_ERROR(SBE_FUNC"getscom_abs failed," + "l_rc=[0x%08X], i_addr=[0x%08X]", + l_rc, i_addr); + break; + } + + SBE_DEBUG(SBE_FUNC"l_data=[0x%08X%08X]", + SBE::higher32BWord(o_pData[l_count]), + SBE::lower32BWord(o_pData[l_count])); + ++l_count; + ++i_addr; + } + + // Set the Ack bit in SBE->PSU DB register + // if the message requires ack and if its a final read operation + if ((i_isFinalRead) && (SBE_SEC_OPERATION_SUCCESSFUL == l_rc)) + { + l_rc = sbeAcknowledgeHost(); + if (l_rc) + { + SBE_ERROR(SBE_FUNC " Failed to Sent Ack to Host over " + "SBE_SBE2PSU_DOORBELL_SET_BIT1"); + } + } + return l_rc; + + #undef SBE_FUNC +} + +/////////////////////////////////////////////////////////////////// +// SBE->PSU register access utilities +/////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////// +uint32_t sbeIntrHostUponRespWaiting () +{ + uint32_t l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + + // Interrupt the host by setting bit0 in SBE->PSU DB register + // if the caller requested for it. + if (SBE_GLOBAL->sbePsu2SbeCmdReqHdr.flags & SBE_PSU_FLAGS_RESP_REQUIRED) + { + l_rc = sbeSetSbe2PsuDbBitX(SBE_SBE2PSU_DOORBELL_SET_BIT0); + } + return l_rc; +} + +/////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////// +uint32_t sbeAcknowledgeHost () +{ + uint32_t l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + + // Set the Ack bit in SBE->PSU DB register + // if the caller requested for it. + if (SBE_GLOBAL->sbePsu2SbeCmdReqHdr.flags & SBE_PSU_FLAGS_ACK_REQUIRED) + { + l_rc = sbeSetSbe2PsuDbBitX(SBE_SBE2PSU_DOORBELL_SET_BIT1); + } + return l_rc; +} + +/////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////// +uint32_t sbeWriteSbe2PsuMbxReg (uint32_t i_addr, + const uint64_t *i_pData, + const uint8_t i_count, + bool i_setBit0ToIntrHB) +{ + #define SBE_FUNC " sbeWriteSbe2PsuMbxReg " + SBE_DEBUG(SBE_FUNC"i_count[0x%02X], i_addr=[0x%08X]", i_count, i_addr); + uint32_t l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + uint8_t l_count = 0; + + assert( (i_count >0 ) && (NULL != i_pData) ) + assert( (SBE_HOST_PSU_MBOX_REG4 <= i_addr) && + (SBE_HOST_PSU_MBOX_REG7 >= (i_addr + i_count - 1)) ) + + if( SBE_GLOBAL->sbePsu2SbeCmdReqHdr.flags & SBE_PSU_FLAGS_RESP_REQUIRED ) + { + while (l_count < i_count) + { + SBE_DEBUG(SBE_FUNC"l_data=[0x%08X%08X]", + SBE::higher32BWord(*(i_pData+l_count)), + SBE::lower32BWord(*(i_pData+l_count))); + + l_rc = putscom_abs ( i_addr, *(i_pData+l_count) ); + if (l_rc) + { + // Error while reading from PSU->SBE mbx register + SBE_ERROR(SBE_FUNC"putscom_abs failed," + "l_rc=[0x%08X], i_addr=[0x%08X]", + l_rc, i_addr); + break; + } + + ++l_count; + ++i_addr; + } + + if( (i_setBit0ToIntrHB) && (SBE_SEC_OPERATION_SUCCESSFUL == l_rc) ) + { + // indicate the Host via Bit SBE_SBE2PSU_DOORBELL_SET_BIT0 + l_rc = sbeSetSbe2PsuDbBitX(SBE_SBE2PSU_DOORBELL_SET_BIT0); + if(l_rc) + { + SBE_ERROR(SBE_FUNC " Failed to Sent Ack to Host over " + "SBE_SBE2PSU_DOORBELL_SET_BIT0"); + } + } + } + return l_rc; + + #undef SBE_FUNC +} + +/* @brief - Send PSU Chip Op response + * + * @param[in] - i_sbe2PsuRespHdr - Response header + * @param[in] - i_fapiRc - fapi rc of the relevant hwp call + * @param[in/out] - io_rc - rc status of the PSU access utility + * + * @return - void + */ +void sbePSUSendResponse(sbeSbe2PsuRespHdr_t &i_sbe2PsuRespHdr, + uint32_t &i_fapiRc, + uint32_t &io_rc) +{ +#define SBE_FUNC "sbePSUSendResponse" + SBE_ENTER(SBE_FUNC); + do + { + // Making sure the PSU access utility is functional + if(io_rc != SBE_SEC_OPERATION_SUCCESSFUL) + { + break; + } + + uint32_t l_allocatedSize = SBE_GLOBAL->hostFFDCAddr.size; + bool l_is_lastAccess = false; + // Default EX Target Init..Not changing it for the time being + fapi2::Target<fapi2::TARGET_TYPE_EX> l_ex( + fapi2::plat_getTargetHandleByChipletNumber<fapi2::TARGET_TYPE_EX>( + sbeMemAccessInterface::PBA_DEFAULT_EX_CHIPLET_ID)); + p9_PBA_oper_flag l_myPbaFlag; + l_myPbaFlag.setOperationType(p9_PBA_oper_flag::INJ); + + sbeMemAccessInterface l_PBAInterface( + SBE_MEM_ACCESS_PBA, + SBE_GLOBAL->hostFFDCAddr.addr, + &l_myPbaFlag, + SBE_MEM_ACCESS_WRITE, + sbeMemAccessInterface::PBA_GRAN_SIZE_BYTES, + l_ex); + + bool l_internal_ffdc_present = ((i_sbe2PsuRespHdr.primStatus != + SBE_PRI_OPERATION_SUCCESSFUL) || + (i_sbe2PsuRespHdr.secStatus != + SBE_SEC_OPERATION_SUCCESSFUL)); + + // If no ffdc , exit; + sbeResponseFfdc_t l_ffdc; + l_ffdc.setRc(i_fapiRc); + if(l_ffdc.getRc() != fapi2::FAPI2_RC_SUCCESS) + { + // Clear global fapi2::current_err so that + // FFDC can be sent over PBA interface. + // We are good with HWP ffdc, as + // g_FfdcData.fapiRc is a copy of current_err + fapi2::current_err = fapi2::FAPI2_RC_SUCCESS; + + i_sbe2PsuRespHdr.setStatus(SBE_PRI_GENERIC_EXECUTION_FAILURE, + SBE_SEC_GENERIC_FAILURE_IN_EXECUTION); + l_internal_ffdc_present = true; + + SBE_ERROR( SBE_FUNC" FAPI RC:0x%08X", l_ffdc.getRc()); + SBE_INFO(SBE_FUNC" FFDC memory - addr[0x%08X%08X] size[%d]bytes", + static_cast<uint32_t>(SBE::higher32BWord(SBE_GLOBAL->hostFFDCAddr.addr)), + static_cast<uint32_t>(SBE::lower32BWord(SBE_GLOBAL->hostFFDCAddr.addr)), + SBE_GLOBAL->hostFFDCAddr.size); + uint32_t ffdcDataLenInWords = fapi2::g_FfdcData.ffdcLength + / sizeof(uint32_t); + // Set failed command information + l_ffdc.setCmdInfo(i_sbe2PsuRespHdr.seqID, + i_sbe2PsuRespHdr.cmdClass, + i_sbe2PsuRespHdr.command); + // Add HWP specific ffdc data length + l_ffdc.lenInWords += ffdcDataLenInWords; + + uint32_t len = sizeof(sbeResponseFfdc_t); + MEM_AVAILABLE_CHECK(l_allocatedSize, len, l_is_lastAccess); + fapi2::ReturnCode l_fapiRc = l_PBAInterface.accessWithBuffer( + &l_ffdc, + len, + l_is_lastAccess); + if(l_fapiRc != fapi2::FAPI2_RC_SUCCESS) + { + io_rc = SBE_SEC_GENERIC_FAILURE_IN_EXECUTION; + break; + } + MEM_AVAILABLE_CHECK(l_allocatedSize, + ffdcDataLenInWords, + l_is_lastAccess); + l_is_lastAccess = l_is_lastAccess || + !l_internal_ffdc_present || + !SbeRegAccess::theSbeRegAccess().isSendInternalFFDCSet(); + l_fapiRc = l_PBAInterface.accessWithBuffer( + &fapi2::g_FfdcData.ffdcData, + ffdcDataLenInWords, + l_is_lastAccess); + if(l_fapiRc != fapi2::FAPI2_RC_SUCCESS) + { + io_rc = SBE_SEC_GENERIC_FAILURE_IN_EXECUTION; + break; + } + } + + // Send SBE internal ffdc if there is enough memory allocated + if(l_internal_ffdc_present) + { + SBE_ERROR( SBE_FUNC" primaryStatus:0x%08X secondaryStatus:0x%08X", + (uint32_t)i_sbe2PsuRespHdr.primStatus, + (uint32_t)i_sbe2PsuRespHdr.secStatus); + // SBE internal FFDC package + SbeFFDCPackage sbeFfdc; + //Generate all the fields of FFDC package + io_rc = sbeFfdc.sendOverHostIntf(i_sbe2PsuRespHdr, + SBE_FFDC_ALL_DUMP, + &l_PBAInterface, + l_allocatedSize); + if (io_rc) + { + break; + } + } + + // Send the response header + io_rc = sbeWriteSbe2PsuMbxReg(SBE_HOST_PSU_MBOX_REG4, + (uint64_t*)(&i_sbe2PsuRespHdr), + (sizeof(i_sbe2PsuRespHdr)/sizeof(uint64_t)), + true); + if(SBE_SEC_OPERATION_SUCCESSFUL != io_rc) + { + SBE_ERROR(SBE_FUNC" Failed to write to " + "SBE_HOST_PSU_MBOX_REG4"); + } + } while(0); +#undef SBE_FUNC +} diff --git a/src/sbefw/core/sbeHostUtils.H b/src/sbefw/core/sbeHostUtils.H new file mode 100644 index 00000000..3ffa48e1 --- /dev/null +++ b/src/sbefw/core/sbeHostUtils.H @@ -0,0 +1,255 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbeHostUtils.H $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* */ +/* */ +/* 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: ppe/sbe/sbefw/sbeHostUtils.H + * + * @brief This file contains basic SBE PSU hardware specific + * definitions and operations. + * + */ + +#ifndef __SBEFW_SBEHOSTUTILS_H +#define __SBEFW_SBEHOSTUTILS_H + +#include <stdint.h> +#include "ppe42_scom.h" +#include "sbeHostMsg.H" + +/** + * @brief SBE PSU Access register addresses + * + */ +const uint32_t SBE_HOST_PSU_BASE = 0x000D0050; + +const uint32_t SBE_HOST_PSU_MBOX_REG0 = SBE_HOST_PSU_BASE + 0x0000; +const uint32_t SBE_HOST_PSU_MBOX_REG1 = SBE_HOST_PSU_BASE + 0x0001; +const uint32_t SBE_HOST_PSU_MBOX_REG2 = SBE_HOST_PSU_BASE + 0x0002; +const uint32_t SBE_HOST_PSU_MBOX_REG3 = SBE_HOST_PSU_BASE + 0x0003; +const uint32_t SBE_HOST_PSU_MBOX_REG4 = SBE_HOST_PSU_BASE + 0x0004; +const uint32_t SBE_HOST_PSU_MBOX_REG5 = SBE_HOST_PSU_BASE + 0x0005; +const uint32_t SBE_HOST_PSU_MBOX_REG6 = SBE_HOST_PSU_BASE + 0x0006; +const uint32_t SBE_HOST_PSU_MBOX_REG7 = SBE_HOST_PSU_BASE + 0x0007; + + +const uint32_t SBE_PSU2SBE_DOORBELL_REG_RW = 0x000D0060; +const uint32_t SBE_PSU2SBE_DOORBELL_REG_AND = 0x000D0061; +const uint32_t SBE_PSU2SBE_DOORBELL_REG_OR = 0x000D0062; +const uint32_t SBE_PSU2HOST_DOORBELL_REG_RW = 0x000D0063; +const uint32_t SBE_PSU2HOST_DOORBELL_REG_AND = 0x000D0064; +const uint32_t SBE_PSU2HOST_DOORBELL_REG_OR = 0x000D0065; + + +/** + * @brief SBE PSU door bell register Bit definitions + */ +typedef enum +{ + // Bit 0 AND flag for PSU->SBE Doorbell Register; + // When this is set by the host firmware, it would trigger an + // interrupt to the SBE about a waiting message in the Host/SBE + // Mailbox Registers. SBE is responsible for clearing this + // bit upon being interrupted. + SBE_PSU2SBE_DOORBELL_CLEAR_BIT0 = 0x7FFFFFFFFFFFFFFFull, +} sbe_psu2sbeDoorbellReg_UpdateFlags; + +typedef enum +{ + // Bit 0 OR flag for SBE->PSU Doorbell Register; + // When this is set by SBE, it would trigger an interrupt to host + // firmware about a waiting response in the Host/SBE Mailbox Registers 4-7 + SBE_SBE2PSU_DOORBELL_SET_BIT0 = 0x8000000000000000ull, + + // Bit 1 OR flag for SBE->PSU Doorbell Register; + // When this is set by SBE, it would trigger an interrupt to host + // firmware indicating that the message in Host/SBE mailbox registers 0-3 + // has been read by SBE and is being processed + SBE_SBE2PSU_DOORBELL_SET_BIT1 = 0x4000000000000000ull, + + // Bit 2 OR flag for SBE->PSU Doorbell Register; + // When this is set by SBE, it would trigger an interrupt to host + // firmware to trigger Stop15 exit on thread 0 on the master core. + // This would be used to trigger hostboot in istep 16 + SBE_SBE2PSU_DOORBELL_SET_BIT2 = 0x2000000000000000ull, + + // Bit 4 OR flag for SBE->PSU Doorbell Register, + // When this is set by SBE, it would trigger an interrupt to host + // firmware to inform that Host Pass through command received. + SBE_SBE2PSU_DOORBELL_SET_BIT4 = 0x0800000000000000ull, + + // Bit 14 OR flag for SBE->PSU Doorbell Register; + // When this is set by SBE, it would trigger an interrupt to host + // firmware to inform that timer has expired. + SBE_SBE2PSU_DOORBELL_SET_BIT14 = 0x0002000000000000ull, + +} sbe_sbe2psuDoorbellReg_UpdateFlags; + + +/*****************************************************************/ +/** PSU->SBE register access utilities **/ +/*****************************************************************/ + +/** + * @brief sbeClearPsu2SbeDbBitX : Clear given bit in PSU->SBE DB register + * + * @param[in] 64-Bit Scom Data indicating bit position to be cleared + * + * @return RC from the underlying scom utility + * + */ +inline uint32_t sbeClearPsu2SbeDbBitX (const uint64_t i_bit) +{ + return putscom_abs (SBE_PSU2SBE_DOORBELL_REG_AND, i_bit) ; +} + + +/** + * @brief sbeReadPsu2SbeDbReg : Read PSU->SBE DB register + * + * @param[out] 64-Bit Data read from PSU->SBE DB register + * + * @return RC from the underlying scom utility + * + */ +inline uint32_t sbeReadPsu2SbeDbReg (uint64_t *o_data) +{ + return getscom_abs (SBE_PSU2SBE_DOORBELL_REG_RW, o_data) ; +} + + +/** + * @brief sbeReadPsu2SbeMbxReg : Read from PSU->SBE MBX register(s) + * + * @param[in] i_addr + * Starting Mbx Register Address + * @param[in] i_count + * Number of Mbx registers to be read. + * @param[in] i_isFinalRead + * Indicates if its a final read operation for this chip op and + * internally handle the ack + * By default it is false. + * @param[out] o_pData + * Contents of the Mbx registers read into the buffer + * @return Return Code + * SUCCESS or TBD + */ +uint32_t sbeReadPsu2SbeMbxReg (uint32_t i_addr, + const uint8_t i_count, + uint64_t *o_pData, + bool i_isFinalRead = false); + +/*****************************************************************/ +/** SBE->PSU register access utilities **/ +/*****************************************************************/ + +/** + * @brief sbeSetSbe2PsuDbBitX : Set Bit-X in SBE->PSU DB register + * + * @param[in] 64-Bit Scom Data indicating bit position + * + * @return RC from the underlying scom utility + * + */ +inline uint32_t sbeSetSbe2PsuDbBitX (const uint64_t i_bit) +{ + return putscom_abs (SBE_PSU2HOST_DOORBELL_REG_OR, i_bit) ; +} + +/** + * @brief sbeClearSbe2PsuDbBitX : Clear Bit-X in SBE->PSU DB register + * + * @param[in] 64-Bit Scom Data indicating bit position + * + * @return RC from the underlying scom utility + * + */ +inline uint32_t sbeClearSbe2PsuDbBitX (const uint64_t i_bit) +{ + return putscom_abs (SBE_PSU2HOST_DOORBELL_REG_AND, i_bit) ; +} + +/** + * @brief sbeReadSbe2PsuDbReg : Read SBE->PSU DB register + * + * @param[out] 64-Bit Data read from SBE->PSU DB register + * + * @return RC from the underlying scom utility + * + */ +inline uint32_t sbeReadSbe2PsuDbReg (uint64_t *o_data) +{ + return getscom_abs (SBE_PSU2HOST_DOORBELL_REG_RW, o_data) ; +} + +/** + * @brief sbeAcknowledgeHost : Acknowldge by setting bit 1 in + * SBE->PSU DB register if the host had requested for an ack + * + * @return RC from the underlying scom utility + * + */ +uint32_t sbeAcknowledgeHost(); + +/** + * @brief sbeIntrHostUponRespWaiting : Interrupt Host by + * setting bit 0 in SBE->PSU DB register if the host had + * requested for response + * + * @return RC from the underlying scom utility + * + */ +uint32_t sbeIntrHostUponRespWaiting(); + + +/** + * @brief sbeWriteSbe2PsuMbxReg : Write to SBE->PSU MBX register(s) + * + * @param[in] i_addr + * Starting Mbx Register Address + * @param[in] i_pData + * Contains the data to be written into given Mbx registers + * @param[in] i_count + * Number of Mbx registers to be written. + * @param[in] i_setBit0ToIntrHB + * Indicates whether to write Bit0 to interrupt the Host, + * By default it is false. + * @return Return Code + * SUCCESS or TBD + */ +uint32_t sbeWriteSbe2PsuMbxReg (uint32_t i_addr, + const uint64_t *i_pData, + const uint8_t i_count, + bool i_setBit0ToIntrHB = false); + +/* @brief - Send PSU Chip Op response + * + * @param[in] - i_sbe2PsuRespHdr - Response header + * @param[in] - i_fapiRc - fapi rc of the relevant hwp call + * @param[in/out] - io_rc - rc status of the PSU access utility + * + * @return - void + */ +void sbePSUSendResponse(sbeSbe2PsuRespHdr_t &i_sbe2PsuRespHdr, + uint32_t &i_fapiRc, + uint32_t &io_rc); +#endif // __SBEFW_SBEHOSTUTILS_H diff --git a/src/sbefw/core/sbeMemAccessInterface.C b/src/sbefw/core/sbeMemAccessInterface.C new file mode 100644 index 00000000..bb341f38 --- /dev/null +++ b/src/sbefw/core/sbeMemAccessInterface.C @@ -0,0 +1,270 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbeMemAccessInterface.C $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* */ +/* */ +/* 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 "sbeMemAccessInterface.H" + +#ifdef SEEPROM_IMAGE +// Using Function pointer to force long call +p9_adu_access_FP_t p9_adu_access_hwp = &p9_adu_access; +p9_adu_setup_FP_t p9_adu_setup_hwp = &p9_adu_setup; +#endif + +using namespace fapi2; + +void MEM_AVAILABLE_CHECK(uint32_t &io_available_len,uint32_t &io_len_to_send,bool &io_is_last_access) +{ + if(io_len_to_send > io_available_len) + { + SBE_INFO(SBE_FUNC" Allocated memory is less, truncating the access"); + io_len_to_send = io_available_len; + io_is_last_access = true; + } + io_available_len -= io_len_to_send; +} + +ReturnCode sbeMemAccessInterface::setup() +{ +#define SBE_FUNC "sbeMemAccessInterface::setup" + SBE_ENTER(SBE_FUNC); + ReturnCode fapiRc = FAPI2_RC_SUCCESS; + + // Reset the current granule count + iv_currGranule = 0; + iv_intfCleanedUp = false; + SBE_INFO("iv_addr [0x%08x%08x]", SBE::higher32BWord(iv_addr), SBE::lower32BWord(iv_addr)); + if(iv_interface == SBE_MEM_ACCESS_PBA) + { + // Call the PBA setup HWP + SBE_EXEC_HWP(fapiRc, + p9_pba_setup, + plat_getChipTarget(), + iv_ex, + iv_addr, + (iv_mode == SBE_MEM_ACCESS_READ), + ((p9_PBA_oper_flag*)iv_flags)->setFlag(), + iv_maxGranule); + } + if(iv_interface == SBE_MEM_ACCESS_ADU) + { + // Call the ADU setup HWP + SBE_EXEC_HWP(fapiRc, + p9_adu_setup_hwp, + plat_getChipTarget(), + iv_addr, + (iv_mode == SBE_MEM_ACCESS_READ), + ((p9_ADU_oper_flag*)iv_flags)->setFlag(), + iv_maxGranule) + } + // if setup returns error + if(fapiRc != FAPI2_RC_SUCCESS) + { + SBE_ERROR(SBE_FUNC" setup Failed"); + } + else + { + // Assumption is Hwp won't return zero for Num Granules + assert(0 != iv_maxGranule); + + SBE_INFO(SBE_FUNC "Hwp returned iv_maxGranule=[0x%08X]", + iv_maxGranule); + } + return fapiRc; +#undef SBE_FUNC +} + +ReturnCode sbeMemAccessInterface::accessGranule(const bool i_isLastAccess) +{ +#define SBE_FUNC "sbeMemAccessInterface::accessGranule" + SBE_DEBUG(SBE_FUNC); + ReturnCode fapiRc = FAPI2_RC_SUCCESS; + + do + { + // Check if we need to do a setup before access + if(iv_intfCleanedUp) + { + fapiRc = setup(); + // if setup returns error + if( fapiRc != FAPI2_RC_SUCCESS ) + { + break; + } + } + iv_intfCleanedUp = (i_isLastAccess || (iv_maxGranule == 1)); + if(iv_interface == SBE_MEM_ACCESS_PBA) + { + // Call PBA access for read/write + SBE_EXEC_HWP(fapiRc, + p9_pba_access, + plat_getChipTarget(), + iv_addr, + (iv_mode == SBE_MEM_ACCESS_READ), + ((p9_PBA_oper_flag*)iv_flags)->setFlag(), + (iv_currGranule == 0), + iv_intfCleanedUp, + (uint8_t *)&iv_buffer); + } + if(iv_interface == SBE_MEM_ACCESS_ADU) + { + // Call ADU access HWP for ADU write/read request + SBE_EXEC_HWP(fapiRc, + p9_adu_access_hwp, + plat_getChipTarget(), + iv_addr, + (iv_mode == SBE_MEM_ACCESS_READ), + ((p9_ADU_oper_flag*)iv_flags)->setFlag(), + (iv_currGranule == 0), + iv_intfCleanedUp, + (uint8_t *)&iv_buffer) + } + if(fapiRc != FAPI2_RC_SUCCESS) + { + SBE_ERROR(SBE_FUNC" access HWP failed"); + break; + } + iv_maxGranule--; + iv_currGranule++; + // Advance the address + iv_addr += iv_granuleSize; + iv_iterator = (iv_mode == SBE_MEM_ACCESS_READ)? + iv_granuleSize : 0; + } while(false); + + return fapiRc; +#undef SBE_FUNC +} + +ReturnCode sbeMemAccessInterface::accessWithBuffer(const void *io_buffer, + const uint32_t i_len, + const bool i_isLastAccess) +{ +#define SBE_FUNC "sbeMemAccessInterface::accessWithBuffer" + SBE_DEBUG(SBE_FUNC" len[%d]",i_len); + ReturnCode fapiRc = FAPI2_RC_SUCCESS; + uint32_t iterator = 0; + bool is_lastGranule = false; + + do + { + if(iv_mode == SBE_MEM_ACCESS_WRITE) + { + // Fill buffer + while((iv_iterator < iv_granuleSize) && (iterator < i_len)) + { + iv_buffer[iv_iterator++] = ((char*)io_buffer)[iterator++]; + } + // If Adu, put the ecc and itag applicable bytes + if(iv_interface == SBE_MEM_ACCESS_ADU) + { + if(((p9_ADU_oper_flag*)iv_flags)->getEccMode()) + { + iv_buffer[iv_iterator++] = ((char*)io_buffer)[iterator++]; + } + if(((p9_ADU_oper_flag*)iv_flags)->getItagMode()) + { + iv_buffer[iv_iterator++] = ((char*)io_buffer)[iterator++]; + } + } + } + + if(i_isLastAccess) + { + if((iv_mode == SBE_MEM_ACCESS_WRITE) && + (iterator >= i_len)) + { + is_lastGranule = true; + alignAccessWithBuffer(); + } + else if((iv_mode == SBE_MEM_ACCESS_READ) && + ((i_len - iterator) <= iv_granuleSize)) + { + is_lastGranule = true; + iv_iterator = 0; + } + } + if(((iv_mode == SBE_MEM_ACCESS_WRITE) && + (iv_iterator >= iv_granuleSize)) + || + ((iv_mode == SBE_MEM_ACCESS_READ) && + (iv_iterator == 0))) + { + fapiRc = accessGranule(is_lastGranule); + // Break out on error + if(fapiRc != FAPI2_RC_SUCCESS) + { + break; + } + } + + if(iv_mode == SBE_MEM_ACCESS_READ) + { + // Fill the buffer + while((iv_iterator > 0) && (iterator < i_len)) + { + ((char*)io_buffer)[iterator++] = + iv_buffer[iv_granuleSize - iv_iterator]; + iv_iterator--; + } + // If Adu, get the ecc and itag applicable bytes + if(iv_interface == SBE_MEM_ACCESS_ADU) + { + uint32_t index = iv_granuleSize; + if(((p9_ADU_oper_flag*)iv_flags)->getEccMode()) + { + ((char*)io_buffer)[iterator++] = + iv_buffer[index++]; + } + if(((p9_ADU_oper_flag*)iv_flags)->getItagMode()) + { + ((char*)io_buffer)[iterator++] = + iv_buffer[index]; + } + } + } + + // data is completely processed + if(iterator >= i_len) + { + break; + } + } while(true); + + return fapiRc; +#undef SBE_FUNC +} + +void sbeMemAccessInterface::alignAccessWithBuffer() +{ +#define SBE_FUNC "sbeMemAccessInterface::alignAccessWithBuffer" + SBE_DEBUG(SBE_FUNC); + // Required to fill zeroes only if the iv_buffer is partially occupied + if(iv_iterator != 0) + { + // zero filling + while(iv_iterator < iv_granuleSize) + { + iv_buffer[iv_iterator++] = 0; + } + } +#undef SBE_FUNC +} diff --git a/src/sbefw/core/sbeMemAccessInterface.H b/src/sbefw/core/sbeMemAccessInterface.H new file mode 100644 index 00000000..386eba26 --- /dev/null +++ b/src/sbefw/core/sbeMemAccessInterface.H @@ -0,0 +1,182 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbeMemAccessInterface.H $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* */ +/* */ +/* 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 __SBE_MEM_ACCESS_INTERFACE_H +#define __SBE_MEM_ACCESS_INTERFACE_H + +#include "fapi2.H" + +#include "p9_pba_coherent_utils.H" +#include "p9_pba_setup.H" +#include "p9_pba_access.H" + +#include "p9_adu_setup.H" +#include "p9_adu_access.H" +#include "p9_adu_coherent_utils.H" + +/* @brief Enum for read or write interface + * */ +enum sbeMemAccessMode +{ + SBE_MEM_ACCESS_READ = 1, + SBE_MEM_ACCESS_WRITE = 2, +}; + +/* @brief Enum for PBA or ADU interface + * */ +enum sbeMemAccessInterfaceType +{ + SBE_MEM_ACCESS_PBA, + SBE_MEM_ACCESS_ADU, +}; + +// Helper functions +/* + * @brief function to check if the length to send can be + * accomodated in the available memory, else make it a last + * access on the interface + */ +void MEM_AVAILABLE_CHECK(uint32_t &io_available_len, + uint32_t &io_len_to_send, + bool &io_is_last_access); + +class sbeMemAccessInterface +{ + private: + // Bigger of PBA/ADU granules + static constexpr uint32_t MEM_INTERFACE_SIZE_BYTES = 128; + + // Address to start read/write from + uint64_t iv_addr; + // Interface type - PBA/ADU + sbeMemAccessInterfaceType iv_interface; + // Pointer to procedure flags - p9_PBA_oper_flag/p9_ADU_oper_flag + void *iv_flags; + // Read or Write mode + sbeMemAccessMode iv_mode; + // Ex target used in PBA interface, not applicable for ADU + fapi2::Target<fapi2::TARGET_TYPE_EX > iv_ex; + // Number of granule that can be sent before calling setup again + uint32_t iv_maxGranule; + // Iterator to track the current depth of iv_buffer + uint32_t iv_iterator; + // Number of granules sent after the setup + uint32_t iv_currGranule; + // Granule size based on interface - PBA/ADU + uint32_t iv_granuleSize; + // Buffer size is bigger of the two granules + char iv_buffer[MEM_INTERFACE_SIZE_BYTES] __attribute__ ((aligned (8))); + // Interface cleaned up - indicates if the underlying + // HWP cleanup is done for the interface. + // A new object assumes interface is in cleaned up + // state. + // If the interface is in cleaned up state, + // next access will happen only after the setup. + bool iv_intfCleanedUp; + + /* @brief Wrapper function to call setup procedures + * for the interface. This private API is used + * internally as per the state of the object, + * i.e., whenever the iv_maxGranule + * becomes 0, while using interface access APIs + * + * @return fapi rc + */ + fapi2::ReturnCode setup(); + + /* @brief Align and finalize the accessWithBuffer calls - useful in case + * the data to be read/written is not aligned to the + * granule sizes of the interfaces + * + * @return fapi rc + */ + void alignAccessWithBuffer(); + + public: + //Default EX Target ChipletId to be used in PBA by default + static constexpr uint32_t PBA_DEFAULT_EX_CHIPLET_ID = 0x20; + + // PBA / ADU Granule size as per the HWP Requirement + static constexpr uint32_t PBA_GRAN_SIZE_BYTES = 128; + static constexpr uint32_t ADU_GRAN_SIZE_BYTES = 8; + + /* @brief Constructor + * + * @param[in] i_interface Type of the interface + * @param[in] i_addr Address to read/write from + * @param[in] i_flags Pointer to PBA/ADU flags + * @param[in] i_mode Read/Write mode + * @param[in] i_granuleSize Granule size of the interface type + * @param[in] i_ex EX target[Optional in case of ADU] + */ + sbeMemAccessInterface( + sbeMemAccessInterfaceType i_interface, + uint64_t i_addr, + void *i_flags, + sbeMemAccessMode i_mode, + uint32_t i_granuleSize, + fapi2::Target<fapi2::TARGET_TYPE_EX> i_ex + = fapi2::Target<fapi2::TARGET_TYPE_EX>()): + iv_addr(i_addr), + iv_interface(i_interface), + iv_flags(i_flags), + iv_mode(i_mode), + iv_ex(i_ex), + iv_maxGranule(0), + iv_iterator(0), + iv_currGranule(0), + iv_granuleSize(i_granuleSize), + iv_intfCleanedUp(true) + { + } + + void * getBuffer() + { + iv_iterator = iv_granuleSize; + return &iv_buffer; + } + + /* @brief Read/Write a single granule on PBA/ADU interface + * + * @param[in] i_isLastAccess Should the interface be cleaned up + * after this access + * + * @return fapi rc + */ + fapi2::ReturnCode accessGranule(const bool i_isLastAccess = false); + + /* @brief Read/Write on PBA/ADU interface with the given buffer. + * + * @param[in] io_buffer Pointer to the data to read/write + * @param[in] i_len Length of the data to read/write in bytes + * @param[in] i_isLastAccess Should the interface be cleaned up + * after this access + * + * @return fapi rc + */ + fapi2::ReturnCode accessWithBuffer(const void *io_buffer, + const uint32_t i_len, + const bool i_isLastAccess = false); + +}; +#endif //__SBE_MEM_ACCESS_INTERFACE_H diff --git a/src/sbefw/core/sbeSecureMemRegionManager.C b/src/sbefw/core/sbeSecureMemRegionManager.C new file mode 100644 index 00000000..ef81ca87 --- /dev/null +++ b/src/sbefw/core/sbeSecureMemRegionManager.C @@ -0,0 +1,187 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbeSecureMemRegionManager.C $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2017 */ +/* */ +/* */ +/* 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 "sbeSecureMemRegionManager.H" +#include "sbetrace.H" +#include "sbeutil.H" +#include "sbeglobals.H" + +#ifndef __SBEFW_SEEPROM__ +SBESecureMemRegionManager mainStoreSecMemRegionManager( + &SBE_GLOBAL->mainMemRegions[0], + MAX_MAIN_STORE_REGIONS); +SBEOccSramSecMemRegionManager occSramSecRegionManager( + &SBE_GLOBAL->occSramRegions[0], + MAX_OCC_SRAM_REGIONS); + +secureMemRegion_t SBESecureMemRegionManager::getPartialRegionSize( + const secureMemRegion_t i_region) +{ + secureMemRegion_t ret = {}; + for(size_t i = 0; i < iv_regionsOpenCnt; i++) + { + uint64_t minStartAddr = i_region.startAddress < iv_memRegions[i].startAddress ? + i_region.startAddress : iv_memRegions[i].startAddress; + uint64_t iRegionEndAddress = i_region.startAddress + i_region.size - 1; + uint64_t existingRegionEndAddress = iv_memRegions[i].startAddress + iv_memRegions[i].size - 1; + uint64_t maxEndAddr = iRegionEndAddress >= existingRegionEndAddress ? + iRegionEndAddress : existingRegionEndAddress; + + // detect overlap + if((maxEndAddr - minStartAddr + 1) < (i_region.size + iv_memRegions[i].size)) + { + ret = iv_memRegions[i]; + // Give preference to first region + if(i_region.startAddress >= iv_memRegions[i].startAddress && + i_region.startAddress < (iv_memRegions[i].startAddress + + iv_memRegions[i].size)) + { + // Return the existing window to the extent of input window + ret.startAddress = i_region.startAddress; + ret.size = iv_memRegions[i].startAddress + iv_memRegions[i].size + - i_region.startAddress; + if(ret.size > i_region.size) + ret.size = i_region.size; + break; + } + } + } + return ret; +} + +#endif //__SBEFW_SEEPROM__ +#ifdef __SBEFW_SEEPROM__ + +// Public functions +sbeSecondaryResponse SBESecureMemRegionManager::add(const uint64_t i_startAddr, + const uint32_t i_size, + const uint8_t i_mode) +{ + #define SBE_FUNC "SBESecureMemRegionManager::add" + sbeSecondaryResponse rc = SBE_SEC_OPERATION_SUCCESSFUL; + do + { + if(getPartialRegionSize({i_startAddr, i_size, i_mode}).mode) + { + SBE_ERROR(SBE_FUNC" SBE_SEC_MEM_REGION_AMEND_ATTEMPTED"); + rc = SBE_SEC_MEM_REGION_AMEND_ATTEMPTED; + break; + } + if(iv_regionsOpenCnt >= iv_maxRegions) + { + SBE_ERROR(SBE_FUNC" SBE_SEC_MAXIMUM_MEM_REGION_EXCEEDED"); + rc = SBE_SEC_MAXIMUM_MEM_REGION_EXCEEDED; + break; + } + SBE_INFO(SBE_FUNC" Adding region Mem[0x%08X%08X], size[0x%08X]", + SBE::higher32BWord(i_startAddr), + SBE::lower32BWord(i_startAddr), + i_size); + iv_memRegions[iv_regionsOpenCnt++] = {i_startAddr, i_size, i_mode}; + SBE_INFO(SBE_FUNC" after addition iv_regionsOpenCnt [%d]", + iv_regionsOpenCnt); + } while(0); + return rc; + #undef SBE_FUNC +} + +sbeSecondaryResponse SBESecureMemRegionManager::remove(const uint64_t i_startAddr) +{ + #define SBE_FUNC "SBESecureMemRegionManager::remove"; + size_t i = 0; + sbeSecondaryResponse rc = SBE_SEC_OPERATION_SUCCESSFUL; + for(; i < iv_regionsOpenCnt; i++) + { + if(i_startAddr == iv_memRegions[i].startAddress) + { + break; + } + } + if(i < iv_regionsOpenCnt) + { + SBE_INFO(SBE_FUNC" Deleting region i[%d], Mem[0x%08X%08X], size[0x%08X]", + i, + SBE::higher32BWord(iv_memRegions[i].startAddress), + SBE::lower32BWord(iv_memRegions[i].startAddress), + iv_memRegions[i].size); + // Remove the empty slot and maintain contiguous list + for(size_t j = i; j < iv_regionsOpenCnt-1; j++) + { + iv_memRegions[j].startAddress = iv_memRegions[j+1].startAddress; + iv_memRegions[j].size = iv_memRegions[j+1].size; + iv_memRegions[j].mode = iv_memRegions[j+1].mode; + } + + iv_regionsOpenCnt--; + SBE_INFO(SBE_FUNC" After deletion : iv_regionsOpenCnt[%d]", iv_regionsOpenCnt); + } + else + { + SBE_ERROR(SBE_FUNC" SBE_SEC_MEM_REGION_NOT_FOUND"); + rc = SBE_SEC_MEM_REGION_NOT_FOUND; + } + return rc; + #undef SBE_FUNC +} + +#endif //__SBEFW_SEEPROM__ +#ifndef __SBEFW_SEEPROM__ + +sbeSecondaryResponse SBESecureMemRegionManager::isAccessAllowed( + secureMemRegion_t i_region) +{ + #define SBE_FUNC "SBESecureMemRegionManager::isAccessAllowed" + sbeSecondaryResponse rc = SBE_SEC_OPERATION_SUCCESSFUL; + if(SBE_GLOBAL->sbeFWSecurityEnabled) + { + while(i_region.size > 0) + { + secureMemRegion_t foundregion = getPartialRegionSize(i_region); + // Check if the found region has allowable access level + // and that the region overlap is from the beginning itself + if((i_region.mode & foundregion.mode) && + (i_region.startAddress == foundregion.startAddress)) + { + SBE_INFO(SBE_FUNC" foundRegion Mem[0x%08X%08X], size[0x%08X]", + SBE::higher32BWord(foundregion.startAddress), + SBE::lower32BWord(foundregion.startAddress), + foundregion.size); + i_region.size -= foundregion.size; + i_region.startAddress += foundregion.size; + } + else + { + SBE_ERROR(SBE_FUNC" Non secure access to memory blocked " + "Addr[0x%08X%08X] Size[0x%08X]", + SBE::higher32BWord(i_region.startAddress), + SBE::lower32BWord(i_region.startAddress), + i_region.size); + rc = SBE_SEC_BLACKLISTED_MEM_ACCESS; + break; + } + } + } + return rc; + #undef SBE_FUNC +} +#endif //__SBEFW_SEEPROM__ diff --git a/src/sbefw/core/sbeSecureMemRegionManager.H b/src/sbefw/core/sbeSecureMemRegionManager.H new file mode 100644 index 00000000..1d5fc4bd --- /dev/null +++ b/src/sbefw/core/sbeSecureMemRegionManager.H @@ -0,0 +1,148 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbeSecureMemRegionManager.H $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2017 */ +/* */ +/* */ +/* 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 */ +#pragma once + +#include <stdint.h> +#include <stddef.h> +#include "sbe_sp_intf.H" + +enum class memRegionMode:uint8_t +{ + READ = 0x01, + WRITE = 0x02, +}; + +// Structure to define a mem region +typedef struct +{ + uint64_t startAddress; + uint32_t size; + uint32_t mode; +} secureMemRegion_t; + +// OCC SRAM Command buffer +constexpr uint64_t OCC_CMD_ADDR = 0xFFFBE000ull; +constexpr uint32_t OCC_CMD_SIZE = 0xFFFBEFFF - 0xFFFBE000; +// OCC SRAM Response buffer +constexpr uint64_t OCC_RESP_ADDR = 0xFFFBF000ull; +constexpr uint32_t OCC_RESP_SIZE = 0xFFFBFFFF- 0xFFFBF000; + +class SBESecureMemRegionManager +{ + protected: + secureMemRegion_t *iv_memRegions; + const size_t iv_maxRegions; + size_t iv_regionsOpenCnt; + + /* + * @brief getPartialRegionSize - get the overlapping region + * if it exists. + * Also if the overlap is from the beginning, + * first region is returned + * + * + * @param[in] i_region region to check for overlap + * + * @return overlapping region + */ + secureMemRegion_t getPartialRegionSize(const secureMemRegion_t i_region); + + public: + SBESecureMemRegionManager(secureMemRegion_t *i_regions, + size_t i_maxRegions): + iv_memRegions(i_regions), + iv_maxRegions(i_maxRegions) + { + } + + // Disable copy constructors + SBESecureMemRegionManager(const SBESecureMemRegionManager&) = delete; + SBESecureMemRegionManager& operator=(const SBESecureMemRegionManager&) = delete; + + /* + * @brief add - Open a new memory region + * + * @param[in] i_startAddr Start address of the memory region + * @param[in] i_size Size of the memory region + * @param[in] i_mode Bit mapped access mode of the memory region + * + * @return SBE secondary RC + */ + sbeSecondaryResponse add(const uint64_t i_startAddr, + const uint32_t i_size, + const uint8_t i_mode); + /* + * @brief remove - Close a memory region + * + * @param[in] i_startAddr Start address of the memory region + * + * @return SBE secondary RC + */ + sbeSecondaryResponse remove(const uint64_t i_startAddr); + /* + * @brief isAccessAllowed - Check if the access is allowed + * + * @param[in] i_region region to check the access for + * + * @return SBE secondary RC + */ + sbeSecondaryResponse isAccessAllowed(secureMemRegion_t i_region); + + /* + * @brief closeAllRegions - close all non-secure regions + */ + void closeAllRegions() + { + iv_regionsOpenCnt = 0; + } +}; + +class SBEOccSramSecMemRegionManager : public SBESecureMemRegionManager +{ + public: + SBEOccSramSecMemRegionManager(secureMemRegion_t *i_regions, + size_t i_maxRegions): + SBESecureMemRegionManager(i_regions, + i_maxRegions) + { + add(OCC_CMD_ADDR, + OCC_CMD_SIZE, + static_cast<uint8_t>( memRegionMode::WRITE) | + static_cast<uint8_t>(memRegionMode::READ)); + add(OCC_RESP_ADDR, + OCC_RESP_SIZE, + static_cast<uint8_t>(memRegionMode::READ)); + } + + // Disable copy constructors + SBEOccSramSecMemRegionManager(const SBEOccSramSecMemRegionManager&) = delete; + SBEOccSramSecMemRegionManager& operator=(const SBEOccSramSecMemRegionManager&) = delete; + // Disable delete functions + sbeSecondaryResponse remove(const uint64_t i_startAddr) = delete; + void closeAllRegions() = delete; + +}; + +extern SBESecureMemRegionManager mainStoreSecMemRegionManager; +extern SBEOccSramSecMemRegionManager occSramSecRegionManager; diff --git a/src/sbefw/core/sbeSecurity.C b/src/sbefw/core/sbeSecurity.C new file mode 100644 index 00000000..3e0090df --- /dev/null +++ b/src/sbefw/core/sbeSecurity.C @@ -0,0 +1,157 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbeSecurity.C $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2017 */ +/* */ +/* */ +/* 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 "sbeSecurity.H" +#include "sbetrace.H" +#include "sbeglobals.H" + +#include "sbeSecurityGen.H" + +namespace SBE_SECURITY +{ + +// Figure out at compile time, the number of shifts required for the mask +constexpr uint32_t get_shift_len(uint32_t mask, uint8_t shifts = 0) +{ + return ((mask>>shifts) & 0x01) ? (shifts) : (get_shift_len(mask, ++shifts)); +} + +template <typename Func> +map_t<bool, int32_t> binary_search( + const uint32_t search_key, + range_t<int32_t> x_range, + Func get_element) +{ + map_t<bool, int32_t> ret = {false, 0}; // found=false + + while((x_range.start <= x_range.end) && + (ret.key == false)) + { + int32_t midpoint = (x_range.start + x_range.end) / 2; + SBE_DEBUG("binary_search : midpoint[0x%08x]", + midpoint); + uint32_t ele = get_element(midpoint); + SBE_DEBUG("binary_search : search_key[0x%08x] ele[0x%08x]", + search_key, + ele); + if(search_key == ele) + { + ret.key = true; + ret.value = midpoint; + } + else if(search_key < ele) + { + x_range.end = midpoint - 1; + } + else + { + x_range.start = midpoint + 1; + } + SBE_DEBUG("binary_search : x_range.start[0x%08x] x_range.end[0x%08x]", + x_range.start, + x_range.end); + } + SBE_DEBUG("binary_search : ret[%d]",ret.key); + return ret; +} + +template <typename M1_T, typename M1_U, + typename M2_T, typename M2_U, + typename T3> +bool _is_present(const table< map_t< range_t<M1_T>, M1_U > > &table1, + const table< map_t<M2_T, M2_U> > &table2, + const table< T3 > &table3, + const uint32_t i_addr) +{ +#define SBE_FUNC "SBE_SECURITY::_is_present" + SBE_ENTER(SBE_FUNC); + for(size_t i = 0; i < table1.size; i++) + { + uint32_t search_key = (i_addr & table1.mask) >> get_shift_len(table1.mask); + if((table1.table[i].key.start <= search_key) && + (table1.table[i].key.end >= search_key)) + { + SBE_DEBUG(SBE_FUNC" table1:found key[0x%x] table index[%d]", + search_key, i); + // Found the range where key might belong to + search_key = (i_addr & table2.mask) >> get_shift_len(table2.mask); + range_t<int32_t> search_range = {}; + search_range.start = i ? table1.table[i-1].value : 0; + search_range.end = table1.table[i].value - 1; + map_t<bool, int32_t> search_result = + binary_search( + search_key, + search_range, + [&table2](int32_t midpoint) -> uint32_t { + return table2.table[midpoint].key; + }); + if(search_result.key == true) + { + SBE_DEBUG(SBE_FUNC" table2:found key[0x%x] table index[%d]", + search_key, + search_result.value); + // Found the key + search_range.start = (search_result.value ? + table2.table[search_result.value-1].value : 0); + search_range.end = + table2.table[search_result.value].value - 1; + search_key = (i_addr & table3.mask) >> + get_shift_len(table3.mask); + search_result = binary_search( + search_key, + search_range, + [&table3](int32_t midpoint) -> uint32_t { + return table3.table[midpoint]; + }); + if(search_result.key == true) + { + SBE_DEBUG(SBE_FUNC" table3:found key[0x%x] table index[%d]", + search_key, + search_result.value); + // Found the number + return true; + } + } + } + } + SBE_EXIT(SBE_FUNC); + return false; +#undef SBE_FUNC +} + +bool isAllowed(const uint32_t i_addr, accessType type) +{ + bool ret = true; + if(SBE_GLOBAL->sbeFWSecurityEnabled) + { + if(type == WRITE) + ret = WHITELIST::isPresent(i_addr); + else if(type == READ) + ret = !BLACKLIST::isPresent(i_addr); + SBE_INFO("SBE_SECURITY access[%d] allowed[%d] addr[0x%08x]", + type, ret, i_addr); + } + return ret; +} + +} // namespace SBE_SECURITY diff --git a/src/sbefw/core/sbeSecurity.H b/src/sbefw/core/sbeSecurity.H new file mode 100644 index 00000000..3d7ad838 --- /dev/null +++ b/src/sbefw/core/sbeSecurity.H @@ -0,0 +1,91 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbeSecurity.H $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2017 */ +/* */ +/* */ +/* 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 __SBE_SECURITY_H +#define __SBE_SECURITY_H + +#include <stdint.h> + +namespace SBE_SECURITY +{ + typedef enum + { + READ = 0, + WRITE + } accessType; + + // type to define a range + template <typename T> + struct range_t + { + T start; + T end; + }; + + // key-value map used for the tables + template <typename T, typename U> + struct map_t + { + T key; + U value; + }; + + // table data structure + template <typename T> + struct table + { + uint8_t size; + uint32_t mask; + T *table; + }; + + /* @brief isAllowed - Public function used for address verification + * for a given type of access + * + * @param[in] i_addr - given address to verify + * @param[in] accessType - access type - READ/WRITE + * + * @return - boolean to denote if the access on the address + * is allowed or not + */ + bool isAllowed(const uint32_t i_addr, accessType type); + + /* @brief _is_present - Look up tables to find if the given + * address is present + * @param[in] table1 - table 1 - map with a range and running count + * @param[in] table2 - table 2 - map with value and running count + * @param[in] table3 - table 3 - array with values + * @param[in] i_addr - given address to look up + * + * @return - boolean to denote if the address in present + * in the list of tables + */ + template <typename M1_T, typename M1_U, + typename M2_T, typename M2_U, + typename T3> + bool _is_present(const table< map_t< range_t<M1_T>, M1_U > > &table1, + const table< map_t<M2_T, M2_U> > &table2, + const table< T3 > &table3, + const uint32_t i_addr); +} +#endif //__SBE_SECURITY_H diff --git a/src/sbefw/core/sbeSpMsg.C b/src/sbefw/core/sbeSpMsg.C new file mode 100644 index 00000000..b6afb700 --- /dev/null +++ b/src/sbefw/core/sbeSpMsg.C @@ -0,0 +1,36 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbeSpMsg.C $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2017 */ +/* */ +/* */ +/* 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 "sbeutil.H" +#include "sbetrace.H" +#include "sbeSpMsg.H" +#include "sbeglobals.H" + +void sbeRespGenHdr_t::init(void) +{ + magicCode = 0xC0DE; + cmdClass = SBE_GLOBAL->sbeFifoCmdHdr.cmdClass; + command = SBE_GLOBAL->sbeFifoCmdHdr.command; + primaryStatus = SBE_PRI_OPERATION_SUCCESSFUL; + secondaryStatus = SBE_SEC_OPERATION_SUCCESSFUL; +} diff --git a/src/sbefw/core/sbeSpMsg.H b/src/sbefw/core/sbeSpMsg.H new file mode 100644 index 00000000..86f7b9e6 --- /dev/null +++ b/src/sbefw/core/sbeSpMsg.H @@ -0,0 +1,672 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbeSpMsg.H $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2017 */ +/* */ +/* */ +/* 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: ppe/sbe/sbefw/sbeSpMsg.H + * + * @brief This file contains the message structures for FIFO + * communication. + * + */ + +#ifndef __SBEFW_SBESP_MSG_H +#define __SBEFW_SBESP_MSG_H + +#include "sbe_sp_intf.H" + +// @NOTE Make sure all FIFO structures are 32 bit alligned ( the largest +// member should be atleast 4 byte). It is required as in sbe fifo +// operation we are casting these structures to uint32_t pointer. It can +// cause alignment issue if largest member of structure is not atleast +// 32 bit. We can use bit fields to optimize memory requirements. +// These are two coding guidleines we will follow for this file +// 1. All data members less than 32 bits will be bit fields +// 2. All data members more than 32 buts will be divided into small +// members of 32 bit each. This is required as compiler pads structure +// to largest data member and we do not want extra padding for data +// members gretater than 32 bits ( e.g. uint64_t ) +/** + * @brief Command Request Header + */ +typedef struct +{ + uint32_t len; + uint32_t reserved:12; + uint32_t clientId:4; + uint32_t cmdClass:8; + uint32_t command:8; +}sbeFifoCmdReqBuf_t; + +/** + * @brief structure for generic header for fifo response. + * + */ +typedef struct +{ + uint32_t magicCode:16; + uint32_t cmdClass:8; + uint32_t command:8; + uint32_t primaryStatus:16; + uint32_t secondaryStatus:16; + + /** + * @brief set the primary and secondary status + * + * @param[in] i_prim Primary status + * @param[in] i_sec Secondary status + * + * @return + */ + void setStatus( const uint16_t i_prim, const uint16_t i_sec) + { + primaryStatus = i_prim; + secondaryStatus = i_sec; + } + + /** + * @brief set initial values for response header + * + * @note We did not set this in constructor as based on use case + * it is possible that SBE_GLOBAL->sbeFifoCmdHdr does not have proper + * values at time of object creation. + * + */ + void init(); +}sbeRespGenHdr_t; + +/** + * @brief structure for ffdc header for fifo response. + * + */ +typedef struct sbeResponseFfdc +{ + uint32_t magicBytes:16; + uint32_t lenInWords:16; // length in word( 4 byte ) + uint32_t seqId:16; + uint32_t cmdClass:8; + uint32_t cmd:8; + uint32_t fapiRc; + + /** + * @brief set failed command information + * + * @param[in] i_seqId sequence Id of command + * @param[in] i_cmdClass command class + * @param[in] i_cmd command + * + * @return + */ + void inline setCmdInfo(const uint16_t i_seqId, + const uint8_t i_cmdClass, + const uint8_t i_cmd) + { + seqId = i_seqId; + cmdClass = i_cmdClass; + cmd = i_cmd; + } + + /** + * @brief set rc + * + * @param[in] i_rc FAPI RC + * + * @return + */ + void setRc(const uint32_t i_rc) + { + fapiRc = i_rc; + } + + /** + * @brief return fapiRc + * + * @return fapiRc + */ + uint32_t getRc() const + { + return fapiRc; + } + + /** + * @brief constructor + * + * @param[in] i_rc FAPI RC + * + * @return + */ + sbeResponseFfdc() + { + magicBytes = 0xFFDC; + seqId = 0; + cmdClass = SBE_CMD_CLASS_UNKNOWN; + cmd = SBE_CMD_UNKNOWN; + lenInWords = ( sizeof(uint32_t ) // For magicBytes + lenInWords + + sizeof(uint32_t) // For SeqId + CmdClass + Cmd + + sizeof(fapiRc)) + / sizeof(uint32_t); + fapiRc = 0; + } +}sbeResponseFfdc_t; + +/** + * @brief structure for execute istep chipop (0xA101) contents. + * + */ +typedef struct +{ + uint32_t reserved1:8; + uint32_t major:8; + uint32_t reserved2:8; + uint32_t minor:8; +}sbeIstepReqMsg_t; + + +/** + * @brief structure for GetScom Chipop (0xA201) contents. + * + */ +typedef struct +{ + uint32_t hiAddr; + uint32_t lowAddr; +}sbeGetScomReqMsg_t; + +/** + * @brief structure for PutScom Chipop (0xA202) contents. + * + */ +typedef struct +{ + uint32_t hiAddr; + uint32_t lowAddr; + uint32_t hiInputData; + uint32_t lowInputData; + + /** + * @brief return 64-bit Scom data + * + * @return 64-bit Scom data + */ + uint64_t getScomData() + { + uint64_t data = ((uint64_t)hiInputData << 32) | lowInputData; + return data; + } +}sbePutScomReqMsg_t; + +/** + * @brief structure for Modify_Scom Chipop (0xA203) contents. + * + */ +typedef struct +{ + uint32_t reserved:24; + uint32_t opMode:8; + uint32_t hiAddr; + uint32_t lowAddr; + uint32_t hiInputData; + uint32_t lowInputData; + + /** + * @brief return 64-bit modifying data + * + * @return 64-bit modifying data + */ + uint64_t getModifyingData() + { + uint64_t data = ((uint64_t)hiInputData << 32) | lowInputData; + return data; + } +}sbeModifyScomReqMsg_t; + +/** + * @brief structure for PutScom_UnderMask Chipop (0xA204) contents. + * + */ +typedef struct +{ + uint32_t hiAddr; + uint32_t lowAddr; + uint32_t hiInputData; + uint32_t lowInputData; + uint32_t hiMaskData; + uint32_t lowMaskData; + + /** + * @brief return 64-bit input data + * + * @return 64-bit input data + */ + uint64_t getInputData() + { + uint64_t data = ((uint64_t)hiInputData << 32) | lowInputData; + return data; + } + + /** + * @brief return 64-bit input mask + * + * @return 64-bit input mask + */ + uint64_t getInputMask() + { + uint64_t data = ((uint64_t)hiMaskData << 32) | lowMaskData; + return data; + } + + /** + * @brief Determines 64-bit Scom data + * + * @param[in/out] io_scomData 64-bit scom data + */ + void getScomData(uint64_t &io_scomData) + { + uint64_t l_inputMask = getInputMask(); + uint64_t l_inputData = getInputData(); + io_scomData = (io_scomData & (~l_inputMask)) + | (l_inputData & l_inputMask); + } +}sbePutScomUnderMaskReqMsg_t; + +/** + * @brief Structure for SBE Memory Access ChipOps (0xA401/A402) + * + */ +typedef struct +{ + uint32_t coreChipletId:8; //Pervasive Core Chiplet Id for PBA + uint32_t eccByte:8; //Ecc Override Byte from user + uint32_t flags:16; //Operational Flags -refer enum sbeMemoryAccessFlags + uint32_t addrHi; //Higher 32-Bit Memory Address + uint32_t addrLo; //Lower 32-Bit Memory Address + uint32_t len; //Length of Data in Bytes + + /** + * @brief Calculates 64-bit PBA ADU Address + * + * @return Return 64-bit PBA ADU address + */ + uint64_t getAddr() const + { + return (((uint64_t)addrHi << 32) | addrLo); + } + + /** + * @brief Determines if ECC Override bit is set + * + * @return Returns True if ECC Override bit is set + * False if ECC Override bit is not set + */ + bool isEccOverrideFlagSet() const + { + return ((flags & SBE_MEM_ACCESS_FLAGS_ECC_OVERRIDE) ? true : false); + } + + /** + * @brief Determines if ECC required bit is set + * + * @return Returns True if ECC required flag is set + * False if ECC required flag is not set + */ + bool isEccFlagSet() const + { + return ((flags & SBE_MEM_ACCESS_FLAGS_ECC_REQUIRED) ? true : false); + } + + /** + * @brief Determines if Itag required bit is set + * + * @return Returns True if Itag required flag is set + * False if Itag required flag is not set + */ + bool isItagFlagSet() const + { + return ((flags & SBE_MEM_ACCESS_FLAGS_ITAG) ? true : false); + } + + /** + * @brief Determines if Cache Inhibited mode is set + * + * @return Returns True if Cache Inhibited Mode flag is set + * False if Cache Inhibited Mode flag is not set + */ + bool isCacheInhibitModeFlagSet() const + { + return ((flags & SBE_MEM_ACCESS_FLAGS_CACHE_INHIBIT) ? true : false); + } + + /** + * @brief Determines if PBA flag is set + * + * @return Returns True if PBA Flag is set + * False if PBA flag is not set + */ + bool isPbaFlagSet() + { + return ((flags & SBE_MEM_ACCESS_FLAGS_TARGET_PBA) ? true : false); + } + + /** + * @brief Determines if Auto Increment Mode is set + * + * @return Returns True if Auto Increment mode is set + * False if Auto Increment is not set + */ + bool isAutoIncrModeSet() const + { + return ((flags & SBE_MEM_ACCESS_FLAGS_AUTO_INCR_ON) ? true : false); + } + + /** + * @brief Determines if Fast Mode is set + * + * @return Returns True if Fast mode is set + * False if Fast mode is not set + */ + uint32_t isFastModeSet() const + { + return ((flags & SBE_MEM_ACCESS_FLAGS_FAST_MODE_ON) ? true : false); + } + + /** + * @brief Determines if LCO Mode is set + * + * @return Returns True if LCO mode is set + * False if LCO mode is not set + */ + uint32_t isPbaLcoModeSet() const + { + return ((flags & SBE_MEM_ACCESS_FLAGS_LCO_ENABLED) ? true : false); + } + + /** + * @brief Determines if inject Mode is set + * + * @return Returns True if inject mode is set + * False if inject mode is not set + */ + uint32_t isPbaInjectModeSet() const + { + return ((flags & SBE_MEM_ACCESS_FLAGS_INJECT_ON) ? true : false); + } + + /** + * @brief Calculates Data length in alignment with PBA/ADU Cacheline + * (128B/8B respectively) + * + * @return Returns Data length in alignment with PBA/ADU Cacheline + */ + uint64_t getDataLenCacheAlign() const + { + // Expected length in bytes is 1, 2, 4, or multiples of 8, + // won't work for any other values + uint64_t l_len = (len < 8) ? (1) : (len / 8); + if(flags & SBE_MEM_ACCESS_FLAGS_TARGET_PBA) + { + l_len = (l_len / 16); + } + return l_len; + } + + /** + * @brief Determines if it is Host Pass-through Command + * + * @return Returns True if Host Pass-through mode is set + * False if Host Pass-through mode is not set + */ + uint32_t isPbaHostPassThroughModeSet() const + { + return ((flags & SBE_MEM_ACCESS_FLAGS_HOST_PASS_THROUGH) ? true : false); + } + +}sbeMemAccessReqMsgHdr_t; + +/** + * @brief Structure for SBE OCC Get/Put Sram Access ChipOps (0xA403/A404) + */ +typedef struct +{ + uint32_t reserved:24; // Not used + sbeSramAccessMode mode:8; // Channel select 0-3 + uint32_t addr; // 32-Bit Memory Address + uint32_t len; // Length of Data in Bytes +}sbeOccSramAccessReqMsgHdr_t; + +// Maximum number of capabilities +static const uint32_t SBE_MAX_CAPABILITIES = 18; + +/** + * @brief structure for SBE Get Capabilities chipop (0xA802) contents. + * + */ +typedef struct sbeCapabilityRespMsg +{ + uint32_t verMajor:16; + uint32_t verMinor:16; + uint32_t fwCommitId; + char buildTag[20]; + uint32_t capability[SBE_MAX_CAPABILITIES]; + // ctor. constructor will initialise all values. + sbeCapabilityRespMsg(); +}sbeCapabilityRespMsg_t; + +// TODO via RTC 128658 +// We may be able to replace this structure by sbeRespGenHdr_t + +/** + * @brief Command response structure to hold the primary and secondary + * status values. This will be utilized when a command class + * validation or state machine check fails. + * + */ +typedef struct +{ + uint32_t prim_status:16 ; // Primary Response Status + uint32_t sec_status:16 ; // Secondary Response Status + + /** + * @brief initialize the response status + **/ + void init() + { + prim_status = SBE_PRI_OPERATION_SUCCESSFUL; + sec_status = SBE_SEC_OPERATION_SUCCESSFUL; + } + + /** + * @brief set the primary and secondary status + * + * @param[in] i_prim Primary status + * @param[in] i_sec Secondary status + * + **/ + void setStatus(const uint16_t i_prim, const uint16_t i_sec) + { + prim_status = i_prim; + sec_status = i_sec; + } +} sbeCmdRespHdr_t; + +/** + * @brief structure for Stop Clocks Chipop (0xA901) contents. + * + */ +typedef struct +{ + uint32_t targetType:16; + uint32_t reserved:8; + uint32_t chipletId:8; +}sbeStopClocksReqMsgHdr_t; + +/** + * @brief structure for Control Instruction Chipop (0xA701) contents. + * + */ +typedef struct +{ + uint32_t reserved:12; + sbeErrorMode mode:4; + sbeCoreChipletId coreChipletId:8; + sbeThreadNum threadNum:4; + sbeThreadOps threadOps:4; + + /** + * @brief Validate input arguments + * + * @return bool, true if the validation is success, else false for + * validation failure + */ + bool validateInputArgs() + { + bool l_validatePassFlag = true; + // Validate Thread Command / Thread Num / Error Mode + if((threadOps > THREAD_SRESET_INS) || + (mode > IGNORE_HW_ERRORS) || + !((threadNum <= SMT4_THREAD3) || (threadNum == SMT4_THREAD_ALL))) + { + SBE_ERROR(SBE_FUNC "Invalid Parameter by User, ThreadOps[%d] " + "mode[%d] ThreadNum[%d]", (uint32_t)threadOps, (uint32_t)mode, (uint32_t)threadNum); + l_validatePassFlag = false; + } + return l_validatePassFlag; + } + + /** + * @brief Process the input to find out core/thread ids to iterate + * over HWP for the internal business logic + * + * @param[out] o_core, Core Id to start with in the iteration + * @param[out] o_coreCntMax, Core Max count to iterate, start from o_core + * @param[out] o_threadCnt, Thread Num to start with in the iteration + * @param[out] o_threadCntMax, Thread Max Num to iterate, start from + * o_threadCnt + * + * @return void + */ + void processInputDataToIterate(uint8_t & o_core, uint8_t & o_coreCntMax, + uint8_t & o_threadCnt, uint8_t & o_threadCntMax) + { + //Default Init + o_threadCnt = SMT4_THREAD0; + o_threadCntMax = SMT4_THREAD_MAX; + + o_core = SMT4_CORE0_ID; + o_coreCntMax = SMT4_CORE_ID_LAST+1; + + if( SMT4_ALL_CORES != coreChipletId ) + { + o_core = coreChipletId; + o_coreCntMax = coreChipletId; + } + if( SMT4_THREAD_ALL != threadNum ) + { + o_threadCnt = threadNum; + o_threadCntMax = threadNum; + } + } +}sbeCntlInstRegMsgHdr_t; + +/** + * @brief Get Ring access message header + */ +typedef struct +{ + uint32_t ringAddr; + uint32_t ringLenInBits; + uint32_t reserved:16; + uint32_t ringMode:16; +}sbeGetRingAccessMsgHdr_t; + +/** + * @brief maximum double words for putring RS4 payload for chipop operation + */ +static const uint32_t SBE_PUT_RING_RS4_MAX_DOUBLE_WORDS = + SBE_PUT_RING_RS4_MAX_PAYLOAD_BYTES/sizeof(uint64_t); + +/** + * @brief Put Ring message header + */ +typedef struct +{ + uint32_t reserved:16; + uint32_t ringMode:16; +}sbePutRingMsgHdr_t; + +/** + * @brief Put Ring message + * @note This structure should have uint64_t as type as underlying + * platrform cast it to uint64 pointer. If we declare this as + * uint32, we can get allignment errors. + */ +typedef struct +{ + uint64_t rs4Payload[SBE_PUT_RING_RS4_MAX_DOUBLE_WORDS]; +}sbePutRingMsg_t; + +/** + * @brief Reg access message header + */ +typedef struct +{ + uint32_t reserved:8; + uint32_t coreChiplet:8; + uint32_t threadNr:4; + uint32_t regType:4; + uint32_t numRegs:8; + + /** + * @brief checks if it is valid request. + * + * @return true if valid request, false otherwise + */ + bool isValidRequest() const + { + return (( SBE_REG_ACCESS_FPR >= regType ) + &&( SBE_MAX_REG_ACCESS_REGS >= numRegs ) + &&( SMT4_THREAD3 >= threadNr ) + &&( SMT4_CORE0_ID <= coreChiplet ) + &&( SMT4_CORE_ID_LAST >= coreChiplet )) ? true:false; + } +}sbeRegAccessMsgHdr_t; + +/** + * @brief reg scom package + */ +typedef struct +{ + uint32_t regNr; + uint32_t hiData; + uint32_t lowData; + + /** + * @brief data for a register. + * + * @return data. + */ + uint64_t getData() const + { + return (((uint64_t)hiData << 32 ) | lowData ); + } +}sbeRegAccessPackage_t; + +#endif // __SBEFW_SBESP_MSG_H diff --git a/src/sbefw/core/sbeTimerSvc.C b/src/sbefw/core/sbeTimerSvc.C new file mode 100644 index 00000000..eea43b17 --- /dev/null +++ b/src/sbefw/core/sbeTimerSvc.C @@ -0,0 +1,102 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbeTimerSvc.C $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2017 */ +/* */ +/* */ +/* 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: src/sbefw/sbeTimerSvc.C + * + * @brief This file contains the SBE timer service + * + */ + +#include "sbetrace.H" +#include "sbeTimerSvc.H" +#include "sbe_sp_intf.H" +#include "pk.h" + +uint32_t timerService::startTimer(uint32_t i_time, PkTimerCallback i_callBack ) +{ + #define SBE_FUNC "timerService::startTimer " + uint32_t l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + do + { + int l_pkRc = 0; + if( !init ) + { + l_pkRc = pk_timer_create(&fixedTimer, i_callBack, NULL); + if(l_pkRc) + { + SBE_ERROR(SBE_FUNC" Pk Timer Create failed, RC=[%d]", l_pkRc); + l_rc = SBE_SEC_OS_FAILURE; + break; + } + init = true; + } + if( isActive() ) + { + SBE_ERROR(SBE_FUNC" Timer already started"); + l_rc = SBE_SEC_TIMER_ALREADY_STARTED; + break; + } + // Schedule the timer + l_pkRc = pk_timer_schedule(&fixedTimer, + PK_MILLISECONDS((uint32_t)i_time)); + if(l_pkRc) + { + SBE_ERROR(SBE_FUNC" Pk Timer Schedule failed, RC=[%d]", l_pkRc); + l_rc = SBE_SEC_OS_FAILURE; + break; + } + } while(0); + return l_rc; + #undef SBE_FUNC +} + +uint32_t timerService::stopTimer( ) +{ + #define SBE_FUNC "timerService::stopTimer " + uint32_t l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + PkMachineContext ctx; + do + { + // The critical section enter/exit set is done to ensure + // pk_timer_cancel operations are non-interrupible. + pk_critical_section_enter(&ctx); + if( !isActive() ) + { + SBE_INFO(SBE_FUNC" Timer is not running"); + break; + } + // Cancel the timer + int l_pkRc = pk_timer_cancel(&fixedTimer ); + if(l_pkRc) + { + SBE_ERROR(SBE_FUNC" Pk Timer cancel failed, RC=[%d]", l_pkRc); + l_rc = SBE_SEC_OS_FAILURE; + break; + } + } while(0); + pk_critical_section_exit(&ctx); + return l_rc; + #undef SBE_FUNC +} + diff --git a/src/sbefw/core/sbeTimerSvc.H b/src/sbefw/core/sbeTimerSvc.H new file mode 100644 index 00000000..39ac046d --- /dev/null +++ b/src/sbefw/core/sbeTimerSvc.H @@ -0,0 +1,68 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbeTimerSvc.H $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2017 */ +/* */ +/* */ +/* 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: src/sbefw/sbeTimerSvc.H + * + * @brief This file contains the SBE Timer Service + * + */ + +#ifndef __SBEFW_TIMER_SVC_H +#define __SBEFW_TIMER_SVC_H +#include <stdint.h> +#include "pk_api.h" + +// structure for timer service +struct timerService +{ + bool init; /* Timer initialised */ + PkTimer fixedTimer; /* pk timer */ + + /** + * @brief start timer + * + * @param[in] i_time time in ms + * @param[in] i_callBack callback function on timer expiry + * + * @return error code as per sbe secondary errors + */ + uint32_t startTimer(uint32_t i_time, PkTimerCallback i_callBack ); + + /** + * @brief stop timer + * + * @return error code as per sbe secondary errors + */ + uint32_t stopTimer(); + + /** + * @brief Returns timer status + */ + inline bool isActive() + { + return ( init && pk_deque_is_queued( &(fixedTimer.deque) )); + } +}; + +#endif //__SBEFW_TIMER_SVC_H diff --git a/src/sbefw/core/sbeXipUtils.H b/src/sbefw/core/sbeXipUtils.H new file mode 100644 index 00000000..29df84f2 --- /dev/null +++ b/src/sbefw/core/sbeXipUtils.H @@ -0,0 +1,63 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbeXipUtils.H $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* */ +/* */ +/* 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 SBE_XIP_UTILS_H +#define SBE_XIP_UTILS_H + +#include "p9_xip_image.h" +#include "ppe42_scom.h" // for PPE_STVD +#include "sbe_link.H" // for SBE_BASE_ORIGIN, SBE_SEEPROM_BASE_ORIGIN + +// Unconditional jump to a memory location +#define JUMP_TO_ADDR(VAL ) \ +{ \ +asm volatile ( \ + "mtlr %0 \n\t" \ + : \ + : "r" (VAL)); \ +asm volatile ( \ + "blr \n\t" \ + : \ + );\ +} + +// PIBMEM start address +const uint32_t g_pibMemAddr = SBE_BASE_ORIGIN; +// SEEPROM start address +const uint32_t g_headerAddr = SBE_SEEPROM_BASE_ORIGIN; +// IVPR register address +const uint32_t g_ivprLoc = 0xC0000160; + +// Get XIP image header +inline P9XipHeader * getXipHdr() +{ + P9XipHeader *hdr = (P9XipHeader *)( g_headerAddr ); + return hdr; +} + +// Get Section start addess +inline uint8_t * getSectionAddr( P9XipSection * i_section ) +{ + return ( (uint8_t *)( g_headerAddr + i_section->iv_offset)); +} +#endif // SBE_XIP_UTILS_H diff --git a/src/sbefw/core/sbe_host_intf.H b/src/sbefw/core/sbe_host_intf.H new file mode 100644 index 00000000..f392851c --- /dev/null +++ b/src/sbefw/core/sbe_host_intf.H @@ -0,0 +1,135 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbe_host_intf.H $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* */ +/* */ +/* 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: ppe/sbe/sbefw/sbe_host_intf.H + * + * @brief This file contains the Host-SBE interface protocol common details + */ + +#ifndef __SBEFW_SBE_HOST_INTF_H +#define __SBEFW_SBE_HOST_INTF_H + +#include <stdint.h> + +/** + * $Version: Conforms to HOST-SBE Interface Spec v0.9b + */ + +/* + * Constants for SBE FW major and minor number + */ +static const uint16_t SBE_SBEFW_HOST_MAJOR_VERSION = 1; +static const uint16_t SBE_SBEFW_HOST_MINOR_VERSION = 0; + +/** + * @brief enums for SBE-Host interface command class + */ +enum sbePsuCommandClass + { + SBE_PSU_CMD_CLASS_UNKNOWN = 0, + SBE_PSU_CMD_CLASS_CORE_STATE = 0xD1, + SBE_PSU_CMD_CLASS_RING_ACCESS = 0xD3, + SBE_PSU_CMD_CLASS_CNTRL_TIMER = 0xD4, + SBE_PSU_CMD_CLASS_SECURITY_CONTROL_MSG = 0xD6, + SBE_PSU_CMD_CLASS_GENERIC = 0xD7, + }; + +/** + * @brief enums for SBE-Host interface core state control commands + */ +enum sbePsuCoreStateControlCommands +{ + SBE_PSU_CMD_CONTROL_DEADMAN = 0x01, + SBE_PSU_CMD_UNKNOWN = 0xFF, +}; + +/** + * @brief enums for SBE-Host interface control timer commands + */ +enum sbePsuControlTimerCommands +{ + SBE_PSU_CMD_CONTROL_TIMER = 0x01, + SBE_PSU_CMD_CONTROL_TIMER_UNKNOWN = 0xFF, +}; + +/** + * @brief enums for SBE-Host interface ring access messages + */ +enum sbePsuRingAccessMessages +{ + SBE_PSU_MSG_PUT_RING_FROM_IMAGE = 0x01, + SBE_PSU_MSG_UNKNOWN = 0xFF, +}; + +/** + * @brief enums for SBE-Host interface for unsecure memory regions commands + */ +enum sbePsuUpdateMemoryRegionMessages +{ + SBE_PSU_MSG_UPDATE_MEM_REGION = 0x01, +}; + +/** + * @brief enums for SBE-Host interface for generic commands + */ +enum sbePsuGenericMessages +{ + SBE_PSU_GENERIC_MSG_READ_SBE_MEM = 0x03, + SBE_PSU_GENERIC_MSG_SET_FFDC_ADDR = 0x04, + SBE_PSU_GENERIC_MSG_QUIESCE = 0x05, + SBE_PSU_GENERIC_MSG_SYSTEM_FABRIC_MAP = 0x06, + SBE_PSU_GENERIC_MSG_STASH_MPIPL_CONFIG = 0x07, + SBE_PSU_GENERIC_MSG_UNKNOWN = 0xFF, +}; + +/** + * @brief enums denoting control flags + * + */ +enum sbePsuControlFlags +{ + SBE_PSU_FLAGS_RESP_REQUIRED = 0x0100, + SBE_PSU_FLAGS_ACK_REQUIRED = 0x0200, +}; + +enum sbePsuDmtCmdFlags +{ + SBE_PSU_FLAGS_START_DMT = 0x0001, + SBE_PSU_FLAGS_STOP_DMT = 0x0002, +}; + +enum sbePsuCntrlTimerFlags +{ + SBE_PSU_FLAGS_START_TIMER = 0x0001, + SBE_PSU_FLAGS_STOP_TIMER = 0x0002, +}; + +enum sbeUnsecureMemRegionControlFlags +{ + SBE_MEM_REGION_OPEN_RO = 0x0011, + SBE_MEM_REGION_OPEN_RW = 0x0012, + SBE_MEM_REGION_CLOSE = 0x0020, +}; + +#endif // __SBEFW_SBE_HOST_INTF_H diff --git a/src/sbefw/core/sbe_sp_intf.H b/src/sbefw/core/sbe_sp_intf.H new file mode 100644 index 00000000..23881746 --- /dev/null +++ b/src/sbefw/core/sbe_sp_intf.H @@ -0,0 +1,521 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbe_sp_intf.H $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2017 */ +/* */ +/* */ +/* 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 sbe_sp_intf.H + * + * @brief This file contains the SP - SBE interface protocol common details + */ + +#ifndef __SBEFW_SBE_SP_INTF_H +#define __SBEFW_SBE_SP_INTF_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * $Version: Conforms to SP-SBE Interface Spec v0.8e + */ + +/* + * Constants for SBE FW major and minor number + */ +static const uint16_t SBE_FW_MAJOR_VERSION = 1; +static const uint16_t SBE_FW_MINOR_VERSION = 1; + +/** + * @brief enums for SBE command classes + * +*/ +enum sbeCommandClass +{ + SBE_CMD_CLASS_UNKNOWN = 0, + SBE_CMD_CLASS_IPL_CONTROL = 0xA1, + SBE_CMD_CLASS_SCOM_ACCESS = 0xA2, + SBE_CMD_CLASS_RING_ACCESS = 0xA3, + SBE_CMD_CLASS_MEMORY_ACCESS = 0xA4, + SBE_CMD_CLASS_REGISTER_ACCESS = 0xA5, + SBE_CMD_CLASS_ARRAY_ACCESS = 0xA6, + SBE_CMD_CLASS_INSTRUCTION_CONTROL = 0xA7, + SBE_CMD_CLASS_GENERIC_MESSAGE = 0xA8, + SBE_CMD_CLASS_MPIPL_COMMANDS = 0xA9, +}; + +static const uint8_t SBE_CMD_UNKNOWN = 0x00; + +/** + * @brief enums for SBE Istep Control command class + * +*/ +enum sbeIplControlCommands +{ + SBE_CMD_EXECUTE_ISTEP = 0x01, /* Execute istep */ + SBE_CMD_SUSPEND_IO = 0x02, /* Suspend IO */ +}; + +/** + * @brief enums for SCOM Access Messages + * +*/ +enum sbeScomAccessCommands +{ + SBE_CMD_GETSCOM = 0x01, /* Get SCOM */ + SBE_CMD_PUTSCOM = 0x02, /* Put SCOM */ + SBE_CMD_MODIFYSCOM = 0x03, /* Modify SCOM */ + SBE_CMD_PUTSCOM_MASK = 0x04, /* Put SCOM under mask */ + SBE_CMD_MULTISCOM = 0x05, /* Execute Multi SCOM */ +}; + +/** + * @brief enum for modify mode + * +*/ +enum sbeChipOpModifyMode +{ + SBE_MODIFY_MODE_OR = 0x01, + SBE_MODIFY_MODE_AND = 0x02, + SBE_MODIFY_MODE_XOR = 0x03, +}; + +/** + * @brief enums for Ring Access Messages + * +*/ +enum sbeRingAccessCommands +{ + SBE_CMD_GETRING = 0x01, /* Get Ring */ + SBE_CMD_PUTRING = 0x02, /* Put Ring */ +}; + +/** + * @brief enums for Memory Access Messages + * +*/ +enum sbeMemoryAccesCommands +{ + SBE_CMD_GETMEM = 0x01, /* Get Memory (Proc/PBA) */ + SBE_CMD_PUTMEM = 0x02, /* Put Memory (Proc/PBA) */ + SBE_CMD_GETSRAM_OCC = 0x03, /* Get Memory (OCC SRAM) */ + SBE_CMD_PUTSRAM_OCC = 0x04, /* Put Memory (OCC SRAM) */ +}; + +/** + * @brief enums for GPR/SPR/FPR Access Messages + * +*/ +enum sbeRegisterAccessCommands +{ + SBE_CMD_GETREG = 0x01, /* Get Register (GPR,SPR,FPR) */ + SBE_CMD_PUTREG = 0x02, /* Put Register (GPR,SPR,FPR) */ +}; + +/** + * @brief enums for Trace Array Access Messages + * +*/ +enum sbeArrayAccessCommands +{ + SBE_CMD_CONTROL_FAST_ARRAY = 0x01, /* Control Fast Array */ + SBE_CMD_CONTROL_TRACE_ARRAY = 0x02, /* Control Trace Array */ +}; + +/** + * @brief enums for Instruction Control Messages + * +*/ +enum sbeInstructionControlCommands +{ + SBE_CMD_CONTROL_INSTRUCTIONS = 0x01, /* Control Instructions */ +}; + +/** + * @brief enums for Generic Messages + * +*/ +enum sbeGenericMessageCommands +{ + SBE_CMD_GET_SBE_FFDC = 0x01, /* Get FFDC */ + SBE_CMD_GET_SBE_CAPABILITIES = 0x02, /* GET SBE capabilities */ + SBE_CMD_GET_FREQ_SUPPORTED = 0x03, /* Get Supported frequencies */ + SBE_CMD_QUIESCE = 0x06, /* Sbe Quiesce */ +}; + +enum sbeMpIplCommands +{ + SBE_CMD_MPIPL_ENTER = 0x01, /* Enter MPIPL */ + SBE_CMD_MPIPL_CONTINUE = 0x02, /* Continue MPIPL */ + SBE_CMD_MPIPL_STOPCLOCKS = 0x03, /* Stop Clocks */ +}; + +/** + * @brief enums for primary SBE response + * +*/ +enum sbePrimResponse +{ + SBE_PRI_OPERATION_SUCCESSFUL = 0x00, + SBE_PRI_INVALID_COMMAND = 0x01, + SBE_PRI_INVALID_DATA = 0x02, + SBE_PRI_USER_ERROR = 0x03, + SBE_PRI_INTERNAL_ERROR = 0x04, + SBE_PRI_UNSECURE_ACCESS_DENIED = 0x05, + SBE_PRI_GENERIC_EXECUTION_FAILURE = 0xFE, +}; + +/** + * @brief enums for secondary SBE response + * @TODO via RTC: 129763 + * Discuss on SBE_SEC_INVALID_TARGET_ID_PASSED + * +*/ +enum sbeSecondaryResponse +{ + SBE_SEC_OPERATION_SUCCESSFUL = 0x00, + SBE_SEC_COMMAND_CLASS_NOT_SUPPORTED = 0x01, + SBE_SEC_COMMAND_NOT_SUPPORTED = 0x02, + SBE_SEC_INVALID_ADDRESS_PASSED = 0x03, + SBE_SEC_INVALID_TARGET_TYPE_PASSED = 0x04, + SBE_SEC_INVALID_CHIPLET_ID_PASSED = 0x05, + SBE_SEC_SPECIFIED_TARGET_NOT_PRESENT = 0x06, + SBE_SEC_SPECIFIED_TARGET_NOT_FUNCTIONAL = 0x07, + SBE_SEC_COMMAND_NOT_ALLOWED_IN_THIS_STATE = 0x08, + SBE_SEC_FUNCTIONALITY_NOT_SUPPORTED = 0x09, + SBE_SEC_GENERIC_FAILURE_IN_EXECUTION = 0x0A, + SBE_SEC_BLACKLISTED_REG_ACCESS = 0x0B, + SBE_SEC_OS_FAILURE = 0x0C, + SBE_SEC_FIFO_ACCESS_FAILURE = 0x0D, + SBE_SEC_UNEXPECTED_EOT_INSUFFICIENT_DATA = 0x0E, + SBE_SEC_UNEXPECTED_EOT_EXCESS_DATA = 0x0F, + SBE_SEC_HW_OP_TIMEOUT = 0x10, + SBE_SEC_PCB_PIB_ERR = 0x11, + SBE_SEC_FIFO_PARITY_ERROR = 0x12, + SBE_SEC_TIMER_ALREADY_STARTED = 0x13, + SBE_SEC_BLACKLISTED_MEM_ACCESS = 0x14, + SBE_SEC_MEM_REGION_NOT_FOUND = 0x15, + SBE_SEC_MAXIMUM_MEM_REGION_EXCEEDED = 0x16, + SBE_SEC_MEM_REGION_AMEND_ATTEMPTED = 0x17, + SBE_SEC_INPUT_BUFFER_OVERFLOW = 0x18, + SBE_SEC_INVALID_PARAMS = 0x19, + SBE_SEC_BLACKLISTED_CHIPOP_ACCESS = 0x20, +}; + +/** + * @brief enums for SBE command timeout values + * +*/ +enum sbeCmdRespTimeout +{ + SBE_CMD_TIMEOUT_SHORT_IN_MSEC = 100, + SBE_CMD_TIMEOUT_LONG_IN_MSEC = 30000, +}; + +/** + * @brief capabilities index values. + * Get Capability response will return 18 capabilities. This + * enum tells the index for each capability. Currently each generic + * functionality( scom, IPL ) etc span across two capabilities. + */ +enum +{ + GENERIC_CAPABILTITY_START_IDX = 0, + IPL_CAPABILITY_START_IDX = GENERIC_CAPABILTITY_START_IDX + 2, + SCOM_CAPABILITY_START_IDX = GENERIC_CAPABILTITY_START_IDX + 4, + RING_CAPABILITY_START_IDX = GENERIC_CAPABILTITY_START_IDX + 6, + MEMORY_CAPABILITY_START_IDX = GENERIC_CAPABILTITY_START_IDX + 8, + REGISTER_CAPABILITY_START_IDX = GENERIC_CAPABILTITY_START_IDX + 10, + ARRAY_CAPABILITY_START_IDX = GENERIC_CAPABILTITY_START_IDX + 12, + INSTRUCTION_CTRL_CAPABILITY_START_IDX = GENERIC_CAPABILTITY_START_IDX + 14, + GENERIC_CHIPOP_CAPABILITY_START_IDX = GENERIC_CAPABILTITY_START_IDX + 16, +}; +/** + * @brief capabilities enum values. + * + */ +enum +{ + HWP_FFDC_COLLECTION_SUPPPORTED = 0x00000001, + SBE_FFDC_COLLECTION_SUPPPORTED = 0x00000002, + ADDRESS_BLACKLISTING_SUPPPORTED = 0x00000004, + FIFO_RESET_SUPPPORTED = 0x00000008, + EXECUTE_ISTEP_SUPPPORTED = 0xA1000001, + SUSPEND_IO_SUPPPORTED = 0xA1000002, + GET_SCOM_SUPPPORTED = 0xA2000001, + PUT_SCOM_SUPPPORTED = 0xA2000002, + MODIFY_SCOM_SUPPPORTED = 0xA2000004, + PUT_SCOM_UNDER_MASK_SUPPPORTED = 0xA2000008, + MULTI_SCOM_SUPPPORTED = 0xA2000010, + GET_RING_SUPPPORTED = 0xA3000001, + PUT_RING_SUPPPORTED = 0xA3000002, + GET_MEMORY_SUPPPORTED = 0xA4000001, + PUT_MEMORY_SUPPPORTED = 0xA4000002, + GET_SRAM_OCC_SUPPPORTED = 0xA4000004, + PUT_SRAM_OCC_SUPPPORTED = 0xA4000008, + GET_SRAM_CME_SUPPPORTED = 0xA4000010, + PUT_SRAM_CME_SUPPPORTED = 0xA4000020, + GET_REGISTER_SUPPPORTED = 0xA5000001, + PUT_REGISTER_SUPPPORTED = 0xA5000002, + CONTROL_FAST_ARRAY_SUPPPORTED = 0xA6000001, + CONTROL_TRACE_ARRAY_SUPPPORTED = 0xA6000002, + CONTROL_INSTRUCTIONS_SUPPPORTED = 0xA7000001, + GET_SBE_FFDC_SUPPPORTED = 0xA8000001, + GET_SBE_CAPABILITIES_SUPPPORTED = 0xA8000002, + GET_SBE_FREQUENCIES_SUPPPORTED = 0xA8000004, + GET_SBE_STATE_SUPPPORTED = 0xA8000008, + SBE_QUIESCE = 0xA8000010, + STOP_CLOCKS_MPIPL_SUPPORTED = 0xA9000004, +}; + +/** + * * @brief enums for SBE Memory Access command flags + * + */ +enum sbeMemoryAccessFlags +{ + SBE_MEM_ACCESS_FLAGS_TARGET_PROC = 0x0001, //required in ADU + SBE_MEM_ACCESS_FLAGS_TARGET_PBA = 0x0002, //required in PBA + SBE_MEM_ACCESS_FLAGS_AUTO_INCR_ON = 0x0004, + SBE_MEM_ACCESS_FLAGS_ECC_REQUIRED = 0x0008, //required only in ADU-GET + SBE_MEM_ACCESS_FLAGS_ECC_OVERRIDE = 0x0008, //required only in ADU-PUT + SBE_MEM_ACCESS_FLAGS_ITAG = 0x0010, //ITAG Mode in ADU + SBE_MEM_ACCESS_FLAGS_FAST_MODE_ON = 0x0020, + SBE_MEM_ACCESS_FLAGS_LCO_ENABLED = 0x0040, //required only in PBA-PUT + SBE_MEM_ACCESS_FLAGS_CACHE_INHIBIT = 0x0080, //required in I/O oper ADU + SBE_MEM_ACCESS_FLAGS_HOST_PASS_THROUGH = 0x0100, // Host pass through mode (PBA) + SBE_MEM_ACCESS_FLAGS_INJECT_ON = 0x0200, // Inject mode ( PBA put ) +}; + +/** + * @brief enum for various modes for Sram Access + */ +enum sbeSramAccessMode +{ + NORMAL_MODE = 0x1, + DEBUG_MODE = 0x2, + CIRCULAR_MODE = 0x3, +}; +/* + * Constants for maximum number of register supported in reg access chipop. + */ +static const uint32_t SBE_MAX_REG_ACCESS_REGS = 64; + +/** + * @brief Error Mode enum + */ +enum sbeErrorMode +{ + EXIT_ON_FIRST_ERROR = 0x0, // Bail out on first error + IGNORE_HW_ERRORS = 0x01, // Attempt best case +}; + +/** + * @brief Core Chiplet Id Enum + */ +enum sbeCoreChipletId +{ + SMT4_CORE0_ID = 0x20, + SMT4_CORE_ID_LAST = 0x37, + SMT4_ALL_CORES = 0xFF, +}; + +/** + * @brief EX Chiplet Id Enum + */ +enum sbeExChipletId +{ + EX_ALL_CHIPLETS = 0xFF, +}; + +/** + * @brief Thread Num Enum + */ +enum sbeThreadNum +{ + SMT4_THREAD0 = 0x0, + SMT4_THREAD1 = 0x1, + SMT4_THREAD2 = 0x2, + SMT4_THREAD3 = 0x3, + SMT4_THREAD_MAX = 0x4, + SMT4_THREAD_ALL = 0xF, +}; + +/** + * @brief Thread Operation Enum + */ +enum sbeThreadOps +{ + THREAD_START_INS = 0x0, + THREAD_STOP_INS = 0x1, + THREAD_STEP_INS = 0x2, + THREAD_SRESET_INS = 0x3, +}; + +/** + * @brief enums for Reg access register type + * + */ +enum sbeRegAccesRegType +{ + SBE_REG_ACCESS_GPR = 0x00, + SBE_REG_ACCESS_SPR = 0x01, + SBE_REG_ACCESS_FPR = 0x02, +}; + + +// Base Target Type offset maintined by SBE to be used across different chip-ops +// Need to avoid any duplicate target type since it is used to convert into FAPI +// target via file sbefapiutil.C + +/* + * @brief enums for target types used in ring access chip op and + * in stop clocks chip ops +*/ +typedef enum +{ + TARGET_PROC_CHIP = 0x0000, + TARGET_EX = 0x0001, + TARGET_PERV = 0x0002, + TARGET_MCS = 0x0003, + TARGET_EQ = 0x0004, + TARGET_CORE = 0x0005, +} sbeTargetTypes_t; + +/** + * @brief Pervasive Chiplet Id Enum + */ +enum sbePervChipletId +{ + PERV_CHIPLET = 0x01, +}; + +/** + * @brief Nest Chiplet Id Enum + */ +enum sbeNestChipletId +{ + NEST_ID_0 = 0x02, + NEST_ID_LAST = 0x05, +}; + +/** + * @brief XBus Chiplet Id Enum + */ +enum sbeXBusChipletId +{ + XBUS_ID = 0x06, +}; + +/** + * @brief MC Bist Chiplet Id Enum + */ +enum sbeMcbistChipletId +{ + MCBIST_ID_0 = 0x07, + MCBIST_ID_LAST = 0x08, +}; + +/** + * @brief OBus Chiplet Id Enum + */ +enum sbeObusChipletId +{ + OBUS_ID_0 = 0x09, + OBUS_ID_LAST = 0x0C, +}; + +/** + * @brief PCIe Chiplet Id Enum + */ +enum sbePcieChipletId +{ + PCIE_ID_0 = 0x0D, + PCIE_ID_LAST = 0x0F, +}; + +/** + * @brief Cache Chiplet Id Enum + */ +enum sbeCacheChipletId +{ + EQ_ID_0 = 0x10, + EQ_ID_LAST = 0x15, + EQ_ALL_CHIPLETS = 0xFF, +}; + +/* + * @brief maximum length for putring RS4 payload for chipop operation +*/ +static const uint32_t SBE_PUT_RING_RS4_MAX_PAYLOAD_BYTES = 512; +/* + * @brief enums for access modes used in ring access chip op + */ +typedef enum +{ + SBE_RING_MODE_NO_HEADER_CHECK = 0x0001, ///< Don't check header + SBE_RING_MODE_SET_PULSE_NO_OPCG_COND = 0x0002, ///< Set pulse with + /// no OPCG conditioning + SBE_RING_MODE_SET_PULSE_NSL = 0x0004, ///< Set pulse with NSL + /// pulse + SBE_RING_MODE_SET_PULSE_SL = 0x0008, ///< Set pulse with SL + /// pulse + SBE_RING_MODE_SET_PULSE_ALL = 0x0010, ///< Set pulse with pulse + /// to all hold types + SBE_RING_MODE_FASTARRAY = 0x0020, //Fast array mode + + SBE_RING_MODE_APPLY_OVERRIDE = 0x0040, //override mode +} sbeRingAccessModes_t; + +// Trace array chip-op operation bitmaps +static const uint16_t SBE_TA_RESET = 0x0001; +static const uint16_t SBE_TA_RESTART = 0x0002; +static const uint16_t SBE_TA_STOP = 0x0004; +static const uint16_t SBE_TA_COLLECT_DUMP = 0x0008; +static const uint16_t SBE_TA_IGNORE_MUX_SETTING = 0x0010; + +/* + * @brief enums for fast array control mode + */ +typedef enum +{ + FASTARRAY_SETUP = 0x01, + FASTARRAY_SKIPCYCLES = 0x02, + FASTARRAY_CLEANUP = 0x03, +} sbeFastArrayControlModes_t; + +/* + * @brief enums for SBE client ID + */ +typedef enum +{ + CLIENT_DEFAULT = 0x0, + CLIENT_SP = 0x1, + CLIENT_HOST = 0x2, + CLIENT_LAB = 0x3, + CLIENT_OCC = 0x4, +} sbeClientId_t; + +#ifdef __cplusplus +} +#endif + +#endif /* __SBEFW_SBE_SP_INTF_H */ diff --git a/src/sbefw/core/sbecmdCntrlTimer.C b/src/sbefw/core/sbecmdCntrlTimer.C new file mode 100644 index 00000000..e24698ae --- /dev/null +++ b/src/sbefw/core/sbecmdCntrlTimer.C @@ -0,0 +1,144 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbecmdCntrlTimer.C $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2017 */ +/* */ +/* */ +/* 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: src/sbefw/sbecmdCntrlTimer.C + * + * @brief This file contains the SBE Timer Commands + * + */ + +#include "sbecmdCntrlTimer.H" +#include "sbetrace.H" +#include "sbe_sp_intf.H" +#include "sbeFFDC.H" +#include "sbeHostMsg.H" +#include "sbeHostUtils.H" +#include "sbeTimerSvc.H" +#include "sbeglobals.H" + +#include "fapi2.H" +using namespace fapi2; + +// Global instance to track PK timer +static timerService g_hostTimerSvc; + +// Callback +void sbeTimerExpiryCallback(void *) +{ + #define SBE_FUNC "sbeTimerExpiryCallback " + SBE_ENTER(SBE_FUNC); + + do + { + // indicate the Host via Bit SBE_SBE2PSU_DOORBELL_SET_BIT14 + // that Timer has expired + SBE_INFO(SBE_FUNC "Updating door bell bit 14"); + uint32_t l_rc = sbeSetSbe2PsuDbBitX(SBE_SBE2PSU_DOORBELL_SET_BIT14); + if(l_rc) + { + SBE_ERROR(SBE_FUNC " Failed to Write " + "SBE_SBE2PSU_DOORBELL_SET_BIT14"); + pk_halt(); + } + }while(0); + SBE_EXIT(SBE_FUNC); + #undef SBE_FUNC + +} +///////////////////////////////////////////////////////////////////// + +//---------------------------------------------------------------------------- +uint32_t sbeCntrlTimer( uint8_t *i_pArg ) +{ + #define SBE_FUNC "sbeCntrlTimer " + SBE_ENTER(SBE_FUNC); + uint32_t l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + uint32_t l_fapiRc = FAPI2_RC_SUCCESS; + + do + { + if(SBE_GLOBAL->sbePsu2SbeCmdReqHdr.flags & SBE_PSU_FLAGS_START_TIMER) + { + uint64_t time = 0; + l_rc = sbeReadPsu2SbeMbxReg(SBE_HOST_PSU_MBOX_REG1, + (sizeof(time)/sizeof(uint64_t)), + &time, true); + + if(SBE_SEC_OPERATION_SUCCESSFUL != l_rc) + { + SBE_ERROR(SBE_FUNC" Failed to extract SBE_HOST_PSU_MBOX_REG1"); + break; + } + + SBE_INFO(SBE_FUNC "Start Timer. Time: [%08X]", + SBE::lower32BWord(time)); + + l_rc = g_hostTimerSvc.startTimer( (uint32_t )time, + (PkTimerCallback)&sbeTimerExpiryCallback); + if(SBE_SEC_OPERATION_SUCCESSFUL != l_rc) + { + SBE_GLOBAL->sbeSbe2PsuRespHdr.setStatus(SBE_PRI_INTERNAL_ERROR, l_rc); + SBE_ERROR(SBE_FUNC" g_hostTimerSvc.startTimer failed"); + l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + break; + } + break; + } + // Acknowledge host + l_rc = sbeAcknowledgeHost(); + if(l_rc) + { + SBE_ERROR(SBE_FUNC " Failed to Sent Ack to Host over " + "SBE_SBE2PSU_DOORBELL_SET_BIT1"); + break; + } + + if(SBE_GLOBAL->sbePsu2SbeCmdReqHdr.flags & SBE_PSU_FLAGS_STOP_TIMER) + { + SBE_INFO(SBE_FUNC "Stop Timer."); + l_rc = g_hostTimerSvc.stopTimer( ); + if(SBE_SEC_OPERATION_SUCCESSFUL != l_rc) + { + SBE_GLOBAL->sbeSbe2PsuRespHdr.setStatus(SBE_PRI_INTERNAL_ERROR, l_rc); + SBE_ERROR(SBE_FUNC" g_hostTimerSvc.stopTimer failed"); + l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + break; + } + break; + } + + SBE_GLOBAL->sbeSbe2PsuRespHdr.setStatus( SBE_PRI_INVALID_COMMAND, + SBE_SEC_COMMAND_NOT_SUPPORTED); + SBE_ERROR(SBE_FUNC" Not a valid flag 0x%4X", + (uint16_t) SBE_GLOBAL->sbePsu2SbeCmdReqHdr.flags); + }while(0); + + // Send the response + sbePSUSendResponse(SBE_GLOBAL->sbeSbe2PsuRespHdr, l_fapiRc, l_rc); + + SBE_EXIT(SBE_FUNC); + return l_rc; + #undef SBE_FUNC +} + diff --git a/src/sbefw/core/sbecmdCntrlTimer.H b/src/sbefw/core/sbecmdCntrlTimer.H new file mode 100644 index 00000000..8adec307 --- /dev/null +++ b/src/sbefw/core/sbecmdCntrlTimer.H @@ -0,0 +1,45 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbecmdCntrlTimer.H $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* */ +/* */ +/* 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: ppe/sbe/sbefw/sbecmdCntrlTimer.H + * + * @brief This file contains the SBE control timer command details + * + */ + +#ifndef __SBEFW_SBECMD_CNTRL_TIMER_H +#define __SBEFW_SBECMD_CNTRL_TIMER_H + +#include <stdint.h> + +/** + * @brief SBE Psu Control timer chipop (0xD401) + * + * @param[in] i_pArg Buffer to be passed to the function (not used as of now) + * + * @return Rc from the Psu access utility + */ +uint32_t sbeCntrlTimer( uint8_t *i_pArg ); + +#endif // __SBEFW_SBECMD_CNTRL_TIMER_H diff --git a/src/sbefw/core/sbecmdcntlinst.C b/src/sbefw/core/sbecmdcntlinst.C new file mode 100644 index 00000000..8674c97a --- /dev/null +++ b/src/sbefw/core/sbecmdcntlinst.C @@ -0,0 +1,203 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbecmdcntlinst.C $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* */ +/* */ +/* 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: ppe/sbe/sbefw/sbecmdcntlinst.C + * + * @brief This file contains the SBE Control Instruction chipOps + * + */ + +#include "sbecmdcntlinst.H" +#include "sbefifo.H" +#include "sbe_sp_intf.H" +#include "sbetrace.H" +#include "sbeFifoMsgUtils.H" + +#include "fapi2.H" +#include "p9_thread_control.H" + +using namespace fapi2; + +// TODO via RTC 152424 +// Currently all proecdures in core directory are in seeprom. +// So we have to use function pointer to force a long call. +#ifdef SEEPROM_IMAGE +p9_thread_control_FP_t threadCntlhwp = &p9_thread_control; +#endif + +/* @brief Map User Thread Command to Hwp ThreadCommands Enum */ +ThreadCommands getThreadCommand(const sbeCntlInstRegMsgHdr_t & i_req) +{ + ThreadCommands l_cmd = PTC_CMD_START; + switch(i_req.threadOps) + { + case THREAD_START_INS: l_cmd = PTC_CMD_START; break; + case THREAD_STOP_INS: l_cmd = PTC_CMD_STOP; break; + case THREAD_STEP_INS: l_cmd = PTC_CMD_STEP; break; + case THREAD_SRESET_INS: l_cmd = PTC_CMD_SRESET; break; + } + return l_cmd; +} + +/* @brief Map User Mode Command to Hwp Warn Check flag */ +inline bool getWarnCheckFlag(const sbeCntlInstRegMsgHdr_t & i_req) +{ + bool l_warnCheck = false; + if( EXIT_ON_FIRST_ERROR != i_req.mode ) + { + l_warnCheck = true; + } + return l_warnCheck; +} + +/////////////////////////////////////////////////////////////////////// +// @brief sbeCntlInst Sbe control instructions function +// +// @return RC from the underlying FIFO utility +/////////////////////////////////////////////////////////////////////// +uint32_t sbeCntlInst(uint8_t *i_pArg) +{ + #define SBE_FUNC " sbeCntlInst " + SBE_ENTER(SBE_FUNC); + + uint32_t l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + ReturnCode l_fapiRc = FAPI2_RC_SUCCESS; + sbeRespGenHdr_t l_respHdr; + l_respHdr.init(); + sbeResponseFfdc_t l_ffdc; + + // Create the req struct for Control Instructions Chip-op + sbeCntlInstRegMsgHdr_t l_req = {0}; + + do + { + // Get the Req Struct Data sbeCntlInstRegMsgHdr_t from upstream Fifo + uint32_t l_len2dequeue = sizeof(l_req) / sizeof(uint32_t); + l_rc = sbeUpFifoDeq_mult (l_len2dequeue, (uint32_t *)&l_req, true); + + // If FIFO failure + if ( SBE_SEC_OPERATION_SUCCESSFUL != l_rc ) + { + // Let command processor routine to handle the RC. + break; + } + + SBE_INFO("mode[0x%04X] coreChipletId[0x%08X] threadNum[0x%04X] " + "threadOps[0x%04X] ", l_req.mode, l_req.coreChipletId, + l_req.threadNum, l_req.threadOps); + + // Validate Input Args + if( false == l_req.validateInputArgs()) + { + SBE_ERROR(SBE_FUNC "ValidateAndMapInputArgs failed"); + l_respHdr.setStatus( SBE_PRI_INVALID_DATA, + SBE_SEC_GENERIC_FAILURE_IN_EXECUTION ); + break; + } + + // Fetch HWP mapped values + bool l_warnCheck = getWarnCheckFlag(l_req); + ThreadCommands l_cmd = getThreadCommand(l_req); + + // Default assignment not required since it is assigned below + uint8_t l_core, l_coreCntMax; + uint8_t l_threadCnt, l_threadCntMax; + + l_req.processInputDataToIterate(l_core, l_coreCntMax, + l_threadCnt, l_threadCntMax); + fapi2::buffer<uint64_t> l_data64; + uint64_t l_state; + do + { + fapi2::Target<fapi2::TARGET_TYPE_CORE> + l_coreTgt(plat_getTargetHandleByChipletNumber + <fapi2::TARGET_TYPE_CORE>(l_core)); + if(!l_coreTgt.isFunctional()) + { + continue; + } + + uint8_t l_thread = l_threadCnt; + do + { + // Call the Procedure + SBE_EXEC_HWP(l_fapiRc, + threadCntlhwp, + l_coreTgt, + (SINGLE_THREAD_BIT_MASK >> l_thread), + l_cmd, l_warnCheck, + l_data64, l_state) + + if(l_fapiRc != FAPI2_RC_SUCCESS) + { + SBE_ERROR(SBE_FUNC "Failed for Core[%d] Thread [%d] " + "Cmd[%d] Mode[%d]", l_core, l_thread, l_req.threadOps, + l_req.mode); + if(IGNORE_HW_ERRORS == l_req.mode) + { + // No need to delete the l_fapiRc handle,it will get + // over-written + SBE_INFO(SBE_FUNC "Continuing in case of HW Errors" + " As user has passed to ignore errors."); + continue; + } + else + { + SBE_ERROR(SBE_FUNC "Breaking out, since User has " + "Selected the mode to exit on first error."); + l_respHdr.setStatus(SBE_PRI_GENERIC_EXECUTION_FAILURE, + SBE_SEC_GENERIC_FAILURE_IN_EXECUTION); + l_ffdc.setRc(l_fapiRc); + break; + } + } + }while(++l_thread < l_threadCntMax); + + // If FapiRc from the inner loop (thread loop), just break here + if ((l_fapiRc) && (IGNORE_HW_ERRORS != l_req.mode)) + { + break; // From core while loop + } + }while(++l_core < l_coreCntMax); + + }while(0); + + // Create the Response to caller + do + { + // If there was a FIFO error, will skip sending the response, + // instead give the control back to the command processor thread + if ( SBE_SEC_OPERATION_SUCCESSFUL != l_rc) + { + break; + } + + l_rc = sbeDsSendRespHdr(l_respHdr, &l_ffdc); + }while(0); + + SBE_EXIT(SBE_FUNC); + return l_rc; + #undef SBE_FUNC +} + diff --git a/src/sbefw/core/sbecmdcntlinst.H b/src/sbefw/core/sbecmdcntlinst.H new file mode 100644 index 00000000..f0515602 --- /dev/null +++ b/src/sbefw/core/sbecmdcntlinst.H @@ -0,0 +1,50 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbecmdcntlinst.H $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* */ +/* */ +/* 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: ppe/sbe/sbefw/sbecmdcntlinst.H + * + * @brief This file contains the Interfaces for Control Instructions chip-ops + * + */ + +#ifndef __SBEFW_SBECMDCNTLINST_H +#define __SBEFW_SBECMDCNTLINST_H + +#include <stdint.h> + + +// This is used to find out the array index in g_control_reg_map in +// p9_thread_control.C +static const uint8_t SINGLE_THREAD_BIT_MASK = 0x08; + +/** + * @brief sbeCntlInst : Implements SBE Control instructions ChipOp + * + * @param[in] i_pArg Buffer to be passed to the function (not used as of now) + * + * @return Rc from the FIFO access utility + */ +uint32_t sbeCntlInst (uint8_t *i_pArg); + +#endif /* __SBEFW_SBECMDCNTLINST_H */ diff --git a/src/sbefw/core/sbecmdcntrldmt.C b/src/sbefw/core/sbecmdcntrldmt.C new file mode 100644 index 00000000..4fac1d59 --- /dev/null +++ b/src/sbefw/core/sbecmdcntrldmt.C @@ -0,0 +1,367 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbecmdcntrldmt.C $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* */ +/* */ +/* 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: sbe/sbefw/sbecmdcntrldmt.C + * + * @brief This file contains the Core State Control Messages + * + */ + +#include "sbecmdcntrldmt.H" +#include "sbetrace.H" +#include "sbe_build_info.H" +#include "sbeHostMsg.H" +#include "sbeHostUtils.H" +#include "sberegaccess.H" +#include "sbestates.H" +#include "sbe_sp_intf.H" +#include "fapi2.H" +#include "plat_hw_access.H" +#include "p9_sbe_check_master_stop15.H" +#ifdef DD2 +#include "p9_collect_deadman_ffdc.H" +#endif +#include "p9_perv_scom_addresses.H" +#include "p9_block_wakeup_intr.H" +#include "sbeTimerSvc.H" +#include "sbeglobals.H" + +using namespace fapi2; + +#ifdef SEEPROM_IMAGE +// Using Function pointer to force long call +p9_sbe_check_master_stop15_FP_t p9_sbe_check_master_stop15_hwp = + &p9_sbe_check_master_stop15; +p9_block_wakeup_intr_FP_t p9_block_wakeup_intr_hwp = + &p9_block_wakeup_intr; +#endif + +//////////////////////////////////////////////////////////////////// +//Static initialization of the Dmt Pk timer +static timerService g_sbe_pk_dmt_timer; + +///////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////// +void sbeDmtPkExpiryCallback(void *) +{ + #define SBE_FUNC "sbeDmtPkExpiryCallback" + SBE_INFO (SBE_FUNC "DMT Callback Timer has expired..Checkstop the system"); + ReturnCode fapiRc = FAPI2_RC_SUCCESS; + + (void)SbeRegAccess::theSbeRegAccess().stateTransition( + SBE_DUMP_FAILURE_EVENT); + + // check stop the system + plat_target_handle_t l_hndl; + fapiRc = putscom_abs_wrap(&l_hndl, PERV_N3_LOCAL_FIR_OR, + ((uint64_t)1 << N3_FIR_CORE_CHECKSTOP_BIT)); + if(fapiRc != FAPI2_RC_SUCCESS) + { + // Scom failed + SBE_ERROR (SBE_FUNC "PutScom failed: REG PERV_N3_LOCAL_FIR"); + pk_halt(); + } + + (void)SbeRegAccess::theSbeRegAccess().updateAsyncFFDCBit(true); + #undef SBE_FUNC +} + +///////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////// +uint32_t sbeCollectDeadmanFfdc (void) +{ + #define SBE_FUNC "sbeCollectDeadmanFfdc" + uint32_t rc = SBE_SEC_OPERATION_SUCCESSFUL; + + // trace the saved aync ffdc reason and SBE state as info for debug + SBE_INFO (SBE_FUNC "FFDC Reason: 0x%08X States - Curr: %d Prev: %d", + SBE_GLOBAL->asyncFfdcRC, + SbeRegAccess::theSbeRegAccess().getSbeState(), + SbeRegAccess::theSbeRegAccess().getSbePrevState()); + + fapi2::Target<fapi2::TARGET_TYPE_CORE> coreTarget ( + plat_getTargetHandleByChipletNumber <fapi2::TARGET_TYPE_CORE> ( + (SBE_GLOBAL->deadmanCore + CORE_CHIPLET_OFFSET) )); + +#ifdef DD2 + ReturnCode fapiRc = FAPI2_RC_SUCCESS; + // p9_collect_deadman_ffdc collects the required ffdc into the fapi rc + // which will be available in the SBE Global HWP FFDC region + SBE_EXEC_HWP ( fapiRc, + p9_collect_deadman_ffdc, + coreTarget, + SBE_GLOBAL->asyncFfdcRC ); +#endif + + return rc; + #undef SBE_FUNC +} + +///////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////// +uint32_t sbeStartCntlDmt() +{ + #define SBE_FUNC "sbeStartCntlDmt" + uint32_t l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + uint32_t l_fapiRc = FAPI2_RC_SUCCESS; + + do + { + // Fetch the Timer Value and Start a Pk Timer + uint64_t l_timerVal = 0; + l_rc = sbeReadPsu2SbeMbxReg(SBE_HOST_PSU_MBOX_REG1, + (sizeof(l_timerVal)/sizeof(uint64_t)), + &l_timerVal, true ); + if(SBE_SEC_OPERATION_SUCCESSFUL != l_rc) + { + SBE_ERROR(SBE_FUNC" Failed to extract SBE_HOST_PSU_MBOX_REG1"); + break; + } + + l_rc = g_sbe_pk_dmt_timer.startTimer( (uint32_t )l_timerVal, + (PkTimerCallback)&sbeDmtPkExpiryCallback); + if(SBE_SEC_OPERATION_SUCCESSFUL != l_rc) + { + SBE_GLOBAL->sbeSbe2PsuRespHdr.setStatus(SBE_PRI_INTERNAL_ERROR, l_rc); + SBE_ERROR(SBE_FUNC" g_sbe_pk_dmt_timer.startTimer failed"); + l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + } + + sbePSUSendResponse(SBE_GLOBAL->sbeSbe2PsuRespHdr, l_fapiRc, l_rc); + + if(SBE_SEC_OPERATION_SUCCESSFUL != l_rc) + { + SBE_ERROR(SBE_FUNC" Failed to send response to Hostboot "); + break; + } + + // Set DMT State + (void)SbeRegAccess::theSbeRegAccess().stateTransition( + SBE_DMT_ENTER_EVENT); + // To start, assume no errors will hit when starting DMT and hence + // default to potential timeout in stopping DMT for FFDC + SBE_GLOBAL->asyncFfdcRC = RC_CHECK_MASTER_STOP15_DEADMAN_TIMEOUT; + + Target<TARGET_TYPE_PROC_CHIP > l_procTgt = plat_getChipTarget(); + // Fetch the Master EX + uint8_t exId = 0; + uint8_t fuseMode = 0; + FAPI_ATTR_GET(fapi2::ATTR_MASTER_EX,l_procTgt,exId); + FAPI_ATTR_GET(ATTR_FUSED_CORE_MODE, Target<TARGET_TYPE_SYSTEM>(), fuseMode); + fapi2::Target<fapi2::TARGET_TYPE_EX > + exTgt(plat_getTargetHandleByInstance<fapi2::TARGET_TYPE_EX>(exId)); + + bool hwpFailed = false; + // Initialise both cores with fapi2::RC_CHECK_MASTER_STOP15_PENDING + uint32_t rcFapi[2] = {RC_CHECK_MASTER_STOP15_PENDING}; + + // Call HWP p9_sbe_check_master_stop15 in a loop as long as the timer is + // active and HWP returns RC_CHECK_MASTER_STOP15_PENDING + do + { + uint8_t coreCnt = 0; + + for (auto &coreTgt : exTgt.getChildren<fapi2::TARGET_TYPE_CORE>()) + { + // Skip calling on core that already entered stop15 + if (rcFapi[coreCnt] == RC_CHECK_MASTER_STOP15_PENDING) + { + SBE_GLOBAL->deadmanCore = coreTgt.get().getTargetInstance(); + // Core0 is assumed to be the master core + SBE_INFO ( SBE_FUNC + "Executing p9_sbe_check_master_stop15_hwp for" + " Core[%d]", SBE_GLOBAL->deadmanCore ); + SBE_EXEC_HWP ( l_fapiRc, + p9_sbe_check_master_stop15_hwp, + coreTgt); + rcFapi[coreCnt++] = l_fapiRc; + + if (! ((FAPI2_RC_SUCCESS == l_fapiRc) || + (RC_CHECK_MASTER_STOP15_PENDING == l_fapiRc)) ) + { + hwpFailed = true; + // Mark the failure point .. + SBE_GLOBAL->asyncFfdcRC = + RC_CHECK_MASTER_STOP15_INVALID_STATE; + SBE_ERROR ( SBE_FUNC" p9_sbe_check_master_stop15 failed" + "on core[%d]", SBE_GLOBAL->deadmanCore ); + break; + } + + if (!fuseMode) + { // mark odd core as succeeded & exit the core loop + rcFapi[coreCnt] = FAPI2_RC_SUCCESS; + break; + } + } + } // Core loop for check master stop 15 + + // Either Core failed or Both Cores succeeded + if ( hwpFailed || ((FAPI2_RC_SUCCESS == rcFapi[0]) && + (FAPI2_RC_SUCCESS == rcFapi[1]))) + { // Exit timer loop + break; + } + + // Wait if either or both cores are pending to enter stop 15 + // and no error on either cores + pk_sleep(PK_MILLISECONDS(SBE_DMT_SLEEP_INTERVAL)); + + // loop back only if timer is still active + } while (g_sbe_pk_dmt_timer.isActive()); + + if (hwpFailed) + { // exit the do .. while (0) outermost loop + break; + } + + // Both cores entered stop 15 successfully, now unblock interrupts + for (auto coreTgt : exTgt.getChildren<fapi2::TARGET_TYPE_CORE>()) + { + SBE_GLOBAL->deadmanCore = coreTgt.get().getTargetInstance(); + SBE_INFO(SBE_FUNC "Executing p9_block_wakeup_intr_hwp for Core[%d]", + SBE_GLOBAL->deadmanCore); + SBE_EXEC_HWP(l_fapiRc, p9_block_wakeup_intr_hwp, coreTgt, + p9pmblockwkup::CLEAR); + if (l_fapiRc) + { + // Mark the failure point .. SBE waits for DMT timer to expire + SBE_GLOBAL->asyncFfdcRC = RC_BLOCK_WAKEUP_INTR_CHECK_FAIL; + SBE_ERROR(SBE_FUNC" p9_block_wakeup_intr failed for " + "Core[%d]", SBE_GLOBAL->deadmanCore); + + break; + } + // If Success for the First core & it's a Fuse core then + // continue here for the Second core then go on to press the + // Door Bell + if(!fuseMode) + { + break; + } + } + + // Break out for the p9_block_wakeup_intr failure above + // Dont press the Door bell + if(l_fapiRc) + { + break; + } + + // Entered stop15 and unblocked interrupts .. + // Indicate the Host via Bit SBE_SBE2PSU_DOORBELL_SET_BIT2 + // that Stop15 exit + l_rc = sbeSetSbe2PsuDbBitX(SBE_SBE2PSU_DOORBELL_SET_BIT2); + if(l_rc) + { + SBE_ERROR(SBE_FUNC " Failed to Write " + "SBE_SBE2PSU_DOORBELL_SET_BIT2"); + } + } while(0); // Outer loop + + return l_rc; + #undef SBE_FUNC +} + +///////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////// +uint32_t sbeStopCntlDmt() +{ + #define SBE_FUNC "sbeStopCntlDmt " + uint32_t l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + uint32_t l_fapiRc = FAPI2_RC_SUCCESS; + + do + { + SBE_INFO(SBE_FUNC "Stop Timer."); + l_rc = g_sbe_pk_dmt_timer.stopTimer( ); + if(SBE_SEC_OPERATION_SUCCESSFUL != l_rc) + { + SBE_GLOBAL->sbeSbe2PsuRespHdr.setStatus ( SBE_PRI_INTERNAL_ERROR, + l_rc ); + SBE_ERROR(SBE_FUNC"g_sbe_pk_dmt_timer.stopTimer failed"); + l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + break; + } + + // Reset Async FFDC RC to default success + SBE_GLOBAL->asyncFfdcRC = FAPI2_RC_SUCCESS; + // Set Runtime State + (void)SbeRegAccess::theSbeRegAccess().stateTransition( + SBE_DMT_COMP_EVENT); + }while(0); + // Send the response + sbePSUSendResponse(SBE_GLOBAL->sbeSbe2PsuRespHdr, l_fapiRc, l_rc); + + return l_rc; + #undef SBE_FUNC +} + +///////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////// +uint32_t sbeControlDeadmanTimer (uint8_t *i_pArg) +{ + #define SBE_FUNC "sbeControlDeadmanTimer" + SBE_ENTER(SBE_FUNC); + uint32_t l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + + do + { + if(SBE_GLOBAL->sbePsu2SbeCmdReqHdr.flags & SBE_PSU_FLAGS_START_DMT) + { + l_rc = sbeStartCntlDmt(); + if(SBE_SEC_OPERATION_SUCCESSFUL != l_rc) + { + SBE_ERROR(SBE_FUNC " Failed sbeStartCntlDmt"); + } + break; + } + // Send Ack to Host via SBE_SBE2PSU_DOORBELL_SET_BIT1 + // This util method will check internally on the mbox0 register if ACK + // is requested. + l_rc = sbeAcknowledgeHost(); + if(l_rc) + { + SBE_ERROR(SBE_FUNC " Failed to Sent Ack to Host over " + "SBE_SBE2PSU_DOORBELL_SET_BIT1"); + break; + } + + if(SBE_GLOBAL->sbePsu2SbeCmdReqHdr.flags & SBE_PSU_FLAGS_STOP_DMT) + { + l_rc = sbeStopCntlDmt(); + if(SBE_SEC_OPERATION_SUCCESSFUL != l_rc) + { + SBE_ERROR(SBE_FUNC " Failed sbeStopCntlDmt"); + } + break; + } + SBE_ERROR(SBE_FUNC" Not a valid command "); + l_rc = SBE_SEC_COMMAND_NOT_SUPPORTED; + }while(0); // End of do-while + + SBE_EXIT(SBE_FUNC); + return l_rc; + #undef SBE_FUNC +} diff --git a/src/sbefw/core/sbecmdcntrldmt.H b/src/sbefw/core/sbecmdcntrldmt.H new file mode 100644 index 00000000..a598e037 --- /dev/null +++ b/src/sbefw/core/sbecmdcntrldmt.H @@ -0,0 +1,67 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbecmdcntrldmt.H $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* */ +/* */ +/* 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: ppe/sbe/sbefw/sbecmdcntrldmt.H + * + * @brief This file contains the Core State Control Messages API header + * + */ + +#ifndef __SBEFW_SBECMDCNTRLDMT_H +#define __SBEFW_SBECMDCNTRLDMT_H + +#include <stdint.h> + +// Define for the Sleep interval between continuous HWP calls +// for DMT functionality in Millisecond +static const uint8_t SBE_DMT_SLEEP_INTERVAL = 1; + +// Bit-32 used to checkstop the system, since this is directly getting +// inserted, we need to use bit (63-32) = 31st bit. +static const uint64_t N3_FIR_CORE_CHECKSTOP_BIT = 31; // 63-32 = 31 + +/** + * @brief Callback for Timer Expiry for DMT + * + * @return void + */ +void sbeDmtPkExpiryCallback(void *arg); + +/** + * @brief Called to collect FFDC for the Deadman loop timeout + * into the SBE global HWP FFDC region + * @return SBE Secondary RC + */ +uint32_t sbeCollectDeadmanFfdc (void); + +/** + * @brief Control Deadman Timer command (0xD101) + * + * @param[in] i_pArg Buffer to be passed to the function (not used as of now) + * + * @return RC from the PSU access utility + */ +uint32_t sbeControlDeadmanTimer(uint8_t *i_pArg); + +#endif // __SBEFW_SBECMDCNTRLDMT_H diff --git a/src/sbefw/core/sbecmdfastarray.C b/src/sbefw/core/sbecmdfastarray.C new file mode 100644 index 00000000..78b08921 --- /dev/null +++ b/src/sbefw/core/sbecmdfastarray.C @@ -0,0 +1,145 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbecmdfastarray.C $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* */ +/* */ +/* 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 "sbecmdfastarray.H" +#include "sbefifo.H" +#include "sbe_sp_intf.H" +#include "sbetrace.H" +#include "sbeFifoMsgUtils.H" +#include "sbeutil.H" +#include "sbefapiutil.H" +#include "fapi2.H" + +#include "p9_sbe_fastarray_setup.H" +#include "p9_sbe_fastarray_cleanup.H" +#include "p9_sbe_fastarray_abist_catchup.H" + +#ifdef SEEPROM_IMAGE +// Using Function pointer to force long call +p9_sbe_fastarray_setup_FP_t p9_sbe_fastarray_setup_hwp = + &p9_sbe_fastarray_setup; +p9_sbe_fastarray_cleanup_FP_t p9_sbe_fastarray_cleanup_hwp = + &p9_sbe_fastarray_cleanup; +p9_sbe_fastarray_abist_catchup_FP_t p9_sbe_fastarray_abist_catchup_hwp = + &p9_sbe_fastarray_abist_catchup; +#endif + +using namespace fapi2; + +uint32_t sbeControlFastArray(uint8_t *i_pArg) +{ + #define SBE_FUNC " sbeControlFastArray" + SBE_ENTER(SBE_FUNC); + uint32_t l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + + sbeControlFastArrayCMD_t l_req = {}; + sbeRespGenHdr_t respHdr; + respHdr.init(); + sbeResponseFfdc_t l_ffdc; + ReturnCode l_fapiRc; + uint32_t l_len = 0; + + do + { + l_len = sizeof(sbeControlFastArrayCMD_t)/sizeof(uint32_t); + l_rc = sbeUpFifoDeq_mult (l_len, (uint32_t *)&l_req); //EOT fetch + + // If FIFO access failure + CHECK_SBE_RC_AND_BREAK_IF_NOT_SUCCESS(l_rc); + + SBE_INFO(SBE_FUNC" targetType [0x%04X] chipletId [0x%02X]", + static_cast<uint16_t>(l_req.targetType), + static_cast<uint8_t>(l_req.chipletId)); + // Construct a Target from Chiplet ID and Target Type + plat_target_handle_t l_tgtHndl; + if(!sbeGetFapiTargetHandle(l_req.targetType, l_req.chipletId, + l_tgtHndl)) + { + SBE_ERROR(SBE_FUNC "Invalid target - Type [0x%04x] Chiplet [0x%02X]", + static_cast<uint16_t>(l_req.targetType), + static_cast<uint8_t>(l_req.chipletId)); + respHdr.setStatus(SBE_PRI_INVALID_DATA, + SBE_SEC_INVALID_TARGET_TYPE_PASSED); + break; + } + + // Relevant only when mode is set up + uint64_t l_clock_regions = 0; + // Relevant only when mode is skip cycles + uint32_t l_clock_cycles = 0; + switch(l_req.mode) + { + case FASTARRAY_SETUP: + l_clock_regions = (MASK_ZERO_H32B_UINT64(l_req.hData) << 32)| + l_req.lData; + SBE_INFO(SBE_FUNC" setup:clockregion [0x%08X%08X]", + static_cast<uint32_t>(SBE::higher32BWord(l_clock_regions)), + static_cast<uint32_t>(SBE::lower32BWord(l_clock_regions))); + SBE_EXEC_HWP(l_fapiRc, + p9_sbe_fastarray_setup_hwp, + l_tgtHndl, + l_clock_regions); + break; + case FASTARRAY_SKIPCYCLES: + l_clock_cycles = l_req.lData; + SBE_INFO(SBE_FUNC" abist catchup:skipcycles [0x%08X]", + static_cast<uint32_t>(l_clock_cycles)); + SBE_EXEC_HWP(l_fapiRc, + p9_sbe_fastarray_abist_catchup_hwp, + l_tgtHndl, + l_clock_cycles); + break; + case FASTARRAY_CLEANUP: + SBE_INFO(SBE_FUNC" cleanup"); + SBE_EXEC_HWP(l_fapiRc, + p9_sbe_fastarray_cleanup_hwp, + l_tgtHndl); + break; + } + if(l_fapiRc != FAPI2_RC_SUCCESS) + { + SBE_ERROR(SBE_FUNC" HWP failure:mode [0x%02X]", + static_cast<uint8_t>(l_req.mode)); + SBE_ERROR(SBE_FUNC" targetType [0x%04X] " + "chipletId [0x%02X] data[0-31] [0x%08X] " + "data[0-31] [0x%08X]", + static_cast<uint16_t>(l_req.targetType), + static_cast<uint8_t>(l_req.chipletId), + static_cast<uint32_t>(l_req.hData), + static_cast<uint32_t>(l_req.lData)); + l_ffdc.setRc(l_fapiRc); + } + + } while(false); + + // Now build and enqueue response into downstream FIFO + // If there was a FIFO error, will skip sending the response, + // instead give the control back to the command processor thread + if ( SBE_SEC_OPERATION_SUCCESSFUL == l_rc ) + { + l_rc = sbeDsSendRespHdr( respHdr, &l_ffdc); + } + SBE_EXIT(SBE_FUNC); + return l_rc; + #undef SBE_FUNC +} diff --git a/src/sbefw/core/sbecmdfastarray.H b/src/sbefw/core/sbecmdfastarray.H new file mode 100644 index 00000000..950420b3 --- /dev/null +++ b/src/sbefw/core/sbecmdfastarray.H @@ -0,0 +1,51 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbecmdfastarray.H $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* */ +/* */ +/* 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 __SBE_CMDFASTARRAY_H +#define __SBE_CMDFASTARRAY_H + +#include <stdint.h> + +/* + * @brief Fast array command structure + * + * */ +typedef struct +{ + uint32_t targetType:16; + uint32_t chipletId:8; + uint32_t mode:8; + uint32_t hData; + uint32_t lData; +} sbeControlFastArrayCMD_t; + +/** + * @brief Control Fast Array Command (0xA601) + * + * @param[in] i_pArg Buffer to be passed to the function (not used as of now) + * + * @return RC from the FIFO access utility + */ +uint32_t sbeControlFastArray(uint8_t *i_pArg); + +#endif //__SBE_CMDFASTARRAY_H diff --git a/src/sbefw/core/sbecmdgeneric.C b/src/sbefw/core/sbecmdgeneric.C new file mode 100644 index 00000000..593e012f --- /dev/null +++ b/src/sbefw/core/sbecmdgeneric.C @@ -0,0 +1,532 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbecmdgeneric.C $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2017 */ +/* */ +/* */ +/* 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: ppe/sbe/sbefw/sbecmdgeneric.C + * + * @brief This file contains the SBE generic Commands + * + */ + +#include "sbecmdgeneric.H" +#include "sbefifo.H" +#include "sbetrace.H" +#include "sbe_sp_intf.H" +#include "sbe_build_info.H" +#include "sbeFifoMsgUtils.H" +#include "sbeFFDC.H" +#include "sberegaccess.H" +#include "sbestates.H" +#include "sbeHostMsg.H" +#include "sbeHostUtils.H" +#include "sbeglobals.H" +#include "sbeXipUtils.H" + +#include "fapi2.H" +//#include "p9_xip_image.h" + +using namespace fapi2; + +#ifdef __SBEFW_SEEPROM__ +// Forward declaration +sbeCapabilityRespMsg::sbeCapabilityRespMsg() +{ + verMajor= SBE_FW_MAJOR_VERSION; + verMinor = SBE_FW_MINOR_VERSION; + fwCommitId = SBE_COMMIT_ID; + // Get hbbl section + P9XipHeader *hdr = getXipHdr(); + for(uint32_t idx=0; idx<sizeof(hdr->iv_buildTag); idx++) + { + buildTag[idx] = hdr->iv_buildTag[idx]; + } + + // We can remove this for llop once all capabilities + // are supported + for(uint32_t idx = 0; idx < SBE_MAX_CAPABILITIES; idx++ ) + { + capability[idx] = 0; + } + // @TODO via RTC : 160602 + // Update Capability flags based on lastes spec. + capability[IPL_CAPABILITY_START_IDX] = + EXECUTE_ISTEP_SUPPPORTED | + SUSPEND_IO_SUPPPORTED; + + capability[SCOM_CAPABILITY_START_IDX] = + GET_SCOM_SUPPPORTED | + PUT_SCOM_SUPPPORTED | + MODIFY_SCOM_SUPPPORTED | + PUT_SCOM_UNDER_MASK_SUPPPORTED ; + + capability[GENERIC_CHIPOP_CAPABILITY_START_IDX] = + GET_SBE_FFDC_SUPPPORTED | + GET_SBE_CAPABILITIES_SUPPPORTED| + SBE_QUIESCE; + + capability[MEMORY_CAPABILITY_START_IDX] = + GET_MEMORY_SUPPPORTED | + PUT_MEMORY_SUPPPORTED | + GET_SRAM_OCC_SUPPPORTED | + PUT_SRAM_OCC_SUPPPORTED; + + capability[INSTRUCTION_CTRL_CAPABILITY_START_IDX] = + CONTROL_INSTRUCTIONS_SUPPPORTED; + + capability[REGISTER_CAPABILITY_START_IDX] = + GET_REGISTER_SUPPPORTED | + PUT_REGISTER_SUPPPORTED ; + + capability[RING_CAPABILITY_START_IDX] = + GET_RING_SUPPPORTED | + PUT_RING_SUPPPORTED; +} +// Functions +//---------------------------------------------------------------------------- +uint32_t sbeGetCapabilities (uint8_t *i_pArg) +{ + #define SBE_FUNC "sbeGetCapabilities " + uint32_t rc = SBE_SEC_OPERATION_SUCCESSFUL; + uint32_t len = 0; + sbeRespGenHdr_t respHdr; + respHdr.init(); + sbeCapabilityRespMsg_t capMsg; + + do + { + // Dequeue the EOT entry as no more data is expected. + rc = sbeUpFifoDeq_mult (len, NULL); + // @TODO via RTC : 130575 + // Optimize both the RC handling and + // FIFO operation infrastructure. + if ( rc != SBE_SEC_OPERATION_SUCCESSFUL ) + { + // Let command processor routine to handle the RC + break; + } + + len = sizeof(capMsg)/sizeof(uint32_t); + rc = sbeDownFifoEnq_mult ( len, ( uint32_t *) &capMsg); + if (rc) + { + break; + } + + rc = sbeDsSendRespHdr(respHdr); + }while(0); + + if( rc ) + { + SBE_ERROR( SBE_FUNC"Failed. rc[0x%X]", rc); + } + return rc; + #undef SBE_FUNC +} + +// Functions +//---------------------------------------------------------------------------- +uint32_t sbeGetFfdc (uint8_t *i_pArg) +{ + #define SBE_FUNC "sbeGetFfdc " + SBE_ENTER(SBE_FUNC); + uint32_t rc = SBE_SEC_OPERATION_SUCCESSFUL; + uint32_t len = 0; + sbeRespGenHdr_t respHdr; + respHdr.init(); + + do + { + // Dequeue the EOT entry as no more data is expected. + rc = sbeUpFifoDeq_mult (len, NULL); + + if ( rc != SBE_SEC_OPERATION_SUCCESSFUL ) + { + // Let command processor routine to handle the RC + break; + } + + SbeFFDCPackage sbeFfdcPack; + sbeResponseFfdc_t l_ffdc; + + // If need be, force collect HWP FFDC async to the real HWP fail. + // Else, just send back what the SBE already has. + sbeFfdcPack.collectAsyncHwpFfdc (); + + l_ffdc.setRc(g_FfdcData.fapiRc); + SBE_INFO(SBE_FUNC"FAPI RC is %x", g_FfdcData.fapiRc); + // If no ffdc , exit; + if( (l_ffdc.getRc() != FAPI2_RC_SUCCESS)) + { + // making sure ffdc length is multiples of uint32_t + assert((g_FfdcData.ffdcLength % sizeof(uint32_t)) == 0); + uint32_t ffdcDataLenInWords = g_FfdcData.ffdcLength + / sizeof(uint32_t); + // Set failed command information + // Sequence Id is 0 by default for Fifo interface + // @TODO via RTC : 149074 + // primary and secondary status should be picked + // from the globals. + l_ffdc.setCmdInfo(0, respHdr.cmdClass, respHdr.command); + // Add HWP specific ffdc data length + l_ffdc.lenInWords += ffdcDataLenInWords; + len = sizeof(sbeResponseFfdc_t)/sizeof(uint32_t); + rc = sbeDownFifoEnq_mult ( len, ( uint32_t *) &l_ffdc); + if (rc) + { + break; + } + //Send HWP internal Data + rc = sbeDownFifoEnq_mult ( ffdcDataLenInWords, + ( uint32_t *) &g_FfdcData.ffdcData); + if (rc) + { + break; + } + + } + //Send the FFDC data over FIFO. + // @TODO via RTC : 149074 + // primary and secondary status should be picked + // from the globals. + // Check for Primary and Secondary Status from Globals and then send + // internal FFDC. + rc = sbeFfdcPack.sendOverFIFO(respHdr, + SBE_FFDC_ALL_DUMP, + len, + true); + if (rc) + { + break; + } + rc = sbeDsSendRespHdr(respHdr); + + if (rc) + { + break; + } + // If we are able to send ffdc, turn off async ffdc bit + (void)SbeRegAccess::theSbeRegAccess().updateAsyncFFDCBit(false); + SBE_GLOBAL->asyncFfdcRC = FAPI2_RC_SUCCESS; + + }while(0); + + if( rc ) + { + SBE_ERROR( SBE_FUNC"Failed. rc[0x%X]", rc); + } + return rc; + #undef SBE_FUNC +} + +//--------------------------------------------------------------------------- +uint32_t sbeSetFFDCAddr(uint8_t *i_pArg) +{ +#define SBE_FUNC "sbeSetFFDCAddr" + SBE_ENTER(SBE_FUNC); + uint32_t rc = SBE_SEC_OPERATION_SUCCESSFUL; + uint32_t l_fapiRc = FAPI2_RC_SUCCESS; + sbeSetFFDCAddrReq_t l_req = {}; + + do + { + // Extract the request + // and send Ack to Host via SBE_SBE2PSU_DOORBELL_SET_BIT1 + rc = sbeReadPsu2SbeMbxReg(SBE_HOST_PSU_MBOX_REG1, + (sizeof(l_req)/sizeof(uint64_t)), + (uint64_t*)&l_req, + true); + if(SBE_SEC_OPERATION_SUCCESSFUL != rc) + { + SBE_ERROR(SBE_FUNC "Failed to extract SBE_HOST_PSU_MBOX_REG1 and " + "SBE_HOST_PSU_MBOX_REG2"); + break; + } + + l_req.getFFDCAddr(SBE_GLOBAL->hostFFDCAddr); + l_req.getPassThroughCmdAddr(SBE_GLOBAL->hostPassThroughCmdAddr); + + SBE_INFO(SBE_FUNC" Global hostFFDCAddr size[0x%08X] Address[0x%08X%08X]", + static_cast<uint32_t>(SBE_GLOBAL->hostFFDCAddr.size), + static_cast<uint32_t>(SBE::higher32BWord(SBE_GLOBAL->hostFFDCAddr.addr)), + static_cast<uint32_t>(SBE::lower32BWord(SBE_GLOBAL->hostFFDCAddr.addr))); + SBE_INFO(SBE_FUNC" Global hostPassCmdAddr size[0x%08X] Address[0x%08X%08X]", + static_cast<uint32_t>(SBE_GLOBAL->hostPassThroughCmdAddr.size), + static_cast<uint32_t>(SBE::higher32BWord(SBE_GLOBAL->hostPassThroughCmdAddr.addr)), + static_cast<uint32_t>(SBE::lower32BWord(SBE_GLOBAL->hostPassThroughCmdAddr.addr))); + + } while(false); + // Send the response + sbePSUSendResponse(SBE_GLOBAL->sbeSbe2PsuRespHdr, l_fapiRc, rc); + + return rc; + SBE_EXIT(SBE_FUNC); +#undef SBE_FUNC +} + +//---------------------------------------------------------------------------- +uint32_t sbeStashKeyAddrPair( uint8_t *i_pArg ) +{ + #define SBE_FUNC "sbeStashKeyAddrPair" + SBE_ENTER(SBE_FUNC); + uint32_t rc = SBE_SEC_OPERATION_SUCCESSFUL; + uint32_t fapiRc = FAPI2_RC_SUCCESS; + do + { + stashMsg_t l_stashMsg; + // Send Ack to Host via SBE_SBE2PSU_DOORBELL_SET_BIT1, once both + // key/addr is extracted out of MBOX_REG1 and MBOX_REG2 + rc = sbeReadPsu2SbeMbxReg(SBE_HOST_PSU_MBOX_REG1, + (sizeof(stashMsg_t)/sizeof(uint64_t)), + (uint64_t*)&l_stashMsg, true); + if(SBE_SEC_OPERATION_SUCCESSFUL != rc) + { + SBE_ERROR(SBE_FUNC" Failed to extract " + "SBE_HOST_PSU_MBOX_REG1/SBE_HOST_PSU_MBOX_REG2"); + break; + } + + SBE_INFO(SBE_FUNC "Key[0x%08X] Addr[0x%08X %08X]", + l_stashMsg.key, SBE::higher32BWord(l_stashMsg.addr), + SBE::lower32BWord(l_stashMsg.addr)); + + // Update the Key-Addr Pair in local Memory + bool update = SBE_GLOBAL->sbeKeyAddrPair.updatePair(l_stashMsg.key, + l_stashMsg.addr); + if(false == update) + { + // Update RC to indicate Host that Stash memory is full + SBE_GLOBAL->sbeSbe2PsuRespHdr.setStatus( + SBE_PRI_GENERIC_EXECUTION_FAILURE, + SBE_SEC_INPUT_BUFFER_OVERFLOW); + break; + } + }while(0); + + // Send the response + sbePSUSendResponse(SBE_GLOBAL->sbeSbe2PsuRespHdr, fapiRc, rc); + + SBE_EXIT(SBE_FUNC); + return rc; + #undef SBE_FUNC +} + +//---------------------------------------------------------------------------- +uint32_t sbeSetSystemFabricMap( uint8_t *i_pArg ) +{ + #define SBE_FUNC "sbeSetSystemFabricMap" + SBE_ENTER(SBE_FUNC); + uint32_t l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + uint32_t l_fapiRc = FAPI2_RC_SUCCESS; + + do + { + uint64_t l_sysFabricMap = 0; + //send Ack to Host via SBE_SBE2PSU_DOORBELL_SET_BIT1 + l_rc = sbeReadPsu2SbeMbxReg(SBE_HOST_PSU_MBOX_REG1, + (sizeof(l_sysFabricMap)/sizeof(uint64_t)), + &l_sysFabricMap, true); + + if(SBE_SEC_OPERATION_SUCCESSFUL != l_rc) + { + SBE_ERROR(SBE_FUNC" Failed to extract SBE_HOST_PSU_MBOX_REG1"); + break; + } + + SBE_INFO(SBE_FUNC "Sytem Fabric Map [0x%08X][%08X]", + SBE::higher32BWord(l_sysFabricMap), + SBE::lower32BWord(l_sysFabricMap)); + + PLAT_ATTR_INIT(fapi2::ATTR_SBE_SYS_CONFIG, + fapi2::Target<fapi2::TARGET_TYPE_SYSTEM>(), + l_sysFabricMap); + }while(0); + + // Send the response + sbePSUSendResponse(SBE_GLOBAL->sbeSbe2PsuRespHdr, l_fapiRc, l_rc); + + SBE_EXIT(SBE_FUNC); + return l_rc; + #undef SBE_FUNC +} +#endif //__SBEFW_SEEPROM__ + +#ifndef __SBEFW_SEEPROM__ +//---------------------------------------------------------------------------- +uint32_t sbeFifoQuiesce( uint8_t *i_pArg ) +{ + #define SBE_FUNC "sbeFifoQuiesce" + uint32_t rc = SBE_SEC_OPERATION_SUCCESSFUL; + uint32_t len = 0; + sbeRespGenHdr_t respHdr; + respHdr.init(); + + do + { + // Dequeue the EOT entry as no more data is expected. + rc = sbeUpFifoDeq_mult (len, NULL); + CHECK_SBE_RC_AND_BREAK_IF_NOT_SUCCESS(rc); + + // Set Quiesce State + (void)SbeRegAccess::theSbeRegAccess().stateTransition( + SBE_QUIESCE_EVENT); + + rc = sbeDsSendRespHdr(respHdr); + if(rc != SBE_SEC_OPERATION_SUCCESSFUL) + { + SBE_ERROR(SBE_FUNC "sbeDsSendRespHdr failed"); + // Not Breaking here since we can't revert back on the set state + } + }while(0); + + if( rc ) + { + SBE_ERROR( SBE_FUNC"Failed. rc[0x%X]", rc); + } + return rc; + #undef SBE_FUNC +} + +//---------------------------------------------------------------------------- +uint32_t sbePsuQuiesce( uint8_t *i_pArg ) +{ + #define SBE_FUNC "sbePsuQuiesce" + uint32_t rc = SBE_SEC_OPERATION_SUCCESSFUL; + + do + { + // Send Ack to Host via SBE_SBE2PSU_DOORBELL_SET_BIT1 + // This util method will check internally on the mbox0 register if + // ACK is requested. + rc = sbeAcknowledgeHost(); + if (rc != SBE_SEC_OPERATION_SUCCESSFUL) + { + SBE_ERROR(SBE_FUNC " Failed to Sent Ack to Host over " + "SBE_SBE2PSU_DOORBELL_SET_BIT1"); + break; + } + + // Set Quiesce State + (void)SbeRegAccess::theSbeRegAccess().stateTransition( + SBE_QUIESCE_EVENT); + + rc = sbeWriteSbe2PsuMbxReg(SBE_HOST_PSU_MBOX_REG4, + (uint64_t*)(&SBE_GLOBAL->sbeSbe2PsuRespHdr), + (sizeof(SBE_GLOBAL->sbeSbe2PsuRespHdr)/sizeof(uint64_t)), + true); + if(rc != SBE_SEC_OPERATION_SUCCESSFUL) + { + SBE_ERROR(SBE_FUNC" Failed to write SBE_HOST_PSU_MBOX_REG4"); + // Not Breaking here since we can't revert back on the set state + } + }while(0); + + if( rc ) + { + SBE_ERROR( SBE_FUNC"Failed. rc[0x%X]", rc); + } + return rc; + #undef SBE_FUNC +} + +//---------------------------------------------------------------------------- +uint32_t sbeReadMem( uint8_t *i_pArg ) +{ + #define SBE_FUNC "sbeReadMem" + SBE_ENTER(SBE_FUNC); + uint32_t rc = SBE_SEC_OPERATION_SUCCESSFUL; + uint32_t fapiRc = FAPI2_RC_SUCCESS; + sbeReadMemReq_t req = {}; + + do + { + // Extract the request + // and send Ack to Host via SBE_SBE2PSU_DOORBELL_SET_BIT1 + rc = sbeReadPsu2SbeMbxReg(SBE_HOST_PSU_MBOX_REG1, + (sizeof(req)/sizeof(uint64_t)), + (uint64_t*)&req, + true); + if(SBE_SEC_OPERATION_SUCCESSFUL != rc) + { + SBE_ERROR(SBE_FUNC "Failed to extract SBE_HOST_PSU_MBOX_REG1 and " + "SBE_HOST_PSU_MBOX_REG2"); + break; + } + + if(!( req.validateReq()) ) + { + SBE_ERROR(SBE_FUNC"Invalid data. offset:0x%08X size:0x%08X", + req.offset, req.size ); + SBE_GLOBAL->sbeSbe2PsuRespHdr.setStatus(SBE_PRI_USER_ERROR, + SBE_SEC_INVALID_PARAMS); + break; + } + + // Default EX Target Init. As its not LCO mode, ex does not matter. + fapi2::Target<fapi2::TARGET_TYPE_EX> l_ex( + fapi2::plat_getTargetHandleByChipletNumber<fapi2::TARGET_TYPE_EX>( + sbeMemAccessInterface::PBA_DEFAULT_EX_CHIPLET_ID)); + p9_PBA_oper_flag l_myPbaFlag; + l_myPbaFlag.setOperationType(p9_PBA_oper_flag::INJ); + + sbeMemAccessInterface pbaInterface( + SBE_MEM_ACCESS_PBA, + req.responseAddr, + &l_myPbaFlag, + SBE_MEM_ACCESS_WRITE, + sbeMemAccessInterface::PBA_GRAN_SIZE_BYTES, + l_ex); + uint32_t len = req.size; + uint64_t *seepromAddr = req.getEffectiveAddr(); + while( len > 0) + { + uint64_t *dataBuffer = static_cast<uint64_t*> + (pbaInterface.getBuffer()); + for(size_t idx=0; + idx < (sbeMemAccessInterface::PBA_GRAN_SIZE_BYTES/ + sizeof(uint64_t)); + idx++) + { + *dataBuffer = *seepromAddr; + dataBuffer++; + seepromAddr++; + } + + fapi2::ReturnCode fapiRc = pbaInterface.accessGranule( + len == sbeMemAccessInterface::PBA_GRAN_SIZE_BYTES); + if( fapiRc != fapi2::FAPI2_RC_SUCCESS) + { + break; + } + len = len - sbeMemAccessInterface::PBA_GRAN_SIZE_BYTES; + } + } while(false); + + // Send the response + sbePSUSendResponse(SBE_GLOBAL->sbeSbe2PsuRespHdr, fapiRc, rc); + + SBE_EXIT(SBE_FUNC); + return rc; + #undef SBE_FUNC +} +#endif //not __SBEFW_SEEPROM__ + diff --git a/src/sbefw/core/sbecmdgeneric.H b/src/sbefw/core/sbecmdgeneric.H new file mode 100644 index 00000000..05bc435d --- /dev/null +++ b/src/sbefw/core/sbecmdgeneric.H @@ -0,0 +1,166 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbecmdgeneric.H $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* */ +/* */ +/* 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: ppe/sbe/sbefw/sbecmdgeneric.H + * + * @brief This file contains the SBE Generic command details + * + */ + +#ifndef __SBEFW_SBECMDGENERIC_H +#define __SBEFW_SBECMDGENERIC_H + +#include <stdint.h> +#include <p9_sbe_hb_structures.H> + +typedef struct sbeStashMemoryPair +{ + // This is coming from p9_sbe_hb_structures.H + keyAddrPair_t keyValuePairfromHost; + + // Default Constructor to initialize addr/key to 0xFF + sbeStashMemoryPair() + { + for(uint8_t cnt=0; cnt<MAX_ROW_COUNT; cnt++) + { + keyValuePairfromHost.addr[cnt] = 0xFFFFFFFFFFFFFFFFULL; + keyValuePairfromHost.key[cnt] = 0xFF; + } + } + + bool updatePair(uint8_t key, uint64_t addr) + { + bool l_return = false; + // Check if Key already exist, if yes update addr there + for(uint8_t cnt=0; cnt<MAX_ROW_COUNT; cnt++) + { + if(keyValuePairfromHost.key[cnt] == key) + { + keyValuePairfromHost.addr[cnt] = addr; + l_return = true; + break; + } + } + if(false == l_return) // Insert the new key into a free pair + { + for(uint8_t cnt=0; cnt<MAX_ROW_COUNT; cnt++) + { + if(keyValuePairfromHost.key[cnt] == 0xFF) + { + keyValuePairfromHost.key[cnt] = key; + keyValuePairfromHost.addr[cnt] = addr; + l_return = true; + break; + } + } + } + return l_return; + } + + uint64_t fetchStashAddrAttribute() + { + return (uint64_t)((uint8_t*)(&keyValuePairfromHost)); + } +}sbeStashMemoryPair_t; + +// Message struct to receive the key/addr pair from host +typedef struct stashMsg +{ + uint64_t reserve:56; + uint64_t key:8; + uint64_t addr; +}stashMsg_t; + +/** + * @brief retrieve SBE FFDC on request from FSP. (0xA801) + * + * @param[in] i_pArg Buffer to be passed to the function (not used as of now) + * + * @return Rc from the FIFO access utility + */ +uint32_t sbeGetFfdc(uint8_t *i_pArg); + +/** + * @brief SBE Generic capabilities (0xA802) + * + * @param[in] i_pArg Buffer to be passed to the function (not used as of now) + * + * @return Rc from the FIFO access utility + */ +uint32_t sbeGetCapabilities(uint8_t *i_pArg); + +/** + * @brief SBE Fifo Quiesce (0xA806) + * + * @param[in] i_pArg Buffer to be passed to the function (not used as of now) + * + * @return Rc from the FIFO access utility + */ +uint32_t sbeFifoQuiesce(uint8_t *i_pArg); + +/** + * @brief SBE Psu Set FFDC Address(0xD704) + * + * @param[in] i_pArg Buffer to be passed to the function (not used as of now) + * + * @return Rc from the Psu access utility + */ +uint32_t sbeSetFFDCAddr(uint8_t *i_pArg); + +/** + * @brief SBE Psu Quiesce (0xD705) + * + * @param[in] i_pArg Buffer to be passed to the function (not used as of now) + * + * @return Rc from the Psu access utility + */ +uint32_t sbePsuQuiesce(uint8_t *i_pArg); + +/** + * @brief SBE Psu Set System Fabric Map (0xD706) + * + * @param[in] i_pArg Buffer to be passed to the function (not used as of now) + * + * @return Rc from the Psu access utility + */ +uint32_t sbeSetSystemFabricMap(uint8_t *i_pArg); + +/** + * @brief SBE stash the key addr pair into sbe memory (0xD707) + * + * @param[in] i_pArg Buffer to be passed to the function (not used as of now) + * + * @return Rc from the Psu access utility + */ +uint32_t sbeStashKeyAddrPair(uint8_t *i_pArg); + +/** + * @brief Read the data from SBE memory (0xD703) + * + * @param[in] i_pArg Buffer to be passed to the function (not used as of now) + * + * @return Rc from the Psu access utility + */ +uint32_t sbeReadMem(uint8_t *i_pArg); +#endif // __SBEFW_SBECMDGENERIC_H diff --git a/src/sbefw/core/sbecmdiplcontrol.C b/src/sbefw/core/sbecmdiplcontrol.C new file mode 100644 index 00000000..ae811c4c --- /dev/null +++ b/src/sbefw/core/sbecmdiplcontrol.C @@ -0,0 +1,1715 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbecmdiplcontrol.C $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2017 */ +/* */ +/* */ +/* 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: ppe/sbe/sbefw/sbecmdiplcontrol.C + * + * @brief This file contains the SBE istep chipOps + * + */ + +#include "sbecmdiplcontrol.H" +#include "sbefifo.H" +#include "sbetrace.H" +#include "sbe_sp_intf.H" +#include "sbeFifoMsgUtils.H" +#include "assert.h" +#include "sberegaccess.H" +#include "sbestates.H" +#include "sbecmdcntrldmt.H" +#include "sbeglobals.H" +// TODO Workaround +#include "plat_target_parms.H" + +#include "fapi2.H" +#include "p9_misc_scom_addresses_fld.H" +#include "p9_perv_scom_addresses_fld.H" +#include "p9n2_quad_scom_addresses.H" +// Pervasive HWP Header Files ( istep 2) +#include <p9_sbe_attr_setup.H> +#include <p9_sbe_tp_chiplet_init1.H> +#include <p9_sbe_tp_gptr_time_initf.H> +#include <p9_sbe_npll_initf.H> +#include <p9_sbe_npll_setup.H> +#include <p9_sbe_tp_switch_gears.H> +#include <p9_sbe_clock_test2.H> +#include <p9_sbe_tp_chiplet_reset.H> +#include <p9_sbe_tp_repr_initf.H> +#include <p9_sbe_tp_chiplet_init2.H> +#include <p9_sbe_tp_arrayinit.H> +#include <p9_sbe_tp_initf.H> +#include <p9_sbe_tp_chiplet_init3.H> + +// Pervasive HWP Header Files ( istep 3) +#include <p9_sbe_chiplet_reset.H> +#include <p9_sbe_gptr_time_initf.H> +#include <p9_sbe_chiplet_init.H> +#include <p9_sbe_chiplet_pll_initf.H> +#include <p9_sbe_chiplet_pll_setup.H> +#include <p9_sbe_repr_initf.H> +#include <p9_sbe_arrayinit.H> +#include <p9_sbe_tp_enable_ridi.H> +#include <p9_sbe_setup_boot_freq.H> +#include <p9_sbe_nest_initf.H> +#include <p9_sbe_nest_startclocks.H> +#include <p9_sbe_io_initf.H> +#include <p9_sbe_nest_enable_ridi.H> +#include <p9_sbe_startclock_chiplets.H> +#include <p9_sbe_scominit.H> +#include <p9_sbe_lpc_init.H> +#include <p9_sbe_fabricinit.H> +#include <p9_sbe_mcs_setup.H> +#include <p9_sbe_select_ex.H> +// Cache HWP header file +#include <p9_hcd_cache.H> +#include <p9_hcd_cache_dcc_skewadjust_setup.H> +#include <p9_hcd_cache_chiplet_l3_dcc_setup.H> +#include <p9_hcd_cache_dpll_initf.H> +// Core HWP header file +#include <p9_hcd_core.H> + +// istep 5 hwp header files +#include "p9_sbe_instruct_start.H" +#include "p9_sbe_load_bootloader.H" + +// istep mpipl header files +#include "p9_block_wakeup_intr.H" +#include "p9_query_core_access_state.H" +#include "p9_sbe_check_quiesce.H" +#include "p9_l2_flush.H" +#include "p9_l3_flush.H" +#include "p9_sbe_sequence_drtm.H" +#include "p9_thread_control.H" +#include "sbecmdcntlinst.H" +#include "p9_quad_power_off.H" +#include "p9_hcd_cache_stopclocks.H" +#include "p9_stopclocks.H" +#include "p9_suspend_powman.H" +#include "p9_suspend_io.H" + +#include "sbeXipUtils.H" // For getting hbbl offset +#include "sbeutil.H" // For getting SBE_TO_NEST_FREQ_FACTOR + +#include "p9_fbc_utils.H" +#include "sbeSecureMemRegionManager.H" +// Forward declaration +using namespace fapi2; + +bool validateIstep (uint8_t i_major, uint8_t i_minor); + +//typedefs +typedef ReturnCode (*sbeIstepHwpProc_t) + (const Target<TARGET_TYPE_PROC_CHIP> & i_target); + +typedef ReturnCode (*sbeIstepHwpTpSwitchGears_t) + (const Target<TARGET_TYPE_PROC_CHIP> & i_target); + +typedef ReturnCode (*sbeIstepHwpEq_t) + (const Target<TARGET_TYPE_EQ> & i_target); + +typedef ReturnCode (*sbeIstepHwpCore_t) + (const Target<TARGET_TYPE_CORE> & i_target); + +typedef ReturnCode (*sbeIstepHwpExL2Flush_t) + (const Target<TARGET_TYPE_EX> & i_target, + const p9core::purgeData_t & i_purgeData); + +typedef ReturnCode (*sbeIstepHwpExL3Flush_t) + (const Target<TARGET_TYPE_EX> & i_target, + const uint32_t i_purgeType, + const uint32_t i_purgeAddr); + +typedef ReturnCode (*sbeIstepHwpCoreBlockIntr_t) + (const Target<TARGET_TYPE_CORE> & i_target, + const p9pmblockwkup::OP_TYPE i_oper); + +typedef ReturnCode (*sbeIstepHwpCoreScomState_t) + (const Target<TARGET_TYPE_CORE> & i_target, + bool & o_isScom, + bool & o_isScan); + +typedef ReturnCode (*sbeIstepHwpSequenceDrtm_t) + (const Target<TARGET_TYPE_PROC_CHIP> & i_target, + uint8_t & o_status); + +typedef ReturnCode (*sbeIstepHwpQuadPoweroff_t) + (const Target<TARGET_TYPE_EQ> & i_target, + uint64_t * o_ring_save_data); + +typedef ReturnCode (*sbeIstepHwpCacheInitf_t) + (const Target<TARGET_TYPE_EQ> & i_target, + const uint64_t * i_ring_save_data); + +typedef union +{ + sbeIstepHwpProc_t procHwp; + sbeIstepHwpEq_t eqHwp; + sbeIstepHwpCore_t coreHwp; + sbeIstepHwpExL2Flush_t exL2Hwp; + sbeIstepHwpExL3Flush_t exL3Hwp; + sbeIstepHwpCoreBlockIntr_t coreBlockIntrHwp; + sbeIstepHwpCoreScomState_t coreScomStateHwp; + sbeIstepHwpSequenceDrtm_t procSequenceDrtm; + sbeIstepHwpQuadPoweroff_t quadPoweroffHwp; + sbeIstepHwpCacheInitf_t cacheInitfHwp; +}sbeIstepHwp_t; + +// Wrapper function for HWP IPl functions +typedef ReturnCode (*sbeIstep_t)( sbeIstepHwp_t ); + +// Wrapper function which will call HWP. +ReturnCode istepWithProc( sbeIstepHwp_t i_hwp ); +ReturnCode istepHwpTpSwitchGears( sbeIstepHwp_t i_hwp); +ReturnCode istepAttrSetup( sbeIstepHwp_t i_hwp ); +ReturnCode istepNoOp( sbeIstepHwp_t i_hwp ); +ReturnCode istepWithEq( sbeIstepHwp_t i_hwp); +ReturnCode istepWithCore( sbeIstepHwp_t i_hwp); +ReturnCode istepSelectEx( sbeIstepHwp_t i_hwp); +ReturnCode istepLoadBootLoader( sbeIstepHwp_t i_hwp); +ReturnCode istepCheckSbeMaster( sbeIstepHwp_t i_hwp); +ReturnCode istepStartInstruction( sbeIstepHwp_t i_hwp); +ReturnCode istepWithCoreConditional( sbeIstepHwp_t i_hwp); +ReturnCode istepWithEqConditional( sbeIstepHwp_t i_hwp); +ReturnCode istepNestFreq( sbeIstepHwp_t i_hwp); +ReturnCode istepLpcInit( sbeIstepHwp_t i_hwp); +ReturnCode istepCacheInitf( sbeIstepHwp_t i_hwp ); + +//MPIPL Specific +ReturnCode istepWithCoreSetBlock( sbeIstepHwp_t i_hwp ); +ReturnCode istepWithCoreState( sbeIstepHwp_t i_hwp ); +ReturnCode istepMpiplRstClrTpmBits( sbeIstepHwp_t i_hwp ); +ReturnCode istepWithProcQuiesceLQASet( sbeIstepHwp_t i_hwp ); +ReturnCode istepWithExL2Flush( sbeIstepHwp_t i_hwp ); +ReturnCode istepWithExL3Flush( sbeIstepHwp_t i_hwp ); +ReturnCode istepStartMpipl( sbeIstepHwp_t i_hwp ); +ReturnCode istepWithProcSequenceDrtm( sbeIstepHwp_t i_hwp ); +ReturnCode istepMpiplSetFunctionalState( sbeIstepHwp_t i_hwp ); +ReturnCode istepMpiplQuadPoweroff( sbeIstepHwp_t i_hwp ); +ReturnCode istepStopClockMpipl( sbeIstepHwp_t i_hwp ); + +// Utility function to do TPM reset +ReturnCode performTpmReset(); + +//Utility function to update PHB functional State +ReturnCode updatePhbFunctionalState( void ); + +//Utility function to clear crest error latch +ReturnCode resetCrespErrLatch( void ); + +#ifdef SEEPROM_IMAGE + +//Utility function to mask special attention +inline ReturnCode maskSpecialAttn( const Target<TARGET_TYPE_CORE>& i_target ); +// Using function pointer to force long call. +extern p9_stopclocks_FP_t p9_stopclocks_hwp; +extern p9_thread_control_FP_t threadCntlhwp; +#ifndef __SBEFW_SEEPROM__ +p9_suspend_io_FP_t p9_suspend_io_hwp = &p9_suspend_io; +p9_sbe_select_ex_FP_t p9_sbe_select_ex_hwp = &p9_sbe_select_ex; +#endif +#ifdef __SBEFW_SEEPROM__ +extern p9_suspend_io_FP_t p9_suspend_io_hwp; +extern p9_sbe_select_ex_FP_t p9_sbe_select_ex_hwp; +#endif + +#endif + +//structure for mapping SBE wrapper and HWP functions +typedef struct +{ + sbeIstep_t istepWrapper; + sbeIstepHwp_t istepHwp; +}istepMap_t; + + +// constants +static const uint32_t SBE_ROLE_MASK = 0x00000002; +static const uint32_t SBE_SYSTEM_QUIESCE_TIMEOUT_LOOP = 20000; + +static const uint64_t SBE_LQA_DELAY_HW_US = 1000000ULL; // 1ms +static const uint64_t SBE_LQA_DELAY_SIM_CYCLES = 0x1ULL; + +static const uint32_t PEC_PHB_IOVALID_BIT_SHIFT = 59; +static const uint64_t PEC_PHB_IOVALID_BIT_MASK = 0x1ULL; + +// Bit-33 used to checkstop the system, Since this is directly getting inserted +// will have to use bit (63-33) = 30th bit +static const uint64_t N3_FIR_SYSTEM_CHECKSTOP_BIT = 30; // 63-33 = 30 + +#ifndef __SBEFW_SEEPROM__ +sbeRole g_sbeRole = SBE_ROLE_MASTER; + +uint64_t G_ring_save[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + +// Globals +// TODO: via RTC 123602 This global needs to move to a class that will store the +// SBE FFDC. +fapi2::ReturnCode g_iplFailRc = FAPI2_RC_SUCCESS; +#endif + +#ifdef __SBEFW_SEEPROM__ +extern sbeRole g_sbeRole; +extern uint64_t G_ring_save[8]; +extern fapi2::ReturnCode g_iplFailRc; +#endif + + +#ifndef __SBEFW_SEEPROM__ +static istepMap_t g_istepMpiplStartPtrTbl[MPIPL_START_MAX_SUBSTEPS] = + { +#ifdef SEEPROM_IMAGE + // Place holder for StartMpipl, State Change, PHB State Update, + // Clear CRESP error latch register. + // Set MPIPL mode in Sratch Reg 3 + { &istepStartMpipl, NULL }, + // Call suspend powerman + { &istepWithProc, { .procHwp = &p9_suspend_powman }}, + // Find all the child cores within proc and call hwp to know the + // scom state and call instruction control. Also mask spl attention + // from core. + { &istepWithCoreState, { .coreScomStateHwp = &p9_query_core_access_state }}, + // Reset the TPM and clear the TPM deconfig bit, it's not a + // procedure but local SBE function + { &istepMpiplRstClrTpmBits, NULL }, + // quiesce state for all units on the powerbus on its chip + { &istepWithProcQuiesceLQASet, { .procHwp = &p9_sbe_check_quiesce }}, + // L2 cache flush via purge engine on each EX + { &istepWithExL2Flush, { .exL2Hwp = &p9_l2_flush }}, + // L3 cache flush via purge engine on each EX + { &istepWithExL3Flush, { .exL3Hwp = &p9_l3_flush }}, + // Check on Quiescing of all Chips in a System by Local SBE + { &istepWithProcSequenceDrtm, { .procSequenceDrtm = &p9_sbe_sequence_drtm }}, +#endif + }; + +static istepMap_t g_istepMpiplContinuePtrTbl[MPIPL_CONTINUE_MAX_SUBSTEPS] = + { +#ifdef SEEPROM_IMAGE + // Setup EC/EQ guard records + { &istepMpiplSetFunctionalState, NULL}, + { &istepNoOp, NULL }, // Witherspoon only (mpipl_dump_reg) + { &istepNoOp, NULL }, // Witherspoon only (mpipl_query_quad_access_state) + { &istepNoOp, NULL }, // Witherspoon only (mpipl_hcd_core_stopclocks) + { &istepNoOp, NULL }, // Witherspoon only (mpipl_hcd_cache_stopclocks) + // p9_quad_power_off + { istepMpiplQuadPoweroff, { .quadPoweroffHwp = &p9_quad_power_off} }, + // No-op + { &istepNoOp, NULL}, +#endif + }; + +static istepMap_t g_istepStopClockPtrTbl[ISTEP_STOPCLOCK_MAX_SUBSTEPS] = + { +#ifdef SEEPROM_IMAGE + // Stop Clock Mpipl + { &istepStopClockMpipl, NULL}, +#endif + }; + +// File static data +static istepMap_t g_istep2PtrTbl[ ISTEP2_MAX_SUBSTEPS ] = + { +#ifdef SEEPROM_IMAGE + { NULL, NULL }, + { &istepAttrSetup, { .procHwp = &p9_sbe_attr_setup }}, + { &istepWithProc, { .procHwp = &p9_sbe_tp_chiplet_init1 }}, + { &istepWithProc, { .procHwp = &p9_sbe_tp_gptr_time_initf }}, + { &istepNoOp, NULL }, // DFT only + { &istepWithProc, { .procHwp = &p9_sbe_npll_initf }}, + { &istepNestFreq, { .procHwp = &p9_sbe_npll_setup }}, + { &istepHwpTpSwitchGears, { .procHwp = &p9_sbe_tp_switch_gears }}, + { &istepWithProc, { .procHwp = &p9_sbe_clock_test2 }}, + { &istepWithProc, { .procHwp = &p9_sbe_tp_chiplet_reset }}, + { &istepWithProc, { .procHwp = &p9_sbe_tp_repr_initf }}, + { &istepWithProc, { .procHwp = &p9_sbe_tp_chiplet_init2 }}, + { &istepNoOp, NULL }, // DFT only + { &istepWithProc, { .procHwp = &p9_sbe_tp_arrayinit }}, + { &istepWithProc, { .procHwp = &p9_sbe_tp_initf }}, + { &istepNoOp, NULL }, // DFT only + { &istepWithProc, { .procHwp = &p9_sbe_tp_chiplet_init3 }}, +#endif + }; + +static istepMap_t g_istep3PtrTbl[ ISTEP3_MAX_SUBSTEPS ] = + { +#ifdef SEEPROM_IMAGE + { &istepWithProc, { .procHwp = &p9_sbe_chiplet_reset }}, + { &istepWithProc, { .procHwp = &p9_sbe_gptr_time_initf }}, + { &istepWithProc, { .procHwp = &p9_sbe_chiplet_pll_initf }}, + { &istepWithProc, { .procHwp = &p9_sbe_chiplet_pll_setup }}, + { &istepWithProc, { .procHwp = &p9_sbe_repr_initf }}, + { &istepWithProc, { .procHwp = &p9_sbe_chiplet_init }}, + { &istepNoOp, NULL }, // DFT only + { &istepWithProc, { .procHwp = &p9_sbe_arrayinit }}, + { &istepNoOp, NULL }, // DFT only + { &istepWithProc, { .procHwp = &p9_sbe_tp_enable_ridi }}, + { &istepWithProc, { .procHwp = &p9_sbe_setup_boot_freq }}, + { &istepWithProc, { .procHwp = &p9_sbe_nest_initf }}, + { &istepWithProc, { .procHwp = &p9_sbe_nest_startclocks }}, + { &istepWithProc, { .procHwp = &p9_sbe_nest_enable_ridi }}, + { &istepWithProc, { .procHwp = &p9_sbe_io_initf }}, + { &istepWithProc, { .procHwp = &p9_sbe_startclock_chiplets }}, + { &istepWithProc, { .procHwp = &p9_sbe_scominit }}, + { &istepLpcInit, { .procHwp = &p9_sbe_lpc_init }}, + { &istepWithProc, { .procHwp = &p9_sbe_fabricinit }}, + { &istepCheckSbeMaster, NULL }, + { &istepWithProc, { .procHwp = &p9_sbe_mcs_setup }}, + { &istepSelectEx, NULL }, +#endif + }; +static istepMap_t g_istep4PtrTbl[ ISTEP4_MAX_SUBSTEPS ] = + { +#ifdef SEEPROM_IMAGE + { &istepWithEq, { .eqHwp = &p9_hcd_cache_poweron} }, + { &istepWithEq, { .eqHwp = &p9_hcd_cache_chiplet_reset } }, + { &istepWithEq, { .eqHwp = &p9_hcd_cache_chiplet_l3_dcc_setup }}, + { &istepWithEq, { .eqHwp = &p9_hcd_cache_gptr_time_initf }}, + { &istepWithEq, { .eqHwp = &p9_hcd_cache_dpll_initf }}, + { &istepWithEq, { .eqHwp = &p9_hcd_cache_dpll_setup }}, + { &istepWithEq, { .eqHwp = &p9_hcd_cache_dcc_skewadjust_setup }}, + { &istepWithEq, { .eqHwp = &p9_hcd_cache_chiplet_init }}, + { &istepWithEq, { .eqHwp = &p9_hcd_cache_repair_initf }}, + { &istepWithEq, { .eqHwp = &p9_hcd_cache_arrayinit }}, + { &istepNoOp, NULL }, // DFT Only + { &istepNoOp, NULL }, // DFT Only + { &istepCacheInitf, { .cacheInitfHwp = &p9_hcd_cache_initf }}, + { &istepWithEqConditional, { .eqHwp = &p9_hcd_cache_startclocks }}, + { &istepWithEqConditional, { .eqHwp = &p9_hcd_cache_scominit }}, + { &istepWithEqConditional, { .eqHwp = &p9_hcd_cache_scomcust }}, + { &istepNoOp, NULL }, // Runtime only + { &istepNoOp, NULL }, // Runtime only + { &istepNoOp, NULL }, // stub for SBE + { &istepNoOp, NULL }, // stub for SBE + { &istepWithCore, { .coreHwp = &p9_hcd_core_poweron }}, + { &istepWithCore, { .coreHwp = &p9_hcd_core_chiplet_reset }}, + { &istepWithCore, { .coreHwp = &p9_hcd_core_gptr_time_initf }}, + { &istepWithCore, { .coreHwp = &p9_hcd_core_chiplet_init }}, + { &istepWithCore, { .coreHwp = &p9_hcd_core_repair_initf }}, + { &istepWithCore, { .coreHwp = &p9_hcd_core_arrayinit }}, + { &istepNoOp, NULL }, // DFT Only + { &istepNoOp, NULL }, // DFT Only + { &istepWithCore, { .coreHwp = &p9_hcd_core_initf }}, + { &istepWithCoreConditional, + { .coreHwp = &p9_hcd_core_startclocks }}, + { &istepWithCoreConditional, { .coreHwp = &p9_hcd_core_scominit }}, + { &istepWithCoreConditional, { .coreHwp = &p9_hcd_core_scomcust }}, + { &istepNoOp, NULL }, + { &istepNoOp, NULL }, +#endif + }; + +// TODO via RTC 135345 +// Add the support for istep 5 HWP +static istepMap_t g_istep5PtrTbl[ ISTEP5_MAX_SUBSTEPS ] + { +#ifdef SEEPROM_IMAGE + { &istepLoadBootLoader, NULL }, + { &istepStartInstruction, { .coreHwp = &p9_sbe_instruct_start }}, +#endif + }; +#endif //#ifndef __SBEFW_SEEPROM__ + + +// Functions +#ifndef __SBEFW_SEEPROM__ +//---------------------------------------------------------------------------- +uint32_t sbeHandleIstep (uint8_t *i_pArg) +{ + #define SBE_FUNC "sbeHandleIstep " + SBE_ENTER(SBE_FUNC); + uint32_t rc = SBE_SEC_OPERATION_SUCCESSFUL; + ReturnCode fapiRc = FAPI2_RC_SUCCESS; + uint32_t len = 0; + sbeIstepReqMsg_t req; + sbeRespGenHdr_t respHdr; + respHdr.init(); + sbeResponseFfdc_t ffdc; + + // NOTE: In this function we will have two loops + // First loop will deque data and prepare the response + // Second response will enque the data on DS FIFO + //loop 1 + do + { + len = sizeof( req )/sizeof(uint32_t); + rc = sbeUpFifoDeq_mult ( len, (uint32_t *)&req); + if (rc != SBE_SEC_OPERATION_SUCCESSFUL) //FIFO access issue + { + SBE_ERROR(SBE_FUNC"FIFO dequeue failed, rc[0x%X]", rc); + break; + } + + if( false == validateIstep( req.major, req.minor ) ) + { + SBE_ERROR(SBE_FUNC" Invalid Istep. major:0x%08x" + " minor:0x%08x", + (uint32_t)req.major, (uint32_t)req.minor); + // @TODO via RTC 132295. + // Need to change code asper better error handling. + respHdr.setStatus( SBE_PRI_INVALID_DATA, + SBE_SEC_GENERIC_FAILURE_IN_EXECUTION); + break; + } + + fapiRc = sbeExecuteIstep( req.major, req.minor ); + if( fapiRc != FAPI2_RC_SUCCESS ) + { + SBE_ERROR(SBE_FUNC" sbeExecuteIstep() Failed. major:0x%08x" + " minor:0x%08x", + (uint32_t)req.major, + (uint32_t)req.minor); + respHdr.setStatus( SBE_PRI_GENERIC_EXECUTION_FAILURE, + SBE_SEC_GENERIC_FAILURE_IN_EXECUTION); + ffdc.setRc(fapiRc); + break; + } + + }while(0); + + //loop 2 + do + { + // FIFO error + if ( rc ) + { + break; + } + + rc = sbeDsSendRespHdr(respHdr, &ffdc); + }while(0); + + if( rc ) + { + SBE_ERROR( SBE_FUNC"Failed. rc[0x%X]", rc); + } + SBE_EXIT(SBE_FUNC); + return rc; + #undef SBE_FUNC +} + +//---------------------------------------------------------------------------- +// @note This is the responsibilty of caller to verify major/minor +// number before calling this function + +// @TODO via RTC 129077. +// This function should check for system checkstop as well. +ReturnCode sbeExecuteIstep (const uint8_t i_major, const uint8_t i_minor) +{ + #define SBE_FUNC "sbeExecuteIstep " + SBE_INFO(SBE_FUNC"Major number:0x%x minor number:0x%x", + i_major, i_minor ); + + ReturnCode rc = FAPI2_RC_SUCCESS; + switch( i_major ) + { + case SBE_ISTEP2: + rc = (g_istep2PtrTbl[i_minor-1].istepWrapper)( + g_istep2PtrTbl[i_minor-1].istepHwp); + break; + + case SBE_ISTEP3: + rc = (g_istep3PtrTbl[i_minor-1].istepWrapper)( + g_istep3PtrTbl[i_minor-1].istepHwp); + break; + + case SBE_ISTEP4: + rc = (g_istep4PtrTbl[i_minor-1].istepWrapper)( + g_istep4PtrTbl[i_minor-1].istepHwp); + break; + + case SBE_ISTEP5: + rc = (g_istep5PtrTbl[i_minor-1].istepWrapper)( + g_istep5PtrTbl[i_minor-1].istepHwp); + break; + + case SBE_ISTEP_MPIPL_START: + rc = (g_istepMpiplStartPtrTbl[i_minor-1].istepWrapper)( + g_istepMpiplStartPtrTbl[i_minor-1].istepHwp); + break; + + case SBE_ISTEP_MPIPL_CONTINUE: + rc = (g_istepMpiplContinuePtrTbl[i_minor-1].istepWrapper)( + g_istepMpiplContinuePtrTbl[i_minor-1].istepHwp); + break; + + case SBE_ISTEP_STOPCLOCK: + rc = (g_istepStopClockPtrTbl[i_minor-1].istepWrapper)( + g_istepStopClockPtrTbl[i_minor-1].istepHwp); + break; + + // We should never reach here as before calling this validation has + // been done. + default: + assert(0); + break; + } + + (void)SbeRegAccess::theSbeRegAccess().updateSbeStep(i_major, i_minor); + + if(rc != FAPI2_RC_SUCCESS) + { + SBE_ERROR( SBE_FUNC" FAPI RC:0x%08X", rc); + (void)SbeRegAccess::theSbeRegAccess().stateTransition( + SBE_DUMP_FAILURE_EVENT); + } + + return rc; + #undef SBE_FUNC +} + +//---------------------------------------------------------------------------- +bool validateIstep (const uint8_t i_major, const uint8_t i_minor) +{ + bool valid = true; + do + { + if( 0 == i_minor ) + { + valid = false; + break; + } + + switch( i_major ) + { + case SBE_ISTEP2: + // istep 2.1 loads image to PIBMEM + // So SBE control loop can not execute istep 2.1. + if(( i_minor > ISTEP2_MAX_SUBSTEPS ) || ( i_minor == 1) ) + { + valid = false; + } + break; + + case SBE_ISTEP3: + if( (i_minor > ISTEP3_MAX_SUBSTEPS ) || + ((SBE_ROLE_SLAVE == g_sbeRole) && + (i_minor > SLAVE_LAST_MINOR_ISTEP)) ) + { + valid = false; + } + break; + + case SBE_ISTEP4: + if( (i_minor > ISTEP4_MAX_SUBSTEPS ) || + (SBE_ROLE_SLAVE == g_sbeRole) ) + { + valid = false; + } + break; + + case SBE_ISTEP5: + if( (i_minor > ISTEP5_MAX_SUBSTEPS ) || + (SBE_ROLE_SLAVE == g_sbeRole) ) + { + valid = false; + } + break; + + case SBE_ISTEP_MPIPL_START: + if( i_minor > MPIPL_START_MAX_SUBSTEPS ) + { + valid = false; + } + break; + + case SBE_ISTEP_MPIPL_CONTINUE: + if( i_minor > MPIPL_CONTINUE_MAX_SUBSTEPS ) + { + valid = false; + } + break; + + case SBE_ISTEP_STOPCLOCK: + if( i_minor > ISTEP_STOPCLOCK_MAX_SUBSTEPS ) + { + valid = false; + } + break; + + default: + valid = false; + break; + } + } while(0); + + return valid; +} + +//---------------------------------------------------------------------------- + +ReturnCode performAttrSetup( ) +{ + #define SBE_FUNC "performAttrSetup " + SBE_ENTER("performAttrSetup "); + Target<TARGET_TYPE_PROC_CHIP > proc = plat_getChipTarget(); + ReturnCode rc = FAPI2_RC_SUCCESS; + do + { + SBE_EXEC_HWP(rc, p9_sbe_attr_setup, proc) + if( rc != FAPI2_RC_SUCCESS ) + { + break; + } + // Apply the gard records + rc = plat_ApplyGards(); + + //Getting CBS_CS register value + fapi2::buffer<uint64_t> tempReg = 0; + plat_target_handle_t hndl; + rc = getscom_abs_wrap(&hndl, + PERV_CBS_CS_SCOM, tempReg.pointer()); + if( rc != FAPI2_RC_SUCCESS ) + { + break; + } + SBE_GLOBAL->sbeFWSecurityEnabled = + tempReg.getBit<PERV_CBS_CS_SECURE_ACCESS_BIT>(); + }while(0); + SBE_EXIT(SBE_FUNC); + return rc; + #undef SBE_FUNC +} + +//---------------------------------------------------------------------------- + +ReturnCode istepAttrSetup( sbeIstepHwp_t i_hwp) +{ + return performAttrSetup(); +} + +//---------------------------------------------------------------------------- + +ReturnCode istepWithProc( sbeIstepHwp_t i_hwp) +{ + ReturnCode rc = FAPI2_RC_SUCCESS; + Target<TARGET_TYPE_PROC_CHIP > proc = plat_getChipTarget(); + assert( NULL != i_hwp.procHwp ); + SBE_EXEC_HWP(rc, i_hwp.procHwp,proc) + return rc; +} +//---------------------------------------------------------------------------- + +ReturnCode istepHwpTpSwitchGears( sbeIstepHwp_t i_hwp) +{ + ReturnCode rc = FAPI2_RC_SUCCESS; + Target<TARGET_TYPE_PROC_CHIP > proc = plat_getChipTarget(); + assert( NULL != i_hwp.procHwp ); + SBE_EXEC_HWP(rc, i_hwp.procHwp,proc) + + // backup i2c mode register + uint32_t reg_address = PU_MODE_REGISTER_B; + PPE_LVD( reg_address, SBE_GLOBAL->i2cModeRegister); + + return rc; +} + +//---------------------------------------------------------------------------- + +ReturnCode istepNestFreq( sbeIstepHwp_t i_hwp) +{ + #define SBE_FUNC "istepNestFreq " + Target<TARGET_TYPE_PROC_CHIP > proc = plat_getChipTarget(); + ReturnCode rc = FAPI2_RC_SUCCESS; + assert( NULL != i_hwp.procHwp ); + do + { + SBE_EXEC_HWP(rc, i_hwp.procHwp,proc) + if( rc != FAPI2_RC_SUCCESS ) + { + break; + } + // Update PK frequency + SBE::updatePkFreq(); + }while(0); + return rc; + #undef SBE_FUNC +} + +//---------------------------------------------------------------------------- +//---------------------------------------------------------------------------- + +ReturnCode istepSelectEx( sbeIstepHwp_t i_hwp) +{ + ReturnCode rc = FAPI2_RC_SUCCESS; + Target<TARGET_TYPE_PROC_CHIP > proc = plat_getChipTarget(); + // TODO via RTC 135345 + // Once multicast targets are supported, we may need to pass + // p9selectex::ALL as input. + SBE_EXEC_HWP(rc, p9_sbe_select_ex_hwp, proc, p9selectex::SINGLE) + return rc; +} + +//---------------------------------------------------------------------------- +ReturnCode istepWithEq( sbeIstepHwp_t i_hwp) +{ + ReturnCode rc = FAPI2_RC_SUCCESS; + // TODO via RTC 135345 + // Curently we are passing Hard code eq target. Finally it is + // going to be a multicast target. Once multicast support is + // present, use the right target. + fapi2::Target<fapi2::TARGET_TYPE_EQ > eqTgt; + // Put this in scope so that vector can be freed up before calling hwp. + { + Target<TARGET_TYPE_PROC_CHIP > proc = plat_getChipTarget(); + auto eqList = proc.getChildren<fapi2::TARGET_TYPE_EQ>(); + // As it is workaround lets assume there will always be atleast one + // functional eq. No need to validate. + eqTgt = eqList[0]; + } + + assert( NULL != i_hwp.eqHwp ); + SBE_EXEC_HWP(rc, i_hwp.eqHwp, eqTgt ) + return rc; +} + +//---------------------------------------------------------------------------- +ReturnCode istepCacheInitf (sbeIstepHwp_t i_hwp ) +{ + #define SBE_FUNC "istepCacheInitf" + SBE_ENTER(SBE_FUNC); + ReturnCode l_rc = FAPI2_RC_SUCCESS; + + // TODO via RTC 135345 + fapi2::Target<fapi2::TARGET_TYPE_EQ > eqTgt; + // Put this in scope so that vector can be freed up before calling hwp. + { + Target<TARGET_TYPE_PROC_CHIP > proc = plat_getChipTarget(); + auto eqList = proc.getChildren<fapi2::TARGET_TYPE_EQ>(); + // As it is workaround lets assume there will always be atleast one + // functional eq. No need to validate. + eqTgt = eqList[0]; + } + + SBE_EXEC_HWP(l_rc, i_hwp.cacheInitfHwp, eqTgt, G_ring_save) + SBE_EXIT(SBE_FUNC); + return l_rc; + #undef SBE_FUNC +} + +//---------------------------------------------------------------------------- +ReturnCode istepWithCore( sbeIstepHwp_t i_hwp) +{ + #define SBE_FUNC "istepWithCore" + ReturnCode rc = FAPI2_RC_SUCCESS; + + // Get master Ex + uint8_t exId = 0; + uint8_t fuseMode = 0; + Target<TARGET_TYPE_PROC_CHIP > proc = plat_getChipTarget(); + FAPI_ATTR_GET(fapi2::ATTR_MASTER_EX,proc,exId); + FAPI_ATTR_GET(ATTR_FUSED_CORE_MODE, Target<TARGET_TYPE_SYSTEM>(), fuseMode); + fapi2::Target<fapi2::TARGET_TYPE_EX > + exTgt(plat_getTargetHandleByInstance<fapi2::TARGET_TYPE_EX>(exId)); + assert( NULL != i_hwp.coreHwp ); + + for (auto &coreTgt : exTgt.getChildren<fapi2::TARGET_TYPE_CORE>()) + { + // Core0 is assumed to be the master core + SBE_EXEC_HWP(rc, i_hwp.coreHwp, coreTgt) + if(rc != FAPI2_RC_SUCCESS) + { + SBE_ERROR(SBE_FUNC " istepWithCore failed, RC=[0x%08X]", rc); + break; + } + // Only continue in case of istep4 && fuse core mode + if(!( (fuseMode) && + (SbeRegAccess::theSbeRegAccess().getSbeMajorIstepNumber() == + SBE_ISTEP4) ) ) + { + break; + } + } + return rc; + #undef SBE_FUNC +} + +//---------------------------------------------------------------------------- + +ReturnCode istepWithEqConditional( sbeIstepHwp_t i_hwp) +{ + SBE_ENTER("istepWithEqCondtional"); + fapi2::Target<fapi2::TARGET_TYPE_SYSTEM > sysTgt; + ReturnCode rc = FAPI2_RC_SUCCESS; + do + { + uint8_t iplPhase = ENUM_ATTR_SYSTEM_IPL_PHASE_HB_IPL; + FAPI_ATTR_GET(ATTR_SYSTEM_IPL_PHASE, sysTgt, iplPhase); + if( ENUM_ATTR_SYSTEM_IPL_PHASE_CACHE_CONTAINED == iplPhase ) + { + break; + } + rc = istepWithEq(i_hwp); + }while(0); + SBE_EXIT("istepWithEqCondtional"); + return rc; +} + +//---------------------------------------------------------------------------- + +ReturnCode istepWithCoreConditional( sbeIstepHwp_t i_hwp) +{ + SBE_ENTER("istepWithCoreCondtional"); + fapi2::Target<fapi2::TARGET_TYPE_SYSTEM > sysTgt; + ReturnCode rc = FAPI2_RC_SUCCESS; + do + { + uint8_t iplPhase = ENUM_ATTR_SYSTEM_IPL_PHASE_HB_IPL; + FAPI_ATTR_GET(ATTR_SYSTEM_IPL_PHASE, sysTgt, iplPhase); + if( ENUM_ATTR_SYSTEM_IPL_PHASE_CACHE_CONTAINED == iplPhase ) + { + break; + } + rc = istepWithCore(i_hwp); + }while(0); + SBE_EXIT("istepWithCoreCondtional"); + return rc; +} + +//---------------------------------------------------------------------------- +constexpr uint32_t HB_MEM_WINDOW_SIZE = 32*1024*1024; //32 MB +ReturnCode istepLoadBootLoader( sbeIstepHwp_t i_hwp) +{ + ReturnCode rc = FAPI2_RC_SUCCESS; + // Get master Ex + uint8_t exId = 0; + Target< TARGET_TYPE_SYSTEM > sysTgt; + Target<TARGET_TYPE_PROC_CHIP > proc = plat_getChipTarget(); + FAPI_ATTR_GET(fapi2::ATTR_MASTER_EX,proc,exId); + fapi2::Target<fapi2::TARGET_TYPE_EX > + exTgt(plat_getTargetHandleByInstance<fapi2::TARGET_TYPE_EX>(exId)); + // Get hbbl section + P9XipHeader *hdr = getXipHdr(); + P9XipSection *hbblSection = &(hdr->iv_section[P9_XIP_SECTION_SBE_HBBL]); + + uint64_t drawer_base_address_nm0, drawer_base_address_nm1; + uint64_t drawer_base_address_m; + uint64_t drawer_base_address_mmio; + uint64_t l_hostboot_hrmor_offset; + do + { + // Update the ATTR_SBE_ADDR_KEY_STASH_ADDR before calling the bootloader, + // since it is going to access these data from inside. + uint64_t addr = SBE_GLOBAL->sbeKeyAddrPair.fetchStashAddrAttribute(); + PLAT_ATTR_INIT(fapi2::ATTR_SBE_ADDR_KEY_STASH_ADDR, sysTgt, addr); + SBE_EXEC_HWP(rc, p9_sbe_load_bootloader, proc, exTgt, hbblSection->iv_size, + getSectionAddr(hbblSection)) + if(rc != FAPI2_RC_SUCCESS) + { + SBE_ERROR(" p9_sbe_load_bootloader failed"); + break; + } + + // Open HB Dump memory Region + fapi2::Target<fapi2::TARGET_TYPE_SYSTEM> FAPI_SYSTEM; + FAPI_ATTR_GET(fapi2::ATTR_HOSTBOOT_HRMOR_OFFSET, + FAPI_SYSTEM, + l_hostboot_hrmor_offset); + rc = p9_fbc_utils_get_chip_base_address_no_aliases( + proc, + ABS_FBC_GRP_ID_ONLY, + drawer_base_address_nm0, + drawer_base_address_nm1, + drawer_base_address_m, + drawer_base_address_mmio); + if(rc != FAPI2_RC_SUCCESS) + { + SBE_ERROR(" p9_fbc_utils_get_chip_base_address failed"); + break; + } + drawer_base_address_nm0 += l_hostboot_hrmor_offset; + SBE_INFO("istep 5.1 HB Dump mem Region [0x%08X%08X]", + SBE::higher32BWord(drawer_base_address_nm0), + SBE::lower32BWord(drawer_base_address_nm0)); + mainStoreSecMemRegionManager.add(drawer_base_address_nm0, + HB_MEM_WINDOW_SIZE, + static_cast<uint8_t>(memRegionMode::READ)); + + } while(0); + return rc; +} + +//---------------------------------------------------------------------------- + +ReturnCode istepStartInstruction( sbeIstepHwp_t i_hwp) +{ + ReturnCode rc = FAPI2_RC_SUCCESS; + rc = istepWithCore(i_hwp); + if(rc == FAPI2_RC_SUCCESS) + { + (void)SbeRegAccess::theSbeRegAccess().stateTransition( + SBE_RUNTIME_EVENT); + } + return rc; +} + +//---------------------------------------------------------------------------- +ReturnCode istepCheckSbeMaster( sbeIstepHwp_t i_hwp) +{ + #define SBE_FUNC "istepCheckSbeMaster " + ReturnCode rc = FAPI2_RC_SUCCESS; + do + { + rc = performTpmReset(); + if( rc != FAPI2_RC_SUCCESS ) + { + SBE_ERROR(SBE_FUNC" performTpmReset failed"); + break; + } + g_sbeRole = SbeRegAccess::theSbeRegAccess().isSbeSlave() ? + SBE_ROLE_SLAVE : SBE_ROLE_MASTER; + SBE_INFO(SBE_FUNC"g_sbeRole [%x]", g_sbeRole); + if(SBE_ROLE_SLAVE == g_sbeRole) + { + (void)SbeRegAccess::theSbeRegAccess().stateTransition( + SBE_RUNTIME_EVENT); + } + }while(0); + return rc; + #undef SBE_FUNC +} + +//---------------------------------------------------------------------------- +ReturnCode istepNoOp( sbeIstepHwp_t i_hwp) +{ + SBE_INFO("istepNoOp"); + return FAPI2_RC_SUCCESS ; +} + +//---------------------------------------------------------------------------- +void sbeDoContinuousIpl() +{ + #define SBE_FUNC "sbeDoContinuousIpl " + SBE_ENTER(SBE_FUNC); + ReturnCode l_rc = FAPI2_RC_SUCCESS; + do + { + // An array that holds the max number of minor steps per major step + const uint8_t l_minorSteps[] = + { + ISTEP2_MAX_SUBSTEPS, + ISTEP3_MAX_SUBSTEPS, + ISTEP4_MAX_SUBSTEPS, + ISTEP5_MAX_SUBSTEPS + }; + + // Where does each minor istep start from? + const uint8_t l_minorStartStep[] = + { + ISTEP2_MINOR_START, + ISTEP_MINOR_START, + ISTEP_MINOR_START, + ISTEP_MINOR_START + }; + + // Set SBE state as IPLing + (void)SbeRegAccess::theSbeRegAccess().stateTransition( + SBE_PLCK_EVENT); + bool l_done = false; + // Run isteps + for(uint8_t l_major = SBE_ISTEP_FIRST; + (l_major <= SBE_ISTEP_LAST_MASTER) && + (false == l_done); + ++l_major) + { + for(uint8_t l_minor = l_minorStartStep[l_major - SBE_ISTEP_FIRST]; + l_minor <= l_minorSteps[l_major - SBE_ISTEP_FIRST]; + ++l_minor) + { + l_rc = sbeExecuteIstep(l_major, l_minor); + if(l_rc != FAPI2_RC_SUCCESS) + { + SBE_ERROR(SBE_FUNC"Failed istep execution in plck mode: " + "Major: %d, Minor: %d", l_major, l_minor); + l_done = true; + (void)SbeRegAccess::theSbeRegAccess().updateAsyncFFDCBit( + true); + break; + } + // Check if we are at step 3.20 on the slave SBE + if(((SBE_ISTEP_LAST_SLAVE == l_major) && + (SLAVE_LAST_MINOR_ISTEP == l_minor)) && + (SBE_ROLE_SLAVE == g_sbeRole)) + { + l_done = true; + break; + } + } + } + } while(false); + // Store l_rc in a global variable that will be a part of the SBE FFDC + g_iplFailRc = l_rc; + SBE_EXIT(SBE_FUNC); + #undef SBE_FUNC +} +#endif // #ifndef __SBEFW_SEEPROM__ + +// MPIPL Specific +#ifdef __SBEFW_SEEPROM__ +//---------------------------------------------------------------------------- +ReturnCode istepWithCoreSetBlock( sbeIstepHwp_t i_hwp) +{ + #define SBE_FUNC "istepWithCoreSetBlock" + SBE_ENTER(SBE_FUNC); + ReturnCode l_rc = FAPI2_RC_SUCCESS; + Target<TARGET_TYPE_PROC_CHIP > l_procTgt = plat_getChipTarget(); + for (auto l_coreTgt : l_procTgt.getChildren<fapi2::TARGET_TYPE_CORE>()) + { + SBE_EXEC_HWP(l_rc, i_hwp.coreBlockIntrHwp, l_coreTgt, p9pmblockwkup::SET) + if(l_rc != FAPI2_RC_SUCCESS) + { + SBE_ERROR(SBE_FUNC " p9_block_wakeup_intr failed, RC=[0x%08X]", + l_rc); + break; + } + } + SBE_EXIT(SBE_FUNC); + return l_rc; + #undef SBE_FUNC +} + +//---------------------------------------------------------------------------- +ReturnCode istepWithCoreState( sbeIstepHwp_t i_hwp) +{ + #define SBE_FUNC "istepWithCoreState" + SBE_ENTER(SBE_FUNC); + ReturnCode l_rc = FAPI2_RC_SUCCESS; + Target<TARGET_TYPE_PROC_CHIP > l_procTgt = plat_getChipTarget(); + for (auto l_coreTgt : l_procTgt.getChildren<fapi2::TARGET_TYPE_CORE>()) + { + bool l_isScanEnable = false; + bool l_isCoreScomEnabled = false; + SBE_EXEC_HWP(l_rc, i_hwp.coreScomStateHwp, l_coreTgt, + l_isCoreScomEnabled, l_isScanEnable) + if(l_rc != FAPI2_RC_SUCCESS) + { + SBE_ERROR(SBE_FUNC " p9_query_core_access_state failed, " + "RC=[0x%08X]", l_rc); + break; + } + if(l_isCoreScomEnabled) //true + { + uint8_t l_thread = SMT4_THREAD0; + fapi2::buffer<uint64_t> l_data64; + uint64_t l_state; + bool l_warnCheck = true; + do + { + // Call instruction control stop + // TODO RTC 164425 - Can we pass in 1111 i.e. all threads at the + // same time instead of individual threads + SBE_EXEC_HWP(l_rc, threadCntlhwp, l_coreTgt, + (SINGLE_THREAD_BIT_MASK >> l_thread), + PTC_CMD_STOP, l_warnCheck,l_data64, l_state) + if(l_rc != FAPI2_RC_SUCCESS) + { + SBE_ERROR(SBE_FUNC "p9_thread_control stop Failed for " + "Core Thread RC[0x%08X]", l_rc); + break; + } + }while(++l_thread < SMT4_THREAD_MAX); + + l_rc = maskSpecialAttn(l_coreTgt); + if( l_rc != FAPI2_RC_SUCCESS) + { + SBE_ERROR(SBE_FUNC "maskSpecialAttn failed"); + break; + } + } + } + SBE_EXIT(SBE_FUNC); + return l_rc; + #undef SBE_FUNC +} + +//---------------------------------------------------------------------------- +ReturnCode istepMpiplRstClrTpmBits( sbeIstepHwp_t i_hwp) +{ + #define SBE_FUNC "istepMpiplRstClrTpmBits" + SBE_ENTER(SBE_FUNC); + + ReturnCode l_rc = performTpmReset(); + if( l_rc != FAPI2_RC_SUCCESS ) + { + SBE_ERROR(SBE_FUNC" performTpmReset failed"); + } + + SBE_EXIT(SBE_FUNC); + return l_rc; + #undef SBE_FUNC +} + +//---------------------------------------------------------------------------- +ReturnCode istepWithExL2Flush( sbeIstepHwp_t i_hwp) +{ + #define SBE_FUNC "istepWithExL2Flush" + SBE_ENTER(SBE_FUNC); + ReturnCode l_rc = FAPI2_RC_SUCCESS; + + Target<TARGET_TYPE_PROC_CHIP > l_procTgt = plat_getChipTarget(); + for (auto l_exTgt : l_procTgt.getChildren<fapi2::TARGET_TYPE_EX>()) + { + p9core::purgeData_t l_purgeData; + // TODO RTC 164425 need to check if L2 is Scomable + // This will come from the HWP team. + SBE_EXEC_HWP(l_rc, i_hwp.exL2Hwp, l_exTgt, l_purgeData) + if(l_rc != FAPI2_RC_SUCCESS) + { + SBE_ERROR(SBE_FUNC " p9_l2_flush failed, RC=[0x%08X]", l_rc); + break; + } + } + SBE_EXIT(SBE_FUNC); + return l_rc; + #undef SBE_FUNC +} + +//---------------------------------------------------------------------------- +ReturnCode istepWithExL3Flush( sbeIstepHwp_t i_hwp) +{ + #define SBE_FUNC "istepWithExL3Flush" + SBE_ENTER(SBE_FUNC); + ReturnCode l_rc = FAPI2_RC_SUCCESS; + + Target<TARGET_TYPE_PROC_CHIP > l_procTgt = plat_getChipTarget(); + for (auto l_exTgt : l_procTgt.getChildren<fapi2::TARGET_TYPE_EX>()) + { + // TODO RTC 164425 need to check if L3 is Scomable + // This will come from the HWP team. + SBE_EXEC_HWP(l_rc, i_hwp.exL3Hwp, l_exTgt, L3_FULL_PURGE, 0x0) + if(l_rc != FAPI2_RC_SUCCESS) + { + SBE_ERROR(SBE_FUNC " p9_l3_flush failed, RC=[0x%08X]", l_rc); + break; + } + } + SBE_EXIT(SBE_FUNC); + return l_rc; + #undef SBE_FUNC +} + +//---------------------------------------------------------------------------- +ReturnCode istepWithProcSequenceDrtm( sbeIstepHwp_t i_hwp) +{ + #define SBE_FUNC "istepWithProcSequenceDrtm" + SBE_ENTER(SBE_FUNC); + ReturnCode l_rc = FAPI2_RC_SUCCESS; + Target<TARGET_TYPE_PROC_CHIP > l_procTgt = plat_getChipTarget(); + + uint8_t l_status = 0; + size_t l_timeOut = SBE_SYSTEM_QUIESCE_TIMEOUT_LOOP; + while(l_timeOut) + { + SBE_EXEC_HWP(l_rc, i_hwp.procSequenceDrtm, l_procTgt, l_status) + if(l_rc != FAPI2_RC_SUCCESS) + { + SBE_ERROR(SBE_FUNC "p9_sbe_sequence_drtm failed, RC=[0x%08X]",l_rc); + break; + } + if(l_status) + { + SBE_INFO(SBE_FUNC "p9_sbe_sequence_drtm LQA SBE System Quiesce done"); + break; + } + else + { + l_timeOut--; + // delay prior to repeating the above + FAPI_TRY(fapi2::delay(SBE_LQA_DELAY_HW_US, SBE_LQA_DELAY_SIM_CYCLES), + "Error from delay"); + } + } + // Checkstop system if SBE system quiesce not set after the loop + if(!l_status || l_rc) + { + SBE_ERROR(SBE_FUNC "p9_sbe_sequence_drtm LQA SBE System Quiesce failed," + "Either System Quiesce Achieved not true or procedure " + "failed RC=[0x%08X]",l_rc); + // check stop the system + // TODO RTC 164425 this needs to be replicated on any MPIPL Hwp failure + Target<TARGET_TYPE_PROC_CHIP > l_proc = plat_getChipTarget(); + l_rc = putscom_abs_wrap(&l_proc, PERV_N3_LOCAL_FIR_OR, + ((uint64_t)1 << N3_FIR_SYSTEM_CHECKSTOP_BIT)); + if(l_rc != FAPI2_RC_SUCCESS) + { + // Scom failed + SBE_ERROR(SBE_FUNC "PutScom failed for REG PERV_N3_LOCAL_FIR"); + // TODO - Store the response in Async Response + // RTC:149074 + } + } +fapi_try_exit: + if(fapi2::current_err) + { + l_rc = fapi2::current_err; + } + SBE_EXIT(SBE_FUNC); + return l_rc; + #undef SBE_FUNC +} + +//---------------------------------------------------------------------------- +ReturnCode istepStartMpipl( sbeIstepHwp_t i_hwp) +{ + #define SBE_FUNC "istepStartMpipl" + SBE_ENTER(SBE_FUNC); + ReturnCode rc = FAPI2_RC_SUCCESS; + + (void)SbeRegAccess::theSbeRegAccess().stateTransition( + SBE_ENTER_MPIPL_EVENT); + // Set MPIPL mode bit in Scratch Reg 3 + (void)SbeRegAccess::theSbeRegAccess().setMpIplMode(true); + // Close all non-secure memory regions + mainStoreSecMemRegionManager.closeAllRegions(); + + do + { + rc = updatePhbFunctionalState(); + if(rc != FAPI2_RC_SUCCESS) + { + SBE_ERROR(SBE_FUNC "updatePhbFunctionalState failed"); + break; + } + rc = resetCrespErrLatch(); + if(rc != FAPI2_RC_SUCCESS) + { + SBE_ERROR(SBE_FUNC "resetCrespErrLatch failed"); + break; + } + + }while(0); + + SBE_EXIT(SBE_FUNC); + return rc; + #undef SBE_FUNC +} + +//---------------------------------------------------------------------------- +ReturnCode istepMpiplQuadPoweroff( sbeIstepHwp_t i_hwp) +{ + #define SBE_FUNC "istepMpiplQuadPoweroff" + SBE_ENTER(SBE_FUNC); + ReturnCode l_rc = FAPI2_RC_SUCCESS; + if(g_sbeRole == SBE_ROLE_MASTER) + { + Target<TARGET_TYPE_PROC_CHIP > l_proc = plat_getChipTarget(); + // Fetch the MASTER_CORE attribute + uint8_t l_coreId = 0; + FAPI_ATTR_GET(fapi2::ATTR_MASTER_CORE, l_proc, l_coreId); + // Construct the Master Core Target + fapi2::Target<fapi2::TARGET_TYPE_CORE > l_core( + plat_getTargetHandleByChipletNumber<fapi2::TARGET_TYPE_CORE>( + l_coreId + CORE_CHIPLET_OFFSET)); + fapi2::Target<fapi2::TARGET_TYPE_EQ> l_quad = + l_core.getParent<fapi2::TARGET_TYPE_EQ>(); + SBE_EXEC_HWP(l_rc, i_hwp.quadPoweroffHwp, l_quad, G_ring_save) + } + SBE_EXIT(SBE_FUNC); + return l_rc; + #undef SBE_FUNC +} + +//---------------------------------------------------------------------------- +ReturnCode istepWithProcQuiesceLQASet( sbeIstepHwp_t i_hwp ) +{ + #define SBE_FUNC "istepWithProcQuiesceLQASet" + SBE_ENTER(SBE_FUNC); + ReturnCode l_rc = FAPI2_RC_SUCCESS; + do + { + l_rc = istepWithProc(i_hwp); + if(l_rc == FAPI2_RC_SUCCESS) + { + //set the LQA Bit + // TODO RTC 164425 - Create another istep for Setting LQA bit after + // L2/L3 flush istep + Target<TARGET_TYPE_PROC_CHIP > l_proc = plat_getChipTarget(); + uint64_t l_data = 0x1000000000000000ULL; //Set bit3 + l_rc = putscom_abs_wrap(&l_proc, PU_SECURITY_SWITCH_REGISTER_SCOM, l_data); + if(l_rc != FAPI2_RC_SUCCESS) + { + SBE_ERROR(SBE_FUNC "PutScom failed for PU_SECURITY_SWITCH_REGISTER_SCOM"); + break; + } + l_data = 0; + l_rc = getscom_abs_wrap (&l_proc, PU_SECURITY_SWITCH_REGISTER_SCOM, &l_data); + if(l_rc != FAPI2_RC_SUCCESS) + { + SBE_ERROR(SBE_FUNC "GetScom failed for PU_SECURITY_SWITCH_REGISTER_SCOM"); + break; + } + SBE_INFO(SBE_FUNC "PU_SECURITY_SWITCH_REGISTER_SCOM Data [0x%08X][%08X]", + (uint32_t)((l_data >> 32) & 0xFFFFFFFF), (uint32_t)(l_data & 0xFFFFFFFF)); + } + }while(0); + SBE_EXIT(SBE_FUNC); + return l_rc; + #undef SBE_FUNC +} + +//---------------------------------------------------------------------------- +ReturnCode istepMpiplSetFunctionalState( sbeIstepHwp_t i_hwp ) +{ + #define SBE_FUNC "istepMpiplSetFunctionalState" + SBE_ENTER(SBE_FUNC); + Target<TARGET_TYPE_PROC_CHIP > proc = plat_getChipTarget(); + ReturnCode rc = FAPI2_RC_SUCCESS; + do + { + // Read the EQ and EC gard attributes from the chip target + fapi2::buffer<uint64_t> l_scratchReg1 = 0; + uint64_t l_scratchReg8 = 0; + static const uint64_t SCRATCH8_SCRATCH1REG_VALID_BIT = + 0x8000000000000000ULL; + fapi2::buffer<uint8_t> l_eqMask = 0; + fapi2::buffer<uint32_t> l_ecMask = 0; + plat_target_handle_t l_hndl; + + // Set MPIPL mode bit in Scratch Reg 3 + (void)SbeRegAccess::theSbeRegAccess().setMpIplMode(true); + + rc = getscom_abs_wrap (&l_hndl, + PERV_SCRATCH_REGISTER_8_SCOM, + &l_scratchReg8); + if( rc != FAPI2_RC_SUCCESS ) + { + SBE_ERROR(SBE_FUNC" Failed to read Scratch RegR8"); + break; + } + if(l_scratchReg8 & SCRATCH8_SCRATCH1REG_VALID_BIT) + { + rc = getscom_abs_wrap (&l_hndl, + PERV_SCRATCH_REGISTER_1_SCOM, + &l_scratchReg1()); + if( rc != FAPI2_RC_SUCCESS ) + { + SBE_ERROR(SBE_FUNC" Failed to read Scratch Reg1"); + break; + } + + l_scratchReg1.extract<0, 6>(l_eqMask); + l_scratchReg1.extract<8, 24>(l_ecMask); + SBE_INFO(SBE_FUNC" Setting ATTR_EQ_GARD [0x%08X] " + "ATTR_EC_GARD [0x%08X]", + l_eqMask, l_ecMask); + + PLAT_ATTR_INIT(fapi2::ATTR_EQ_GARD, proc, l_eqMask); + PLAT_ATTR_INIT(fapi2::ATTR_EC_GARD, proc, l_ecMask); + + // Apply the gard records + rc = plat_ApplyGards(); + if( rc != FAPI2_RC_SUCCESS ) + { + SBE_ERROR(SBE_FUNC" Failed to to apply gard records"); + break; + } + + // TODO via RTC 135345 + // Once multicast targets are supported, we may need to pass + // p9selectex::ALL as input. + SBE_EXEC_HWP(rc, p9_sbe_select_ex_hwp, proc, p9selectex::SINGLE) + if( rc != FAPI2_RC_SUCCESS ) + { + SBE_ERROR(SBE_FUNC" Failed hwp p9_sbe_select_ex_hwp"); + break; + } + } + else + { + SBE_ERROR(SBE_FUNC " Scratch Reg 1 is invalid," + "not applying gard records"); + } + }while(0); + SBE_EXIT(SBE_FUNC); + return rc; + #undef SBE_FUNC +} + +//---------------------------------------------------------------------------- +ReturnCode istepStopClockMpipl( sbeIstepHwp_t i_hwp ) +{ + #define SBE_FUNC "istepStopClockMpipl" + SBE_ENTER(SBE_FUNC); + uint32_t l_fapiRc = FAPI2_RC_SUCCESS; + p9_stopclocks_flags l_flags; // Default Flag Values + Target<TARGET_TYPE_PROC_CHIP > l_procTgt = plat_getChipTarget(); + p9hcd::P9_HCD_CLK_CTRL_CONSTANTS l_clk_regions = + p9hcd::CLK_REGION_ALL_BUT_PLL_REFR; + p9hcd::P9_HCD_EX_CTRL_CONSTANTS l_ex_select = p9hcd::BOTH_EX; + + l_flags.clearAll(); + l_flags.stop_core_clks = true; + l_flags.stop_cache_clks = true; + + SBE_EXEC_HWP(l_fapiRc, + p9_stopclocks_hwp, + l_procTgt, + l_flags, + l_clk_regions, + l_ex_select); + + SBE_EXIT(SBE_FUNC); + return l_fapiRc; + #undef SBE_FUNC +} + +//---------------------------------------------------------------------------- +inline ReturnCode maskSpecialAttn( const Target<TARGET_TYPE_CORE>& i_target ) +{ +#define SBE_FUNC "maskSpecialAttn " + SBE_ENTER(SBE_FUNC); + ReturnCode rc = FAPI2_RC_SUCCESS; + do + { + uint64_t maskData = 0; + const uint64_t ecMask = 0xffc0000000000000; + rc = getscom_abs_wrap (&i_target, P9N2_EX_SPA_MASK, &maskData ); + if( rc ) + { + SBE_ERROR(SBE_FUNC" Failed to read P9N2_EX_SPA_MASK"); + break; + } + maskData = maskData | ecMask; + rc = putscom_abs_wrap (&i_target, P9N2_EX_SPA_MASK, maskData ); + if( rc ) + { + SBE_ERROR(SBE_FUNC" Failed to write P9N2_EX_SPA_MASK"); + break; + } + }while(0); + SBE_EXIT(SBE_FUNC); + return rc; +#undef SBE_FUNC +} +#endif //#ifdef __SBEFW_SEEPROM__ + +#ifndef __SBEFW_SEEPROM__ +//---------------------------------------------------------------------------- +ReturnCode performTpmReset() +{ + #define SBE_FUNC "performTpmReset " + SBE_ENTER(SBE_FUNC); + ReturnCode rc = FAPI2_RC_SUCCESS; + do + { + constexpr uint64_t tpmBitMask = 0x0008000000000000ULL; + plat_target_handle_t tgtHndl; + uint64_t regData = 0; + rc = getscom_abs_wrap (&tgtHndl, + PU_PRV_MISC_PPE, + ®Data); + if( rc != FAPI2_RC_SUCCESS ) + { + SBE_ERROR(SBE_FUNC" Failed to read SBE internal reg for TPM reset"); + break; + } + + // To do TPM reset, first we should set bit 12 of PU_PRV_MISC_PPE + // and then clear it up. + regData = regData | tpmBitMask; + rc = putscom_abs_wrap(&tgtHndl, PU_PRV_MISC_PPE, regData); + if( rc != FAPI2_RC_SUCCESS ) + { + SBE_ERROR(SBE_FUNC" Failed to set TPM mask"); + break; + } + + regData = regData & ( ~tpmBitMask); + rc = putscom_abs_wrap(&tgtHndl, PU_PRV_MISC_PPE, regData); + if( rc != FAPI2_RC_SUCCESS ) + { + SBE_ERROR(SBE_FUNC" Failed to clear TPM mask"); + break; + } + + }while(0); + SBE_EXIT(SBE_FUNC); + return rc; + #undef SBE_FUNC +} + +//---------------------------------------------------------------------------- +ReturnCode istepLpcInit( sbeIstepHwp_t i_hwp) +{ + ReturnCode rc = FAPI2_RC_SUCCESS; + Target<TARGET_TYPE_PROC_CHIP > proc = plat_getChipTarget(); + assert( NULL != i_hwp.procHwp ); + if( !(SbeRegAccess::theSbeRegAccess().isSbeSlave()) ) + { + SBE_EXEC_HWP(rc, i_hwp.procHwp,proc); + } + return rc; +} + +//---------------------------------------------------------------------------- +ReturnCode updatePhbFunctionalState( void ) +{ + #define SBE_FUNC "updatePhbFunctionalState" + SBE_ENTER(SBE_FUNC); + ReturnCode rc = FAPI2_RC_SUCCESS; + const uint64_t pci_cplt_conf1[3] = {PEC_0_CPLT_CONF1, PEC_1_CPLT_CONF1, PEC_2_CPLT_CONF1}; + // TODO workaround + extern std::vector<fapi2::plat_target_handle_t> G_vec_targets; + Target<TARGET_TYPE_PROC_CHIP > procTgt = plat_getChipTarget(); + auto phbTgt_vec = procTgt.getChildren<fapi2::TARGET_TYPE_PHB>(); + + for (auto &phbTgt : phbTgt_vec) + { + //Get the PHB id + uint8_t phb_id = 0; + uint8_t pci_id = 0; + uint8_t phbPerPciCnt = 0; + uint64_t data = 0; + + FAPI_ATTR_GET(fapi2::ATTR_CHIP_UNIT_POS, phbTgt, phb_id); + if(phb_id == 1 || phb_id == 2) + { + pci_id = 1; + phbPerPciCnt = phb_id - 1; // To rotate per phb cnt within PCI from 0 to 1 + } + else if(phb_id > 2) + { + pci_id = 2; + phbPerPciCnt = phb_id - 3; // To rotate per phb cnt within PCI from 0 to 1 + } + rc = getscom_abs_wrap (&procTgt, pci_cplt_conf1[pci_id], &data); + if(rc != FAPI2_RC_SUCCESS) + { + SBE_ERROR(SBE_FUNC" Failed to read Pec[%d] Chiplet Config1 register",pci_id); + break; + } + // Fetch bit4 from D000009 for PHB0 + // Fetch bit4/5 from E000009 for PHB1/2 + // Fetch bit4/5/6 from F000009 for PHB3/4/5 + if( !((data >> (PEC_PHB_IOVALID_BIT_SHIFT - phbPerPciCnt)) & PEC_PHB_IOVALID_BIT_MASK) ) + { + SBE_INFO(SBE_FUNC "PHB[%d] setting up as Non-Functional", phb_id); + static_cast<plat_target_handle_t&>(phbTgt.operator ()()).setFunctional(false); + G_vec_targets.at(PHB_TARGET_OFFSET+ phb_id) = (fapi2::plat_target_handle_t)(phbTgt.get()); + } + } + SBE_EXIT(SBE_FUNC); + return rc; +#undef SBE_FUNC +} + +//---------------------------------------------------------------------------- +ReturnCode resetCrespErrLatch( void ) +{ + #define SBE_FUNC "resetCrespErrLatch" + SBE_ENTER(SBE_FUNC); + ReturnCode rc = FAPI2_RC_SUCCESS; + static const uint64_t BIT_63_MASK = 0x01; + do + { + Target<TARGET_TYPE_PROC_CHIP > procTgt = plat_getChipTarget(); + uint64_t data; + rc = getscom_abs_wrap (&procTgt, PU_PB_CENT_SM0_PB_CENT_MODE, + &data); + if( rc ) + { + break; + } + data = data | BIT_63_MASK; + rc = putscom_abs_wrap (&procTgt, PU_PB_CENT_SM0_PB_CENT_MODE, + data); + if( rc ) + { + break; + } + data = data &(~BIT_63_MASK); + rc = putscom_abs_wrap (&procTgt, PU_PB_CENT_SM0_PB_CENT_MODE, + data); + if( rc ) + { + break; + } + }while(0); + if( rc ) + { + SBE_ERROR(SBE_FUNC" Failed to reset Cresp error latch"); + } + SBE_EXIT(SBE_FUNC); + return rc; +#undef SBE_FUNC +} + +/////////////////////////////////////////////////////////////////////// +// @brief sbeHandleSuspendIO Sbe suspend IO function +// +// @return RC from the underlying FIFO utility +/////////////////////////////////////////////////////////////////////// +uint32_t sbeHandleSuspendIO(uint8_t *i_pArg) +{ + #define SBE_FUNC " sbeHandleSuspendIO " + SBE_ENTER(SBE_FUNC); + uint32_t rc = SBE_SEC_OPERATION_SUCCESSFUL; + ReturnCode fapiRc = FAPI2_RC_SUCCESS; + uint32_t len = 0; + sbeRespGenHdr_t respHdr; + respHdr.init(); + sbeResponseFfdc_t ffdc; + Target<TARGET_TYPE_PROC_CHIP > procTgt = plat_getChipTarget(); + + do + { + // Dequeue the EOT entry as no more data is expected. + rc = sbeUpFifoDeq_mult (len, NULL); + CHECK_SBE_RC_AND_BREAK_IF_NOT_SUCCESS(rc); + + // Update the PHB functional State before suspend io procedure + fapiRc = updatePhbFunctionalState(); + if(fapiRc != FAPI2_RC_SUCCESS) + { + SBE_ERROR(SBE_FUNC "updatePhbFunctionalState failed"); + respHdr.setStatus( SBE_PRI_GENERIC_EXECUTION_FAILURE, + SBE_SEC_GENERIC_FAILURE_IN_EXECUTION); + ffdc.setRc(fapiRc); + break; + } + + SBE_EXEC_HWP(fapiRc, p9_suspend_io_hwp, procTgt, false); + if( fapiRc != FAPI2_RC_SUCCESS ) + { + SBE_ERROR(SBE_FUNC "p9_suspend_io hwp failed"); + respHdr.setStatus( SBE_PRI_GENERIC_EXECUTION_FAILURE, + SBE_SEC_GENERIC_FAILURE_IN_EXECUTION); + ffdc.setRc(fapiRc); + break; + } + }while(0); + + // Create the Response to caller + do + { + // If there was a FIFO error, will skip sending the response, + // instead give the control back to the command processor thread + CHECK_SBE_RC_AND_BREAK_IF_NOT_SUCCESS(rc); + rc = sbeDsSendRespHdr( respHdr, &ffdc); + }while(0); + + SBE_EXIT(SBE_FUNC); + return rc; + #undef SBE_FUNC +} +#endif //#ifndef __SBEFW_SEEPROM__ + diff --git a/src/sbefw/core/sbecmdiplcontrol.H b/src/sbefw/core/sbecmdiplcontrol.H new file mode 100644 index 00000000..7b05f3f7 --- /dev/null +++ b/src/sbefw/core/sbecmdiplcontrol.H @@ -0,0 +1,132 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbecmdiplcontrol.H $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2017 */ +/* */ +/* */ +/* 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: ppe/sbe/sbefw/sbecmdiplcontrol.H + * + * @brief This file contains the SBE command details + * + */ + +#ifndef __SBEFW_SBECMDIPLCONTROL_H +#define __SBEFW_SBECMDIPLCONTROL_H + +#include <stdint.h> +#include "sbecmdgeneric.H" + + +namespace fapi2 +{ + class ReturnCode; +} + +// Major isteps which are supported +typedef enum +{ + SBE_ISTEP2 = 2, + SBE_ISTEP_FIRST = SBE_ISTEP2, + SBE_ISTEP3 = 3, + SBE_ISTEP_LAST_SLAVE = SBE_ISTEP3, + SBE_ISTEP4 = 4, + SBE_ISTEP5 = 5, + SBE_ISTEP_LAST_MASTER = SBE_ISTEP5, +}sbe_supported_steps_t; + +// Major MPIPL isteps which are supported +static const uint32_t SBE_ISTEP_MPIPL_START = 96; +static const uint32_t SBE_ISTEP_MPIPL_CONTINUE = 97; +static const uint32_t SBE_ISTEP_STOPCLOCK = 98; +static const uint32_t MPIPL_START_MAX_SUBSTEPS = 8; +static const uint32_t MPIPL_CONTINUE_MAX_SUBSTEPS = 7; +static const uint32_t ISTEP_STOPCLOCK_MAX_SUBSTEPS = 1; + +// constants +static const uint32_t ISTEP2_MAX_SUBSTEPS = 17; +static const uint32_t ISTEP3_MAX_SUBSTEPS = 22; +static const uint32_t ISTEP4_MAX_SUBSTEPS = 34; +static const uint32_t ISTEP5_MAX_SUBSTEPS = 2; +static const uint8_t ISTEP_MINOR_START = 1; +static const uint8_t SLAVE_LAST_MINOR_ISTEP = 20; +static const uint8_t ISTEP2_MINOR_START = 2; + +extern uint64_t G_ring_save[8]; +extern const uint64_t G_ring_index[10]; + +/** + * @brief Support function to execute specific istep + * + * @param[in] i_major Major Istep Number + * @param[in] i_minor Minor Istep Number + * + * @return FAPI2_RC_SUCCESS if success, else error code. + */ +fapi2::ReturnCode sbeExecuteIstep (uint8_t i_major, uint8_t i_minor); + + +/** + * @brief execute istep chipop (0xA101) + * + * @param[in] i_pArg Buffer to be passed to the function (not used as of now) + * + * @return Rc from the FIFO access utility + */ +uint32_t sbeHandleIstep(uint8_t *i_pArg); + +/** + * @brief Executes IPL steps in continuous mode. + * + * @par On the master SBE, this will run + * all steps from 2.2 to 5.2. On the slave SBE, it runs all steps from 2.2 + * to 3.18. + * In case an error is encountered, the execution is aborted. + */ +void sbeDoContinuousIpl(); + +/** + * @brief Handles Sbe Get FFDC chip-op (0xA801) + * + * @param[in] i_pArg Buffer to be passed to the function (not used as of now) + * + * @return Rc from the FIFO access utility + */ +uint32_t sbeGetSbeFfdc(uint8_t *i_pArg); + +/** + * @brief Handles Sbe Get FFDC chip-op (0xA803) + * + * @param[in] i_pArg Buffer to be passed to the function (not used as of now) + * + * @return Rc from the FIFO access utility + */ +uint32_t sbeGetFreqSupported(uint8_t *i_pArg); + +/** + * @brief execute suspend IO chip-op (0xA102) + * + * @param[in] i_pArg Buffer to be passed to the function (not used as of now) + * + * @return Rc from the FIFO access utility + */ +uint32_t sbeHandleSuspendIO(uint8_t *i_pArg); + +#endif // __SBEFW_SBECMDIPLCONTROL_H diff --git a/src/sbefw/core/sbecmdmemaccess.C b/src/sbefw/core/sbecmdmemaccess.C new file mode 100644 index 00000000..1160043d --- /dev/null +++ b/src/sbefw/core/sbecmdmemaccess.C @@ -0,0 +1,799 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbecmdmemaccess.C $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2017 */ +/* */ +/* */ +/* 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: ppe/sbe/sbefw/sbecmdmemaccess.C + * + * @brief This file contains the SBE Memory Access chipOps + * + */ + +#include "sbecmdmemaccess.H" +#include "sbefifo.H" +#include "sbe_sp_intf.H" +#include "sbetrace.H" +#include "sbeFifoMsgUtils.H" +#include "sbeutil.H" +#include "sbeHostUtils.H" +#include "sbeglobals.H" +#include "sbeSecureMemRegionManager.H" + +#include "fapi2.H" + +#include "sbeMemAccessInterface.H" + +using namespace fapi2; + +// Buffer requirement for ADU and PBA on the stack +constexpr uint32_t MAX_ADU_BUFFER = 5; // 40bytes +constexpr uint32_t MAX_PBA_BUFFER = 32; + +// Multiplier factor with respect to the FIFO length +constexpr uint32_t ADU_SIZE_MULTIPLIER_FOR_LEN_ALIGNMENT = 2; +constexpr uint32_t PBA_SIZE_MULTIPLIER_FOR_LEN_ALIGNMENT = 32; + +/** + * @brief static definition of parameters passed in adu chip-ops + */ +constexpr uint32_t SBE_ADU_LOCK_TRIES = 3; + +#ifndef __SBEFW_SEEPROM__ +/////////////////////////////////////////////////////////////////////// +// @brief align4ByteWordLength - Internal Method to this file +// Align the length passed and return number of words +// +// @param [in] i_len, length pass from user in Bytes +// +// @return Number of words (number of 4byte length) +/////////////////////////////////////////////////////////////////////// +inline uint32_t align4ByteWordLength(uint32_t i_len) +{ + if(i_len % 4 != 0) + { + i_len = i_len + (4 - (i_len % 4)); + } + return(i_len/4); +} + +/////////////////////////////////////////////////////////////////////// +// @brief calInterAduLenForUpFifo - Internal Method to this file +// Calculate Intermediate Adu Data length for Upstream Fifo +// +// @param [in] i_mod, Modulus number from user, (from numGranules % 4) +// could be any values from 1,2,3 +// @param [in] i_itag, Itag flag +// @param [in] i_ecc, Ecc flag +// +// @return length in bytes for intermediate ADU length +/////////////////////////////////////////////////////////////////////// +inline uint32_t calInterAduLenForUpFifo(uint8_t i_mod, bool i_itag, bool i_ecc) +{ + //Default init length with either Ecc or Itag + uint32_t l_len = + ((sbeMemAccessInterface::ADU_GRAN_SIZE_BYTES + 1) * (1 + i_mod)); + // If ECC and iTag bit is also part of the buffer + if(i_itag && i_ecc) + { + l_len = l_len + (1 + i_mod); + } + return (l_len); +} + +/////////////////////////////////////////////////////////////////////// +// @brief sbeAduLenInUpStreamFifo - Internal Method to this file +// Calculate the Final Size which is write/read to/from HWP +// +// @param [in] i_numGranules, Number of granules read/write +// @param [in] i_granuleSize +// @param [in] i_itag, Itag flag +// @param [in] i_ecc, Ecc flag +// +// @return Length in bytes for ADU to be put in Upstream FIFO +/////////////////////////////////////////////////////////////////////// +inline uint32_t sbeAduLenInUpStreamFifo(uint32_t i_numGranules, + uint32_t i_granuleSize, + bool i_itag, + bool i_ecc) +{ + uint32_t l_respLen = i_numGranules * i_granuleSize; + if(i_itag) + { + // Add one byte for Itag for Each Granule Completed + l_respLen = l_respLen + i_numGranules; + } + if(i_ecc) + { + // Add one byte for Ecc for Each Granule Completed + l_respLen = l_respLen + i_numGranules; + } + return l_respLen; +} + +/////////////////////////////////////////////////////////////////////// +// @brief flushUpstreamFifo - Internal Method to this file, to flush +// out the upstream fifo +// +// @param [in] i_primaryStatus, Fapi RC +// +// @return RC from the underlying FIFO utility +/////////////////////////////////////////////////////////////////////// +inline uint32_t flushUpstreamFifo (const uint32_t &i_primaryStatus) +{ + uint32_t l_len2dequeue = 0; + uint32_t l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + if ( i_primaryStatus != SBE_PRI_OPERATION_SUCCESSFUL) + { + l_rc = sbeUpFifoDeq_mult(l_len2dequeue, NULL, + true, true); + } + // For other success paths, just attempt to offload + // the next entry, which is supposed to be the EOT entry + else + { + l_rc = sbeUpFifoDeq_mult(l_len2dequeue, NULL, true); + } + return l_rc; +} + +/////////////////////////////////////////////////////////////////////// +// @brief processPbaRequest - Internal Method to this file, +// To process the PBA Access request +// +// @param [in] i_hdr, Message Request Header +// @param [in] i_isFlagRead, Read/Write Flag +// +// @return RC from the method +/////////////////////////////////////////////////////////////////////// +uint32_t processPbaRequest(const sbeMemAccessReqMsgHdr_t &i_hdr, + const bool i_isFlagRead) +{ + #define SBE_FUNC " processPbaRequest " + SBE_ENTER(SBE_FUNC); + uint32_t l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + + ReturnCode l_fapiRc = FAPI2_RC_SUCCESS; + sbeRespGenHdr_t l_respHdr; + l_respHdr.init(); + sbeResponseFfdc_t l_ffdc; + + // Default for PBA + uint32_t l_granuleSize = sbeMemAccessInterface::PBA_GRAN_SIZE_BYTES; + uint64_t l_addr = 0; + // Keeps track of number of granules sent to HWP + uint64_t l_granulesCompleted = 0; + // Input Data length in alignment with PBA (128 Bytes) + uint64_t l_lenCacheAligned = 0; + + do + { + // If not Host Pass through command, simply set the addr from the command + if(!i_hdr.isPbaHostPassThroughModeSet()) + { + l_addr = i_hdr.getAddr(); + // Check if the access to the address is allowed + l_respHdr.secondaryStatus = mainStoreSecMemRegionManager.isAccessAllowed( + {l_addr, + i_hdr.len, + (i_isFlagRead ? static_cast<uint8_t>(memRegionMode::READ): + static_cast<uint8_t>(memRegionMode::WRITE))}); + if(l_respHdr.secondaryStatus != SBE_SEC_OPERATION_SUCCESSFUL) + { + l_respHdr.primaryStatus = SBE_PRI_UNSECURE_ACCESS_DENIED; + break; + } + } + // If it is Host Pass through command, set the address using the Host pass + // through address already set in the global and using the addr here in the + // command as index to that address + else + { + l_addr = SBE_GLOBAL->hostPassThroughCmdAddr.addr + i_hdr.getAddr(); + // Check if the size pass in the command is less than the size mentioned + // in the Host Pass Through globals + if((i_hdr.getAddr() + i_hdr.len) > SBE_GLOBAL->hostPassThroughCmdAddr.size) + { + // Break out, Invalid Size + SBE_ERROR("User size[0x%08X] exceeds the Host Pass Through Mode " + "size[0x%08X] Start Index[0x%08X %08X]", + i_hdr.len, SBE_GLOBAL->hostPassThroughCmdAddr.size, + SBE::higher32BWord(i_hdr.getAddr()), + SBE::lower32BWord(i_hdr.getAddr())); + l_respHdr.setStatus( SBE_PRI_INVALID_DATA, + SBE_SEC_GENERIC_FAILURE_IN_EXECUTION ); + } + } + + // Default EX Target Init..Not changing it for the time being + Target<TARGET_TYPE_EX> l_ex( + plat_getTargetHandleByChipletNumber<TARGET_TYPE_EX>( + sbeMemAccessInterface::PBA_DEFAULT_EX_CHIPLET_ID)); + + p9_PBA_oper_flag l_myPbaFlag; + // Determine the access flags + // Fast mode flag + if(i_hdr.isFastModeSet()) + { + l_myPbaFlag.setFastMode(true); + SBE_INFO(SBE_FUNC "Fast Mode is set"); + } + + // inject mode flag + if(i_hdr.isPbaInjectModeSet()) + { + l_myPbaFlag.setOperationType(p9_PBA_oper_flag::INJ); // Inject operation + SBE_INFO(SBE_FUNC "inject Mode is set"); + } + + // By default, ex_chipletId printed below won't be used unless accompanied + // by LCO_mode (LCO Mode for PBA-Put) + if(i_hdr.isPbaLcoModeSet()) + { + SBE_INFO(SBE_INFO "LCO Mode is set with Ex ChipletId[%d]", + (i_hdr.coreChipletId)/2); + //Derive the EX target from the input Core Chiplet Id + //Core0/1 -> EX0, Core2/3 -> EX1, Core4/5 -> EX2, Core6/7 -> EX3 + //..so on + l_ex = plat_getTargetHandleByChipletNumber<fapi2::TARGET_TYPE_EX> + (i_hdr.coreChipletId); + l_myPbaFlag.setOperationType(p9_PBA_oper_flag::LCO); // LCO operation + } + + l_lenCacheAligned = i_hdr.getDataLenCacheAlign(); + SBE_DEBUG(SBE_FUNC "Data Aligned Len / Number of data granules = %d", + l_lenCacheAligned); + + sbeMemAccessInterface l_PBAInterface(SBE_MEM_ACCESS_PBA, + l_addr, + &l_myPbaFlag, + (i_isFlagRead ? + SBE_MEM_ACCESS_READ: + SBE_MEM_ACCESS_WRITE), + l_granuleSize, + l_ex); + + while (l_granulesCompleted < l_lenCacheAligned) + { + // Breaking out here if invalid size + if(l_respHdr.primaryStatus != SBE_PRI_OPERATION_SUCCESSFUL) + { + break; + } + + // If this is putmem request, read input data from the upstream FIFO + if (!i_isFlagRead) + { + // l_sizeMultiplier * 4B Upstream FIFO = Granule size 128B + uint32_t l_len2dequeue = sbeMemAccessInterface::PBA_GRAN_SIZE_BYTES + / sizeof(uint32_t); + l_rc = sbeUpFifoDeq_mult (l_len2dequeue, + (uint32_t *)l_PBAInterface.getBuffer(), + false); + CHECK_SBE_RC_AND_BREAK_IF_NOT_SUCCESS(l_rc); + } + + // Call the PBA HWP + l_fapiRc = l_PBAInterface.accessGranule( + l_granulesCompleted==(l_lenCacheAligned-1)); + // if error + if(l_fapiRc != FAPI2_RC_SUCCESS) + { + // Respond with HWP FFDC + l_respHdr.setStatus( SBE_PRI_GENERIC_EXECUTION_FAILURE, + SBE_SEC_GENERIC_FAILURE_IN_EXECUTION ); + l_ffdc.setRc(l_fapiRc); + break; + } + + // If this is a getmem request, + // need to push the data into the downstream FIFO + if (i_isFlagRead) + { + // Number of 4Bytes to put, to align with Granule Size + // l_len*4 = Granule Size + uint32_t l_len = sbeMemAccessInterface::PBA_GRAN_SIZE_BYTES + / sizeof(uint32_t); + l_rc = sbeDownFifoEnq_mult (l_len, + (uint32_t *)l_PBAInterface.getBuffer()); + CHECK_SBE_RC_AND_BREAK_IF_NOT_SUCCESS(l_rc); + } + + l_granulesCompleted++; + } // End..while (l_granulesCompleted < l_lenCacheAligned); + } while(0); + + // Now build and enqueue response into downstream FIFO + do + { + // If there was a FIFO error, will skip sending the response, + // instead give the control back to the command processor thread + CHECK_SBE_RC_AND_BREAK_IF_NOT_SUCCESS(l_rc); + // If there was a HWP failure for putmem request, + // need to Flush out upstream FIFO, until EOT arrives + if (!i_isFlagRead) + { + l_rc = flushUpstreamFifo(l_respHdr.primaryStatus); + CHECK_SBE_RC_AND_BREAK_IF_NOT_SUCCESS(l_rc); + } + + // first enqueue the length of data actually written + uint32_t l_len = 1; + uint32_t l_respLen = l_granulesCompleted * l_granuleSize; + + SBE_INFO(SBE_FUNC "Total length Pushed for ChipOp [%d]", l_respLen); + l_rc = sbeDownFifoEnq_mult ( l_len, &l_respLen ); + CHECK_SBE_RC_AND_BREAK_IF_NOT_SUCCESS(l_rc); + + l_rc = sbeDsSendRespHdr( l_respHdr, &l_ffdc); + // Indicate the host in put pass through mode via Interrupt + if(!l_rc && i_hdr.isPbaHostPassThroughModeSet() && !i_isFlagRead) + { + l_rc = sbeSetSbe2PsuDbBitX(SBE_SBE2PSU_DOORBELL_SET_BIT4); + } + } while(false); + + SBE_EXIT(SBE_FUNC); + return l_rc; + #undef SBE_FUNC +} + +/////////////////////////////////////////////////////////////////////// +// @brief processAduRequest - Internal Method to this file, +// To process the ADU Access request +// +// @param [in] i_hdr, Message Request Header +// @param [in] i_isFlagRead, Read/Write Flag +// +// @return RC from the method +/////////////////////////////////////////////////////////////////////// +#define IS_ONE_BIT_SET(x) ((x & (x-1)) == 0) +#define GET_8_BYTE_ALIGNED_OFFSET(x) ((x & 0x07) * 8) +uint32_t processAduRequest(const sbeMemAccessReqMsgHdr_t &i_hdr, + const bool i_isFlagRead) +{ + #define SBE_FUNC " processAduRequest " + SBE_ENTER(SBE_FUNC); + uint32_t l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + + ReturnCode l_fapiRc = FAPI2_RC_SUCCESS; + sbeRespGenHdr_t l_respHdr; + l_respHdr.init(); + sbeResponseFfdc_t l_ffdc; + + // Default for ADU + uint32_t l_sizeMultiplier = ADU_SIZE_MULTIPLIER_FOR_LEN_ALIGNMENT; + uint32_t l_granuleSize = sbeMemAccessInterface::ADU_GRAN_SIZE_BYTES; + + // Keeps track of number of granules sent to HWP + uint64_t l_granulesCompleted = 0; + p9_ADU_oper_flag l_aduFlag; + // For local Use + bool l_isEccMode = i_hdr.isEccFlagSet(); + bool l_isItagMode = i_hdr.isItagFlagSet(); + uint64_t l_addr = i_hdr.getAddr(); + + do + { + l_aduFlag.setTransactionSize(p9_ADU_oper_flag::TSIZE_8); + // For len lesser than 8, only 1,2 and 4 lengths are allowed + if(i_hdr.len < 8) + { + if(IS_ONE_BIT_SET(i_hdr.len) == false) + { + l_respHdr.setStatus(SBE_PRI_INVALID_DATA, + SBE_SEC_GENERIC_FAILURE_IN_EXECUTION); + SBE_ERROR(SBE_FUNC"Invalid length[%d] - " + "supported values[1/2/4/multiples of 8]", + i_hdr.len); + break; + } + l_sizeMultiplier = 1; + l_granuleSize = i_hdr.len; + l_aduFlag.setTransactionSize((p9_ADU_oper_flag::Transaction_size_t)(i_hdr.len)); + } + //Default Operation Type is DMA_PARTIAL + l_aduFlag.setOperationType(p9_ADU_oper_flag::DMA_PARTIAL); + l_aduFlag.setLockControl(false); + l_aduFlag.setOperFailCleanup(true); + l_aduFlag.setNumLockAttempts(SBE_ADU_LOCK_TRIES); + + // Fast Mode / Ecc mode / Cache Inhibit Mode / Auto Increment + // required in ADU operations. + if(i_hdr.isFastModeSet()) + { + l_aduFlag.setFastMode(true); + } + // Set DMA_PARTIAL mode by default + l_aduFlag.setOperationType(p9_ADU_oper_flag::DMA_PARTIAL); + if(i_hdr.isCacheInhibitModeFlagSet()) + { + l_aduFlag.setOperationType(p9_ADU_oper_flag::CACHE_INHIBIT); + } + if(i_hdr.isItagFlagSet()) + { + l_aduFlag.setItagMode(true); + } + if(i_hdr.isAutoIncrModeSet()) + { + l_aduFlag.setAutoIncrement(true); + } + + if(!i_isFlagRead) // ECC override in write mode + { + if(i_hdr.isEccOverrideFlagSet()) + { + l_aduFlag.setEccItagOverrideMode(true); + l_aduFlag.setEccMode(true); + } + } + else // ECC required in read mode + { + if(i_hdr.isEccFlagSet()) + { + l_aduFlag.setEccMode(true); + } + } + + // Input Data length in alignment with ADU + // 1 for 1/2/4 Bytes else number of multiples of 8 Bytes + uint64_t l_lenCacheAligned = i_hdr.getDataLenCacheAlign(); + SBE_DEBUG(SBE_FUNC "User length [%d], Data Aligned Len / " + "Number of data granules = %d", + i_hdr.len, l_lenCacheAligned); + + sbeMemAccessInterface l_ADUInterface(SBE_MEM_ACCESS_ADU, + l_addr, + &l_aduFlag, + (i_isFlagRead ? + SBE_MEM_ACCESS_READ : + SBE_MEM_ACCESS_WRITE), + sbeMemAccessInterface::ADU_GRAN_SIZE_BYTES); + // Check if the access to the address is allowed + l_respHdr.secondaryStatus = mainStoreSecMemRegionManager.isAccessAllowed( + {l_addr, + i_hdr.len, + (i_isFlagRead ? static_cast<uint8_t>(memRegionMode::READ): + static_cast<uint8_t>(memRegionMode::WRITE))}); + if(l_respHdr.secondaryStatus != SBE_SEC_OPERATION_SUCCESSFUL) + { + l_respHdr.primaryStatus = SBE_PRI_UNSECURE_ACCESS_DENIED; + break; + } + // 8Byte granule for ADU access + uint64_t l_dataFifo[MAX_ADU_BUFFER] = {0}; + while (l_granulesCompleted < l_lenCacheAligned) + { + // With ECC or ITAG the output length of a granule will become + // 9 bytes instead of 8, To align it we will merge 4 output granule + // before putting it in the Downstream FIFO i.e. 9*4 = 36Bytes + // which is 4Bytes aligned size. + // With Both ECC and ITag, the o/p length of a granule will become + // 10Bytes instead of 8, To align it we will merge 4 output granule + // before putting it in the Downstream FIFO i.e. 10*4 = 40bytes + // So in ADU Read case we will use the same buffer with 10Bytes + // offset to fill the 40bytes. + + // Both Ecc and ITag Present = 40Bytes is the alignment length + /* D[00] D[01] D[02] D[03] D[04] D[05] D[06] D[07] -> 8 Data Bytes + * D[08-Itag] D[09-Ecc] D[0a] D[0b] D[0c] D[0d] D[0e] D[0f] -> 6D B + * D[10] D[11] D [12-Itag] D[13-Ecc] D[14] D[15] D[16] D[17] + * D[18] D[19] D[1a] D[1b] D[1c-Itag] D[1d-Ecc] D[1e] D[1f] + * D[20] D[21] D[22] D[23] D[24] D[25] D[26-Itag] D[27-Ecc] + */ + // Only Ecc Present = 36 Bytes is the alignment length + /* D[00] D[01] D[02] D[03] D[04] D[05] D[06] D[07] -> 8 Data Bytes + * D[08-Ecc] D[09] D[0a] D[0b] D[0c] D[0d] D[0e] D[0f] -> 7D B + * D[10] D[11-Ecc] D [12] D[13] D[14] D[15] D[16] D[17] + * D[18] D[19] D[1a-Ecc] D[1b] D[1c] D[1d] D[1e] D[1f] + * D[20] D[21] D[22] D[23-Ecc] + */ + // Only ITag Present = 36 Bytes is the alignment length + /* D[00] D[01] D[02] D[03] D[04] D[05] D[06] D[07] -> 8 Data Bytes + * D[08-Itag] D[09] D[0a] D[0b] D[0c] D[0d] D[0e] D[0f] -> 7D B + * D[10] D[11-Itag] D [12] D[13] D[14] D[15] D[16] D[17] + * D[18] D[19] D[1a-Itag] D[1b] D[1c] D[1d] D[1e] D[1f] + * D[20] D[21] D[22] D[23-Itag] + */ + uint8_t l_bufIdx = 0; + + // If this is putmem request, read input data from the upstream FIFO + if (!i_isFlagRead) + { + // l_sizeMultiplier * 4B Upstream FIFO = Granule size 8B + uint32_t l_len2dequeue = l_sizeMultiplier; + l_rc = sbeUpFifoDeq_mult (l_len2dequeue, + (uint32_t *)&l_dataFifo, + false); + CHECK_SBE_RC_AND_BREAK_IF_NOT_SUCCESS(l_rc); + SBE_DEBUG("l_dataFifo#1 0x%08x%08x", SBE::higher32BWord(l_dataFifo[0]), + SBE::lower32BWord(l_dataFifo[0])); + // For lengths 1,2 and 4, data needs to be shift-aligned to + // 8-byte address boundary. + l_dataFifo[0] >>= GET_8_BYTE_ALIGNED_OFFSET(l_addr); + SBE_DEBUG("l_dataFifo#2 0x%08x%08x", SBE::higher32BWord(l_dataFifo[0]), + SBE::lower32BWord(l_dataFifo[0])); + + // Insert the ECC if ECC Mode is set + if(l_isEccMode) + { + uint8_t l_eccPos = 8; + if(l_isItagMode) + { + l_eccPos = 9; + } + ((uint8_t*)&l_dataFifo)[l_eccPos] = i_hdr.eccByte; + } + } + else + { + //Adu Read Mode - with either ECC or ITag or Both + // Calculate the MODULUS + uint8_t l_mod = (l_granulesCompleted % 4); + if( (l_mod) && ((l_isEccMode) || (l_isItagMode)) ) + { + // Default Init it for 1byte extra + l_bufIdx = (sbeMemAccessInterface::ADU_GRAN_SIZE_BYTES + * l_mod) + l_mod; + if((l_isEccMode) && (l_isItagMode)) + { + l_bufIdx = l_bufIdx + l_mod; + } + } + } + l_fapiRc = l_ADUInterface.accessWithBuffer( + &(((uint8_t *)&(l_dataFifo))[l_bufIdx]), + sbeMemAccessInterface::ADU_GRAN_SIZE_BYTES, + (l_granulesCompleted == (l_lenCacheAligned-1))); + // if error + if( (l_fapiRc != FAPI2_RC_SUCCESS) ) + { + // Respond with HWP FFDC + l_respHdr.setStatus( SBE_PRI_GENERIC_EXECUTION_FAILURE, + SBE_SEC_GENERIC_FAILURE_IN_EXECUTION ); + l_ffdc.setRc(l_fapiRc); + break; + } + + // If this is a getmem request, + // need to push the data into the downstream FIFO + if (i_isFlagRead) + { + // Number of 4Bytes to put, to align with Granule Size + uint32_t l_len = l_sizeMultiplier; // l_len*4 = Granule Size + + //Enter the below 'if' if ADU Read Mode with Either Ecc or ITag + //or both set. During non-aligned Transaction (but not the last) + //then set the len as zero so as to skip the unalign byte send, + //during next transaction when the data is aligned it will take + //care of sending all granules. + //If the below condition is not met then for ADU Read Mode will + //happen to write on DownStream FIFO for each granule. + + if((l_isEccMode) || (l_isItagMode)) + { + //Calculate the MODULUS + uint8_t l_mod = (l_granulesCompleted % 4); + if( (l_mod == 3) || + ((l_granulesCompleted+1) == l_lenCacheAligned) ) + { + l_len = calInterAduLenForUpFifo(l_mod,l_isItagMode, + l_isEccMode); + l_len = align4ByteWordLength(l_len); + } + else + { + // If it is not the last granule or on the 4th entry + // into the data buffer, need not send it to Upstream + // Fifo + l_len = 0; + } + } + if(l_len) + { + SBE_DEBUG("l_dataFifo#3 0x%08x%08x", SBE::higher32BWord(l_dataFifo[0]), + SBE::lower32BWord(l_dataFifo[0])); + // For lengths 1,2 and 4, data needs to be extracted from + // shift-aligned 8-byte address boundary. + l_dataFifo[0] <<= GET_8_BYTE_ALIGNED_OFFSET(l_addr); + SBE_DEBUG("l_dataFifo#4 0x%08x%08x", SBE::higher32BWord(l_dataFifo[0]), + SBE::lower32BWord(l_dataFifo[0])); + + l_rc = sbeDownFifoEnq_mult (l_len, (uint32_t *)&l_dataFifo); + CHECK_SBE_RC_AND_BREAK_IF_NOT_SUCCESS(l_rc); + } + } + l_addr += l_granuleSize; + l_granulesCompleted++; + } // End..while (l_granulesCompleted < l_lenCacheAligned); + } while(false); + + // Now build and enqueue response into downstream FIFO + do + { + // If there was a FIFO error, will skip sending the response, + // instead give the control back to the command processor thread + CHECK_SBE_RC_AND_BREAK_IF_NOT_SUCCESS(l_rc); + // If there was a HWP failure for putmem request, + // need to Flush out upstream FIFO, until EOT arrives + if (!i_isFlagRead) + { + l_rc = flushUpstreamFifo(l_respHdr.primaryStatus); + CHECK_SBE_RC_AND_BREAK_IF_NOT_SUCCESS(l_rc); + } + + // first enqueue the length of data actually written + uint32_t l_len = 1; + uint32_t l_respLen = sbeAduLenInUpStreamFifo( + l_granulesCompleted, + l_granuleSize, + l_isItagMode, + l_isEccMode); + + SBE_INFO(SBE_FUNC "Total length Pushed for ChipOp [%d]", l_respLen); + l_rc = sbeDownFifoEnq_mult ( l_len, &l_respLen ); + CHECK_SBE_RC_AND_BREAK_IF_NOT_SUCCESS(l_rc); + + l_rc = sbeDsSendRespHdr( l_respHdr, &l_ffdc); + } while(false); + + SBE_EXIT(SBE_FUNC); + return l_rc; + #undef SBE_FUNC +} + +/////////////////////////////////////////////////////////////////////// +// @brief sbeMemAccess_Wrap Memory Access Wrapper function +// +// @param [in] i_isFlagRead Flag to indicate the memory Access Type +// true : GetMem ChipOp +// false : PutMem ChipOp +// +// @return RC from the method +/////////////////////////////////////////////////////////////////////// +uint32_t sbeMemAccess_Wrap(const bool i_isFlagRead) +{ + #define SBE_FUNC " sbeMemAccess_Wrap " + SBE_ENTER(SBE_FUNC); + + uint32_t l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + // Create an instance of Memory Access ChipOp structure + sbeMemAccessReqMsgHdr_t l_req = {0}; + + // Offload the common header from the Upstream FIFO + uint32_t l_len2dequeue = sizeof(l_req) / sizeof(uint32_t); + l_rc = sbeUpFifoDeq_mult(l_len2dequeue, (uint32_t *)&l_req, i_isFlagRead); + + if(!l_rc) + { + // Calculate the PBA/ADU address from the given input + SBE_INFO(SBE_FUNC "Address Upper[0x%08X] Lower[0x%08X] Flags[0x%08X] " + "Length[0x%08X]", ((l_req.getAddr()>>32) & 0xFFFFFFFF), + (l_req.getAddr() & 0xFFFFFFFF), l_req.flags, l_req.len); + + // PBA + bool l_isPBA = l_req.isPbaFlagSet(); + if(l_isPBA) + { + l_rc = processPbaRequest(l_req, i_isFlagRead); + if(l_rc) + { + SBE_ERROR(SBE_FUNC "processPbaRequest failed"); + } + } + // ADU + else + { + l_rc = processAduRequest(l_req, i_isFlagRead); + if(l_rc) + { + SBE_ERROR(SBE_FUNC "processAduRequest failed"); + } + } + } + // If there was a FIFO error, will skip sending the response, + // instead give the control back to the command processor thread + SBE_EXIT(SBE_FUNC); + return l_rc; + #undef SBE_FUNC +} + +////////////////////////////////////////////////////// +////////////////////////////////////////////////////// +uint32_t sbePutMem (uint8_t *i_pArg) +{ + return sbeMemAccess_Wrap (false); +} + +///////////////////////////////////////////////////// +////////////////////////////////////////////////////// +uint32_t sbeGetMem (uint8_t *i_pArg) +{ + return sbeMemAccess_Wrap (true); +} +#endif //not __SBEFW_SEEPROM__ +#ifdef __SBEFW_SEEPROM__ + +uint32_t sbeUpdateMemAccessRegion (uint8_t *i_pArg) +{ + #define SBE_FUNC "sbeManageMemAccessRegion" + SBE_ENTER(SBE_FUNC); + uint32_t rc = SBE_SEC_GENERIC_FAILURE_IN_EXECUTION; + uint32_t fapiRc = FAPI2_RC_SUCCESS; + sbeMemRegionReq_t req = {}; + + do + { + rc = sbeReadPsu2SbeMbxReg(SBE_HOST_PSU_MBOX_REG1, + (sizeof(req)/sizeof(uint64_t)), + (uint64_t*)&req, + true); + if(SBE_SEC_OPERATION_SUCCESSFUL != rc) + { + SBE_ERROR(SBE_FUNC "Failed to extract SBE_HOST_PSU_MBOX_REG1 and " + "SBE_HOST_PSU_MBOX_REG2"); + break; + } + + SBE_INFO(SBE_FUNC" Addr[0x%08x%08x] size[0x%08x] flags[0x%04x]", + SBE::higher32BWord(req.startAddress), + SBE::lower32BWord(req.startAddress), + req.size, + SBE_GLOBAL->sbePsu2SbeCmdReqHdr.flags); + + uint16_t mode = SBE_GLOBAL->sbePsu2SbeCmdReqHdr.flags & 0x00FF; + if(mode == SBE_MEM_REGION_CLOSE) + { + SBE_GLOBAL->sbeSbe2PsuRespHdr.secStatus = + mainStoreSecMemRegionManager.remove(req.startAddress); + } + else + { + uint8_t memMode = 0; + if(mode == SBE_MEM_REGION_OPEN_RO) + { + memMode = static_cast<uint8_t>(memRegionMode::READ); + } + else if(mode == SBE_MEM_REGION_OPEN_RW) + { + memMode = static_cast<uint8_t>(memRegionMode::READ) | + static_cast<uint8_t>(memRegionMode::WRITE); + } + SBE_GLOBAL->sbeSbe2PsuRespHdr.secStatus = + mainStoreSecMemRegionManager.add(req.startAddress, + req.size, + memMode); + } + if(SBE_GLOBAL->sbeSbe2PsuRespHdr.secStatus != + SBE_SEC_OPERATION_SUCCESSFUL) + { + SBE_GLOBAL->sbeSbe2PsuRespHdr.primStatus = SBE_PRI_USER_ERROR; + } + } while(false); + + // Send the response + sbePSUSendResponse(SBE_GLOBAL->sbeSbe2PsuRespHdr, fapiRc, rc); + + SBE_EXIT(SBE_FUNC); + return rc; + #undef SBE_FUNC +} +#endif //__SBEFW_SEEPROM__ diff --git a/src/sbefw/core/sbecmdmemaccess.H b/src/sbefw/core/sbecmdmemaccess.H new file mode 100644 index 00000000..54c9aa39 --- /dev/null +++ b/src/sbefw/core/sbecmdmemaccess.H @@ -0,0 +1,70 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbecmdmemaccess.H $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* */ +/* */ +/* 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: ppe/sbe/sbefw/sbecmdmemaccess.H + * + * @brief This file contains the Interfaces for the Memory Access chip-ops + * + */ + +#ifndef __SBEFW_SBECMDMEMACCESS_H +#define __SBEFW_SBECMDMEMACCESS_H + +#include <stdint.h> + +typedef struct +{ + uint64_t reserved:32; + uint64_t size:32; + uint64_t startAddress:64; +} sbeMemRegionReq_t; + +/** + * @brief sbeUpdateMemAccessRegion - manage the unsecure memory regions + * + * @param[in] i_pArg Buffer to be passed to the function (not used as of now) + * + * @return Rc from the FIFO access utility + */ +uint32_t sbeUpdateMemAccessRegion (uint8_t *i_pArg); + +/** + * @brief sbeGetMem : Implements SBE Get Memory ChipOp + * + * @param[in] i_pArg Buffer to be passed to the function (not used as of now) + * + * @return Rc from the FIFO access utility + */ +uint32_t sbeGetMem (uint8_t *i_pArg); + +/** + * @brief sbePutMem : Implements SBE Put Memory ChipOp + * + * @param[in] i_pArg Buffer to be passed to the function (not used as of now) + * + * @return Rc from the FIFO access utility + */ +uint32_t sbePutMem (uint8_t *i_pArg); + +#endif /* __SBEFW_SBECMDMEMACCESS_H */ diff --git a/src/sbefw/core/sbecmdmpipl.C b/src/sbefw/core/sbecmdmpipl.C new file mode 100644 index 00000000..3179382f --- /dev/null +++ b/src/sbefw/core/sbecmdmpipl.C @@ -0,0 +1,430 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbecmdmpipl.C $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* */ +/* */ +/* 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: ppe/src/sbefw/sbecmdmpipl.C + * + * @brief This file contains the SBE MPIPL chipOps + * + */ + +#include "sbefifo.H" +#include "sbeSpMsg.H" +#include "sbe_sp_intf.H" +#include "sbetrace.H" +#include "sbeFifoMsgUtils.H" +#include "sbecmdmpipl.H" +#include "sberegaccess.H" +#include "sbefapiutil.H" +#include "sbecmdiplcontrol.H" + +#include "p9_hcd_core_stopclocks.H" +#include "p9_hcd_cache_stopclocks.H" +#include "p9_stopclocks.H" +#include "fapi2.H" + +using namespace fapi2; + +// Defines for stop clock +#define SBE_IS_EX0(chipletId) \ + (!(((chipletId - CORE_CHIPLET_OFFSET) & 0x0002) >> 1)) + +/* @brief Bitmapped enumeration to identify the stop clock HWP call + */ +enum stopClockHWPType +{ + SC_NONE = 0x00, + SC_PROC = 0x01, // Call p9_stopclocks + SC_CACHE = 0x02, // Call p9_hcd_cache_stopclocks + SC_CORE = 0x04, // Call p9_hcd_core_stopclocks +}; + +#ifdef __SBEFW_SEEPROM__ + +#ifdef SEEPROM_IMAGE + // Using function pointer to force long call. +p9_hcd_cache_stopclocks_FP_t p9_hcd_cache_stopclocks_hwp = &p9_hcd_cache_stopclocks; +p9_hcd_core_stopclocks_FP_t p9_hcd_core_stopclocks_hwp = &p9_hcd_core_stopclocks; +p9_stopclocks_FP_t p9_stopclocks_hwp = &p9_stopclocks; +#endif + + +/////////////////////////////////////////////////////////////////////// +// @brief sbeEnterMpipl Sbe enter MPIPL function +// +// @return RC from the underlying FIFO utility +/////////////////////////////////////////////////////////////////////// +uint32_t sbeEnterMpipl(uint8_t *i_pArg) +{ + #define SBE_FUNC " sbeEnterMpipl " + SBE_ENTER(SBE_FUNC); + uint32_t l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + uint32_t l_fapiRc = FAPI2_RC_SUCCESS; + uint32_t len = 0; + sbeRespGenHdr_t l_respHdr; + l_respHdr.init(); + sbeResponseFfdc_t l_ffdc; + + do + { + // Dequeue the EOT entry as no more data is expected. + l_rc = sbeUpFifoDeq_mult (len, NULL); + CHECK_SBE_RC_AND_BREAK_IF_NOT_SUCCESS(l_rc); + + uint32_t l_minor = 1; + do + { + l_fapiRc = sbeExecuteIstep(SBE_ISTEP_MPIPL_START, l_minor); + if(l_fapiRc != FAPI2_RC_SUCCESS) + { + SBE_ERROR(SBE_FUNC "Failed in Mpipl Start in ChipOp Mode " + "Minor: %d", l_minor); + l_respHdr.setStatus( SBE_PRI_GENERIC_EXECUTION_FAILURE, + SBE_SEC_GENERIC_FAILURE_IN_EXECUTION); + l_ffdc.setRc(l_fapiRc); + // reset attribute. We do not want to reset register, so do not + // use setMpIplMode + uint8_t isMpipl = 0; + PLAT_ATTR_INIT(ATTR_IS_MPIPL, Target<TARGET_TYPE_SYSTEM>(), + isMpipl); + break; + } + ++l_minor; + }while(l_minor<=MPIPL_START_MAX_SUBSTEPS); + + }while(0); + + // Create the Response to caller + do + { + // If there was a FIFO error, will skip sending the response, + // instead give the control back to the command processor thread + CHECK_SBE_RC_AND_BREAK_IF_NOT_SUCCESS(l_rc); + l_rc = sbeDsSendRespHdr( l_respHdr, &l_ffdc); + }while(0); + + SBE_EXIT(SBE_FUNC); + return l_rc; + #undef SBE_FUNC +} + +/////////////////////////////////////////////////////////////////////// +// @brief sbeContinueMpipl Sbe Continue MPIPL function +// +// @return RC from the underlying FIFO utility +/////////////////////////////////////////////////////////////////////// +uint32_t sbeContinueMpipl(uint8_t *i_pArg) +{ + #define SBE_FUNC " sbeContinueMpipl " + SBE_ENTER(SBE_FUNC); + uint32_t l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + uint32_t len = 0; + + ReturnCode l_fapiRc = FAPI2_RC_SUCCESS; + sbeResponseFfdc_t l_ffdc; + sbeRespGenHdr_t l_respHdr; + l_respHdr.init(); + + do + { + // Dequeue the EOT entry as no more data is expected. + l_rc = sbeUpFifoDeq_mult (len, NULL); + CHECK_SBE_RC_AND_BREAK_IF_NOT_SUCCESS(l_rc); + + sbeRole l_sbeRole = SbeRegAccess::theSbeRegAccess().isSbeSlave() ? + SBE_ROLE_SLAVE : SBE_ROLE_MASTER; + // Run isteps + const uint8_t isteps[][3] = { + // Major Num, Minor Start, Minor End + {SBE_ISTEP_MPIPL_CONTINUE, ISTEP_MINOR_START, MPIPL_CONTINUE_MAX_SUBSTEPS}, + {SBE_ISTEP4, ISTEP_MINOR_START, ISTEP4_MAX_SUBSTEPS}, + {SBE_ISTEP5, ISTEP_MINOR_START, ISTEP5_MAX_SUBSTEPS}}; + // Loop through isteps + for( auto istep : isteps) + { + // This is required here to skip the major istep 4/5 in slave + if((SBE_ROLE_SLAVE == l_sbeRole) && + (istep[0] == SBE_ISTEP4 || istep[0] == SBE_ISTEP5)) + { + (void)SbeRegAccess::theSbeRegAccess().stateTransition( + SBE_RUNTIME_EVENT); + continue; + } + for(uint8_t l_minor = istep[1]; l_minor <= istep[2]; l_minor++) + { + l_fapiRc = sbeExecuteIstep(istep[0], l_minor); + if(l_fapiRc != FAPI2_RC_SUCCESS) + { + SBE_ERROR(SBE_FUNC "Failed in Mpipl continue in ChipOp " + "Mode Major [%d] Minor [%d]", istep[0], l_minor); + l_respHdr.setStatus( SBE_PRI_GENERIC_EXECUTION_FAILURE, + SBE_SEC_GENERIC_FAILURE_IN_EXECUTION); + l_ffdc.setRc(l_fapiRc); + break; + } + } + if(l_ffdc.getRc() != FAPI2_RC_SUCCESS) + { + break; + } + } + }while(0); + + // reset attribute. We do not want to reset register, so do not + // use setMpIplMode + uint8_t isMpipl = 0; + PLAT_ATTR_INIT(ATTR_IS_MPIPL, Target<TARGET_TYPE_SYSTEM>(), isMpipl); + // Create the Response to caller + // If there was a FIFO error, will skip sending the response, + // instead give the control back to the command processor thread + if(SBE_SEC_OPERATION_SUCCESSFUL == l_rc) + { + l_rc = sbeDsSendRespHdr( l_respHdr, &l_ffdc); + } + SBE_EXIT(SBE_FUNC); + return l_rc; + #undef SBE_FUNC +} + +/////////////////////////////////////////////////////////////////////// +/* @brief Deduce the type of stop clock procedure to call based on + * target and chiplet id combination + * + * @param[in] i_targetType SBE chip-op target type + * @param[in] i_chipletId Chiplet id + * + * @return Bitmapped stopClockHWPType enum values + */ +/////////////////////////////////////////////////////////////////////// +static inline uint32_t getStopClockHWPType(uint32_t i_targetType, + uint32_t i_chipletId) +{ + uint32_t l_rc = SC_NONE; + TargetType l_fapiTarget = sbeGetFapiTargetType( + i_targetType, + i_chipletId); + if((l_fapiTarget == TARGET_TYPE_PROC_CHIP) || + (l_fapiTarget == TARGET_TYPE_PERV) || + ((i_targetType == TARGET_CORE) && (i_chipletId == SMT4_ALL_CORES))|| + ((i_targetType == TARGET_EQ) && (i_chipletId == EQ_ALL_CHIPLETS)) || + ((i_targetType == TARGET_EX) && (i_chipletId == EX_ALL_CHIPLETS))) + { + l_rc |= SC_PROC; + } + if((l_fapiTarget == TARGET_TYPE_CORE) || + (l_fapiTarget == TARGET_TYPE_EX)) + { + l_rc |= SC_CORE; + } + if((l_fapiTarget == TARGET_TYPE_EQ) || + (l_fapiTarget == TARGET_TYPE_EX)) + { + l_rc |= SC_CACHE; + } + return l_rc; +} + +/////////////////////////////////////////////////////////////////////// +/* @brief Prepare Stop clock flags base on Target Type + * + * @param[in] i_targetType SBE chip-op target Type + * + * @return p9_stopclocks_flags + */ +/////////////////////////////////////////////////////////////////////// +static inline p9_stopclocks_flags getStopClocksFlags(uint32_t i_targetType) +{ + p9_stopclocks_flags l_flags; + + if(i_targetType != TARGET_PROC_CHIP) + { + // Clear default flags - only in case the target is not PROC_CHIP + // Otherwise, for a PROC_CHIP target, we want to keep default flags + l_flags.clearAll(); + } + if(i_targetType == TARGET_PERV) + { + // Keep only tp as true + l_flags.stop_tp_clks = true; + } + else if(i_targetType == TARGET_CORE) + { + // Keep only core flag as true + l_flags.stop_core_clks = true; + } + else if(i_targetType == TARGET_EQ) + { + // Keep only cache flag as true + l_flags.stop_cache_clks = true; + } + else if(i_targetType == TARGET_EX) + { + // Keep only cache and core as true + l_flags.stop_cache_clks = true; + l_flags.stop_core_clks = true; + } + + return l_flags; +} + +/////////////////////////////////////////////////////////////////////// +// @brief sbeStopClocks Sbe Stop Clocks function +// +// @return RC from the underlying FIFO utility +/////////////////////////////////////////////////////////////////////// +uint32_t sbeStopClocks(uint8_t *i_pArg) +{ + #define SBE_FUNC " sbeStopClocks" + SBE_ENTER(SBE_FUNC); + uint32_t l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + uint32_t l_fapiRc = FAPI2_RC_SUCCESS; + uint32_t l_len = 0; + sbeResponseFfdc_t l_ffdc; + sbeRespGenHdr_t l_respHdr; + l_respHdr.init(); + sbeStopClocksReqMsgHdr_t l_reqMsg = {0}; + + do + { + // Get the TargetType and ChipletId from the command message + l_len = sizeof(sbeStopClocksReqMsgHdr_t)/sizeof(uint32_t); + l_rc = sbeUpFifoDeq_mult (l_len, (uint32_t *)&l_reqMsg); // EOT fetch + // If FIFO access failure + CHECK_SBE_RC_AND_BREAK_IF_NOT_SUCCESS(l_rc); + + SBE_INFO(SBE_FUNC "TargetType 0x%04X ChipletId 0x%02X", + (uint16_t)l_reqMsg.targetType, + (uint8_t)l_reqMsg.chipletId); + + fapi2::plat_target_handle_t l_tgtHndl; + // Keep these default values in sync with p9_stopclocks.H + p9hcd::P9_HCD_CLK_CTRL_CONSTANTS l_clk_regions + = p9hcd::CLK_REGION_ALL_BUT_PLL_REFR; + p9hcd::P9_HCD_EX_CTRL_CONSTANTS l_ex_select = p9hcd::BOTH_EX; + + // Get the type of stopclocks procedure to call + // based on target and chiplet id + uint32_t l_hwpType = getStopClockHWPType(l_reqMsg.targetType, + l_reqMsg.chipletId); + if(l_hwpType == SC_NONE) + { + // Error in target and chiplet id combination + SBE_ERROR(SBE_FUNC "Invalid TargetType[0x%04X] ChipletId[0x%02X]", + (uint32_t)l_reqMsg.targetType, + (uint32_t)l_reqMsg.chipletId); + l_respHdr.setStatus( SBE_PRI_INVALID_DATA, + SBE_SEC_INVALID_TARGET_TYPE_PASSED ); + break; + } + // All Core/All Cache/All Ex & Perv & Proc are handled here + if(l_hwpType & SC_PROC) + { + SBE_DEBUG(SBE_FUNC " Calling p9_stopclocks"); + p9_stopclocks_flags l_flags = getStopClocksFlags( + l_reqMsg.targetType); + if(l_reqMsg.targetType == TARGET_EX) + { + l_clk_regions = static_cast<p9hcd::P9_HCD_CLK_CTRL_CONSTANTS> + (p9hcd::CLK_REGION_EX0_REFR | + p9hcd::CLK_REGION_EX1_REFR); + } + l_flags.sync_stop_quad_clks = false; + SBE_EXEC_HWP(l_fapiRc, p9_stopclocks_hwp, + plat_getChipTarget(), + l_flags, + l_clk_regions, + l_ex_select); + } + // Specific CORE/EX + if(l_hwpType & SC_CORE) + { + SBE_DEBUG(SBE_FUNC " Calling p9_hcd_core_stopclocks"); + sbeGetFapiTargetHandle(l_reqMsg.targetType, + l_reqMsg.chipletId, + l_tgtHndl); + if(l_reqMsg.targetType == TARGET_EX) + { + Target<TARGET_TYPE_EX> l_exTgt(l_tgtHndl); + for(auto &l_childCore : + l_exTgt.getChildren<TARGET_TYPE_CORE>()) + { + SBE_EXEC_HWP(l_fapiRc, + p9_hcd_core_stopclocks_hwp, + l_childCore, + false); + } + } + else + { + SBE_EXEC_HWP(l_fapiRc, p9_hcd_core_stopclocks_hwp, l_tgtHndl, false); + } + } + // Specific EQ/EX + if(l_hwpType & SC_CACHE) + { + SBE_DEBUG(SBE_FUNC " Calling p9_hcd_cache_stopclocks"); + if(l_reqMsg.targetType == TARGET_EX) + { + // Modify l_clk_regions based on chiplet Id + l_clk_regions = SBE_IS_EX0(l_reqMsg.chipletId) ? + p9hcd::CLK_REGION_EX0_REFR : p9hcd::CLK_REGION_EX1_REFR; + // Modify l_ex_select based on chiplet ID + l_ex_select = SBE_IS_EX0(l_reqMsg.chipletId) ? + p9hcd::EVEN_EX : p9hcd::ODD_EX; + Target<TARGET_TYPE_EX> l_ex_target(l_tgtHndl); + l_tgtHndl = l_ex_target.getParent<TARGET_TYPE_EQ>(); + } + SBE_EXEC_HWP(l_fapiRc, p9_hcd_cache_stopclocks_hwp, + l_tgtHndl, + (p9hcd::P9_HCD_CLK_CTRL_CONSTANTS)l_clk_regions, + (p9hcd::P9_HCD_EX_CTRL_CONSTANTS)l_ex_select, + false); + } + + if( l_fapiRc != FAPI2_RC_SUCCESS ) + { + SBE_ERROR(SBE_FUNC" Stopclocks failed for TargetType [0x%04X] " + "ChipletId [0x%02X]", + (uint16_t)l_reqMsg.targetType, + (uint8_t)l_reqMsg.chipletId); + l_respHdr.setStatus( SBE_PRI_GENERIC_EXECUTION_FAILURE, + SBE_SEC_GENERIC_FAILURE_IN_EXECUTION); + l_ffdc.setRc(l_fapiRc); + break; + } + }while(0); + + // Create the Response to caller + // If there was a FIFO error, will skip sending the response, + // instead give the control back to the command processor thread + if(SBE_SEC_OPERATION_SUCCESSFUL == l_rc) + { + l_rc = sbeDsSendRespHdr( l_respHdr, &l_ffdc); + } + + SBE_EXIT(SBE_FUNC); + return l_rc; + #undef SBE_FUNC +} + +#endif //__SBEFW_SEEPROM__ diff --git a/src/sbefw/core/sbecmdmpipl.H b/src/sbefw/core/sbecmdmpipl.H new file mode 100644 index 00000000..0acb3efd --- /dev/null +++ b/src/sbefw/core/sbecmdmpipl.H @@ -0,0 +1,63 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbecmdmpipl.H $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* */ +/* */ +/* 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: ppe/src/sbefw/sbecmdmpipl.H + * + * @brief This file contains the Interfaces for MPIPL chip-ops + * + */ + +#ifndef __SBEFW_SBECMDMPIPL_H +#define __SBEFW_SBECMDMPIPL_H + +#include <stdint.h> + +/** + * @brief Handles Sbe Enter Mpipl chip-op (0xA901) + * + * @param[in] i_pArg Buffer to be passed to the function (not used as of now) + * + * @return Rc from the FIFO access utility + */ +uint32_t sbeEnterMpipl(uint8_t *i_pArg); + +/** + * @brief Handles Sbe Continue Mpipl chip-op (0xA902) + * + * @param[in] i_pArg Buffer to be passed to the function (not used as of now) + * + * @return Rc from the FIFO access utility + */ +uint32_t sbeContinueMpipl(uint8_t *i_pArg); + +/** + * @brief Handles Sbe Stop Clocks chip-op (0xA903) + * + * @param[in] i_pArg Buffer to be passed to the function (not used as of now) + * + * @return Rc from the FIFO access utility + */ +uint32_t sbeStopClocks(uint8_t *i_pArg); + +#endif /* __SBEFW_SBECMDMPIPL_H */ diff --git a/src/sbefw/core/sbecmdparser.C b/src/sbefw/core/sbecmdparser.C new file mode 100644 index 00000000..1671f8a3 --- /dev/null +++ b/src/sbefw/core/sbecmdparser.C @@ -0,0 +1,603 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbecmdparser.C $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2017 */ +/* */ +/* */ +/* 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: ppe/sbe/sbefw/sbecmdparser.C + * + * @brief This file contains the SBE FIFO Commands + * + */ + +#include "sbecmdparser.H" +#include "sbecmdscomaccess.H" +#include "sbecmdiplcontrol.H" +#include "sbecmdgeneric.H" +#include "sbecmdmemaccess.H" +#include "sbecmdregaccess.H" +#include "sbecmdcntrldmt.H" +#include "sbecmdringaccess.H" +#include "sbecmdsram.H" +#include "sbecmdcntlinst.H" +#include "sbecmdringaccess.H" +#include "sbetrace.H" +#include "sbe_sp_intf.H" +#include "sbeHostMsg.H" +#include "sbe_host_intf.H" +#include "sbestates.H" +#include "sberegaccess.H" +#include "sbecmdmpipl.H" +#include "sbecmdtracearray.H" +#include "sbecmdCntrlTimer.H" +#include "sbecmdfastarray.H" +#include "sbeglobals.H" + +// Declaration +static const uint16_t HARDWARE_FENCED_STATE = + SBE_FENCE_AT_CONTINUOUS_IPL|SBE_FENCE_AT_DMT; + +static const uint16_t PUT_HARDWARE_FENCED_STATE = + HARDWARE_FENCED_STATE|SBE_FENCE_AT_MPIPL; + +//////////////////////////////////////////////////////////////// +// @brief g_sbeScomCmdArray +//////////////////////////////////////////////////////////////// +static sbeCmdStruct_t g_sbeScomCmdArray [] = +{ + {sbeGetScom, + SBE_CMD_GETSCOM, + HARDWARE_FENCED_STATE, + }, + {sbePutScom, + SBE_CMD_PUTSCOM, + HARDWARE_FENCED_STATE, + }, + {sbeModifyScom, + SBE_CMD_MODIFYSCOM, + HARDWARE_FENCED_STATE, + }, + {sbePutScomUnderMask, + SBE_CMD_PUTSCOM_MASK, + HARDWARE_FENCED_STATE, + }, + {sbeMultiScom, + SBE_CMD_MULTISCOM, + HARDWARE_FENCED_STATE, + }, +}; + +//////////////////////////////////////////////////////////////// +// @brief g_sbeIplControlCmdArray +// +//////////////////////////////////////////////////////////////// +static sbeCmdStruct_t g_sbeIplControlCmdArray [] = +{ + {sbeHandleIstep, + SBE_CMD_EXECUTE_ISTEP, + HARDWARE_FENCED_STATE|SBE_FENCE_AT_DUMPING, + }, + {sbeHandleSuspendIO, + SBE_CMD_SUSPEND_IO, + SBE_FENCE_AT_DUMPING, + }, +}; + +//////////////////////////////////////////////////////////////// +// @brief g_sbeGenericCmdArray +// +//////////////////////////////////////////////////////////////// +static sbeCmdStruct_t g_sbeGenericCmdArray [] = +{ + {sbeGetCapabilities, + SBE_CMD_GET_SBE_CAPABILITIES, + SBE_NO_FENCE, + }, + + {sbeGetFfdc, + SBE_CMD_GET_SBE_FFDC, + SBE_NO_FENCE, + }, + + {sbeFifoQuiesce, + SBE_CMD_QUIESCE, + SBE_NO_FENCE, + }, +}; + +////////////////////////////////////////////////////////////// +// @brief g_sbeMemoryAccessCmdArray +// +////////////////////////////////////////////////////////////// +static sbeCmdStruct_t g_sbeMemoryAccessCmdArray [] = +{ + {sbeGetMem, + SBE_CMD_GETMEM, + SBE_FENCE_AT_CONTINUOUS_IPL, + }, + + {sbePutMem, + SBE_CMD_PUTMEM, + PUT_HARDWARE_FENCED_STATE, + }, + + {sbeGetOccSram, + SBE_CMD_GETSRAM_OCC, + HARDWARE_FENCED_STATE, + }, + + {sbePutOccSram, + SBE_CMD_PUTSRAM_OCC, + PUT_HARDWARE_FENCED_STATE, + }, +}; + +////////////////////////////////////////////////////////////// +// @brief g_sbeInstructionCntlCmdArray +// +////////////////////////////////////////////////////////////// +static sbeCmdStruct_t g_sbeInstructionCntlCmdArray[] = +{ + {sbeCntlInst, + SBE_CMD_CONTROL_INSTRUCTIONS, + HARDWARE_FENCED_STATE, + }, +}; + +////////////////////////////////////////////////////////////// +// @brief g_sbeRegAccessCmdArray +// +////////////////////////////////////////////////////////////// +static sbeCmdStruct_t g_sbeRegAccessCmdArray [] = +{ + {sbeGetReg, + SBE_CMD_GETREG, + HARDWARE_FENCED_STATE, + }, + + {sbePutReg, + SBE_CMD_PUTREG, + PUT_HARDWARE_FENCED_STATE | SBE_FENCE_AT_SECURE_MODE, + }, +}; + +////////////////////////////////////////////////////////////// +// @brief g_sbeMpiplCmdArray +// +////////////////////////////////////////////////////////////// +static sbeCmdStruct_t g_sbeMpiplCmdArray[] = +{ + {sbeEnterMpipl, + SBE_CMD_MPIPL_ENTER, + PUT_HARDWARE_FENCED_STATE|SBE_FENCE_AT_ISTEP| + SBE_FENCE_AT_DUMPING, + // Allow Fspless system to enter MPIPL + // Issue 157287 + }, + + {sbeContinueMpipl, + SBE_CMD_MPIPL_CONTINUE, + HARDWARE_FENCED_STATE|SBE_FENCE_AT_ISTEP| + SBE_FENCE_AT_RUNTIME|SBE_FENCE_AT_DUMPING, + // Only allowed State is MPIPL + }, + + {sbeStopClocks, + SBE_CMD_MPIPL_STOPCLOCKS, + HARDWARE_FENCED_STATE|SBE_FENCE_AT_DUMPING, + }, +}; + +////////////////////////////////////////////////////////////// +// @brief g_sbeRingAccessCmdArray +// +////////////////////////////////////////////////////////////// +static sbeCmdStruct_t g_sbeRingAccessCmdArray [] = +{ + {sbeGetRing, + SBE_CMD_GETRING, + SBE_FENCE_AT_CONTINUOUS_IPL|SBE_FENCE_AT_QUIESCE, + }, + + {sbePutRing, + SBE_CMD_PUTRING, + HARDWARE_FENCED_STATE|SBE_FENCE_AT_QUIESCE, + }, +}; + +// @brief g_sbeArrayAccessCmdArray[] +// +//////////////////////////////////////////////////////////////// +static sbeCmdStruct_t g_sbeArrayAccessCmdArray[] = +{ + {sbeControlFastArray, + SBE_CMD_CONTROL_FAST_ARRAY, + SBE_FENCE_AT_QUIESCE, + }, + {sbeControlTraceArray, + SBE_CMD_CONTROL_TRACE_ARRAY, + SBE_FENCE_AT_QUIESCE, + }, +}; + +////////////////////////////////////////////////////////////// +// @brief g_sbeCoreStateControlCmdArray +// +////////////////////////////////////////////////////////////// +static sbeCmdStruct_t g_sbeCoreStateControlCmdArray [] = +{ + {sbeControlDeadmanTimer, + SBE_PSU_CMD_CONTROL_DEADMAN, + SBE_FENCE_AT_CONTINUOUS_IPL|SBE_FENCE_AT_QUIESCE| + SBE_FENCE_AT_MPIPL|SBE_FENCE_AT_ISTEP| + SBE_FENCE_AT_DUMPING, + }, +}; + +////////////////////////////////////////////////////////////// +// @brief g_sbeControlTimerCmdArray +// +////////////////////////////////////////////////////////////// +static sbeCmdStruct_t g_sbeControlTimerCmdArray [] = +{ + {sbeCntrlTimer, + SBE_PSU_CMD_CONTROL_TIMER, + SBE_FENCE_AT_CONTINUOUS_IPL|SBE_FENCE_AT_QUIESCE| + SBE_FENCE_AT_MPIPL|SBE_FENCE_AT_DUMPING, + }, +}; + +////////////////////////////////////////////////////////////// +// @brief g_sbePutRingFromImageCmdArray +// +////////////////////////////////////////////////////////////// +static sbeCmdStruct_t g_sbePutRingFromImageCmdArray [] = +{ + {sbePutRingFromImagePSU, + SBE_PSU_MSG_PUT_RING_FROM_IMAGE, + PUT_HARDWARE_FENCED_STATE|SBE_FENCE_AT_QUIESCE, + }, +}; +// +////////////////////////////////////////////////////////////// +// @brief g_sbePsuGenericCmdArray +// +////////////////////////////////////////////////////////////// +static sbeCmdStruct_t g_sbePsuMemRegionCmdArray[] = +{ + {sbeUpdateMemAccessRegion, + SBE_PSU_MSG_UPDATE_MEM_REGION, + SBE_FENCE_AT_QUIESCE, + }, +}; + +////////////////////////////////////////////////////////////// +// @brief g_sbePsuGenericCmdArray +// +////////////////////////////////////////////////////////////// +static sbeCmdStruct_t g_sbePsuGenericCmdArray[] = +{ + {sbeReadMem, + SBE_PSU_GENERIC_MSG_READ_SBE_MEM, + SBE_NO_FENCE, + }, + + {sbeSetFFDCAddr, + SBE_PSU_GENERIC_MSG_SET_FFDC_ADDR, + SBE_NO_FENCE, + }, + + {sbePsuQuiesce, + SBE_PSU_GENERIC_MSG_QUIESCE, + SBE_NO_FENCE, + }, + + {sbeSetSystemFabricMap, + SBE_PSU_GENERIC_MSG_SYSTEM_FABRIC_MAP, + SBE_NO_FENCE, + }, + + {sbeStashKeyAddrPair, + SBE_PSU_GENERIC_MSG_STASH_MPIPL_CONFIG, + SBE_NO_FENCE, + }, +}; + +//////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////// +uint8_t sbeGetCmdStructAttr (const uint8_t i_cmdClass, + sbeCmdStruct_t **o_ppCmd) +{ + #define SBE_FUNC " sbeGetCmdStructAttr " + uint8_t l_numCmds = 0; + *o_ppCmd = NULL; + + switch(i_cmdClass) + { + // FIFO Commands + case SBE_CMD_CLASS_IPL_CONTROL: + // @TODO via RTC : 128655 + // Use C++ style typecase + l_numCmds = sizeof(g_sbeIplControlCmdArray) / + sizeof(sbeCmdStruct_t); + *o_ppCmd = (sbeCmdStruct_t*)g_sbeIplControlCmdArray; + break; + case SBE_CMD_CLASS_SCOM_ACCESS: + l_numCmds = sizeof(g_sbeScomCmdArray) / + sizeof(sbeCmdStruct_t); + *o_ppCmd = (sbeCmdStruct_t*)g_sbeScomCmdArray; + break; + case SBE_CMD_CLASS_GENERIC_MESSAGE: + l_numCmds = sizeof(g_sbeGenericCmdArray) / + sizeof(sbeCmdStruct_t); + *o_ppCmd = (sbeCmdStruct_t*)g_sbeGenericCmdArray; + break; + + case SBE_CMD_CLASS_MEMORY_ACCESS: + l_numCmds = sizeof(g_sbeMemoryAccessCmdArray) / + sizeof(sbeCmdStruct_t); + *o_ppCmd = (sbeCmdStruct_t*)g_sbeMemoryAccessCmdArray; + break; + + case SBE_CMD_CLASS_INSTRUCTION_CONTROL: + l_numCmds = sizeof(g_sbeInstructionCntlCmdArray) / + sizeof(sbeCmdStruct_t); + *o_ppCmd = (sbeCmdStruct_t*)g_sbeInstructionCntlCmdArray; + break; + + case SBE_CMD_CLASS_REGISTER_ACCESS: + l_numCmds = sizeof(g_sbeRegAccessCmdArray) / + sizeof(sbeCmdStruct_t); + *o_ppCmd = (sbeCmdStruct_t*)g_sbeRegAccessCmdArray; + break; + + case SBE_CMD_CLASS_RING_ACCESS: + l_numCmds = sizeof(g_sbeRingAccessCmdArray) / + sizeof(sbeCmdStruct_t); + *o_ppCmd = (sbeCmdStruct_t*)g_sbeRingAccessCmdArray; + break; + + case SBE_CMD_CLASS_MPIPL_COMMANDS: + l_numCmds = sizeof(g_sbeMpiplCmdArray) / + sizeof(sbeCmdStruct_t); + *o_ppCmd = (sbeCmdStruct_t*)g_sbeMpiplCmdArray; + break; + + case SBE_CMD_CLASS_ARRAY_ACCESS: + l_numCmds = sizeof(g_sbeArrayAccessCmdArray) / + sizeof(sbeCmdStruct_t); + *o_ppCmd = (sbeCmdStruct_t*)g_sbeArrayAccessCmdArray; + break; + + // PSU Commands + case SBE_PSU_CMD_CLASS_CORE_STATE: + l_numCmds = sizeof(g_sbeCoreStateControlCmdArray) / + sizeof(sbeCmdStruct_t); + *o_ppCmd = (sbeCmdStruct_t*)g_sbeCoreStateControlCmdArray; + break; + + case SBE_PSU_CMD_CLASS_RING_ACCESS: + l_numCmds = sizeof(g_sbePutRingFromImageCmdArray) / + sizeof(sbeCmdStruct_t); + *o_ppCmd = (sbeCmdStruct_t*)g_sbePutRingFromImageCmdArray; + break; + + case SBE_PSU_CMD_CLASS_GENERIC: + l_numCmds = sizeof(g_sbePsuGenericCmdArray) / + sizeof(sbeCmdStruct_t); + *o_ppCmd = (sbeCmdStruct_t*)g_sbePsuGenericCmdArray; + break; + + case SBE_PSU_CMD_CLASS_SECURITY_CONTROL_MSG: + l_numCmds = sizeof(g_sbePsuMemRegionCmdArray) / + sizeof(sbeCmdStruct_t); + *o_ppCmd = (sbeCmdStruct_t*)g_sbePsuMemRegionCmdArray; + break; + + case SBE_PSU_CMD_CLASS_CNTRL_TIMER: + l_numCmds = sizeof(g_sbeControlTimerCmdArray) / + sizeof(sbeCmdStruct_t); + *o_ppCmd = (sbeCmdStruct_t*)g_sbeControlTimerCmdArray; + break; + + + // This will grow with each class of chipOp in future + default: + break; + } + return l_numCmds; + #undef SBE_FUNC +} + + +//////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////// +uint8_t sbeValidateCmdClass (const uint8_t i_cmdClass, + const uint8_t i_cmdOpcode) +{ + #define SBE_FUNC " sbeValidateCmdClass " + uint8_t l_rc = SBE_SEC_COMMAND_NOT_SUPPORTED; + + SBE_INFO(SBE_FUNC"i_cmdClass[0x%02X], " + "i_cmdOpcode[0x%02X]", i_cmdClass, i_cmdOpcode); + + do + { + uint8_t l_numCmds = 0; + sbeCmdStruct_t *l_pCmd = NULL; + + l_numCmds = sbeGetCmdStructAttr (i_cmdClass, &l_pCmd); + if (!l_numCmds) + { + SBE_ERROR(SBE_FUNC"SBE_SEC_COMMAND_CLASS_NOT_SUPPORTED " + "i_cmdClass[0x%02X], i_cmdOpcode[0x%02X]", + i_cmdClass, i_cmdOpcode); + // Command class not supported + l_rc = SBE_SEC_COMMAND_CLASS_NOT_SUPPORTED; + break; + } + + // @TODO via RTC : 128654 + // Analyze on merging the validation functions into one + // and also on using loop vs switch case performance + for (uint8_t l_cnt = 0; l_cnt < l_numCmds; ++l_cnt, ++l_pCmd) + { + if (i_cmdOpcode == l_pCmd->cmd_opcode) + { + // Command found + l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + break; + } + } + } while (false); + + return l_rc; + #undef SBE_FUNC +} + +//////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////// +sbeChipOpRc_t sbeIsCmdAllowed (const uint8_t i_cmdClass, + const uint8_t i_cmdOpcode) +{ + #define SBE_FUNC " sbeIsCmdAllowedAtState " + bool l_ret = true; + sbeChipOpRc_t retRc; + uint8_t l_numCmds = 0; + sbeCmdStruct_t *l_pCmd = NULL; + l_numCmds = sbeGetCmdStructAttr (i_cmdClass, &l_pCmd); + + for (uint8_t l_cnt = 0; l_cnt < l_numCmds; ++l_cnt, ++l_pCmd) + { + if (i_cmdOpcode == l_pCmd->cmd_opcode) + { + // Get the Present State + uint64_t l_state = + SbeRegAccess::theSbeRegAccess().getSbeState(); + SBE_INFO(SBE_FUNC "SBE State [0x%08X] Fence State[0x%04X]", + (uint32_t)(l_state & 0xFFFFFFFF),l_pCmd->cmd_state_fence); + + switch(l_state) + { + case SBE_STATE_UNKNOWN: + case SBE_STATE_FAILURE: + // All operations are fenced here, return false + // Reset is the only Option available + break; + + case SBE_STATE_IPLING: + { + l_ret = ((l_pCmd->cmd_state_fence & + SBE_FENCE_AT_CONTINUOUS_IPL)? false:true); + break; + } + + case SBE_STATE_ISTEP: + { + l_ret = ((l_pCmd->cmd_state_fence & + SBE_FENCE_AT_ISTEP)? false:true); + break; + } + + case SBE_STATE_RUNTIME: + { + l_ret = ((l_pCmd->cmd_state_fence & + SBE_FENCE_AT_RUNTIME)? false:true); + break; + } + + case SBE_STATE_DUMP: + { + l_ret = ((l_pCmd->cmd_state_fence & + SBE_FENCE_AT_DUMPING)? false:true); + break; + } + + case SBE_STATE_MPIPL: + { + l_ret = ((l_pCmd->cmd_state_fence & + SBE_FENCE_AT_MPIPL)? false:true); + break; + } + + case SBE_STATE_DMT: + { + l_ret = ((l_pCmd->cmd_state_fence & + SBE_FENCE_AT_DMT)? false:true); + break; + } + + case SBE_STATE_QUIESCE: + { + l_ret = ((l_pCmd->cmd_state_fence & + SBE_FENCE_AT_QUIESCE)? false:true); + break; + } + + default: + l_ret = false; + break; + } + + if(false == l_ret) + { + retRc.primStatus = SBE_PRI_INVALID_COMMAND; + retRc.secStatus = SBE_SEC_COMMAND_NOT_ALLOWED_IN_THIS_STATE; + break; + } + // Check if the command is allowed in current security mode + if((SBE_GLOBAL->sbeFWSecurityEnabled) + && (SBE_FENCE_AT_SECURE_MODE & l_pCmd->cmd_state_fence)) + { + retRc.primStatus = SBE_PRI_UNSECURE_ACCESS_DENIED; + retRc.secStatus = SBE_SEC_BLACKLISTED_CHIPOP_ACCESS; + break; + } + break; + } + } + return retRc; + #undef SBE_FUNC +} + +//////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////// +sbeCmdFunc_t sbeFindCmdFunc (const uint8_t i_cmdClass, + const uint8_t i_cmdOpcode) + +{ + #define SBE_FUNC " sbeFindCmdFunc " + uint8_t l_numCmds = 0; + sbeCmdStruct_t *l_pCmd = NULL; + + l_numCmds = sbeGetCmdStructAttr (i_cmdClass, &l_pCmd); + + for (uint8_t l_cnt = 0; l_cnt < l_numCmds; ++l_cnt, ++l_pCmd) + { + if (i_cmdOpcode == l_pCmd->cmd_opcode) + { + break; + } + } + + return l_pCmd ? (l_pCmd->cmd_func) : NULL; + #undef SBE_FUNC +} diff --git a/src/sbefw/core/sbecmdparser.H b/src/sbefw/core/sbecmdparser.H new file mode 100644 index 00000000..3d90c007 --- /dev/null +++ b/src/sbefw/core/sbecmdparser.H @@ -0,0 +1,135 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbecmdparser.H $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2017 */ +/* */ +/* */ +/* 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: ppe/sbe/sbefw/sbecmdparser.H + * + * @brief This file contains the SBE command details + * + */ + +#ifndef __SBEFW_SBECMDPARSER_H +#define __SBEFW_SBECMDPARSER_H + +#include <stdint.h> +#include "sbe_sp_intf.H" + +// Chip-op response codes +typedef struct sbeChipOpRc +{ + sbePrimResponse primStatus; + sbeSecondaryResponse secStatus; + + sbeChipOpRc():primStatus(SBE_PRI_OPERATION_SUCCESSFUL), + secStatus(SBE_SEC_OPERATION_SUCCESSFUL) + {} + + bool success() + { + return (primStatus == SBE_PRI_OPERATION_SUCCESSFUL) && + (secStatus == SBE_SEC_OPERATION_SUCCESSFUL); + } +} sbeChipOpRc_t; + +/** + * @brief SBE Command structure associating an opcode of a command + * to the processing function as well as the allowed states + * + */ +typedef uint32_t (*sbeChipOpFunc_t) (uint8_t *i_pArg); + +typedef struct sbeCmdStruct { + sbeChipOpFunc_t cmd_func; /* Command function pointer */ + uint8_t cmd_opcode; /* Command opcode */ + uint16_t cmd_state_fence; /* Command fencing based on SBE state */ +} sbeCmdStruct_t; + +/** + * @brief SBE Command Fence attributes + * + */ +enum sbe_command_fence_attrs +{ + SBE_NO_FENCE = 0x0000, ///< Allow cmd in all states + SBE_FENCE_AT_DUMPING = 0x0001, ///< Fence off at DUMPING State + SBE_FENCE_AT_MPIPL = 0x0002, ///< Fence off at MPIPL state + SBE_FENCE_AT_CONTINUOUS_IPL = 0x0004, ///< Fence off at cont IPL + SBE_FENCE_AT_ISTEP = 0x0008, ///< Fence off at istep state + SBE_FENCE_AT_RUNTIME = 0x0010, ///< Fence off at Runtime state + SBE_FENCE_AT_QUIESCE = 0x0020, ///< Fense off at Quiesce state + SBE_FENCE_AT_DMT = 0x0040, ///< Fense off at DMT state + SBE_FENCE_AT_SECURE_MODE = 0x0080, ///< Fense off in secure mode +}; + +/** + * @brief sbeValidateCmdClass Validates the command class and opcode + * + * @param[in] i_cmdClass Command class code + * @param[in] i_cmdOpcode Command opcode + * + * @return uint8_t return code + * SBE_SEC_OPERATION_SUCCESSFUL - Command found + * SBE_SEC_COMMAND_CLASS_NOT_SUPPORTED + * SBE_SEC_COMMAND_NOT_SUPPORTED + */ +uint8_t sbeValidateCmdClass (const uint8_t i_cmdClass, + const uint8_t i_cmdOpcode); + +/** + * @brief sbeIsCmdAllowed Validates if the command is allowed + * at the current SBE state + * + * @param[in] i_cmdClass Command class code + * @param[in] i_cmdOpcode Command opcode + * + * @return sbeChipOpRc_t Indicating primary and secondary status of + * chip-op + */ +sbeChipOpRc_t sbeIsCmdAllowed (const uint8_t i_cmdClass, + const uint8_t i_cmdOpcode); + + +/** + * @brief sbeCmdFunc_t Typical signature for any SBE ChipOp back-end function + * + * @param[in] uint8_t *i_pArg Pointer to the argument to be passed to + * the chipOp function + * + * @return uint32_t Return code from the chipOp function + */ +typedef uint32_t ( *sbeCmdFunc_t ) (uint8_t *i_pArg); + + +/** + * @brief sbeFindCmdFunc Finds the function corresponding to the command + * + * @param[in] i_cmdClass Command class code + * @param[in] i_cmdOpcode Command opcode + * + * @return sbeCmdFunc_t A pointer to the corresponding ChipOps function + */ +sbeCmdFunc_t sbeFindCmdFunc (const uint8_t i_cmdClass, + const uint8_t i_cmdOpcode); + + +#endif // __SBEFW_SBECMDPARSER_H diff --git a/src/sbefw/core/sbecmdprocessor.C b/src/sbefw/core/sbecmdprocessor.C new file mode 100644 index 00000000..aacf892a --- /dev/null +++ b/src/sbefw/core/sbecmdprocessor.C @@ -0,0 +1,397 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbecmdprocessor.C $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2017 */ +/* */ +/* */ +/* 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: ppe/sbe/sbefw/sbecmdprocessor.C + * + * @brief This file contains the SBE Command processing Thread Routines + * + */ + + +#include "sbeexeintf.H" +#include "sbefifo.H" +#include "sbecmdparser.H" +#include "sbeirq.H" +#include "sbetrace.H" +#include "sbe_sp_intf.H" +#include "assert.h" +#include "sbeFifoMsgUtils.H" +#include "sbeerrorcodes.H" +#include "sbeHostUtils.H" +#include "sbeHostMsg.H" +#include "sbecmdiplcontrol.H" +#include "sberegaccess.H" +#include "sbestates.H" +#include "fapi2.H" +#include "sbeutil.H" +#include "sbeglobals.H" +using namespace fapi2; + +// Forward declaration for performAttrSetup +ReturnCode performAttrSetup( ); + +///////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////// +void sbeHandlePsuResponse (const uint32_t i_rc) +{ + #define SBE_FUNC " sbeHandlePsuResponse " + uint32_t l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + + do + { + uint8_t l_cnt = 0; + switch (i_rc) + { + case SBE_SEC_COMMAND_CLASS_NOT_SUPPORTED: + case SBE_SEC_COMMAND_NOT_SUPPORTED: + case SBE_SEC_COMMAND_NOT_ALLOWED_IN_THIS_STATE: + case SBE_SEC_BLACKLISTED_CHIPOP_ACCESS: + // Caller sent an invalid Command class/opcode + // Set the Ack bit in SBE->PSU DB register + l_rc = sbeAcknowledgeHost(); + if (SBE_SEC_OPERATION_SUCCESSFUL != l_rc) + { + break; + } + // Set primary and secondary status + SBE_GLOBAL->sbeSbe2PsuRespHdr.setStatus(SBE_PRI_INVALID_COMMAND, i_rc); + + // Now Update SBE->PSU Mbx Reg4 with response + l_cnt = sizeof(SBE_GLOBAL->sbeSbe2PsuRespHdr)/ + sizeof(uint64_t); + l_rc = sbeWriteSbe2PsuMbxReg(SBE_HOST_PSU_MBOX_REG4, + reinterpret_cast<const uint64_t *>( + &SBE_GLOBAL->sbeSbe2PsuRespHdr), l_cnt, true); + break; + + case SBE_SEC_OS_FAILURE: + // Set primary and secondary status + SBE_GLOBAL->sbeSbe2PsuRespHdr.setStatus(SBE_PRI_GENERIC_EXECUTION_FAILURE, + i_rc); + + // Now Update SBE->PSU Mbx Reg4 with response + l_cnt = sizeof(SBE_GLOBAL->sbeSbe2PsuRespHdr)/ + sizeof(uint64_t); + l_rc = sbeWriteSbe2PsuMbxReg(SBE_HOST_PSU_MBOX_REG4, + reinterpret_cast<const uint64_t *>( + &SBE_GLOBAL->sbeSbe2PsuRespHdr), l_cnt, true); + break; + + case SBE_SEC_OPERATION_SUCCESSFUL: + // Services code successfully executed the chipOp. + SBE_INFO(SBE_FUNC"PSU ChipOp Done"); + break; + + default: + // The only possibility (as of now) to reach till this point + // is when there was a mbx register access (scom) failure + // happened. Going to return to the waiting loop. + break; + } + } while(false); + + #undef SBE_FUNC +} + + +///////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////// +void sbeHandleFifoResponse (const uint32_t i_rc) +{ + #define SBE_FUNC " sbeHandleFifoResponse " + SBE_ENTER(SBE_FUNC); + + do + { + uint16_t l_primStatus = SBE_PRI_OPERATION_SUCCESSFUL; + uint32_t l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + + // Handle FIFO reset case + if (i_rc == SBE_FIFO_RESET_RECEIVED) + { + break; + } + + if ( (i_rc == SBE_SEC_UNEXPECTED_EOT_INSUFFICIENT_DATA) || + (i_rc == SBE_SEC_UNEXPECTED_EOT_EXCESS_DATA) ) + { + l_primStatus = SBE_PRI_INVALID_DATA; + } + + uint32_t l_len2dequeue = 0; + sbeRespGenHdr_t l_hdr; + l_hdr.init(); + uint32_t l_secStatus = i_rc; + + switch (i_rc) + { + case SBE_SEC_COMMAND_CLASS_NOT_SUPPORTED: + case SBE_SEC_COMMAND_NOT_SUPPORTED: + case SBE_SEC_COMMAND_NOT_ALLOWED_IN_THIS_STATE: + case SBE_SEC_BLACKLISTED_CHIPOP_ACCESS: + // Caller sent Invalid Command + + case SBE_SEC_OS_FAILURE: + // PK API Failures + + // Flush out the upstream FIFO till EOT arrives + l_len2dequeue = 1; + l_rc = sbeUpFifoDeq_mult (l_len2dequeue, NULL, + true, true); + + if ( (l_rc == SBE_FIFO_RESET_RECEIVED) || + (l_rc == SBE_SEC_FIFO_ACCESS_FAILURE) ) + { + break; + } + + if (l_rc) + { + l_secStatus = l_rc; + } + + // Don't break here to force the flow through + // the next case to enqueue the response into + // the downstream FIFO + + case SBE_SEC_UNEXPECTED_EOT_INSUFFICIENT_DATA: + case SBE_SEC_UNEXPECTED_EOT_EXCESS_DATA: + // EOT arrived prematurely in upstream FIFO + // or there were unexpected data in upstream FIFO + + SBE_ERROR(SBE_FUNC"Operation failure, " + "l_primStatus[0x%08X], " + "l_secStatus[0x%08X]", + l_primStatus, l_secStatus); + l_hdr.setStatus(l_primStatus, l_secStatus); + + l_rc = sbeDsSendRespHdr(l_hdr); + if (l_rc) + { + SBE_ERROR(SBE_FUNC"sbeDownFifoEnq_mult failure," + " l_rc[0x0%08X]", l_rc); + // not attempting to signal EOT + break; + } + // Follow through to signal EOT in downstream + + case SBE_SEC_OPERATION_SUCCESSFUL: // Successful execution + // Signal EOT in Downstream FIFO + l_rc = sbeDownFifoSignalEot(); + if (l_rc) + { + SBE_ERROR(SBE_FUNC"sbeDownFifoSignalEot failure," + " l_rc[0x0%08X]", l_rc); + } + SBE_INFO(SBE_FUNC"ChipOp Done"); + break; + + default: + break; + } + } while (false); + + #undef SBE_FUNC +} + +ReturnCode sbeDestRuntimeSetup() +{ + #define SBE_FUNC " sbeDestRuntimeSetup " + SBE_ENTER( SBE_FUNC ); + ReturnCode rc = FAPI2_RC_SUCCESS; + do + { + rc = performAttrSetup(); + if( rc != FAPI2_RC_SUCCESS ) + { + SBE_ERROR(SBE_FUNC"performAttrSetup failed"); + break; + } + SBE::updatePkFreq(); + }while(0); + SBE_EXIT("SBE_FUNC"); + return rc; + #undef SBE_FUNC +} + + +////////////////////////////////////////////////////// +////////////////////////////////////////////////////// +void sbeSyncCommandProcessor_routine(void *i_pArg) +{ + #define SBE_FUNC " sbeSyncCommandProcessor_routine " + SBE_ENTER(SBE_FUNC); + + // Update SBE msgg reg to indicate that control loop + // is ready now to receive data on its interfaces + (void)SbeRegAccess::theSbeRegAccess().setSbeReady(); + + // Check the destination bit at the start + if(true == SbeRegAccess::theSbeRegAccess().isDestBitRuntime()) + { + SBE_INFO(SBE_FUNC"Destination bit tells us to go to runtime"); + (void)SbeRegAccess::theSbeRegAccess(). + updateSbeState(SBE_STATE_RUNTIME); + // Do the runtime setup + ReturnCode rc = sbeDestRuntimeSetup(); + if( rc != FAPI2_RC_SUCCESS ) + { + SBE_ERROR(SBE_FUNC"sbeDestRuntimeSetup failed"); + pk_halt(); + } + } + else if(SbeRegAccess::theSbeRegAccess().isIstepMode()) + { + SBE_INFO(SBE_FUNC"Continuous IPL mode not set, will wait for " + "commands..."); + (void)SbeRegAccess::theSbeRegAccess(). + updateSbeState(SBE_STATE_ISTEP); + } + else + { + SBE_INFO(SBE_FUNC"Continuous IPL Mode set... IPLing"); + (void)SbeRegAccess::theSbeRegAccess(). + updateSbeState(SBE_STATE_IPLING); + sbeDoContinuousIpl(); + } + + do + { + uint32_t l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + + // Wait for new command processing + int l_rcPk = pk_semaphore_pend ( + &SBE_GLOBAL->sbeSemCmdProcess, PK_WAIT_FOREVER); + + do + { + // Local Variables + uint8_t l_cmdClass = 0; + uint8_t l_cmdOpCode = 0; + + // Reset the value of fapi2::current_err from previous value. + // This is required as none of procedure set this value in success + // case. So if we do not reset previous value, previous failure + // will impact new chipops also. + fapi2::current_err = fapi2::FAPI2_RC_SUCCESS; + + // Check on the Rx Thread Interrupt Bits for Interrupt Status + if ( SBE_GLOBAL->sbeIntrSource.isSet(SBE_RX_ROUTINE, + SBE_INTERFACE_PSU) ) + { + l_rc = SBE_GLOBAL->sbeSbe2PsuRespHdr.secStatus; + l_cmdClass = SBE_GLOBAL->sbePsu2SbeCmdReqHdr.cmdClass; + l_cmdOpCode = SBE_GLOBAL->sbePsu2SbeCmdReqHdr.command; + // Set this here, so that during response handling we know which + // interrupt we are processing, need not check for + // SBE_GLOBAL->sbeIntrSource again + SBE_GLOBAL->sbeIntrSource.setIntrSource(SBE_PROC_ROUTINE, + SBE_INTERFACE_PSU); + } + else if ( SBE_GLOBAL->sbeIntrSource.isSet(SBE_RX_ROUTINE, + SBE_INTERFACE_FIFO) ) + { + l_rc = SBE_GLOBAL->sbeCmdRespHdr.sec_status; + l_cmdClass = SBE_GLOBAL->sbeFifoCmdHdr.cmdClass; + l_cmdOpCode = SBE_GLOBAL->sbeFifoCmdHdr.command; + SBE_INFO(SBE_FUNC"Processing command from client :0x%01X", + (uint32_t)(SBE_GLOBAL->sbeFifoCmdHdr.clientId)); + // Set this here, so that during response handling we know which + // interrupt we are processing, need not check for + // SBE_GLOBAL->sbeIntrSource again + SBE_GLOBAL->sbeIntrSource.setIntrSource(SBE_PROC_ROUTINE, + SBE_INTERFACE_FIFO); + } + else // SBE_INTERFACE_FIFO_RESET or SBE_INTERFACE_UNKNOWN + { + SBE_ERROR(SBE_FUNC"Unexpected interrupt communicated to the " + "processor thread. Interrupt source: 0x%02X 0x%02X", + SBE_GLOBAL->sbeIntrSource.intrSource, SBE_GLOBAL->sbeIntrSource.rxThrIntrSource); + assert(false); + break; + } + + // PK API failure + if (l_rcPk != PK_OK) + { + SBE_ERROR(SBE_FUNC"pk_semaphore_pend failed, " + "l_rcPk=%d, SBE_GLOBAL->sbeSemCmdRecv.count=%d", + l_rcPk, SBE_GLOBAL->sbeSemCmdRecv.count); + + // If it's a semphore_pend error then update the same to show + // internal failure + l_rc = SBE_SEC_OS_FAILURE; + } + + // Check for error which Receiver thread might have set + if (l_rc != SBE_SEC_OPERATION_SUCCESSFUL) + { + break; + } + + // Get the command function + sbeCmdFunc_t l_pFuncP = sbeFindCmdFunc (l_cmdClass, l_cmdOpCode); + assert( l_pFuncP ) + + // Call the ChipOp function + l_rc = l_pFuncP ((uint8_t *)i_pArg); + + } while(false); // Inner do..while loop ends here + + SBE_INFO (SBE_FUNC"Command processesed. l_rc=[0x%04X]", l_rc ); + + if ( SBE_GLOBAL->sbeIntrSource.isSet(SBE_PROC_ROUTINE, SBE_INTERFACE_PSU) ) + { + sbeHandlePsuResponse (l_rc); + + // Enable Host interrupt + SBE_GLOBAL->sbeIntrSource.clearIntrSource(SBE_ALL_HANDLER,SBE_INTERFACE_PSU); + pk_irq_enable(SBE_IRQ_HOST_PSU_INTR); + } + else if ( SBE_GLOBAL->sbeIntrSource.isSet(SBE_PROC_ROUTINE, SBE_INTERFACE_FIFO) ) + { + sbeHandleFifoResponse (l_rc); + + // Enable the new data available interrupt + SBE_GLOBAL->sbeIntrSource.clearIntrSource(SBE_ALL_HANDLER,SBE_INTERFACE_FIFO); + pk_irq_enable(SBE_IRQ_SBEFIFO_DATA); + pk_irq_enable(SBE_IRQ_SBEFIFO_RESET); + } + } while(true); // Thread always exists + SBE_EXIT(SBE_FUNC); +} + +////////////////////////////////////////////////////// +////////////////////////////////////////////////////// +void sbeAsyncCommandProcessor_routine(void *arg) +{ + SBE_INFO("sbeAsyncCommandProcessor Thread started"); + + do + { + // @TODO RTC via : 130392 + // Add infrastructure for host interface + + } while(0); +} diff --git a/src/sbefw/core/sbecmdreceiver.C b/src/sbefw/core/sbecmdreceiver.C new file mode 100644 index 00000000..ca716c65 --- /dev/null +++ b/src/sbefw/core/sbecmdreceiver.C @@ -0,0 +1,308 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbecmdreceiver.C $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2017 */ +/* */ +/* */ +/* 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: ppe/sbe/sbefw/sbecmdreceiver.C + * + * @brief This file contains the SBE Command Receiver Thread Routine + * + */ + + +#include "sbeexeintf.H" +#include "sbefifo.H" +#include "sbecmdparser.H" +#include "sbeirq.H" +#include "sbetrace.H" +#include "sbe_sp_intf.H" +#include "sbeFifoMsgUtils.H" +#include "sbeerrorcodes.H" +#include "sbeHostMsg.H" +#include "sbeHostUtils.H" +#include "sberegaccess.H" +#include "sbeutil.H" +#include "sbeglobals.H" + +////////////////////////////////////////////////////// +////////////////////////////////////////////////////// +void sbeCommandReceiver_routine(void *i_pArg) +{ + #define SBE_FUNC " sbeCommandReceiver_routine " + SBE_ENTER(SBE_FUNC); + uint32_t l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + sbeInterfaceSrc_t curInterface = SBE_INTERFACE_UNKNOWN; + + // Set Current State to First State i.e. Unknown + (void)SbeRegAccess::theSbeRegAccess().updateSbeState(SBE_STATE_UNKNOWN); + + do + { + // @TODO via RTC: 128944 + // Read Scratchpad + // Wait for new data in FIFO or FIFO reset interrupt or PSU interrupt + int l_rcPk = pk_semaphore_pend (&SBE_GLOBAL->sbeSemCmdRecv, PK_WAIT_FOREVER); + + do + { + uint8_t l_cmdClass = SBE_CMD_CLASS_UNKNOWN; + uint8_t l_command = 0xFF; + + // pk API failure + if (l_rcPk != PK_OK) + { + break; + } + + SBE_DEBUG(SBE_FUNC"Receiver unblocked"); + + // The responsibility of this thread is limited to reading off + // the FIFO or PSU interfaces to be able to decode the command + // class and the command opcode parameters. + + // Received FIFO Reset interrupt + if ( SBE_GLOBAL->sbeIntrSource.isSet(SBE_INTERRUPT_ROUTINE, + SBE_INTERFACE_FIFO_RESET) ) + { + SBE_ERROR(SBE_FUNC"FIFO reset received"); + l_rc = SBE_FIFO_RESET_RECEIVED; + curInterface = SBE_INTERFACE_FIFO_RESET; + break; + } + + // Received PSU interrupt + if ( SBE_GLOBAL->sbeIntrSource.isSet(SBE_INTERRUPT_ROUTINE, + SBE_INTERFACE_PSU) ) + { + //Clear the Interrupt Source bit for PSU + SBE_GLOBAL->sbeIntrSource.clearIntrSource(SBE_INTERRUPT_ROUTINE, + SBE_INTERFACE_PSU); + curInterface = SBE_INTERFACE_PSU; + // First clear PSU->SBE DB bit 0 + l_rc = sbeClearPsu2SbeDbBitX(SBE_PSU2SBE_DOORBELL_CLEAR_BIT0); + if (l_rc) + { + break; + } + + // Initialize the SBE_GLOBAL->sbePsu2SbeCmdReqHdr + SBE_GLOBAL->sbePsu2SbeCmdReqHdr.init(); + // Read the request field from PSU->SBE Mbx Reg0 + uint8_t l_cnt = sizeof(SBE_GLOBAL->sbePsu2SbeCmdReqHdr)/sizeof(uint64_t); + + l_rc = sbeReadPsu2SbeMbxReg(SBE_HOST_PSU_MBOX_REG0, l_cnt, + (uint64_t *)&SBE_GLOBAL->sbePsu2SbeCmdReqHdr); + + SBE_GLOBAL->sbeSbe2PsuRespHdr.init(); + l_cmdClass = SBE_GLOBAL->sbePsu2SbeCmdReqHdr.cmdClass; + l_command = SBE_GLOBAL->sbePsu2SbeCmdReqHdr.command; + } // end if loop for PSU interface chipOp handling + + // Received FIFO New Data interrupt + else if ( SBE_GLOBAL->sbeIntrSource.isSet(SBE_INTERRUPT_ROUTINE, + SBE_INTERFACE_FIFO) ) + { + //Clear the Interrupt Source bit for FIFO + SBE_GLOBAL->sbeIntrSource.clearIntrSource(SBE_INTERRUPT_ROUTINE, + SBE_INTERFACE_FIFO); + curInterface = SBE_INTERFACE_FIFO; + + // This thread will attempt to unblock the command processor + // thread on the following scenarios: + // - Normal scenarios where SBE would need to respond to FSP + // via downstream FIFO. This includes SUCCESS cases as well + // as the cases for Invalid Data sequence or Command + // validation failure. + // - if there is a need to handle FIFO reset + + // Accordingly, this will update SBE_GLOBAL->sbeCmdRespHdr.prim_status + // and SBE_GLOBAL->sbeCmdRespHdr.sec_status for command processor thread + // to handle them later in the sequence. + + SBE_GLOBAL->sbeFifoCmdHdr.cmdClass = SBE_CMD_CLASS_UNKNOWN; + SBE_GLOBAL->sbeCmdRespHdr.init(); + uint32_t len = sizeof(SBE_GLOBAL->sbeFifoCmdHdr)/sizeof(uint32_t); + l_rc = sbeUpFifoDeq_mult ( len, (uint32_t *)&SBE_GLOBAL->sbeFifoCmdHdr, + false ); + + // If FIFO reset is requested, + if (l_rc == SBE_FIFO_RESET_RECEIVED) + { + SBE_ERROR(SBE_FUNC"FIFO reset received"); + break; + } + + // If we received EOT out-of-sequence + if ( (l_rc == SBE_SEC_UNEXPECTED_EOT_INSUFFICIENT_DATA) || + (l_rc == SBE_SEC_UNEXPECTED_EOT_EXCESS_DATA) ) + { + SBE_ERROR(SBE_FUNC"sbeUpFifoDeq_mult failure, " + " l_rc=[0x%08X]", l_rc); + SBE_GLOBAL->sbeCmdRespHdr.setStatus(SBE_PRI_INVALID_DATA, l_rc); + + // Reassign l_rc to Success to Unblock command processor + // thread and let that take the necessary action. + l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + break; + } + + l_cmdClass = SBE_GLOBAL->sbeFifoCmdHdr.cmdClass; + l_command = SBE_GLOBAL->sbeFifoCmdHdr.command; + } // end else if loop for FIFO interface chipOp handling + + // Any other FIFO access issue + if ( l_rc != SBE_SEC_OPERATION_SUCCESSFUL) + { + break; + } + + // validate the command class and sub-class opcodes + l_rc = sbeValidateCmdClass (l_cmdClass, l_command) ; + + if (l_rc) + { + // Command Validation failed; + SBE_ERROR(SBE_FUNC"Command validation failed"); + if ( SBE_INTERFACE_PSU == curInterface ) + { + SBE_GLOBAL->sbeSbe2PsuRespHdr.setStatus(SBE_PRI_INVALID_COMMAND,l_rc); + } + else if ( SBE_INTERFACE_FIFO == curInterface ) + { + SBE_GLOBAL->sbeCmdRespHdr.setStatus(SBE_PRI_INVALID_COMMAND, l_rc); + } + + // Reassign l_rc to Success to Unblock command processor + // thread and let that take the necessary action. + l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + break; + } + + // Need to return from receiver thread itself for fenced rejection + // of command, but there might be contention on the response sent + // over FIFO/Mailbox usage. + sbeChipOpRc_t cmdAllowedStatus = sbeIsCmdAllowed(l_cmdClass, l_command); + if( !cmdAllowedStatus.success() && !SBE::isSimicsRunning() ) + { + SBE_ERROR("Chip-Op CmdClass[0x%02X] Cmd[0x%02X] not allowed " + "secondary status[0x%04X] State - [0x%02X]", + l_cmdClass,l_command, + cmdAllowedStatus.secStatus, + SbeRegAccess::theSbeRegAccess().getSbeState()); + + if ( SBE_INTERFACE_PSU == curInterface ) + { + SBE_GLOBAL->sbeSbe2PsuRespHdr.setStatus(cmdAllowedStatus.primStatus, + cmdAllowedStatus.secStatus); + } + else if ( SBE_INTERFACE_FIFO == curInterface ) + { + SBE_GLOBAL->sbeCmdRespHdr.setStatus(cmdAllowedStatus.primStatus, + cmdAllowedStatus.secStatus); + } + + l_rc = cmdAllowedStatus.secStatus; + break; + } + } while (false); // Inner do..while ends + + SBE_GLOBAL->sbeIntrSource.setIntrSource(SBE_RX_ROUTINE, curInterface ); + + // If there was a FIFO reset request, + if (l_rc == SBE_FIFO_RESET_RECEIVED) + { + // Perform FIFO Reset + uint32_t l_rc = sbeUpFifoPerformReset(); + if (l_rc) + { + // Perform FIFO Reset failed + SBE_ERROR(SBE_FUNC"Perform FIFO Reset failed, " + "l_rc=[0x%08X]", l_rc); + // Collect FFDC? + } + + if ( SBE_GLOBAL->sbeIntrSource.isSet(SBE_RX_ROUTINE, SBE_INTERFACE_FIFO) ) + { + SBE_GLOBAL->sbeIntrSource.clearIntrSource(SBE_ALL_HANDLER, + SBE_INTERFACE_FIFO); + } + + if ( SBE_GLOBAL->sbeIntrSource.isSet(SBE_RX_ROUTINE, + SBE_INTERFACE_FIFO_RESET) ) + { + SBE_GLOBAL->sbeIntrSource.clearIntrSource(SBE_ALL_HANDLER, + SBE_INTERFACE_FIFO_RESET); + } + + pk_irq_enable(SBE_IRQ_SBEFIFO_DATA); + pk_irq_enable(SBE_IRQ_SBEFIFO_RESET); + continue; + } // FIFO reset handling ends + + // Unblock the command processor thread + // if we could dequeue the header successfully, + if ((l_rcPk == PK_OK) && (l_rc == SBE_SEC_OPERATION_SUCCESSFUL)) + { + l_rcPk = pk_semaphore_post(&SBE_GLOBAL->sbeSemCmdProcess); + } + + // Handle Cmd not in a valid state here + + if ((l_rcPk != PK_OK) || (l_rc != SBE_SEC_OPERATION_SUCCESSFUL)) + { + if( (l_rc != SBE_SEC_COMMAND_NOT_ALLOWED_IN_THIS_STATE) && + (l_rc != SBE_SEC_BLACKLISTED_CHIPOP_ACCESS )) + { + // It's likely a code bug or PK failure, + // or any other PSU/FIFO access (scom) failure. + + // Add Error trace, collect FFDC and + // continue wait for the next interrupt + SBE_ERROR(SBE_FUNC"Unexpected failure, " + "l_rcPk=[%d], SBE_GLOBAL->sbeSemCmdProcess.count=[%d], l_rc=[%d]", + l_rcPk, SBE_GLOBAL->sbeSemCmdProcess.count, l_rc); + pk_halt(); + } + if ( SBE_INTERFACE_PSU == curInterface ) + { + sbeHandlePsuResponse(l_rc); + SBE_GLOBAL->sbeIntrSource.clearIntrSource(SBE_ALL_HANDLER, + SBE_INTERFACE_PSU); + pk_irq_enable(SBE_IRQ_HOST_PSU_INTR); + } + else if ( SBE_INTERFACE_FIFO == curInterface ) + { + sbeHandleFifoResponse(l_rc); + SBE_GLOBAL->sbeIntrSource.clearIntrSource(SBE_ALL_HANDLER, + SBE_INTERFACE_FIFO); + pk_irq_enable(SBE_IRQ_SBEFIFO_DATA); + pk_irq_enable(SBE_IRQ_SBEFIFO_RESET); + } + continue; + } + + SBE_DEBUG(SBE_FUNC"Posted SBE_GLOBAL->sbeSemCmdProcess, " + "SBE_GLOBAL->sbeSemCmdProcess.count=[%d]", SBE_GLOBAL->sbeSemCmdProcess.count); + + } while (true); // thread always exists + #undef SBE_FUNC +} diff --git a/src/sbefw/core/sbecmdregaccess.C b/src/sbefw/core/sbecmdregaccess.C new file mode 100644 index 00000000..40d3537c --- /dev/null +++ b/src/sbefw/core/sbecmdregaccess.C @@ -0,0 +1,281 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbecmdregaccess.C $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* */ +/* */ +/* 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: ppe/sbe/sbefw/sbecmdregaccess.C + * + * @brief This file contains the SBE Reg Access chipOps + * + */ + +#include "sbecmdregaccess.H" +#include "sbefifo.H" +#include "sbe_sp_intf.H" +#include "sbetrace.H" +#include "sbeFifoMsgUtils.H" +#include "p9_ram_core.H" + +using namespace fapi2; + +Enum_RegType getRegType( const sbeRegAccessMsgHdr_t ®Req) +{ + Enum_RegType type = REG_GPR; + switch( regReq.regType ) + { + case SBE_REG_ACCESS_SPR: + type = REG_SPR; + break; + + case SBE_REG_ACCESS_FPR: + type = REG_FPR; + break; + } + return type; +} + +////////////////////////////////////////////////////// +////////////////////////////////////////////////////// +uint32_t sbeGetReg(uint8_t *i_pArg) +{ + #define SBE_FUNC " sbeGetReg " + SBE_ENTER(SBE_FUNC); + + uint32_t rc = SBE_SEC_OPERATION_SUCCESSFUL; + sbeRegAccessMsgHdr_t regReqMsg; + uint32_t reqData[SBE_MAX_REG_ACCESS_REGS]; + sbeRespGenHdr_t respHdr; + respHdr.init(); + sbeResponseFfdc_t ffdc; + ReturnCode fapiRc; + + do + { + // Get the reg access header + uint32_t len = sizeof(sbeRegAccessMsgHdr_t)/sizeof(uint32_t); + rc = sbeUpFifoDeq_mult (len, (uint32_t *)®ReqMsg, false); + + // If FIFO access failure + if (rc != SBE_SEC_OPERATION_SUCCESSFUL) + { + // Let command processor routine to handle the RC. + break; + } + if( false == regReqMsg.isValidRequest() ) + { + SBE_ERROR(SBE_FUNC" Invalid request. core: 0x%02x threadNr:0x%x" + " regType:0x%01x numRegs:0x%02x", regReqMsg.coreChiplet, + regReqMsg.threadNr, regReqMsg.regType, regReqMsg.numRegs); + + respHdr.setStatus( SBE_PRI_INVALID_DATA, + SBE_SEC_GENERIC_FAILURE_IN_EXECUTION); + break; + } + + len = regReqMsg.numRegs; + rc = sbeUpFifoDeq_mult (len, reqData, true); + if (rc != SBE_SEC_OPERATION_SUCCESSFUL) + { + break; + } + uint8_t core = regReqMsg.coreChiplet; +#ifdef SEEPROM_IMAGE + RamCore ramCore( plat_getTargetHandleByChipletNumber + <fapi2::TARGET_TYPE_CORE>(core), + regReqMsg.threadNr ); +#endif + + SBE_EXEC_HWP_NOARG(fapiRc, ramCore.ram_setup) + if( fapiRc != FAPI2_RC_SUCCESS ) + { + SBE_ERROR(SBE_FUNC" ram_setup failed. threadNr:0x%x" + "chipletId:0x%02x", (uint32_t)regReqMsg.threadNr, core); + respHdr.setStatus( SBE_PRI_GENERIC_EXECUTION_FAILURE, + SBE_SEC_GENERIC_FAILURE_IN_EXECUTION); + ffdc.setRc(fapiRc); + break; + } + + fapi2::buffer<uint64_t> data64; + uint64_t respData = 0; + for( uint32_t regIdx = 0; regIdx < regReqMsg.numRegs; regIdx++ ) + { + SBE_EXEC_HWP(fapiRc, ramCore.get_reg, getRegType(regReqMsg), reqData[regIdx], + &data64, true ) + if( fapiRc != FAPI2_RC_SUCCESS ) + { + SBE_ERROR(SBE_FUNC" get_reg failed. threadNr:0x%x" + "chipletId:0x%02x, regNr:%u regType:%u ", + regReqMsg.threadNr, core, reqData[regIdx], + regReqMsg.regType); + respHdr.setStatus( SBE_PRI_GENERIC_EXECUTION_FAILURE, + SBE_SEC_GENERIC_FAILURE_IN_EXECUTION); + ffdc.setRc(fapiRc); + break; + } + respData = data64; + // Now enqueue into the downstream FIFO + len = sizeof( respData )/sizeof(uint32_t); + rc = sbeDownFifoEnq_mult (len, ( uint32_t *)&respData); + if (rc) + { + break; + } + } + // HWP team does not care about cleanup for failure case. + // So call cleaup only for success case. + if( ffdc.getRc() ) + { + break; + } + SBE_EXEC_HWP_NOARG(fapiRc, ramCore.ram_cleanup) + if( fapiRc != FAPI2_RC_SUCCESS ) + { + SBE_ERROR(SBE_FUNC" ram_cleanup failed. threadNr:0x%x" + "chipletId:0x%02x", (uint32_t)regReqMsg.threadNr, core); + respHdr.setStatus( SBE_PRI_GENERIC_EXECUTION_FAILURE, + SBE_SEC_GENERIC_FAILURE_IN_EXECUTION); + ffdc.setRc(fapiRc); + } + }while(false); + + if ( SBE_SEC_OPERATION_SUCCESSFUL == rc ) + { + rc = sbeDsSendRespHdr( respHdr, &ffdc); + } + + SBE_EXIT(SBE_FUNC); + return rc; + #undef SBE_FUNC +} +////////////////////////////////////////////////////// +////////////////////////////////////////////////////// +uint32_t sbePutReg(uint8_t *i_pArg) +{ + #define SBE_FUNC " sbePutReg " + SBE_ENTER(SBE_FUNC); + + uint32_t rc = SBE_SEC_OPERATION_SUCCESSFUL; + sbeRegAccessMsgHdr_t regReqMsg; + sbeRespGenHdr_t respHdr; + respHdr.init(); + sbeResponseFfdc_t ffdc; + ReturnCode fapiRc; + + do + { + // Get the reg access header + uint32_t len = sizeof(sbeRegAccessMsgHdr_t)/sizeof(uint32_t); + rc = sbeUpFifoDeq_mult (len, (uint32_t *)®ReqMsg, false); + + // If FIFO access failure + if (rc != SBE_SEC_OPERATION_SUCCESSFUL) + { + // Let command processor routine to handle the RC. + break; + } + if( false == regReqMsg.isValidRequest() ) + { + SBE_ERROR(SBE_FUNC" Invalid request. threadNr:0x%x" + " regType:0x%02x numRegs:0x%02x", + (uint32_t)regReqMsg.threadNr, + (uint32_t)regReqMsg.regType, + (uint32_t)regReqMsg.numRegs); + respHdr.setStatus( SBE_PRI_INVALID_DATA, + SBE_SEC_GENERIC_FAILURE_IN_EXECUTION); + break; + } + + sbeRegAccessPackage_t regPkg[SBE_MAX_REG_ACCESS_REGS]; + len = (sizeof(sbeRegAccessPackage_t)/sizeof(uint32_t)) * + regReqMsg.numRegs; + rc = sbeUpFifoDeq_mult (len, (uint32_t *) regPkg,true ); + if (rc != SBE_SEC_OPERATION_SUCCESSFUL) + { + break; + } + uint8_t core = regReqMsg.coreChiplet; +#ifdef SEEPROM_IMAGE + RamCore ramCore( plat_getTargetHandleByChipletNumber + <fapi2::TARGET_TYPE_CORE>(core), + regReqMsg.threadNr ); +#endif + + SBE_EXEC_HWP_NOARG(fapiRc, ramCore.ram_setup) + if( fapiRc != FAPI2_RC_SUCCESS ) + { + SBE_ERROR(SBE_FUNC" ram_setup failed. threadNr:0x%x" + "chipletId:0x%02x", (uint32_t)regReqMsg.threadNr, core); + respHdr.setStatus( SBE_PRI_GENERIC_EXECUTION_FAILURE, + SBE_SEC_GENERIC_FAILURE_IN_EXECUTION); + ffdc.setRc(fapiRc); + break; + } + + fapi2::buffer<uint64_t> data64; + for( uint32_t regIdx = 0; regIdx < regReqMsg.numRegs; regIdx++ ) + { + data64 = regPkg[regIdx].getData(); + SBE_EXEC_HWP(fapiRc, ramCore.put_reg, getRegType(regReqMsg), + regPkg[regIdx].regNr, + &data64, true ) + if( fapiRc != FAPI2_RC_SUCCESS ) + { + SBE_ERROR(SBE_FUNC" get_reg failed. threadNr:0x%x" + "chipletId:0x%02x, regNr:%u regType:%u ", + regReqMsg.threadNr, core, regPkg[regIdx].regNr, + regReqMsg.regType); + respHdr.setStatus( SBE_PRI_GENERIC_EXECUTION_FAILURE, + SBE_SEC_GENERIC_FAILURE_IN_EXECUTION); + ffdc.setRc(fapiRc); + break; + } + } + // HWP team does not care about cleanup for failure case. + // So call cleaup only for success case. + if( ffdc.getRc() ) + { + break; + } + SBE_EXEC_HWP_NOARG(fapiRc, ramCore.ram_cleanup) + if( fapiRc ) + { + SBE_ERROR(SBE_FUNC" ram_cleanup failed. threadNr:0x%x" + " chipletId:0x%02x", + (uint32_t)regReqMsg.threadNr, core); + respHdr.setStatus( SBE_PRI_GENERIC_EXECUTION_FAILURE, + SBE_SEC_GENERIC_FAILURE_IN_EXECUTION); + ffdc.setRc(fapiRc); + } + + }while(false); + + if ( SBE_SEC_OPERATION_SUCCESSFUL == rc ) + { + rc = sbeDsSendRespHdr( respHdr, &ffdc); + } + + SBE_EXIT(SBE_FUNC); + return rc; + #undef SBE_FUNC +} + diff --git a/src/sbefw/core/sbecmdregaccess.H b/src/sbefw/core/sbecmdregaccess.H new file mode 100644 index 00000000..05c10d8d --- /dev/null +++ b/src/sbefw/core/sbecmdregaccess.H @@ -0,0 +1,56 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbecmdregaccess.H $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* */ +/* */ +/* 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: ppe/sbe/sbefw/sbecmdregaccess.H + * + * @brief This file contains the Interfaces for the SCOM Access chip-ops + * + */ + +#ifndef __SBEFW_SBECMDREGACCESS_H +#define __SBEFW_SBECMDREGACCESS_H + +#include <stdint.h> + +/** + * @brief sbeGetRegs : Get the reg data + * + * @param[in] i_pArg Buffer to be passed to the function (not used as of now) + * + * @return Rc from the FIFO access utility + */ +uint32_t sbeGetReg(uint8_t *i_pArg); + + +/** + * @brief sbePutRegs : Put the reg data + * + * @param[in] i_pArg Buffer to be passed to the function (not used as of now) + * + * @return Rc from the FIFO access utility + */ +uint32_t sbePutReg(uint8_t *i_pArg); + + +#endif /* __SBEFW_SBECMDREGACCESS_H */ diff --git a/src/sbefw/core/sbecmdringaccess.C b/src/sbefw/core/sbecmdringaccess.C new file mode 100644 index 00000000..1db28734 --- /dev/null +++ b/src/sbefw/core/sbecmdringaccess.C @@ -0,0 +1,361 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbecmdringaccess.C $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* */ +/* */ +/* 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: ppe/sbe/sbefw/sbecmdringaccess.C + * + * @brief This file contains the SBE Ring Access chipOps + * + */ + +#include "sbecmdringaccess.H" +#include "sbefifo.H" +#include "sbe_sp_intf.H" +#include "sbetrace.H" +#include "sbeHostMsg.H" +#include "sbeHostUtils.H" +#include "sbeFifoMsgUtils.H" +#include "sbeutil.H" +#include "sbefapiutil.H" +#include "fapi2.H" +#include "plat_hw_access.H" +#include "sbeglobals.H" + +using namespace fapi2; + +static const uint32_t SIZE_OF_LENGTH_INWORDS = 1; +static const uint32_t NUM_WORDS_PER_GRANULE = 2; +static const uint32_t GETRING_GRANULE_SIZE_IN_BITS = 64; + + +uint32_t sbePutRingFromImagePSU (uint8_t *i_pArg) +{ + #define SBE_FUNC " sbePutRingFromImagePSU " + SBE_ENTER(SBE_FUNC); + uint32_t l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + uint32_t l_fapiRc = FAPI2_RC_SUCCESS; + sbePSUPutRingCMD_t l_cmd = {0}; + do + { + // Fetch Ring ID, Ring mode and pervasive chiplet id from the message + // and also send Ack to Host via SBE_SBE2PSU_DOORBELL_SET_BIT1 + l_rc = sbeReadPsu2SbeMbxReg(SBE_HOST_PSU_MBOX_REG1, + (sizeof(l_cmd)/sizeof(uint64_t)), + (uint64_t*)&l_cmd, + true); + if(SBE_SEC_OPERATION_SUCCESSFUL != l_rc) + { + SBE_ERROR(SBE_FUNC "Failed to extract SBE_HOST_PSU_MBOX_REG1 and " + "SBE_HOST_PSU_MBOX_REG2"); + break; + } + + // Construct a Target from Chiplet ID and Target Type + fapi2::plat_target_handle_t l_tgtHndl; + if(!sbeGetFapiTargetHandle(l_cmd.TargetType, l_cmd.ChipletID, + l_tgtHndl)) + { + SBE_ERROR(SBE_FUNC "Invalid target type [0x%04x]", + (uint16_t)l_cmd.TargetType); + SBE_GLOBAL->sbeSbe2PsuRespHdr.setStatus(SBE_PRI_INVALID_DATA, + SBE_SEC_INVALID_TARGET_TYPE_PASSED); + break; + } + fapi2::Target<TARGET_TYPE_ALL> l_Tgt(l_tgtHndl); + + // Initialize with HEADER CHECK mode + uint16_t l_ringMode = sbeToFapiRingMode(l_cmd.RingMode); + + l_fapiRc = (uint32_t)putRing(l_Tgt, (RingID)l_cmd.RingID, + (RingMode)l_ringMode); + if(l_fapiRc != FAPI2_RC_SUCCESS) + { + SBE_ERROR(SBE_FUNC "putRing HWP failure - " + "MSG - Target Type [0x%04x] Ring ID [0x%04x]" + " Ring Mode [0x%04x] Chiplet ID [0x%04x]", + l_cmd.TargetType, + l_cmd.RingID, + l_cmd.RingMode, + l_cmd.ChipletID); + break; + } + }while(0); // End of do-while + + // Send the response + sbePSUSendResponse(SBE_GLOBAL->sbeSbe2PsuRespHdr, l_fapiRc, l_rc); + + SBE_EXIT(SBE_FUNC); + return l_rc; + #undef SBE_FUNC +} + +////////////////////////////////////////////////////// +////////////////////////////////////////////////////// +uint32_t sbeGetRing(uint8_t *i_pArg) +{ + #define SBE_FUNC " sbeGetRing " + SBE_ENTER(SBE_FUNC); + + uint32_t l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + sbeGetRingAccessMsgHdr_t l_reqMsg; + sbeRespGenHdr_t respHdr; + respHdr.init(); + sbeResponseFfdc_t l_ffdc; + ReturnCode l_fapiRc; + uint32_t l_len = 0; + + //Note-Read operation flow is SHIFT and then READ. + // First time , the shift count will be 0.. because of the way it + // works. if we shift 64bits in the very first iteration then we + // loose first 64 bit. But still we should update l_bitSentCnt + // because we are sending back this data + uint32_t l_bitSentCnt = 64; + const uint32_t LONG_ROTATE_ADDRESS = 0x0003E000; + + do + { + // Get the ring access header + l_len = sizeof(sbeGetRingAccessMsgHdr_t)/sizeof(uint32_t); + l_rc = sbeUpFifoDeq_mult (l_len, (uint32_t *)&l_reqMsg); // EOT fetch + + // If FIFO access failure + CHECK_SBE_RC_AND_BREAK_IF_NOT_SUCCESS(l_rc); + + SBE_INFO(SBE_FUNC "Ring Address 0x%08X User Ring Mode 0x%04X " + "Length in Bits 0x%08X", + (uint32_t)l_reqMsg.ringAddr, + (uint32_t)l_reqMsg.ringMode, + (uint32_t)l_reqMsg.ringLenInBits); + + uint16_t l_ringMode = sbeToFapiRingMode(l_reqMsg.ringMode); + + // Call getRing_setup - loads the scan region data for the given ring + // address and updates the check word data + l_fapiRc = fapi2::getRing_setup(l_reqMsg.ringAddr, + (fapi2::RingMode)l_ringMode); + if( l_fapiRc != FAPI2_RC_SUCCESS ) + { + SBE_ERROR(SBE_FUNC" getRing_setup failed. RingAddress:0x%08X " + "RingMode:0x%04x", l_reqMsg.ringAddr, l_ringMode); + respHdr.setStatus( SBE_PRI_GENERIC_EXECUTION_FAILURE, + SBE_SEC_GENERIC_FAILURE_IN_EXECUTION); + l_ffdc.setRc(l_fapiRc); + break; + } + // Calculate the iteration length + uint32_t l_loopCnt = + (l_reqMsg.ringLenInBits / GETRING_GRANULE_SIZE_IN_BITS); + // Check for modulus - remainder + uint8_t l_mod = (l_reqMsg.ringLenInBits % GETRING_GRANULE_SIZE_IN_BITS); + if(l_mod) + { + ++l_loopCnt; + } + + // fix for the alignment issue + uint32_t l_buf[NUM_WORDS_PER_GRANULE]__attribute__ ((aligned (8))) ={0}; + uint32_t l_bitShift = 0; + l_len = NUM_WORDS_PER_GRANULE; + plat_target_handle_t l_hndl; + uint32_t l_chipletId = (uint32_t)(l_reqMsg.ringAddr) & 0xFF000000; + uint32_t l_scomAddress = 0; + + // Fetch the ring data in bits, each iteration will give you 64bits + for(uint32_t l_cnt=0; l_cnt < l_loopCnt; l_cnt++) + { + + l_scomAddress = LONG_ROTATE_ADDRESS | l_chipletId; + l_scomAddress |= l_bitShift; + l_fapiRc = getscom_abs_wrap (&l_hndl, + l_scomAddress, + (uint64_t*)&l_buf); + + if( l_fapiRc != FAPI2_RC_SUCCESS ) + { + SBE_ERROR(SBE_FUNC" getRing_granule_data failed. " + "RingAddress:0x%08X RingMode:0x%04x", + l_reqMsg.ringAddr, l_ringMode); + respHdr.setStatus( SBE_PRI_GENERIC_EXECUTION_FAILURE, + SBE_SEC_GENERIC_FAILURE_IN_EXECUTION); + l_ffdc.setRc(l_fapiRc); + break; + } + // if the length of ring is not divisible by 64 then mod value + // should be considered which will match with the length in bits + // that passed + if((l_cnt == (l_loopCnt -1)) && (l_mod)) + { + l_bitShift = l_mod; + } + // Send it to DS Fifo + // If this is the last iteration in the loop, let the full 64bit + // go, even for 1bit of remaining length. The length passed to + // the user will take care of actual number of bits. + l_rc = sbeDownFifoEnq_mult (l_len, (uint32_t *)&l_buf); + CHECK_SBE_RC_AND_BREAK_IF_NOT_SUCCESS(l_rc); + l_bitSentCnt = l_bitSentCnt + l_bitShift; + l_bitShift = GETRING_GRANULE_SIZE_IN_BITS; + } + if ( (l_fapiRc == FAPI2_RC_SUCCESS) && + (l_rc == SBE_SEC_OPERATION_SUCCESSFUL) ) + { + if (!l_mod) + { + l_mod = GETRING_GRANULE_SIZE_IN_BITS; + } + //Here we need to shift with the mod value to enter into the + //starting position of the ring.But the data is already read in the + //above for loop.. so here we ignore the data + l_scomAddress = LONG_ROTATE_ADDRESS | l_chipletId; + l_scomAddress |= l_mod; + l_fapiRc = getscom_abs_wrap (&l_hndl, + l_scomAddress, + (uint64_t*)&l_buf); + + if( l_fapiRc != FAPI2_RC_SUCCESS ) + { + SBE_ERROR(SBE_FUNC" getRing_granule_data failed. " + "RingAddress:0x%08X RingMode:0x%04x", + l_reqMsg.ringAddr, l_ringMode); + respHdr.setStatus( SBE_PRI_GENERIC_EXECUTION_FAILURE, + SBE_SEC_GENERIC_FAILURE_IN_EXECUTION); + l_ffdc.setRc(l_fapiRc); + break; + } + + // Call getRing_verifyAndcleanup - verify the check word data is + // matching or not and will clean up the scan region data + l_fapiRc = getRing_verifyAndcleanup((uint32_t)(l_reqMsg.ringAddr), + (fapi2::RingMode)l_ringMode); + if( l_fapiRc != FAPI2_RC_SUCCESS ) + { + SBE_ERROR(SBE_FUNC" getRing_verifyAndcleanup failed. " + "RingAddress:0x%08X RingMode:0x%04x", + l_reqMsg.ringAddr, l_ringMode); + respHdr.setStatus( SBE_PRI_GENERIC_EXECUTION_FAILURE, + SBE_SEC_GENERIC_FAILURE_IN_EXECUTION); + l_ffdc.setRc(l_fapiRc); + } + } + }while(false); + + // Now build and enqueue response into downstream FIFO + // If there was a FIFO error, will skip sending the response, + // instead give the control back to the command processor thread + if ( SBE_SEC_OPERATION_SUCCESSFUL == l_rc ) + { + l_len = SIZE_OF_LENGTH_INWORDS; + l_rc = sbeDownFifoEnq_mult (l_len, &(l_bitSentCnt)); + if(SBE_SEC_OPERATION_SUCCESSFUL == l_rc) + { + l_rc = sbeDsSendRespHdr( respHdr, &l_ffdc); + } + } + SBE_EXIT(SBE_FUNC); + return l_rc; +#undef SBE_FUNC +} + +////////////////////////////////////////////////////// +////////////////////////////////////////////////////// +uint32_t sbePutRing(uint8_t *i_pArg) +{ +#define SBE_FUNC " sbePutRing " + SBE_ENTER(SBE_FUNC); + + uint32_t rc = SBE_SEC_OPERATION_SUCCESSFUL; + sbePutRingMsg_t reqMsg; + sbeRespGenHdr_t respHdr; + respHdr.init(); + sbeResponseFfdc_t ffdc; + ReturnCode fapiRc; + sbePutRingMsgHdr_t hdr; + uint32_t len = 0; + + do + { + // Get the length of payload + // Length is not part of chipop. So take length from total length + len = SBE_GLOBAL->sbeFifoCmdHdr.len - + sizeof(SBE_GLOBAL->sbeFifoCmdHdr)/sizeof(uint32_t); + uint32_t rs4FifoEntries = len - + sizeof(sbePutRingMsgHdr_t)/sizeof(uint32_t); + + if( rs4FifoEntries > (SBE_PUT_RING_RS4_MAX_DOUBLE_WORDS * 2) ) + { + SBE_ERROR(SBE_FUNC" RS4 palyload size is wrong." + "size(entries):0x%08x", rs4FifoEntries); + respHdr.setStatus( SBE_PRI_INVALID_DATA, + SBE_SEC_GENERIC_FAILURE_IN_EXECUTION); + // flush the fifo + rc = sbeUpFifoDeq_mult(len, NULL,true, true); + break; + } + + len = sizeof(sbePutRingMsgHdr_t)/sizeof(uint32_t); + rc = sbeUpFifoDeq_mult (len, (uint32_t *)&hdr, false); + // If FIFO access failure + CHECK_SBE_RC_AND_BREAK_IF_NOT_SUCCESS(rc); + + len = rs4FifoEntries; + rc = sbeUpFifoDeq_mult (len, (uint32_t *)&reqMsg); + // If FIFO access failure + CHECK_SBE_RC_AND_BREAK_IF_NOT_SUCCESS(rc); + + uint16_t ringMode = sbeToFapiRingMode(hdr.ringMode); + bool i_applyOverride = false; + + if (hdr.ringMode & SBE_RING_MODE_APPLY_OVERRIDE) + { + i_applyOverride = true; + } + + + + Target<TARGET_TYPE_PROC_CHIP> proc = plat_getChipTarget(); + // No need to pass length as platform api takes length from payload. + fapiRc = rs4DecompressionSvc(proc, (uint8_t *)reqMsg.rs4Payload, + i_applyOverride, (fapi2::RingMode)ringMode); + if( fapiRc != FAPI2_RC_SUCCESS ) + { + SBE_ERROR(SBE_FUNC" rs4DecompressionSvc failed." + "RingMode:0x%04x", ringMode); + respHdr.setStatus( SBE_PRI_GENERIC_EXECUTION_FAILURE, + SBE_SEC_GENERIC_FAILURE_IN_EXECUTION); + ffdc.setRc(fapiRc); + break; + } + }while(false); + + // Now build and enqueue response into downstream FIFO + // If there was a FIFO error, will skip sending the response, + // instead give the control back to the command processor thread + if ( SBE_SEC_OPERATION_SUCCESSFUL == rc ) + { + rc = sbeDsSendRespHdr( respHdr, &ffdc); + } + SBE_EXIT(SBE_FUNC); + return rc; +#undef SBE_FUNC +} + diff --git a/src/sbefw/core/sbecmdringaccess.H b/src/sbefw/core/sbecmdringaccess.H new file mode 100644 index 00000000..54314c15 --- /dev/null +++ b/src/sbefw/core/sbecmdringaccess.H @@ -0,0 +1,71 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbecmdringaccess.H $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* */ +/* */ +/* 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: ppe/sbe/sbefw/sbecmdringaccess.H + * + * @brief This file contains the Interfaces for the RING Access chip-ops + * + */ + +#ifndef __SBEFW_SBECMDRINGACCESS_H +#define __SBEFW_SBECMDRINGACCESS_H + +#include <stdint.h> + +typedef struct +{ + uint64_t TargetType:16; + uint64_t ChipletID:16; + uint64_t RingID:16; + uint64_t RingMode:16; +} sbePSUPutRingCMD_t; + +/** + * @brief Put Ring From Image Command (0xD301) + * + * @param[in] i_pArg Buffer to be passed to the function (not used as of now) + * + * @return RC from the PSU access utility + */ +uint32_t sbePutRingFromImagePSU(uint8_t *i_pArg); + +/** + * @brief sbeGetRing : Get the ring data + * + * @param[in] i_pArg Buffer to be passed to the function (not used as of now) + * + * @return Rc from the FIFO access utility + */ +uint32_t sbeGetRing(uint8_t *i_pArg); + +/** + * @brief Put Ring Command + * + * @param[in] i_pArg Buffer to be passed to the function (not used as of now) + * + * @return RC from the FIFO access utility + */ +uint32_t sbePutRing(uint8_t *i_pArg); + +#endif /* __SBEFW_SBECMDRINGACCESS_H */ diff --git a/src/sbefw/core/sbecmdscomaccess.C b/src/sbefw/core/sbecmdscomaccess.C new file mode 100644 index 00000000..f2b42608 --- /dev/null +++ b/src/sbefw/core/sbecmdscomaccess.C @@ -0,0 +1,432 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbecmdscomaccess.C $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2017 */ +/* */ +/* */ +/* 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: ppe/sbe/sbefw/sbecmdscomaccess.C + * + * @brief This file contains the SBE SCOM Access chipOps + * + */ + +#include "sbecmdscomaccess.H" +#include "sbefifo.H" +#include "sbe_sp_intf.H" +#include "sbetrace.H" +#include "sbescom.H" +#include "sbeutil.H" +#include "sbeFifoMsgUtils.H" +#include "plat_hw_access.H" +#include "sbeglobals.H" + + +////////////////////////////////////////////////////// +////////////////////////////////////////////////////// +uint32_t sbeGetScom (uint8_t *i_pArg) +{ + #define SBE_FUNC " sbeGetScom " + SBE_ENTER(SBE_FUNC); + + uint32_t l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + sbeGetScomReqMsg_t l_getScomReqMsg; + sbeRespGenHdr_t l_hdr; + l_hdr.init(); + sbeResponseFfdc_t l_ffdc; + + do + { + // Will attempt to dequeue two entries for + // the scom addresses plus the expected + // EOT entry at the end + + uint32_t l_len2dequeue = sizeof(l_getScomReqMsg)/sizeof(uint32_t); + l_rc = sbeUpFifoDeq_mult (l_len2dequeue, (uint32_t *)&l_getScomReqMsg); + + // If FIFO access failure + if (l_rc != SBE_SEC_OPERATION_SUCCESSFUL) + { + // Let command processor routine to handle the RC. + break; + } + + uint32_t l_len2enqueue = 0; + uint32_t l_sbeDownFifoRespBuf[2] = {0}; + + uint64_t l_addr = ( (uint64_t)l_getScomReqMsg.hiAddr << 32) | + l_getScomReqMsg.lowAddr; + uint64_t l_scomData = 0; + SBE_DEBUG(SBE_FUNC"scomAddr[0x%08X%08X]", + l_getScomReqMsg.hiAddr, l_getScomReqMsg.lowAddr); + checkIndirectAndDoScom(true, l_addr, + l_scomData, &l_hdr, + &l_ffdc); + + if (l_hdr.secondaryStatus != SBE_SEC_OPERATION_SUCCESSFUL) // scom failed + { + SBE_ERROR(SBE_FUNC"getscom failed, " + "scomAddr[0x%08X%08X]", + l_getScomReqMsg.hiAddr, l_getScomReqMsg.lowAddr); + break; + } + else // successful scom + { + SBE_DEBUG(SBE_FUNC"getscom succeeds, l_scomData[0x%016X]", + l_scomData); + + l_sbeDownFifoRespBuf[0] = (uint32_t)(l_scomData>>32); + l_sbeDownFifoRespBuf[1] = (uint32_t)(l_scomData); + + // Push the data into downstream FIFO + l_len2enqueue = 2; + l_rc = sbeDownFifoEnq_mult (l_len2enqueue, + &l_sbeDownFifoRespBuf[0]); + if (l_rc) + { + // will let command processor routine + // handle the failure + break; + } + } // end successful scom + + } while(false); + + if(l_rc == SBE_SEC_OPERATION_SUCCESSFUL) + { + // Build the response header packet + l_rc = sbeDsSendRespHdr(l_hdr, &l_ffdc); + // will let command processor routine + // handle the failure + } + + SBE_EXIT(SBE_FUNC); + return l_rc; + #undef SBE_FUNC +} + +///////////////////////////////////////////////////// +////////////////////////////////////////////////////// +uint32_t sbePutScom (uint8_t *i_pArg) +{ + #define SBE_FUNC " sbePutScom " + SBE_ENTER(SBE_FUNC); + + uint32_t l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + sbePutScomReqMsg_t l_putScomReqMsg; + sbeRespGenHdr_t l_hdr; + l_hdr.init(); + sbeResponseFfdc_t l_ffdc; + + do + { + // Will attempt to dequeue four entries for + // the scom address (two entries) and the + // corresponding data (two entries) plus + // the expected EOT entry at the end + + uint32_t l_len2dequeue = sizeof(l_putScomReqMsg)/sizeof(uint32_t); + l_rc = sbeUpFifoDeq_mult (l_len2dequeue, (uint32_t *)&l_putScomReqMsg); + + // If FIFO access failure + if (l_rc != SBE_SEC_OPERATION_SUCCESSFUL) + { + // Let command processor routine to handle the RC. + break; + } + + uint64_t l_scomData = 0; + // successfully dequeued two entries for + // scom address followed by the EOT entry + + // Data entry 0 : Scom Register Address (0..31) + // Data entry 1 : Scom Register Address (32..63) + // Data entry 2 : Scom Register Data (0..31) + // Data entry 3 : Scom Register Data (32..63) + // For Direct SCOM, will ignore entry 0 + + l_scomData = l_putScomReqMsg.getScomData(); + + uint64_t l_addr = ( (uint64_t) l_putScomReqMsg.hiAddr << 32) | + l_putScomReqMsg.lowAddr; + SBE_DEBUG(SBE_FUNC"scomAddr[0x%08X%08X]", + l_putScomReqMsg.hiAddr, l_putScomReqMsg.lowAddr); + checkIndirectAndDoScom(false, l_addr, + l_scomData, &l_hdr, &l_ffdc); + + if (l_hdr.secondaryStatus != SBE_SEC_OPERATION_SUCCESSFUL) // scom failed + { + SBE_ERROR(SBE_FUNC"putscom failure data, " + "scomAddr[0x%08X%08X], " + "scomData[0x%08X%08X]", + l_putScomReqMsg.hiAddr, + l_putScomReqMsg.lowAddr, + SBE::higher32BWord(l_scomData), + SBE::lower32BWord(l_scomData)); + break; + } + + } while(false); + + if(l_rc == SBE_SEC_OPERATION_SUCCESSFUL) + { + // Build the response header packet + l_rc = sbeDsSendRespHdr(l_hdr, &l_ffdc); + // will let command processor routine + // handle the failure + } + + SBE_EXIT(SBE_FUNC); + return l_rc; + #undef SBE_FUNC +} + + +////////////////////////////////////////////////////// +////////////////////////////////////////////////////// +uint32_t sbeModifyScom (uint8_t *i_pArg) +{ + #define SBE_FUNC " sbeModifyScom " + SBE_ENTER(SBE_FUNC); + + uint32_t l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + + sbeModifyScomReqMsg_t l_modifyScomMsg; + sbeRespGenHdr_t l_hdr; + l_hdr.init(); + sbeResponseFfdc_t l_ffdc; + + do + { + // Will attempt to dequeue the following entries: + // Entry 1 : Operation Mode + // Entry 2 : Scom Register Address (0..31) + // Entry 3 : Scom Register Address (32..63) + // Entry 4 : Modifying Data (0..31) + // Entry 5 : Modifying Data (32..63) + // Entry 6 : EOT entry at the end + + uint32_t l_len2dequeue = sizeof(l_modifyScomMsg)/sizeof(uint32_t); + l_rc = sbeUpFifoDeq_mult (l_len2dequeue, (uint32_t *)&l_modifyScomMsg); + + // If FIFO access failure + if (l_rc != SBE_SEC_OPERATION_SUCCESSFUL) + { + // Let command processor routine to handle the RC. + break; + } + + // Modifying Data + uint64_t l_modifyingData = l_modifyScomMsg.getModifyingData(); + + SBE_DEBUG(SBE_FUNC"OpMode[0x%02X], modifyingData[0x%016X]", + l_modifyScomMsg.opMode, + SBE::higher32BWord(l_modifyingData), + SBE::lower32BWord(l_modifyingData)); + + // The following steps need to be done as part of this command : + // 1. Read Register Data (getscom) + // 2. 'AND' the Mask with the data read from register + // 3. 'OR' the modifying data with the result of step 2 + // 4. Write the result of step 3 into the register (putscom) + do + { + // Check for a valid OpMode + if ( (l_modifyScomMsg.opMode != SBE_MODIFY_MODE_OR) && + (l_modifyScomMsg.opMode != SBE_MODIFY_MODE_AND) && + (l_modifyScomMsg.opMode != SBE_MODIFY_MODE_XOR) ) + { + // Invalid Data passed + SBE_ERROR(SBE_FUNC"Invalid OpMode"); + l_hdr.setStatus(SBE_PRI_INVALID_DATA, + SBE_SEC_GENERIC_FAILURE_IN_EXECUTION); + break; + } + + uint64_t l_addr = ( (uint64_t) l_modifyScomMsg.hiAddr << 32) | + l_modifyScomMsg.lowAddr; + uint64_t l_scomData = 0; + SBE_DEBUG(SBE_FUNC"scomAddr[0x%08X%08X]", + l_modifyScomMsg.hiAddr, l_modifyScomMsg.lowAddr); + checkIndirectAndDoScom(true, l_addr, + l_scomData, &l_hdr, &l_ffdc); + + if (l_hdr.secondaryStatus != SBE_SEC_OPERATION_SUCCESSFUL) // scom failed + { + SBE_ERROR(SBE_FUNC"getscom failed," + " ScomAddress[0x%08X %08X]", + l_modifyScomMsg.hiAddr, l_modifyScomMsg.lowAddr); + break; + } + + if (l_modifyScomMsg.opMode == SBE_MODIFY_MODE_OR) + { + l_modifyingData |= l_scomData; + } + else if (l_modifyScomMsg.opMode == SBE_MODIFY_MODE_AND) + { + l_modifyingData &= l_scomData; + } + else + { + l_modifyingData ^= l_scomData; + } + + // Write the modified data + checkIndirectAndDoScom(false, l_addr, + l_modifyingData, &l_hdr, &l_ffdc); + + if (l_hdr.secondaryStatus != SBE_SEC_OPERATION_SUCCESSFUL) // scom failed + { + SBE_ERROR(SBE_FUNC"putscom failed," + " ScomAddress[0x%08X%08X]", + l_modifyScomMsg.hiAddr, l_modifyScomMsg.lowAddr); + SBE_ERROR(SBE_FUNC"modifyingData[0x%08X%08X]", + SBE::higher32BWord(l_modifyingData), + SBE::lower32BWord(l_modifyingData)); + break; + } + } while (false); + + if(l_rc == SBE_SEC_OPERATION_SUCCESSFUL) + { + // Build the response header packet + l_rc = sbeDsSendRespHdr(l_hdr, &l_ffdc); + if (l_rc) + { + // will let command processor routine + // handle the failure + break; + } + } + + } while(false); + + SBE_EXIT(SBE_FUNC); + return l_rc; + #undef SBE_FUNC +} + +///////////////////////////////////////////////////// +////////////////////////////////////////////////////// +uint32_t sbePutScomUnderMask (uint8_t *i_pArg) +{ + #define SBE_FUNC " sbePutScomUnderMask " + SBE_ENTER(SBE_FUNC); + + uint32_t l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + sbePutScomUnderMaskReqMsg_t l_putScomUmaskMsg; + sbeRespGenHdr_t l_hdr; + l_hdr.init(); + sbeResponseFfdc_t l_ffdc; + + do + { + // Will attempt to dequeue the following entries: + // Entry 1 : Scom Register Address (0..31) + // Entry 2 : Scom Register Address (32..63) + // Entry 3 : Modifying Data (0..31) + // Entry 4 : Modifying Data (32..63) + // Entry 5 : Mask Data (0..31) + // Entry 6 : Mask Data (32..63) + // Entry 7 : EOT entry at the end + + uint32_t l_len2dequeue = sizeof(l_putScomUmaskMsg)/sizeof(uint32_t); + l_rc = sbeUpFifoDeq_mult (l_len2dequeue, + (uint32_t *)&l_putScomUmaskMsg); + + // If FIFO access failure + if (l_rc != SBE_SEC_OPERATION_SUCCESSFUL) + { + // Let command processor routine to handle the RC. + break; + } + + SBE_DEBUG(SBE_FUNC"scomAddr[0x%08X%08X]," + "modifyingData[0x%08X%08X]", + l_putScomUmaskMsg.hiAddr, + l_putScomUmaskMsg.lowAddr, + l_putScomUmaskMsg.hiInputData, + l_putScomUmaskMsg.lowInputData); + SBE_INFO(SBE_FUNC"maskData[0x%08X%08X]", + l_putScomUmaskMsg.hiMaskData, + l_putScomUmaskMsg.lowMaskData); + + // PutScomUnderMask formula: + // dest_reg = (dest_reg & ~input_mask) | (input_data & input_mask) + + do + { + uint64_t l_scomData = 0; + + uint64_t l_addr = ( (uint64_t) l_putScomUmaskMsg.hiAddr << 32) | + l_putScomUmaskMsg.lowAddr; + checkIndirectAndDoScom(true, l_addr, + l_scomData, &l_hdr, &l_ffdc); + + if (l_hdr.secondaryStatus == SBE_SEC_OPERATION_SUCCESSFUL) // scom success + { + l_putScomUmaskMsg.getScomData(l_scomData); + + // Write the modified data + checkIndirectAndDoScom(false, l_addr, + l_scomData, &l_hdr, &l_ffdc); + } + + if (l_hdr.secondaryStatus != SBE_SEC_OPERATION_SUCCESSFUL) // scom failed + { + SBE_ERROR(SBE_FUNC"scom failed, " + "ScomAddress[0x%08X%08X]", + l_putScomUmaskMsg.hiAddr, + l_putScomUmaskMsg.lowAddr); + SBE_ERROR(SBE_FUNC"modifyingData[0x%08X%08X]" + "maskData[0x%08X%08X]", + l_putScomUmaskMsg.hiInputData, + l_putScomUmaskMsg.lowInputData, + l_putScomUmaskMsg.hiMaskData, + l_putScomUmaskMsg.lowMaskData); + + break; + } + } while (false); + } while(false); + + if(l_rc == SBE_SEC_OPERATION_SUCCESSFUL) + { + // Build the response header packet + l_rc = sbeDsSendRespHdr(l_hdr, &l_ffdc); + // will let command processor routine + // handle the failure + } + + SBE_EXIT(SBE_FUNC); + return l_rc; + #undef SBE_FUNC +} + +///////////////////////////////////////////////////// +////////////////////////////////////////////////////// +uint32_t sbeMultiScom (uint8_t *i_pArg) +{ + #define SBE_FUNC " sbeMultiScom " + return 0; + #undef SBE_FUNC +} + diff --git a/src/sbefw/core/sbecmdscomaccess.H b/src/sbefw/core/sbecmdscomaccess.H new file mode 100644 index 00000000..bd448053 --- /dev/null +++ b/src/sbefw/core/sbecmdscomaccess.H @@ -0,0 +1,93 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbecmdscomaccess.H $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2017 */ +/* */ +/* */ +/* 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: ppe/sbe/sbefw/sbecmdscomaccess.H + * + * @brief This file contains the Interfaces for the SCOM Access chip-ops + * + */ + +#ifndef __SBEFW_SBECMDSCOMACCESS_H +#define __SBEFW_SBECMDSCOMACCESS_H + +#include <stdint.h> + +/** + * @brief sbeDownFifoGetStatus : Write data into Downstream FIFO + * + * @param[in] i_pArg Buffer to be passed to the function (not used as of now) + * + * @return Rc from the FIFO access utility + */ +uint32_t sbeGetScom (uint8_t *i_pArg); + + +/** + * @brief sbeDownFifoGetStatus : Write data into Downstream FIFO + * + * @param[in] i_pArg Buffer to be passed to the function (not used as of now) + * + * @return Rc from the FIFO access utility + */ +uint32_t sbePutScom (uint8_t *i_pArg); + + +/** + * @brief sbeModifyScom : Modify the Scom data + * This chipOp needs to do the following + * 1. Read Register Data (getscom) + * 2. modify the scomData using the given op mode + * 3. Write the modified Data into the Register (putscom) + * + * @param[in] i_pArg Buffer to be passed to the function (not used as of now) + * + * @return Rc from the FIFO access utility + */ +uint32_t sbeModifyScom (uint8_t *i_pArg); + + +/** + * @brief sbePutScomUnderMask : Write data into Downstream FIFO + * The following steps need to be done as part of this command : + * 1. Read Register Data (getscom) + * 2. 'AND' the Mask with the data read from register + * 3. 'OR' the modifying data with the result of step 2 + * 4. Write the result of step 3 into the register (putscom) + * + * @param[in] i_pArg Buffer to be passed to the function (not used as of now) + * + * @return Rc from the FIFO access utility + */ +uint32_t sbePutScomUnderMask (uint8_t *i_pArg); + +/** + * @brief sbeMultiScom: + * + * @param[in] i_pArg Buffer to be passed to the function (not used as of now) + * + * @return Rc from the FIFO access utility + */ +uint32_t sbeMultiScom (uint8_t *i_pArg); + +#endif /* __SBEFW_SBECMDSCOMACCESS_H */ diff --git a/src/sbefw/core/sbecmdsram.C b/src/sbefw/core/sbecmdsram.C new file mode 100644 index 00000000..ce05f7f6 --- /dev/null +++ b/src/sbefw/core/sbecmdsram.C @@ -0,0 +1,299 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbecmdsram.C $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* */ +/* */ +/* 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: ppe/sbe/sbefw/sbecmdsram.C + * + * @brief This file contains the SBE Sram Access chipOps + * + */ + +#include "sbecmdsram.H" +#include "sbefifo.H" +#include "sbe_sp_intf.H" +#include "sbetrace.H" +#include "sbeFifoMsgUtils.H" +#include "sberegaccess.H" +#include "sbeSecureMemRegionManager.H" + +#include "fapi2.H" +#include "p9_pm_ocb_init.H" +#include "p9_pm_ocb_indir_setup_linear.H" +#include "p9_pm_ocb_indir_access.H" +#include "p9_perv_scom_addresses.H" + +using namespace fapi2; + +#ifdef SEEPROM_IMAGE +// Using Function pointer to force long call +p9_pm_ocb_indir_setup_linear_FP_t p9_ocb_setup_linear_access_hwp = &p9_pm_ocb_indir_setup_linear; +p9_pm_ocb_indir_access_FP_t p9_ocb_indirect_access_hwp = &p9_pm_ocb_indir_access; +#endif + +/////////////////////////////////////////////////////////////////////// +// @brief sbeOccSramAccess_Wrap Occ Sran Access Wrapper function +// +// @param [in] i_isGetFlag Flag to indicate the sram Access Type +// true : GetOccSram ChipOp +// false : PutOccSram ChipOp +// +// @return RC from the underlying FIFO utility +/////////////////////////////////////////////////////////////////////// +uint32_t sbeOccSramAccess_Wrap(const bool i_isGetFlag) +{ + #define SBE_FUNC " sbeOccSramAccess_Wrap " + SBE_ENTER(SBE_FUNC); + + uint32_t l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + + ReturnCode l_fapiRc = FAPI2_RC_SUCCESS; + + sbeRespGenHdr_t l_respHdr; + l_respHdr.init(); + sbeResponseFfdc_t l_ffdc; + + // Total Returned length from the procedure + uint32_t l_totalReturnLen = 0; + + // Create the req struct for the OCC Sram Chip-op + sbeOccSramAccessReqMsgHdr_t l_req = {0}; + + // Check if True - Get / False - Put + p9ocb::PM_OCB_ACCESS_OP l_ocb_access = + (i_isGetFlag)? p9ocb::OCB_GET : p9ocb::OCB_PUT; + // Get the Req Struct Size Data from upstream Fifo + uint32_t l_len2dequeue = sizeof(l_req) / sizeof(uint32_t); + + do + { + l_rc = sbeUpFifoDeq_mult (l_len2dequeue, + (uint32_t *)&l_req, + i_isGetFlag); + + + CHECK_SBE_RC_AND_BREAK_IF_NOT_SUCCESS(l_rc); + SBE_INFO("mode [0x%08X] addr[0x%08X] len[0x%08X]", + (uint32_t)l_req.mode, + (uint32_t)l_req.addr, + (uint32_t)l_req.len); + + // Get the Proc Chip Target to be passed in to the procedure call + Target<fapi2::TARGET_TYPE_PROC_CHIP> l_proc = plat_getChipTarget(); + + // Do linear setup for indirect access HWP for Chan0, Chan2 and Chan3 + // For Circular Mode, Chan1 is assumed to be setup by default + // Linear mode is setup with Linear streaming mode only + + // Sram Access condition to pass valid address during the first access + bool l_validAddrForFirstAccess = true; + + // Channel Selection based on Mode as well as Fsp attchament + p9ocb::PM_OCB_CHAN_NUM l_chan = p9ocb::OCB_CHAN0; + switch(l_req.mode) + { + case NORMAL_MODE: + if(false == SbeRegAccess::theSbeRegAccess().isFspSystem()) + { + l_chan = p9ocb::OCB_CHAN2; + } + break; + + case DEBUG_MODE: + l_chan = p9ocb::OCB_CHAN3; + break; + + case CIRCULAR_MODE: + l_chan = p9ocb::OCB_CHAN1; + l_validAddrForFirstAccess = false; + break; + + default: + SBE_ERROR(SBE_FUNC "Invalid Mode Passed by User"); + l_rc = SBE_SEC_GENERIC_FAILURE_IN_EXECUTION; + l_respHdr.setStatus( SBE_PRI_INVALID_DATA, l_rc); + break; + } + CHECK_SBE_RC_AND_BREAK_IF_NOT_SUCCESS(l_rc); + // Check if the access to the address is allowed + if(l_validAddrForFirstAccess) + { + l_respHdr.secondaryStatus = occSramSecRegionManager.isAccessAllowed( + {static_cast<uint64_t>(l_req.addr)&(0x00000000FFFFFFFFull), + l_req.len, + (i_isGetFlag? static_cast<uint8_t>(memRegionMode::READ): + static_cast<uint8_t>(memRegionMode::WRITE))}); + if(l_respHdr.secondaryStatus != SBE_SEC_OPERATION_SUCCESSFUL) + { + l_respHdr.primaryStatus = SBE_PRI_UNSECURE_ACCESS_DENIED; + break; + } + } + + // Setup Needs to be called in Normal and Debug Mode only + if( (l_req.mode == NORMAL_MODE) || (l_req.mode == DEBUG_MODE) ) + { + SBE_EXEC_HWP(l_fapiRc, p9_ocb_setup_linear_access_hwp,l_proc, l_chan, + p9ocb::OCB_TYPE_LINSTR, + l_req.addr) + if(l_fapiRc != FAPI2_RC_SUCCESS) + { + SBE_ERROR(SBE_FUNC "p9_pm_ocb_indir_setup_linear failed, " + "Channel[0x%02X] Addr[0x%08X]", + l_chan, l_req.addr); + + // Respond with HWP FFDC + l_respHdr.setStatus(SBE_PRI_GENERIC_EXECUTION_FAILURE, + SBE_SEC_GENERIC_FAILURE_IN_EXECUTION); + l_ffdc.setRc(l_fapiRc); + break; + } + } + + //Create a 128 Byte Buffer - 16 64-Bit buffer + // This is our Granule size as well for this HWP + uint32_t l_getBuf[SBE_OCC_SRAM_GRANULE/SBE_32BIT_ALIGN_FACTOR] = {}; + uint32_t l_remainingLen = l_req.len; // Initialize with Total Len + uint32_t l_lenPassedToHwp = 0; + uint32_t l_actLen = 0; // Return Len from Hwp not used + + while(l_remainingLen) + { + if(l_remainingLen <= SBE_OCC_SRAM_GRANULE) + { + l_lenPassedToHwp = l_remainingLen; + } + else + { + l_lenPassedToHwp = SBE_OCC_SRAM_GRANULE; + } + l_remainingLen = l_remainingLen - l_lenPassedToHwp; + + // Fetch buffer from Upstream Fifo for the HWP if it is PutOCC Sram + if(!i_isGetFlag) + { + l_len2dequeue = (l_lenPassedToHwp/SBE_32BIT_ALIGN_FACTOR); + l_rc = sbeUpFifoDeq_mult ( l_len2dequeue, + l_getBuf, + false); + CHECK_SBE_RC_AND_BREAK_IF_NOT_SUCCESS(l_rc); + } + + // Don't need to put any check for Linear/Circular - It's the same + // API for access, For circular valid address flag is false, Hwp + // doesn't need the address field from us. + SBE_EXEC_HWP(l_fapiRc, + p9_ocb_indirect_access_hwp, + l_proc, + l_chan, + l_ocb_access, // Get/Put + (l_lenPassedToHwp/SBE_64BIT_ALIGN_FACTOR), // 64-bit aligned + l_validAddrForFirstAccess, // If requested addr is valid + l_req.addr, // Requested Addr being passed + l_actLen, // O/p from hwp not used + (uint64_t *)l_getBuf) // O/p buffer + if(l_fapiRc != FAPI2_RC_SUCCESS) + { + SBE_ERROR(SBE_FUNC "p9_pm_ocb_indir_access failed, " + "Channel[0x%02X] Addr[0x%08X] 64Bit Aligned Len[0x%08X]", + l_chan, l_req.addr, (l_lenPassedToHwp/SBE_64BIT_ALIGN_FACTOR)); + + // Respond with HWP FFDC + l_respHdr.setStatus(SBE_PRI_GENERIC_EXECUTION_FAILURE, + SBE_SEC_GENERIC_FAILURE_IN_EXECUTION); + l_ffdc.setRc(l_fapiRc); + break; + } + + l_totalReturnLen = l_totalReturnLen + l_lenPassedToHwp; + // Change this to false, so that Indirect Access Hwp doesn't + // reset the Address to starting point. + l_validAddrForFirstAccess = false; + + if(i_isGetFlag) // Get Occ Sram + { + l_len2dequeue = (l_lenPassedToHwp/SBE_32BIT_ALIGN_FACTOR); + // Push this into the downstream FIFO + l_rc = sbeDownFifoEnq_mult (l_len2dequeue, l_getBuf); + CHECK_SBE_RC_AND_BREAK_IF_NOT_SUCCESS(l_rc); + + } + } // End of while Put/Get from Hwp + }while(0); + + do + { + // If there was a FIFO error, will skip sending the response, + // instead give the control back to the command processor thread + CHECK_SBE_RC_AND_BREAK_IF_NOT_SUCCESS(l_rc); + l_len2dequeue = 0; + if (!i_isGetFlag) + { + // If there was a HWP failure for put sram occ request, + // need to Flush out upstream FIFO, until EOT arrives + if ( l_respHdr.primaryStatus != SBE_PRI_OPERATION_SUCCESSFUL) + { + l_rc = sbeUpFifoDeq_mult(l_len2dequeue, NULL, + true, true); + CHECK_SBE_RC_AND_BREAK_IF_NOT_SUCCESS(l_rc); + } + // For other success paths, just attempt to offload + // the next entry, which is supposed to be the EOT entry + else + { + l_rc = sbeUpFifoDeq_mult(l_len2dequeue, NULL, true); + CHECK_SBE_RC_AND_BREAK_IF_NOT_SUCCESS(l_rc); + } + } + + uint32_t l_len = 1; + // first enqueue the length of data actually written + l_rc = sbeDownFifoEnq_mult(l_len, (uint32_t *)(&l_totalReturnLen)); + + CHECK_SBE_RC_AND_BREAK_IF_NOT_SUCCESS(l_rc); + l_rc = sbeDsSendRespHdr( l_respHdr, &l_ffdc); + }while(0); + + SBE_EXIT(SBE_FUNC); + return l_rc; + #undef SBE_FUNC +} + + +////////////////////////////////////////////////////// +////////////////////////////////////////////////////// +uint32_t sbePutOccSram (uint8_t *i_pArg) +{ + #define SBE_FUNC " sbePutOccSram " + return sbeOccSramAccess_Wrap (false); + #undef SBE_FUNC +} + +///////////////////////////////////////////////////// +////////////////////////////////////////////////////// +uint32_t sbeGetOccSram (uint8_t *i_pArg) +{ + #define SBE_FUNC " sbeGetOccSram " + return sbeOccSramAccess_Wrap (true); + #undef SBE_FUNC +} + diff --git a/src/sbefw/core/sbecmdsram.H b/src/sbefw/core/sbecmdsram.H new file mode 100644 index 00000000..3dd0977b --- /dev/null +++ b/src/sbefw/core/sbecmdsram.H @@ -0,0 +1,64 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbecmdsram.H $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* */ +/* */ +/* 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: ppe/sbe/sbefw/sbecmdsram.H + * + * @brief This file contains the Interfaces for the Sram Access chip-ops + * + */ + +#ifndef __SBEFW_SBECMDSRAM_H +#define __SBEFW_SBECMDSRAM_H + +#include <stdint.h> + +static const uint8_t SBE_32BIT_ALIGN_FACTOR = 4; +static const uint8_t SBE_64BIT_ALIGN_FACTOR = 8; + +static const uint64_t SBE_FWCTRLFLG3_FSP_ATTACHED = 0X1000000000000000; + +/* + * @brief Granule size in Bytes for 'Get from Hwp'/'Put to Hwp' + */ +static const uint32_t SBE_OCC_SRAM_GRANULE = 128; + +/** + * @brief sbeGetOccSram : Implements SBE Get Occ Sram ChipOp + * + * @param[in] i_pArg Buffer to be passed to the function (not used as of now) + * + * @return Rc from the FIFO access utility + */ +uint32_t sbeGetOccSram (uint8_t *i_pArg); + +/** + * @brief sbePutOccSram : Implements SBE Put Occ Sram ChipOp + * + * @param[in] i_pArg Buffer to be passed to the function (not used as of now) + * + * @return Rc from the FIFO access utility + */ +uint32_t sbePutOccSram (uint8_t *i_pArg); + +#endif /* __SBEFW_SBECMDSRAM_H */ diff --git a/src/sbefw/core/sbecmdtracearray.C b/src/sbefw/core/sbecmdtracearray.C new file mode 100644 index 00000000..89641d15 --- /dev/null +++ b/src/sbefw/core/sbecmdtracearray.C @@ -0,0 +1,156 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbecmdtracearray.C $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* */ +/* */ +/* 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: ppe/sbe/sbefw/sbecmdtracearray.C + * + * @brief This file contains the SBE Control Tracearray chipOp + * + */ +#include "sbecmdtracearray.H" +#include "sbefifo.H" +#include "sbe_sp_intf.H" +#include "sbetrace.H" +#include "sbeFifoMsgUtils.H" +#include "sbeutil.H" +#include "sbefapiutil.H" +#include "fapi2.H" + +#include "p9_sbe_tracearray.H" + +using namespace fapi2; + +constexpr uint32_t SBE_TRACE_GRANULE_NUM_ROWS = 1; +constexpr uint32_t SBE_TRACEARRAY_BYTES_PER_ROW = + (P9_TRACEARRAY_BITS_PER_ROW / 8); +constexpr uint32_t SBE_TRACE_GRANULE_NUM_WORDS = + (SBE_TRACE_GRANULE_NUM_ROWS * SBE_TRACEARRAY_BYTES_PER_ROW) / + sizeof(uint32_t); + +#ifdef SEEPROM_IMAGE +p9_sbe_tracearray_FP_t p9_sbe_tracearray_hwp = &p9_sbe_tracearray; +#endif + +uint32_t sbeControlTraceArray(uint8_t *i_pArg) +{ + #define SBE_FUNC " sbeControlTraceArray" + SBE_ENTER(SBE_FUNC); + uint32_t l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + + sbeControlTraceArrayCMD_t l_req = {}; + sbeRespGenHdr_t respHdr; + respHdr.init(); + sbeResponseFfdc_t l_ffdc; + ReturnCode l_fapiRc; + uint32_t l_NumWordsRead = 0; + uint32_t l_len = 0; + + do + { + l_len = sizeof(sbeControlTraceArrayCMD_t)/sizeof(uint32_t); + l_rc = sbeUpFifoDeq_mult (l_len, (uint32_t *)&l_req); //EOT fetch + + // If FIFO access failure + CHECK_SBE_RC_AND_BREAK_IF_NOT_SUCCESS(l_rc); + + SBE_INFO(SBE_FUNC" targetType [0x%04X] chipletId [0x%02X]" + " traceArrayId [0x%04X] operation [0x%04X]", + l_req.targetType, + l_req.chipletId, + l_req.traceArrayId, + l_req.operation); + + // Construct a Target from Chiplet ID and Target Type + fapi2::plat_target_handle_t l_tgtHndl; + if(!sbeGetFapiTargetHandle(l_req.targetType, l_req.chipletId, + l_tgtHndl)) + { + SBE_ERROR(SBE_FUNC "Invalid target type [0x%04x]", + (uint16_t)l_req.targetType); + respHdr.setStatus(SBE_PRI_INVALID_DATA, + SBE_SEC_INVALID_TARGET_TYPE_PASSED); + break; + } + proc_gettracearray_args l_args = {}; + // Fill trace array Id + l_args.trace_bus = (p9_tracearray_bus_id)l_req.traceArrayId; + // Fill control arguments + l_args.reset_post_dump = (l_req.operation & SBE_TA_RESET); + l_args.restart_post_dump = (l_req.operation & SBE_TA_RESTART); + l_args.stop_pre_dump = (l_req.operation & SBE_TA_STOP); + l_args.collect_dump = (l_req.operation & SBE_TA_COLLECT_DUMP); + l_args.ignore_mux_setting = (l_req.operation & + SBE_TA_IGNORE_MUX_SETTING); + + uint64_t l_buffer[SBE_TRACE_GRANULE_NUM_WORDS/2] = {}; + for(uint32_t l_cur_row = 0; l_cur_row < P9_TRACEARRAY_NUM_ROWS; + l_cur_row++) + { + SBE_EXEC_HWP(l_fapiRc, p9_sbe_tracearray_hwp, + l_tgtHndl, + l_args, + l_buffer, + l_cur_row, + SBE_TRACE_GRANULE_NUM_ROWS); + if(l_fapiRc != FAPI2_RC_SUCCESS) + { + SBE_ERROR("p9_sbe_tracearray failed"); + // Respond with HWP FFDC + respHdr.setStatus( SBE_PRI_GENERIC_EXECUTION_FAILURE, + SBE_SEC_GENERIC_FAILURE_IN_EXECUTION ); + l_ffdc.setRc(l_fapiRc); + break; + } + + // If dump is not requested, break from the loop + if(!l_args.collect_dump) + break; + + // Put the buffer onto Fifo + SBE_DEBUG(SBE_FUNC " sending row [%d]", l_cur_row); + l_len = SBE_TRACE_GRANULE_NUM_WORDS; + l_rc = sbeDownFifoEnq_mult (l_len, + reinterpret_cast<uint32_t *>(l_buffer)); + CHECK_SBE_RC_AND_BREAK_IF_NOT_SUCCESS(l_rc); + l_NumWordsRead += SBE_TRACE_GRANULE_NUM_WORDS; + } + + } while(false); + + // Now build and enqueue response into downstream FIFO + // If there was a FIFO error, will skip sending the response, + // instead give the control back to the command processor thread + if ( SBE_SEC_OPERATION_SUCCESSFUL == l_rc ) + { + SBE_INFO(SBE_FUNC " l_NumWordsRead [%d]", l_NumWordsRead); + l_len = sizeof(l_NumWordsRead)/sizeof(uint32_t); + l_rc = sbeDownFifoEnq_mult (l_len, &l_NumWordsRead); + if(SBE_SEC_OPERATION_SUCCESSFUL == l_rc) + { + l_rc = sbeDsSendRespHdr( respHdr, &l_ffdc); + } + } + SBE_EXIT(SBE_FUNC); + return l_rc; + #undef SBE_FUNC +} diff --git a/src/sbefw/core/sbecmdtracearray.H b/src/sbefw/core/sbecmdtracearray.H new file mode 100644 index 00000000..af8362fd --- /dev/null +++ b/src/sbefw/core/sbecmdtracearray.H @@ -0,0 +1,54 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbecmdtracearray.H $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* */ +/* */ +/* 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: ppe/sbe/sbefw/sbecmdtracearray.H + * + * @brief This file contains the Interfaces for the Tracearray Control chip-op + * + */ + +#ifndef __SBEFW_SBECMDTRACEARRAY_H +#define __SBEFW_SBECMDTRACEARRAY_H + +#include <stdint.h> + +typedef struct +{ + uint32_t targetType:16; + uint32_t reserved:8; + uint32_t chipletId:8; + uint32_t traceArrayId:16; + uint32_t operation:16; +} sbeControlTraceArrayCMD_t; + +/** + * @brief Control Trace Array Command (0xA602) + * + * @param[in] i_pArg Buffer to be passed to the function (not used as of now) + * + * @return RC from the FIFO access utility + */ +uint32_t sbeControlTraceArray(uint8_t *i_pArg); + +#endif //__SBEFW_SBECMDTRACEARRAY_H diff --git a/src/sbefw/core/sbecorefiles.mk b/src/sbefw/core/sbecorefiles.mk new file mode 100644 index 00000000..3cfe235f --- /dev/null +++ b/src/sbefw/core/sbecorefiles.mk @@ -0,0 +1,60 @@ +# IBM_PROLOG_BEGIN_TAG +# This is an automatically generated prolog. +# +# $Source: src/sbefw/core/sbecorefiles.mk $ +# +# OpenPOWER sbe Project +# +# Contributors Listed Below - COPYRIGHT 2015,2017 +# +# +# 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 +SBECORE-CPP-SOURCES = sbemain.C +SBECORE-CPP-SOURCES += sbeirq.C +SBECORE-CPP-SOURCES += sbecmdreceiver.C +SBECORE-CPP-SOURCES += sbecmdprocessor.C +SBECORE-CPP-SOURCES += sbecmdparser.C +SBECORE-CPP-SOURCES += sbecmdscomaccess.C +SBECORE-CPP-SOURCES += sbecmdiplcontrol.C +SBECORE-CPP-SOURCES += pool.C +SBECORE-CPP-SOURCES += sbecmdgeneric.C +SBECORE-CPP-SOURCES += sbeFifoMsgUtils.C +SBECORE-CPP-SOURCES += sbecmdmemaccess.C +SBECORE-CPP-SOURCES += sbeHostUtils.C +SBECORE-CPP-SOURCES += sbecmdcntrldmt.C +SBECORE-CPP-SOURCES += sbecmdsram.C +SBECORE-CPP-SOURCES += sberegaccess.C +SBECORE-CPP-SOURCES += sbecmdcntlinst.C +SBECORE-CPP-SOURCES += sbecmdregaccess.C +SBECORE-CPP-SOURCES += sbeFFDC.C +SBECORE-CPP-SOURCES += sbecmdringaccess.C +SBECORE-CPP-SOURCES += sbescom.C +SBECORE-CPP-SOURCES += sbecmdmpipl.C +SBECORE-CPP-SOURCES += sbefapiutil.C +SBECORE-CPP-SOURCES += sbeutil.C +SBECORE-CPP-SOURCES += sbecmdtracearray.C +SBECORE-CPP-SOURCES += sbeTimerSvc.C +SBECORE-CPP-SOURCES += sbecmdCntrlTimer.C +SBECORE-CPP-SOURCES += sbeHostMsg.C +SBECORE-CPP-SOURCES += sbeSpMsg.C +SBECORE-CPP-SOURCES += sbeglobals.C +SBECORE-CPP-SOURCES += sbeMemAccessInterface.C +SBECORE-CPP-SOURCES += sbeSecureMemRegionManager.C +SBECORE-CPP-SOURCES += sbeSecurity.C + +SBECORE-C-SOURCES = +SBECORE-S-SOURCES = + +SBECORE_OBJECTS = $(SBECORE-C-SOURCES:.c=.o) $(SBECORE-CPP-SOURCES:.C=.o) $(SBECORE-S-SOURCES:.S=.o) diff --git a/src/sbefw/core/sbecoreseepromfiles.mk b/src/sbefw/core/sbecoreseepromfiles.mk new file mode 100644 index 00000000..5c82f5a3 --- /dev/null +++ b/src/sbefw/core/sbecoreseepromfiles.mk @@ -0,0 +1,34 @@ +# IBM_PROLOG_BEGIN_TAG +# This is an automatically generated prolog. +# +# $Source: src/sbefw/core/sbecoreseepromfiles.mk $ +# +# OpenPOWER sbe Project +# +# Contributors Listed Below - COPYRIGHT 2015,2017 +# +# +# 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 +SBECORESEEPROM-CPP-SOURCES = sbecmdgeneric.C +SBECORESEEPROM-CPP-SOURCES += sbecmdmpipl.C +SBECORESEEPROM-CPP-SOURCES += sbecmdmemaccess.C +SBECORESEEPROM-CPP-SOURCES += sbeSecureMemRegionManager.C +SBECORESEEPROM-CPP-SOURCES += sbecmdiplcontrol.C +SBECORESEEPROM-CPP-SOURCES += sbecmdfastarray.C + +SBECORESEEPROM-C-SOURCES = +SBECORESEEPROM-S-SOURCES = + +SBECORESEEPROM_OBJECTS = $(SBECORESEEPROM-C-SOURCES:.c=.o) $(SBECORESEEPROM-CPP-SOURCES:.C=.o) $(SBECORESEEPROM-S-SOURCES:.S=.o) diff --git a/src/sbefw/core/sbeerrorcodes.H b/src/sbefw/core/sbeerrorcodes.H new file mode 100644 index 00000000..01665ba8 --- /dev/null +++ b/src/sbefw/core/sbeerrorcodes.H @@ -0,0 +1,49 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbeerrorcodes.H $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* */ +/* */ +/* 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: ppe/sbe/sbefw/sbeerrorcodes.H + * + * @brief This file contains the SBE internal error status codes + * + */ + +#ifndef __SBEFW_SBEERRORCODES_H +#define __SBEFW_SBEERRORCODES_H + +#include <stdint.h> + + +/** + * @brief enums SBE internal error codes + * +*/ +enum sbeInternalResponseCodes +{ + SBE_FIFO_RESET_RECEIVED = 0xFA00, + SBE_FIFO_RESET_HANDLING_FAILED = 0xFB00, + SBE_FUNC_NOT_SUPPORTED = 0xFC00, +}; + + +#endif // __SBEFW_SBEERRORCODES_H
\ No newline at end of file diff --git a/src/sbefw/core/sbeevents.H b/src/sbefw/core/sbeevents.H new file mode 100644 index 00000000..783dc183 --- /dev/null +++ b/src/sbefw/core/sbeevents.H @@ -0,0 +1,89 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbeevents.H $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* */ +/* */ +/* 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: ppe/sbe/sbefw/sbeevents.H + * + * @brief This file contains interfaces pertaining to the events for state + * transition trigger. + * + */ + +#ifndef __SBEFW_SBEEVENTS_H +#define __SBEFW_SBEEVENTS_H + +/** + * @brief An enumeration of all SBE state transition events + * + */ +enum sbeEvent +{ + SBE_RUNTIME_EVENT = 0x0, // From Unknown/ISTEP/IPLING State + SBE_ISTEP_EVENT = 0x1, // From Unknown State + SBE_PLCK_EVENT = 0x2, // From Unknown state + SBE_DUMP_FAILURE_EVENT = 0x3, // From IPLING/RUNTIME/MPIPL/DMT/Unknown State + SBE_ENTER_MPIPL_EVENT = 0x4, // From Runtime State + SBE_CONTINUE_MPIPL_EVENT = 0x5, // From MPIPL Wait State + SBE_DMT_ENTER_EVENT = 0x6, // From Runtime State + SBE_DMT_COMP_EVENT = 0x7, // From DMT State + SBE_FAILURE_EVENT = 0x8, // From Any State + SBE_QUIESCE_EVENT = 0x9, // From Any State +}; + +// Maximum number of Events per State +enum maxEventPerState +{ + SBE_STATE_UNKNOWN_MAX_EVENT = 4, + SBE_STATE_IPLING_MAX_EVENT = 4, + SBE_STATE_ISTEP_MAX_EVENT = 3, + SBE_STATE_MPIPL_MAX_EVENT = 3, + SBE_STATE_RUNTIME_MAX_EVENT = 5, + SBE_STATE_DMT_MAX_EVENT = 3, + SBE_STATE_DUMP_MAX_EVENT = 0, + SBE_STATE_FAILURE_MAX_EVENT = 0, + SBE_STATE_QUIESCE_MAX_EVENT = 0, + + // Total number of State Transition Events, Addition of all the above + SBE_MAX_TRANSITIONS = 22, +}; + + +// Entry Point to stateTransitionStr_t Map Structure, This adds up all the state +// transition of the previous state, If any more transition is added, this will +// add up to all subsequent entries. This is closely mapped with the sbestates.H +// as well. +enum entryToStateMap +{ + SBE_STATE_UNKNOWN_ENTRY_TO_MAP = 0, + SBE_STATE_IPLING_ENTRY_TO_MAP = SBE_STATE_UNKNOWN_ENTRY_TO_MAP + SBE_STATE_UNKNOWN_MAX_EVENT, // 4 + SBE_STATE_ISTEP_ENTRY_TO_MAP = SBE_STATE_IPLING_ENTRY_TO_MAP + SBE_STATE_IPLING_MAX_EVENT, //8 + SBE_STATE_MPIPL_ENTRY_TO_MAP = SBE_STATE_ISTEP_ENTRY_TO_MAP + SBE_STATE_ISTEP_MAX_EVENT, //11 + SBE_STATE_RUNTIME_ENTRY_TO_MAP = SBE_STATE_MPIPL_ENTRY_TO_MAP + SBE_STATE_MPIPL_MAX_EVENT, //14 + SBE_STATE_DMT_ENTRY_TO_MAP = SBE_STATE_RUNTIME_ENTRY_TO_MAP + SBE_STATE_RUNTIME_MAX_EVENT, //19 + SBE_STATE_DUMP_ENTRY_TO_MAP = SBE_STATE_DMT_ENTRY_TO_MAP + SBE_STATE_DMT_MAX_EVENT, //22 + SBE_STATE_FAILURE_ENTRY_TO_MAP = SBE_STATE_DUMP_ENTRY_TO_MAP + SBE_STATE_DUMP_MAX_EVENT, //22 + SBE_STATE_QUIESCE_ENTRY_TO_MAP = SBE_STATE_FAILURE_ENTRY_TO_MAP + SBE_STATE_FAILURE_MAX_EVENT, //22 +}; + +#endif //__SBEFW_SBEEVENTS_H + diff --git a/src/sbefw/core/sbeexeintf.H b/src/sbefw/core/sbeexeintf.H new file mode 100644 index 00000000..80d89586 --- /dev/null +++ b/src/sbefw/core/sbeexeintf.H @@ -0,0 +1,235 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbeexeintf.H $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2017 */ +/* */ +/* */ +/* 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: ppe/sbe/sbefw/sbeexeintf.H + * + * @brief This file contains the SBE control loop firmware details like + * - Thread priority enums + * - Thread stack size and space enums + * - Thread sub-rountine declarations + * - IRQ setup and ISR declarations + * - Other Common declaration among all the threads + */ + +#ifndef __SBEFW_SBE_H +#define __SBEFW_SBE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "pk.h" + +#ifdef __cplusplus +} +#endif + +/** + * @brief enums for priorities for thread creation + * + */ +typedef enum +{ + THREAD_PRIORITY_MAX_0, + THREAD_PRIORITY_1, + THREAD_PRIORITY_2, + THREAD_PRIORITY_3, + THREAD_PRIORITY_4, + THREAD_PRIORITY_5, + THREAD_PRIORITY_6, + THREAD_PRIORITY_7, + THREAD_PRIORITY_8, + THREAD_PRIORITY_MIN_30 = 30, +} sbeThreadPriorities ; + +/** + * @brief enums for thread stack sizes + * - Non-Critical Stack used by non-critical interrupt handlers + * - Critical Stack used for critical interrupts + * - Stacks for each thread + * + * @TODO via RTC : 128657 + * - Measure the actual thread stack utilization + * - This will be a continuous activity + */ +enum sbeThreadStackSize +{ + SBE_NONCRITICAL_STACK_SIZE = 512, + SBE_THREAD_ASYNC_CMD_PROC_STACK_SIZE = 256, + SBE_THREAD_CMD_RECV_STACK_SIZE = 512, + SBE_THREAD_SYNC_CMD_PROC_STACK_SIZE = 2048, +}; + +/** + * @brief SBE Interface source + * + */ +typedef enum +{ + SBE_INTERFACE_UNKNOWN = 0x00, + SBE_INTERFACE_FIFO = 0x01, + SBE_INTERFACE_PSU = 0x02, + SBE_INTERFACE_FIFO_RESET = 0x04, +} sbeInterfaceSrc_t; + +/* + * @brief Enum for Handler, handling the interrupt and setting/clearing the + * interrupt variable + */ +typedef enum +{ + SBE_ALL_HANDLER = 0x0, + SBE_INTERRUPT_ROUTINE = 0x1, + SBE_RX_ROUTINE = 0x2, + SBE_PROC_ROUTINE = 0x3, +} sbeHandler_t; + +/** + * @brief structure for SBE external Interrupt handling + * + */ +typedef struct +{ + uint8_t intrSource; + uint8_t rxThrIntrSource; + uint8_t procThrIntrSource; + + void setIntrSource(const sbeHandler_t i_handler, + const sbeInterfaceSrc_t i_val) + { + switch(i_handler) + { + case SBE_INTERRUPT_ROUTINE: intrSource |= i_val; break; + case SBE_RX_ROUTINE: rxThrIntrSource |= i_val; break; + case SBE_PROC_ROUTINE: procThrIntrSource |= i_val; break; + case SBE_ALL_HANDLER: break; + } + } + + void clearIntrSource(const sbeHandler_t i_handler, + const sbeInterfaceSrc_t i_val) + { + switch(i_handler) + { + case SBE_INTERRUPT_ROUTINE: intrSource &= ~i_val; break; + case SBE_RX_ROUTINE: rxThrIntrSource &= ~i_val; break; + case SBE_PROC_ROUTINE: procThrIntrSource &= ~i_val; break; + case SBE_ALL_HANDLER: + { + intrSource &= ~i_val; + rxThrIntrSource &= ~i_val; + procThrIntrSource &= ~i_val; + break; + } + } + } + + bool isSet (const sbeHandler_t i_handler, const sbeInterfaceSrc_t i_val) + { + bool l_ret = false; + switch(i_handler) + { + case SBE_INTERRUPT_ROUTINE: l_ret = (intrSource & i_val); break; + case SBE_RX_ROUTINE: l_ret = (rxThrIntrSource & i_val); break; + case SBE_PROC_ROUTINE: l_ret = (procThrIntrSource & i_val); break; + case SBE_ALL_HANDLER: break; + } + return l_ret; + } +} sbeIntrHandle_t; + +/** + * @TODO via RTC : 128658 + * Mutex protect the critical data + * e.g., add Mutex g_sbeMutCmdReqBuf etc. + */ + +/** + * @brief sbeCommandReceiver_routine + * The major responsibilities of this thread are : + * - Determine the reason for the interrupt + * - FIFO New data + * - FIFO reset + * - Host services + * - Dequeue the mandatory 2 entry header from upstream FIFO + * - Command input data validation + * - SBE State and pre-requirements validation + * - FFDC collection and FIFO flush upon validation failure + * - Unblock SBE command processor thread + * - Perform FIFO reset upon request from SP + * + * @param[in] i_pArg - Any buffer needed to be passed to the thread routine + */ +void sbeCommandReceiver_routine(void *i_pArg); + +/** + * @brief sbeSyncCommandProcessor_routine + * The major responsibilities of this thread are : + * - Dequeue data payload from upstream FIFO + * - Un-marshalling of the command request data + * - Blacklist validation + * - FFDC collection upon validation failure + * - Invoke the corresponding Hardware access utility + * or the HWP corresponding to the chipOp request + * - FFDC collection and FIFO flush upon hardware access / HWP failure + * - Build the response buffer with the data and the header + * - Enqueue the response into the Downstream FIFO + * - Un-mask the new data available interrupt + * + * @param[in] i_pArg - Any buffer needed to be passed to the thread routine + */ +void sbeSyncCommandProcessor_routine(void *i_pArg); + +/** + * @brief sbeAsyncCommandProcessor_routine + * @TODO RTC via : 130392 + * Add infrastructure for host interface + * + * @param[in] i_pArg - Any buffer needed to be passed to the thread routine + */ +void sbeAsyncCommandProcessor_routine(void *i_pArg); + + +/* @brief ISR for all SBE External Interrupts + * - FIFO : New data available + * - FIFO : Reset Request + * - PSU : New data available + * + * @param[in/out] i_pArg - Any buffer needed to be passed to the handler + * @param[in] i_irq - IRQ number as defined in the SBE PPE spec + */ +void sbe_interrupt_handler(void* i_pArg, PkIrqId i_irq); + + +/* brief : Register SBE interrupt handlers and enable the IRQs + * + * @return int PK_OK - Success (IRQ Setup was successful) + * PK_INVALID_ARGUMENT_IRQ_HANDLER - Invalid argument passed + * (Code bug) + * + */ +int sbeIRQSetup (void); + + +#endif /* __SBEFW_SBE_H */ diff --git a/src/sbefw/core/sbefapiutil.C b/src/sbefw/core/sbefapiutil.C new file mode 100644 index 00000000..b7cabc29 --- /dev/null +++ b/src/sbefw/core/sbefapiutil.C @@ -0,0 +1,150 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbefapiutil.C $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* */ +/* */ +/* 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: ppe/src/sbefw/sbefapiutil.C + * + * @brief This file contains the SBE FAPI Utility + * + */ + +#include "sbefapiutil.H" + +using namespace fapi2; + +fapi2::TargetType sbeGetFapiTargetType(const uint16_t i_sbeTargetType, + const uint16_t i_chipletId) +{ + TargetType l_fapiTargetType = TARGET_TYPE_NONE; + switch(i_sbeTargetType) + { + case TARGET_EX: + if((i_chipletId >= SMT4_CORE0_ID) && + (i_chipletId <= SMT4_CORE_ID_LAST)) + { + l_fapiTargetType = fapi2::TARGET_TYPE_EX; + } + break; + case TARGET_PERV: + if((i_chipletId >= EQ_ID_0) && (i_chipletId <= EQ_ID_LAST)) + { + l_fapiTargetType = fapi2::TARGET_TYPE_EQ; + } + else if((i_chipletId >= SMT4_CORE0_ID) && + (i_chipletId <= SMT4_CORE_ID_LAST)) + { + l_fapiTargetType = fapi2::TARGET_TYPE_CORE; + } + else + { + l_fapiTargetType = fapi2::TARGET_TYPE_PERV; + } + break; + case TARGET_PROC_CHIP: + l_fapiTargetType = fapi2::TARGET_TYPE_PROC_CHIP; + break; + } + return l_fapiTargetType; +} + +bool sbeGetFapiTargetHandle(const uint16_t i_targetType, + const uint16_t i_chipletId, + fapi2::plat_target_handle_t &o_tgtHndl, + const fapi2::TargetType i_fapiTargetMask) +{ + bool l_rc = true; + + do + { + if(((i_targetType == TARGET_TYPE_CORE) && + (i_chipletId == SMT4_ALL_CORES)) || + ((i_targetType == TARGET_TYPE_EQ) && + (i_chipletId == EQ_ALL_CHIPLETS))) + { + // It's a valid combination for all cores/all EQs + break; + } + fapi2::TargetType l_fapiTargetType = static_cast<TargetType>( + sbeGetFapiTargetType(i_targetType, i_chipletId) + & i_fapiTargetMask); + switch(l_fapiTargetType) + { + case fapi2::TARGET_TYPE_EX: + o_tgtHndl = plat_getTargetHandleByChipletNumber + <fapi2::TARGET_TYPE_EX>(i_chipletId); + break; + case fapi2::TARGET_TYPE_PERV: + o_tgtHndl = plat_getTargetHandleByChipletNumber + <fapi2::TARGET_TYPE_PERV>(i_chipletId); + break; + case fapi2::TARGET_TYPE_EQ: + o_tgtHndl = plat_getTargetHandleByChipletNumber + <fapi2::TARGET_TYPE_EQ>(i_chipletId); + break; + case fapi2::TARGET_TYPE_CORE: + o_tgtHndl = plat_getTargetHandleByChipletNumber + <fapi2::TARGET_TYPE_CORE>(i_chipletId); + break; + case fapi2::TARGET_TYPE_PROC_CHIP: + o_tgtHndl = plat_getChipTarget().get(); + break; + default: + l_rc = false; + break; + } + } while(false); + return l_rc; +} + +uint16_t sbeToFapiRingMode(uint16_t i_ringMode) +{ + uint16_t l_fapiRingMode = RING_MODE_HEADER_CHECK; + + if(i_ringMode & SBE_RING_MODE_SET_PULSE_NO_OPCG_COND) + { + l_fapiRingMode |= RING_MODE_SET_PULSE_NO_OPCG_COND; + } + if(i_ringMode & SBE_RING_MODE_NO_HEADER_CHECK) + { + l_fapiRingMode |= RING_MODE_NO_HEADER_CHECK; + } + if(i_ringMode & SBE_RING_MODE_SET_PULSE_NSL) + { + l_fapiRingMode |= RING_MODE_SET_PULSE_NSL; + } + if(i_ringMode & SBE_RING_MODE_SET_PULSE_SL) + { + l_fapiRingMode |= RING_MODE_SET_PULSE_SL; + } + if(i_ringMode & SBE_RING_MODE_SET_PULSE_ALL) + { + l_fapiRingMode |= RING_MODE_SET_PULSE_ALL; + } + if(i_ringMode & SBE_RING_MODE_FASTARRAY) + { + l_fapiRingMode |= RING_MODE_FASTARRAY; + } + return l_fapiRingMode; +} + + diff --git a/src/sbefw/core/sbefapiutil.H b/src/sbefw/core/sbefapiutil.H new file mode 100644 index 00000000..c2e72387 --- /dev/null +++ b/src/sbefw/core/sbefapiutil.H @@ -0,0 +1,76 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbefapiutil.H $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* */ +/* */ +/* 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: ppe/src/sbefw/sbefapiutil.H + * + * @brief This file contains the SBE FAPI Utility + * + */ + +#ifndef __SBEFW_SBEFAPIUTIL_H +#define __SBEFW_SBEFAPIUTIL_H + +#include <stdint.h> +#include "sbe_sp_intf.H" +#include "sbeutil.H" +#include "fapi2.H" +#include "plat_hw_access.H" + +/* @brief - Map SBE target Types to Fapi Target Types + * + * @param[in] - i_sbeTargetType SBE target type + * @param[in] - i_chipletId Chiplet Id + * + * @return - fapi target type + */ +fapi2::TargetType sbeGetFapiTargetType(const uint16_t i_sbeTargetType, + const uint16_t i_chipletId); + +/*@brief - create fapi target handle for the target type + * + * @param[in] - i_taretType - sbe target type + * @param[in] - i_chipletId - chiplet id + * @param[out] - o_tgtHndl - fapi target handle + * @param[in] - i_fapiTargetMask - expected fapi targets, by default + * no masking + * + * @return - true - on success + * false - on failure + */ +bool sbeGetFapiTargetHandle(const uint16_t i_targetType, + const uint16_t i_chipletId, + fapi2::plat_target_handle_t &o_tgtHndl, + const fapi2::TargetType i_fapiTargetMask = + fapi2::TARGET_TYPE_ALL); + +/*@brief - Map sbe ring access modes to fapi ring access modes + * + * @param[in] - i_ringMode - sbe ring access mode + * + * @return - l_fapiRingMode - fapi ring mode + */ +uint16_t sbeToFapiRingMode(uint16_t i_ringMode); + + +#endif /* __SBEFW_SBEFAPIUTIL_H */ diff --git a/src/sbefw/core/sbefifo.H b/src/sbefw/core/sbefifo.H new file mode 100644 index 00000000..20385e26 --- /dev/null +++ b/src/sbefw/core/sbefifo.H @@ -0,0 +1,231 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbefifo.H $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2017 */ +/* */ +/* */ +/* 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: ppe/sbe/sbefw/sbefifo.H + * + * @brief This file contains basic SBE FIFO hardware specific + * definitions and operations. + * + */ + +#ifndef __SBEFW_SBEFIFO_H +#define __SBEFW_SBEFIFO_H + +#include "sbeexeintf.H" +#include "sbetrace.H" +#include "ppe42_scom.h" +#include "sbe_sp_intf.H" +#include "sbeSpMsg.H" + +/** + * @brief SBE FIFO Access addresses + * + */ +const uint32_t SBE_FIFO_BASE = 0x000B0000; + +const uint32_t SBE_UPSTREAM_FIFO_DEQ_ADD = SBE_FIFO_BASE + 0x0000; +const uint32_t SBE_UPSTREAM_FIFO_STATUS = SBE_FIFO_BASE + 0x0001; +const uint32_t SBE_UPSTREAM_FIFO_SIGNAL_EOT = SBE_FIFO_BASE + 0x0002; +const uint32_t SBE_UPSTREAM_FIFO_REQ_RESET = SBE_FIFO_BASE + 0x0003; +const uint32_t SBE_UPSTREAM_FIFO_PERFORM_RESET = SBE_FIFO_BASE + 0x0004; +const uint32_t SBE_UPSTREAM_FIFO_ACK_EOT = SBE_FIFO_BASE + 0x0005; + +const uint32_t SBE_DOWNSTREAM_FIFO_ENQ_ADD = SBE_FIFO_BASE + 0x0010; +const uint32_t SBE_DOWNSTREAM_FIFO_STATUS = SBE_FIFO_BASE + 0x0011; +const uint32_t SBE_DOWNSTREAM_FIFO_SIGNAL_EOT = SBE_FIFO_BASE + 0x0012; +const uint32_t SBE_DOWNSTREAM_FIFO_REQ_RESET = SBE_FIFO_BASE + 0x0013; +const uint32_t SBE_DOWNSTREAM_FIFO_PERFORM_RESET = SBE_FIFO_BASE + 0x0014; +const uint32_t SBE_DOWNSTREAM_FIFO_ACK_EOT = SBE_FIFO_BASE + 0x0015; + +/** + * @brief SBE Upstream FIFO Status bits + * + */ + +typedef struct +{ + uint32_t valid_flag:1; // Bit 0 + uint32_t eot_flag:1; // Bit 1 + uint32_t parity_err:1; // Bit 2 + uint32_t reserved3_5:3; // Bit 3:5 + uint32_t req_upfifo_reset:1; // Bit 6 + uint32_t req_downfifo_reset:1; // Bit 7 + uint32_t signaling_eot:1; // Bit 8 + uint32_t reserved9:1; // Bit 9 + uint32_t fifo_full:1; // Bit 10 + uint32_t fifo_empty:1; // Bit 11 + uint32_t fifo_entry_count:4; // Bit 12:15 + uint32_t fifo_valid_flags:8; // Bit 16:23 + uint32_t fifo_eot_flags:8; // Bit 24:31 + +} sbe_upfifo_status_t ; + +/** + * @brief 64-bit DW structure for Upstream FIFO Dequeue + * or Downstream FIFO Enqueue + * For Upstream FIFO, + * Bit 0 - 31 : Data, Bit 32 - 63 : Status + * For Downstream FIFO, + * Bit 0 - 31 : Data, Bit 32 - 63 : Unused + * + */ +typedef struct +{ + uint32_t fifo_data; + + // The following status field is applicable only for + // upstream FIFO access and will remain reserved for + // downstream FIFO access + union + { + sbe_upfifo_status_t statusOrReserved; + uint32_t status; + }; +} sbeFifoEntry_t ; + + +/** + * @brief 64-bit DW structure for Upstream FIFO Status Reg Read + * Bit 0 - 31 : Status Data, Bit 32 - 63 : Unused + * + */ +typedef struct +{ + sbe_upfifo_status_t upfifo_status; + uint32_t reserved; +} sbeUpFifoStatusReg_t ; + + +/** + * @brief SBE Downstream FIFO Status bits + * + */ +typedef struct +{ + uint32_t reserved0_1:2; // Bit 0:1 + uint32_t parity_err:1; // Bit 2 + uint32_t reserved3_5:3; // Bit 3:5 + uint32_t req_downfifo_reset:1; // Bit 6 + uint32_t req_upfifo_reset:1; // Bit 7 + uint32_t signaling_eot:1; // Bit 8 + uint32_t reserved9:1; // Bit 9 + uint32_t fifo_full:1; // Bit 10 + uint32_t fifo_empty:1; // Bit 11 + uint32_t fifo_entry_count:4; // Bit 12:15 + uint32_t fifo_valid_flags:8; // Bit 16:23 + uint32_t fifo_eot_flags:8; // Bit 24:31 + +} sbe_downfifo_status_t ; + +/** + * @brief 64-bit DW structure for Downstream FIFO Status Reg Read + * Bit 0 - 31 : Status Data, Bit 32 - 63 : Unused + * + */ +typedef struct +{ + sbe_downfifo_status_t downfifo_status; + uint32_t reserved; +} sbeDownFifoStatusReg_t; + +/*****************************************************************/ +/** Upstream FIFO access utilities **/ +/*****************************************************************/ + +/** + * @brief sbeUpFifoDeq : Read entry and status from Upstream FIFO + * + * @param[out] 64-Bit Data read from Upstream FIFO + * + * @return Rc from the underlying scom utility + * + */ +extern inline uint32_t sbeUpFifoDeq (uint64_t *o_data) +{ + /* For SBE FIFO (PIB) access, chiplet ID should be passed as 0 */ + return getscom_abs(SBE_UPSTREAM_FIFO_DEQ_ADD, o_data); +} + + +/** + * @brief sbeUpFifoPerformReset : Perform Upstream FIFO reset request + * + * @return Rc from the underlying scom utility + * + */ +extern inline uint32_t sbeUpFifoPerformReset (void) +{ + SBE_INFO("sbeUpFifoPerformReset"); + return putscom_abs(SBE_UPSTREAM_FIFO_PERFORM_RESET, ((uint64_t)0x1)<<32); +} + + +/** + * @brief sbeUpFifoAckEot : Acknowledge EOT in Upstream FIFO + * + * @return Rc from the underlying scom utility + * + */ +extern inline uint32_t sbeUpFifoAckEot (void) +{ + SBE_INFO("sbeUpFifoAckEot"); + return putscom_abs(SBE_UPSTREAM_FIFO_ACK_EOT, ((uint64_t)0x1)<<32); +} + + +/*****************************************************************/ +/** Downstream FIFO access utilities **/ +/*****************************************************************/ + +/** + * @brief sbeDownFifoEnq : Write data into Downstream FIFO + * + * @param[in] 64-Bit Data write into Downstream FIFO + * Bit 0-31 : Data + * Bit 32-63 : Unused + * + * @return Rc from the underlying scom utility + */ +extern inline uint32_t sbeDownFifoEnq (const uint64_t i_data) +{ + SBE_DEBUG(">sbeDownFifoEnq"); + return putscom_abs(SBE_DOWNSTREAM_FIFO_ENQ_ADD, i_data); +} + + +/** + * @brief sbeDownFifoGetStatus : Read status from downstream FIFO + * + * @param[out] 64-Bit Read status from downstream FIFO + * Bit 0-31 : Data + * Bit 32-63 : Unused + * + * @return Rc from the underlying scom utility + */ +extern inline uint32_t sbeDownFifoGetStatus (uint64_t *o_data) +{ + return getscom_abs(SBE_DOWNSTREAM_FIFO_STATUS, o_data); +} + +#endif // __SBEFW_SBEFIFO_H diff --git a/src/sbefw/core/sbeglobals.C b/src/sbefw/core/sbeglobals.C new file mode 100644 index 00000000..8d9ef020 --- /dev/null +++ b/src/sbefw/core/sbeglobals.C @@ -0,0 +1,48 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbeglobals.C $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2017 */ +/* */ +/* */ +/* 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 "sbetrace.H" +#include "sbeglobals.H" +#include "sbe_build_info.H" +//////////////////////////////////////////////////////////////// +//// @brief Stacks for Non-critical Interrupts and Threads +////////////////////////////////////////////////////////////////// +// Moved it out-side the scope of Global Class for symbol generation in syms +uint8_t sbe_Kernel_NCInt_stack[SBE_NONCRITICAL_STACK_SIZE]; +uint8_t sbeCommandReceiver_stack[SBE_THREAD_CMD_RECV_STACK_SIZE]; +uint8_t sbeSyncCommandProcessor_stack[SBE_THREAD_SYNC_CMD_PROC_STACK_SIZE]; +uint8_t sbeAsyncCommandProcessor_stack[SBE_THREAD_ASYNC_CMD_PROC_STACK_SIZE]; + +SBEGlobalsSingleton* sbeGlobal = &SBEGlobalsSingleton::getInstance(); +SBEGlobalsSingleton& SBEGlobalsSingleton::getInstance() +{ + static SBEGlobalsSingleton iv_instance; + return iv_instance; +} +// SBE commit id +uint32_t SBEGlobalsSingleton::fwCommitId = SBE_COMMIT_ID; + +secureMemRegion_t SBEGlobalsSingleton::mainMemRegions[MAX_MAIN_STORE_REGIONS] = {}; +secureMemRegion_t SBEGlobalsSingleton::occSramRegions[MAX_OCC_SRAM_REGIONS] = {}; + +uint64_t SBEGlobalsSingleton::i2cModeRegister = 0x004D000000000000ull; diff --git a/src/sbefw/core/sbeglobals.H b/src/sbefw/core/sbeglobals.H new file mode 100644 index 00000000..c26967a6 --- /dev/null +++ b/src/sbefw/core/sbeglobals.H @@ -0,0 +1,138 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbeglobals.H $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2017 */ +/* */ +/* */ +/* 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 __SBE_GLOBALS_H +#define __SBE_GLOBALS_H + +#include "sbeutil.H" +#include "sbeSpMsg.H" +#include "sbeHostMsg.H" +#include "sbestates.H" +#include "sbeexeintf.H" +#include "sbecmdgeneric.H" +#include "sbeSecureMemRegionManager.H" + +#define SBE_GLOBAL sbeGlobal + +constexpr size_t MAX_MAIN_STORE_REGIONS = 8; +constexpr size_t MAX_OCC_SRAM_REGIONS = 2; + +// Extern declartion, Defined in sbeglobal.C +extern uint8_t sbe_Kernel_NCInt_stack[SBE_NONCRITICAL_STACK_SIZE]; +extern uint8_t sbeCommandReceiver_stack[SBE_THREAD_CMD_RECV_STACK_SIZE]; +extern uint8_t sbeSyncCommandProcessor_stack[SBE_THREAD_SYNC_CMD_PROC_STACK_SIZE]; +extern uint8_t sbeAsyncCommandProcessor_stack[SBE_THREAD_ASYNC_CMD_PROC_STACK_SIZE]; + +class SBEGlobalsSingleton +{ + public: + // Disable copy contructor and assingment operator + SBEGlobalsSingleton(const SBEGlobalsSingleton&) = delete; + SBEGlobalsSingleton& operator=(const SBEGlobalsSingleton&) = delete; + static SBEGlobalsSingleton& getInstance(); + + sbeFifoCmdReqBuf_t sbeFifoCmdHdr; + sbeCmdRespHdr_t sbeCmdRespHdr; + sbePsu2SbeCmdReqHdr_t sbePsu2SbeCmdReqHdr; + sbeSbe2PsuRespHdr_t sbeSbe2PsuRespHdr; + sbeIntrHandle_t sbeIntrSource; + //////////////////////////////////////////////////////////////// + //// @brief Global semaphores + ///////////////////////////////////////////////////////////////// + /** + * @brief Global semaphore : SBE_GLOBAL->sbeSemCmdRecv + * + * This is used to synchronize between the ISR and + * the command receiver thread. + * + */ + PkSemaphore sbeSemCmdRecv; + /** + * @brief Global semaphore : SBE_GLOBAL->sbeSemCmdProcess + * + * This is used to synchronize between command receiver thread + * and synchronous command processor thread. + * + */ + PkSemaphore sbeSemCmdProcess; + sbeRole SBERole; + // SBE Frequency. Initially nest frequency is 133 MHZ + uint32_t sbefreq; + // Host specified memory allocations + // passthrough command address + sbeHostAddr_t hostPassThroughCmdAddr; + // ffdc address + sbeHostAddr_t hostFFDCAddr; + // Key Addr Pair + sbeStashMemoryPair_t sbeKeyAddrPair; + // SBE FW security enabled; 0 - disabled; 1 - enabled + uint8_t sbeFWSecurityEnabled; + // Instance of Master EX core to be used for DMT FFDC collection + uint8_t deadmanCore; + // Cached HWP Return Code that hints at what HWP FFDC to collect + uint32_t asyncFfdcRC; + + // SBE commit id + static uint32_t fwCommitId; + + // Secure memory window arrays + static secureMemRegion_t mainMemRegions[MAX_MAIN_STORE_REGIONS]; + static secureMemRegion_t occSramRegions[MAX_OCC_SRAM_REGIONS]; + + // i2c mode register register + static uint64_t i2cModeRegister; + + //////////////////////////////////////////////////////////////// + //// @brief PkThread structure for SBE Command Receiver thread + ////////////////////////////////////////////////////////////////// + PkThread sbeCommandReceiver_thread; + //////////////////////////////////////////////////////////////// + //// @brief PkThread structure for SBE Synchronous ChipOps + //// processing thread + ////////////////////////////////////////////////////////////////// + PkThread sbeSyncCommandProcessor_thread; + //////////////////////////////////////////////////////////////// + ////// @brief PkThread structure for SBE Asynchronous ChipOps + ////// processing thread + ////////////////////////////////////////////////////////////////// + PkThread sbeAsyncCommandProcessor_thread; + private: + /* Constructor + */ + SBEGlobalsSingleton(): + sbeFifoCmdHdr(), + sbeCmdRespHdr(), + sbePsu2SbeCmdReqHdr(), + sbeSbe2PsuRespHdr(), + sbeIntrSource(), + sbeSemCmdRecv(), + sbeSemCmdProcess(), + SBERole(SBE_ROLE_MASTER), + sbefreq(( 133 * 1000 * 1000)/SBE::SBE_TO_NEST_FREQ_FACTOR), + sbeFWSecurityEnabled(1) + { + } +}; +extern SBEGlobalsSingleton* sbeGlobal; +#endif //__SBE_GLOBALS_H + diff --git a/src/sbefw/core/sbeirq.C b/src/sbefw/core/sbeirq.C new file mode 100644 index 00000000..9db6809c --- /dev/null +++ b/src/sbefw/core/sbeirq.C @@ -0,0 +1,316 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbeirq.C $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2017 */ +/* */ +/* */ +/* 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: ppe/sbe/sbefw/sbeirq.C + * + * @brief This sets up and registers SBE ISRs + * + */ + +#include "sbeexeintf.H" +#include "sbeirq.H" +#include "sbetrace.H" +#include "assert.h" +#include "sbeglobals.H" +#include "ppe42_scom.h" +#include "p9_misc_scom_addresses.H" + +//////////////////////////////////////////////////////////////// +// @brief: SBE control loop ISR: +// - FIFO new data available +// - FIFO reset request +// - PSU new data available +// +// @param[in] i_pArg - Unused +// @param[in] i_irq - IRQ number as defined in sbeirq.h +// +//////////////////////////////////////////////////////////////// +void sbe_interrupt_handler (void *i_pArg, PkIrqId i_irq) +{ + #define SBE_FUNC " sbe_interrupt_handler " + SBE_ENTER(SBE_FUNC"i_irq=[0x%02X]",i_irq); + + int l_rc = 0; + + switch (i_irq) + { + case SBE_IRQ_HOST_PSU_INTR: + SBE_GLOBAL->sbeIntrSource.setIntrSource(SBE_INTERRUPT_ROUTINE, + SBE_INTERFACE_PSU); + break; + + case SBE_IRQ_SBEFIFO_DATA: + SBE_GLOBAL->sbeIntrSource.setIntrSource(SBE_INTERRUPT_ROUTINE, + SBE_INTERFACE_FIFO); + pk_irq_disable(SBE_IRQ_SBEFIFO_RESET); + break; + + case SBE_IRQ_SBEFIFO_RESET: + SBE_GLOBAL->sbeIntrSource.setIntrSource(SBE_INTERRUPT_ROUTINE, + SBE_INTERFACE_FIFO_RESET); + pk_irq_disable(SBE_IRQ_SBEFIFO_DATA); + break; + + default: + SBE_ERROR(SBE_FUNC"Unknown IRQ, assert"); + assert(0); + break; + } + // Mask the interrupt + pk_irq_disable(i_irq); + + // Unblock the command receiver thread + l_rc = pk_semaphore_post(&SBE_GLOBAL->sbeSemCmdRecv); + if (l_rc) + { + // If we received an error while posting the semaphore, + // unmask the interrupt back and assert + SBE_ERROR(SBE_FUNC"pk_semaphore_post failed, rc=[%d]", l_rc); + pk_irq_enable(i_irq); + assert(!l_rc); + } + #undef SBE_FUNC +} + +//////////////////////////////////////////////////////////////// +// See sbeexeintf.h for more details +//////////////////////////////////////////////////////////////// +int sbeIRQSetup (void) +{ + #define SBE_FUNC " sbeIRQSetup " + int l_rc = 0; + PkIrqId l_irq; + + // Disable the relevant IRQs while we set them up + pk_irq_disable(SBE_IRQ_HOST_PSU_INTR); + pk_irq_disable(SBE_IRQ_SBEFIFO_DATA); + pk_irq_disable(SBE_IRQ_SBEFIFO_RESET); + + do + { + // Register the IRQ handler with PK + + // PSU New data available interrupt + l_irq = SBE_IRQ_HOST_PSU_INTR; + l_rc = pk_irq_handler_set(l_irq, sbe_interrupt_handler, NULL); + if(l_rc) + { + break; + } + + // FIFO New data available interrupt + l_irq = SBE_IRQ_SBEFIFO_DATA; + l_rc = pk_irq_handler_set(l_irq, sbe_interrupt_handler, NULL); + if(l_rc) + { + break; + } + + // FIFO Reset request + l_irq = SBE_IRQ_SBEFIFO_RESET; + l_rc = pk_irq_handler_set(l_irq, sbe_interrupt_handler, NULL); + if(l_rc) + { + break; + } + + // Enable the IRQ + pk_irq_enable(SBE_IRQ_SBEFIFO_RESET); + pk_irq_enable(SBE_IRQ_SBEFIFO_DATA); + pk_irq_enable(SBE_IRQ_HOST_PSU_INTR); + } while(false); + + if (l_rc) + { + SBE_ERROR (SBE_FUNC"pk_irq_handler_set failed, IRQ=[0x%02X], " + "rc=[%d]", l_irq, l_rc); + } + + return l_rc; + #undef SBE_FUNC +} + +// SBE I2C reset sequence +uint32_t __max_i2c_reset_retrials = 3; + +// bit 0 +#define I2CM_RESET_BIT (0x8000000000000000ull) +// bit 7 +#define I2C_CMD_COMPLETE_BIT (0x0100000000000000ull) +// bit 3 +#define I2C_STOP_BIT (0x1000000000000000ull) +// bit 16-21 +#define I2C_MODE_REG_PORT_BITS (0xFFFF03FFFFFFFFFFull) +// bit 8 +#define I2C_MODE_FGAT_BIT (0x8000000000000000ull) + +#define POLL_BEFORE_I2C_RESET (25600) +#define I2C_CMD_COMPLETE_POLL (0x00003FFF) + +extern "C" void i2c_reset() +{ + // empty cycles before i2c reset + for (auto i = POLL_BEFORE_I2C_RESET; i > 0; --i) { + // Force compiler not to optimize for loop + asm(""); + } + + uint32_t reg_address = 0; + uint64_t value = 0ull; + + // reset I2CM register - 0x000A0001 + reg_address = PU_RESET_REGISTER_B; + value = I2CM_RESET_BIT; + PPE_STVD( reg_address, value); + + // forcefully reset port busy register - 0x000A000E + reg_address = PU_I2C_BUSY_REGISTER_B; + value = I2CM_RESET_BIT; + PPE_STVD( reg_address, value); + + // clear bit 16-21 of mode register + SBE_GLOBAL->i2cModeRegister &= I2C_MODE_REG_PORT_BITS; + // set enchanced mode - fgat bit - 28 + SBE_GLOBAL->i2cModeRegister |= I2C_MODE_FGAT_BIT; + + for( auto port=0; port < 2; port++ ) + { + // write mode register - 0x000A0006 + reg_address = PU_MODE_REGISTER_B; + SBE_GLOBAL->i2cModeRegister |= ((uint64_t)port << 42); + PPE_STVD( reg_address, SBE_GLOBAL->i2cModeRegister ); + + // write command control register - 0x000A0005 + reg_address = PU_COMMAND_REGISTER_B; + value = I2C_STOP_BIT; + PPE_STVD( reg_address, value ); + + // poll cmd complete register 0x000A000B + uint64_t status = 0; + for( auto i=0; i < I2C_CMD_COMPLETE_POLL; i--) + { + reg_address = PU_IMM_RESET_I2C_B; + PPE_LVD( reg_address, status ); + if( status & I2C_CMD_COMPLETE_BIT ) + { + // cmd complete + break; + } + } + if(!( status & I2C_CMD_COMPLETE_BIT )) + { + pk_halt(); + } + } +} + +//////////////////////////////////////////////////////////////// +// SBE handler for the PPE machine check interrupt +//////////////////////////////////////////////////////////////// +// TODO: via RTC 155896 - Change the way bad scoms are handled. +// Once HW375602 is fixed, there will be no need for this +// interrupt handler. +extern "C" void __sbe_machine_check_handler() +{ + asm( + "# reclaim function callstack\n" + "lwz %r0,12(%r1)\n" + "mtlr %r0\n" + "addi %r1,%r1,8\n" + + "# Save r0, r1, r2, r3,r4, r5, r6, r7, r8, r9, r10, r13, r28, r29, r30, r31\n" + "# lr to stack, since it is going to be used by\n" + "# this handler\n" + "stwu %r1, -68(%r1)\n" + "stw %r0, 0(%r1)\n" + "stw %r2, 4(%r1)\n" + "stw %r3, 8(%r1)\n" + "stw %r4, 12(%r1)\n" + "stw %r5, 16(%r1)\n" + "stw %r6, 20(%r1)\n" + "stw %r7, 24(%r1)\n" + "stw %r8, 28(%r1)\n" + "stw %r9, 32(%r1)\n" + "stw %r10, 36(%r1)\n" + "stw %r13, 40(%r1)\n" + "stw %r28, 44(%r1)\n" + "stw %r29, 48(%r1)\n" + "stw %r30, 52(%r1)\n" + "stw %r31, 56(%r1)\n" + + "# Check the MCS bits (29:31) in the ISR to determine the cause for the machine check\n" + "# For a data machine check, the MCS should be 0x001 to 0x011\n" + "mfisr %r4\n" + "andi. %r4, %r4, 0x0007\n" + "bwz %r4, __halt_sbe\n" + "cmpwibgt %r4, 0x0003, __halt_sbe\n" + "# The EDR contains the address that caused the machine check\n" + "mfedr %r4\n" + "srawi %r4, %r4, 16\n" + "# If the address is in the range 0x00000000 - 0x7f000000, we treat it as a\n" + "# failed scom and jump to __scom_error\n" + "cmplwi %r4, 0x8000\n" + "blt __scom_error\n" + "# Else, halt the SBE\n" + "__halt_sbe:\n" + "b pk_halt\n" + "__scom_error:\n" + "# The srr0 contains the address of the instruction that caused the machine\n" + "# check (since the the interrupt is raised *before* the instruction\n" + "# completed execution). Since we want the code to continue with the next\n" + "# instruction, we increment srr0 by 4, restore r4, and rfi to branch to srr0\n" + "mfsrr0 %r4\n" + "addi %r4, %r4, 4\n" + "mtsrr0 %r4\n" + "b __exit\n" + "__sbe_i2c_reset_sequence:\n" + "mflr %r0\n" + "stw %r0, 60(%r1)\n"); + i2c_reset(); + asm( + "lwz %r0, 60(%r1)\n" + "mtlr %r0\n" + "stw %r10, __max_i2c_reset_retrials@sda21(0)\n" + "__exit:\n" + "lwz %r0, 0(%r1)\n" + "lwz %r2, 4(%r1)\n" + "lwz %r3, 8(%r1)\n" + "lwz %r4, 12(%r1)\n" + "lwz %r5, 16(%r1)\n" + "lwz %r6, 20(%r1)\n" + "lwz %r7, 24(%r1)\n" + "lwz %r8, 28(%r1)\n" + "lwz %r9, 32(%r1)\n" + "lwz %r10, 36(%r1)\n" + "lwz %r13, 40(%r1)\n" + "lwz %r28, 44(%r1)\n" + "lwz %r29, 48(%r1)\n" + "lwz %r30, 52(%r1)\n" + "lwz %r31, 56(%r1)\n" + "addi %r1, %r1, 68\n" + + "rfi\n" + ); +} + diff --git a/src/sbefw/core/sbeirq.H b/src/sbefw/core/sbeirq.H new file mode 100644 index 00000000..5700cc9d --- /dev/null +++ b/src/sbefw/core/sbeirq.H @@ -0,0 +1,109 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbeirq.H $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2017 */ +/* */ +/* */ +/* 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: ppe/sbe/sbefw/sbeirq.H + * + * @brief This file contains the SBE PPE Interrupt Request numbers + */ + +#ifndef _SBE_IRQ_H +#define _SBE_IRQ_H + +/** + * @brief SBE PPE IRQ numbers + * + */ + +#define SBE_IRQ_START0 0 /* SBE Start Vector 0 */ +#define SBE_IRQ_START1 1 /* SBE Start Vector 1 */ +#define SBE_IRQ_INTR0 2 /* SBE Interrupt S0 */ +#define SBE_IRQ_INTR1 3 /* SBE Interrupt S1 */ +#define SBE_IRQ_DRTM_REQ 4 /* DRTM late launch request */ +#define SBE_IRQ_SBEFIFO_RESET 5 /* FIFO - Reset request from SE */ +#define SBE_IRQ_SBEFIFO_DATA 6 /* FIFO - Incoming Data Available */ +#define SBE_IRQ_HOST_PSU_INTR 7 /* PSU - Incoming Data Available */ + + +#define SBE_IRQ_RESERVED_8 8 +#define SBE_IRQ_RESERVED_9 9 + +#define SBE_IRQ_RESERVED_10 10 +#define SBE_IRQ_RESERVED_11 11 +#define SBE_IRQ_RESERVED_12 12 +#define SBE_IRQ_RESERVED_13 13 +#define SBE_IRQ_RESERVED_14 14 +#define SBE_IRQ_RESERVED_15 15 +#define SBE_IRQ_RESERVED_16 16 +#define SBE_IRQ_RESERVED_17 17 +#define SBE_IRQ_RESERVED_18 18 +#define SBE_IRQ_RESERVED_19 19 +#define SBE_IRQ_RESERVED_20 20 +#define SBE_IRQ_RESERVED_21 21 +#define SBE_IRQ_RESERVED_22 22 +#define SBE_IRQ_RESERVED_23 23 +#define SBE_IRQ_RESERVED_24 24 +#define SBE_IRQ_RESERVED_25 25 +#define SBE_IRQ_RESERVED_26 26 +#define SBE_IRQ_RESERVED_27 27 +#define SBE_IRQ_RESERVED_28 28 +#define SBE_IRQ_RESERVED_29 29 +#define SBE_IRQ_RESERVED_30 30 +#define SBE_IRQ_RESERVED_31 31 +#define SBE_IRQ_RESERVED_32 32 +#define SBE_IRQ_RESERVED_33 33 +#define SBE_IRQ_RESERVED_34 34 +#define SBE_IRQ_RESERVED_35 35 +#define SBE_IRQ_RESERVED_36 36 +#define SBE_IRQ_RESERVED_37 37 +#define SBE_IRQ_RESERVED_38 38 +#define SBE_IRQ_RESERVED_39 39 +#define SBE_IRQ_RESERVED_40 40 +#define SBE_IRQ_RESERVED_41 41 +#define SBE_IRQ_RESERVED_42 42 +#define SBE_IRQ_RESERVED_43 43 +#define SBE_IRQ_RESERVED_44 44 +#define SBE_IRQ_RESERVED_45 45 +#define SBE_IRQ_RESERVED_46 46 +#define SBE_IRQ_RESERVED_47 47 +#define SBE_IRQ_RESERVED_48 48 +#define SBE_IRQ_RESERVED_49 49 +#define SBE_IRQ_RESERVED_50 50 +#define SBE_IRQ_RESERVED_51 51 +#define SBE_IRQ_RESERVED_52 52 +#define SBE_IRQ_RESERVED_53 53 +#define SBE_IRQ_RESERVED_54 54 +#define SBE_IRQ_RESERVED_55 55 +#define SBE_IRQ_RESERVED_56 56 +#define SBE_IRQ_RESERVED_57 57 +#define SBE_IRQ_RESERVED_58 58 +#define SBE_IRQ_RESERVED_59 59 +#define SBE_IRQ_RESERVED_60 60 +#define SBE_IRQ_RESERVED_61 61 +#define SBE_IRQ_RESERVED_62 62 +#define SBE_IRQ_RESERVED_63 63 + +#define SBE_MACHINE_CHECK_HANDLER \ + b __sbe_machine_check_handler + +#endif //_SBE_IRQ_H diff --git a/src/sbefw/core/sbemain.C b/src/sbefw/core/sbemain.C new file mode 100644 index 00000000..e49fc029 --- /dev/null +++ b/src/sbefw/core/sbemain.C @@ -0,0 +1,341 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbemain.C $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2017 */ +/* */ +/* */ +/* 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: ppe/sbe/sbefw/sbemain.C + * + * @brief This file does the following + * - SBE Application Main entry point + * - PK initialization + * - Thread initialization + * - Semaphore initialization + * - IRQ setup + * - Scheduling of the threads and + * - Starting of the control loop code flow + * + */ + + +#include "sbeexeintf.H" +#include "sbetrace.H" +#include "sberegaccess.H" +#include "sbestates.H" +#include "fapi2.H" // For target init +#include "sbeutil.H" // For getting SBE_TO_NEST_FREQ_FACTOR +#include "sbeglobals.H" +#include "p9_misc_scom_addresses.H" + +// Max defines for Semaphores +static uint32_t MAX_SEMAPHORE_COUNT = 3; + +extern "C" +{ +// These variables are declared in linker script to keep track of +// global constructor pointer functions and sbss section. +extern void (*ctor_start_address)() __attribute__ ((section (".rodata"))); +extern void (*ctor_end_address)() __attribute__ ((section (".rodata"))); +extern uint64_t _sbss_start __attribute__ ((section (".sbss"))); +extern uint64_t _sbss_end __attribute__ ((section (".sbss"))); +// This function will be used to do any C++ handling required before doing +// any main job. Call to this function should get generated by +// compiler. +// TODO via RTC 152070 +// We are also initialising sbss section to zero this function. +// Though it does not do any harm as of now, it is better if we use loader +// or linker script to zero init sbss section. This way we will be future +// garded if pk boot uses some static/global data initialised to +// false in future. +void __eabi() +{ + // Initialise sbss section + uint64_t *startAddr = &_sbss_start; + while ( startAddr != &_sbss_end ) + { + *startAddr = 0; + startAddr++; + } + + // Call global constructors + void(**ctors)() = &ctor_start_address; + while( ctors != &ctor_end_address) + { + (*ctors)(); + ctors++; + } +} +} // end extern "C" + +//////////////////////////////////////////////////////////////// +// @brief sbeInitSems - Create the necessary semaphores +// +// @return PK_OK - Success +// PK_INVALID_SEMAPHORE_AT_CREATE - Invalid PkSemaphore +// PK_INVALID_ARGUMENT_SEMAPHORE - max_count is non-zero +// and less than the initial_count +//////////////////////////////////////////////////////////////// +uint32_t sbeInitSems(void) +{ + SBE_ENTER("sbeInitSems"); + int l_rc = PK_OK; + + do + { + l_rc = pk_semaphore_create(&SBE_GLOBAL->sbeSemCmdRecv, 0, MAX_SEMAPHORE_COUNT); + if (l_rc) + { + break; + } + l_rc = pk_semaphore_create(&SBE_GLOBAL->sbeSemCmdProcess, 0, MAX_SEMAPHORE_COUNT); + if (l_rc) + { + break; + } + } while (false); + + if (l_rc) + { + SBE_ERROR ("pk_semaphore_create, rc=[%d]", l_rc); + } + return l_rc; +} + +//////////////////////////////////////////////////////////////// +// @brief createAndResumeThreadHelper +// - Create and resume the given thread +// +// @param[in/out] io_thread A pointer to an PkThread structure to initialize +// @param[in] i_thread_routine The subroutine that implements the thread +// @param[in/out] io_arg Private data to be passed as the argument to the +// thread routine when it begins execution +// @param[in] i_stack The stack space of the thread +// @param[in] i_stack_size The size of the stack in bytes +// @param[in] i_priority The initial priority of the thread +// +// @return PK_OK Successfully created and resumed the thread +// +// @return PK_INVALID_THREAD_AT_CREATE io_thread is null +// @return PK_INVALID_ARGUMENT_THREAD1 i_thread_routine is null +// @return PK_INVALID_ARGUMENT_THREAD2 i_priority is invalid +// @return PK_INVALID_ARGUMENT_THREAD3 the stack area wraps around +// the end of memory. +// @return PK_STACK_OVERFLOW The stack area at thread creation +// is smaller than the min safe size +// @return PK_INVALID_THREAD_AT_RESUME1 io_thread is null (unlikely) +// @return PK_INVALID_THREAD_AT_RESUME2 The thread is not active, +// i.e. has completed or been deleted, +// @return PK_PRIORITY_IN_USE_AT_RESUME Another thread is already +// mapped at the priority of the thread +//////////////////////////////////////////////////////////////// +uint32_t createAndResumeThreadHelper(PkThread *io_pThread, + PkThreadRoutine i_thread_routine, + void *io_pArg, + PkAddress i_stack, + size_t i_stack_size, + sbeThreadPriorities i_priority) +{ + int l_rc = PK_OK; + + // Thread creation + l_rc = pk_thread_create(io_pThread, + i_thread_routine, + io_pArg, + i_stack, + i_stack_size, + (PkThreadPriority)i_priority); + if(l_rc == PK_OK) + { + // resume the thread once created + l_rc = pk_thread_resume(io_pThread); + } + + // Check for errors creating or resuming the thread + if(l_rc != PK_OK) + { + SBE_ERROR ("Failure creating/resuming thread, rc=[%d]", l_rc); + } + + return l_rc; +} + +//////////////////////////////////////////////////////////////// +// @brief sbeInitThreads +// Create the resume all the firmware threads +// +// @return See createAndResumeThreadHelper for more details +//////////////////////////////////////////////////////////////// +int sbeInitThreads(void) +{ + // Locals + uint32_t l_rc = PK_OK; + + do + { + // Initialize Command receiver thread + l_rc = createAndResumeThreadHelper(&SBE_GLOBAL->sbeCommandReceiver_thread, + sbeCommandReceiver_routine, + (void *)0, + (PkAddress)sbeCommandReceiver_stack, + SBE_THREAD_CMD_RECV_STACK_SIZE, + THREAD_PRIORITY_5); + if (l_rc) + { + break; + } + + // Initialize Synchronous Command Processor thread + l_rc = createAndResumeThreadHelper(&SBE_GLOBAL->sbeSyncCommandProcessor_thread, + sbeSyncCommandProcessor_routine, + (void *)0, + (PkAddress)sbeSyncCommandProcessor_stack, + SBE_THREAD_SYNC_CMD_PROC_STACK_SIZE, + THREAD_PRIORITY_7); + if (l_rc) + { + break; + } + + // Initialize Asynchronous Command Processor thread + l_rc = createAndResumeThreadHelper(&SBE_GLOBAL->sbeAsyncCommandProcessor_thread, + sbeAsyncCommandProcessor_routine, + (void *)0, + (PkAddress)sbeAsyncCommandProcessor_stack, + SBE_THREAD_ASYNC_CMD_PROC_STACK_SIZE, + THREAD_PRIORITY_6); + if (l_rc) + { + break; + } + } while (false); + + // If there are any errors initializing the threads + if( l_rc ) + { + SBE_ERROR ("Error Initializing a thread, rc=[%d]", l_rc); + } + + return l_rc; +} + +//////////////////////////////////////////////////////////////// +// @brief - main : SBE Application main +//////////////////////////////////////////////////////////////// +uint32_t main(int argc, char **argv) +{ + #define SBE_FUNC "main " + SBE_ENTER(SBE_FUNC); + int l_rc = 0; + + // backup i2c mode register + uint32_t reg_address = PU_MODE_REGISTER_B; + PPE_LVD( reg_address, SBE_GLOBAL->i2cModeRegister); + + // @TODO via RTC : 128818 + // Explore on reclaiming the stack + // used by this Initialization code + + do + { + // initializes kernel data - + // stack, threads, timebase, timers, etc. + l_rc = pk_initialize((PkAddress)sbe_Kernel_NCInt_stack, + SBE_NONCRITICAL_STACK_SIZE, + 0, + SBE_GLOBAL->sbefreq ); + if (l_rc) + { + break; + } + + SBE_INFO("Completed PK init"); + + // Initialize the semaphores + l_rc = sbeInitSems(); + if (l_rc) + { + break; + } + + // Initialize SBE control loop threads + l_rc = sbeInitThreads(); + if (l_rc) + { + break; + } + + // Setup SBE PPE IRQs + l_rc = sbeIRQSetup(); + if (l_rc) + { + break; + } + + // TODO via RTC 126146. + // Check if we should call plat_TargetsInit in some other thread. + // We may want to keep only PK init in main and can move + // plat init to some other thread. Only if this is required by more + // than one thread and there can be some race condition, we will + // keep it here before starting other threads. + fapi2::ReturnCode fapiRc = fapi2::plat_TargetsInit(); + if( fapiRc != fapi2::FAPI2_RC_SUCCESS ) + { + SBE_ERROR(SBE_FUNC"plat_TargetsInit failed"); + (void)SbeRegAccess::theSbeRegAccess(). + stateTransition(SBE_FAILURE_EVENT); + // Hard Reset SBE to recover + break; + } + + fapiRc = fapi2::plat_AttrInit(); + if(fapiRc != fapi2::FAPI2_RC_SUCCESS) + { + SBE_ERROR(SBE_FUNC"plat_AttrInit failed"); + (void)SbeRegAccess::theSbeRegAccess(). + stateTransition(SBE_FAILURE_EVENT); + // Hard Reset SBE to recover + break; + } + + if(SbeRegAccess::theSbeRegAccess().init()) + { + SBE_ERROR(SBE_FUNC"Failed to initialize SbeRegAccess."); + // init failure could mean the below will fail too, but attempt it + // anyway + (void)SbeRegAccess::theSbeRegAccess().stateTransition( + SBE_FAILURE_EVENT); + // Hard Reset SBE to recover + break; + } + + if(SBE::isSimicsRunning()) + { + SBE_INFO("SBE is running on simics"); + } + // Start running the highest priority thread. + // This function never returns + pk_start_threads(); + + } while (false); + + SBE_EXIT(SBE_FUNC); + return l_rc; +} diff --git a/src/sbefw/core/sberegaccess.C b/src/sbefw/core/sberegaccess.C new file mode 100644 index 00000000..03ffd852 --- /dev/null +++ b/src/sbefw/core/sberegaccess.C @@ -0,0 +1,356 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sberegaccess.C $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* */ +/* */ +/* 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: ppe/sbe/sbefw/sberegaccess.C + * + * @brief This file contains interfaces to get/set FW flags either in the + * scratch registers and/or the FW attributes. + */ + +#include "sberegaccess.H" +#include "sbetrace.H" +#include "fapi2.H" +#include <ppe42_scom.h> +#include <p9_perv_scom_addresses.H> +#include <p9_misc_scom_addresses.H> + +using namespace fapi2; + +// Struct to Map Current State - Event - Final State Transition +typedef struct stateTransitionStr +{ + uint16_t currState:4; + uint16_t event:4; + uint16_t finalState:4; + uint16_t reserved:4; +} stateTransitionStr_t; + +// Start and End point of Event Transition in stateTransMap Table +typedef struct stateEventRangeStr +{ + uint16_t start:8; + uint16_t end:8; +}stateEventRangeStr_t; + +// Entry Point and End point to the StateTransition Map for a State +// It is sequenced as per the sbeState enum, Don't change the sequence +// of states. Events are incremented w.r.t previous event. +static const stateEventRangeStr_t eventRangePerState[SBE_MAX_STATE] = +{ + {SBE_STATE_UNKNOWN_ENTRY_TO_MAP, SBE_STATE_UNKNOWN_MAX_EVENT}, + {SBE_STATE_IPLING_ENTRY_TO_MAP, SBE_STATE_IPLING_MAX_EVENT}, + {SBE_STATE_ISTEP_ENTRY_TO_MAP, SBE_STATE_ISTEP_MAX_EVENT}, + {SBE_STATE_MPIPL_ENTRY_TO_MAP, SBE_STATE_MPIPL_MAX_EVENT}, + {SBE_STATE_RUNTIME_ENTRY_TO_MAP, SBE_STATE_RUNTIME_MAX_EVENT}, + {SBE_STATE_DMT_ENTRY_TO_MAP, SBE_STATE_DMT_MAX_EVENT}, + {SBE_STATE_DUMP_ENTRY_TO_MAP, SBE_STATE_DUMP_MAX_EVENT}, + {SBE_STATE_FAILURE_ENTRY_TO_MAP, SBE_STATE_FAILURE_MAX_EVENT}, + {SBE_STATE_QUIESCE_ENTRY_TO_MAP, SBE_STATE_QUIESCE_MAX_EVENT}, +}; + +// Map to connect the current State with an event along with the final state +// transition. It is sequenced according to the sbeState enums, Don't change the +// sequence of states. +static const stateTransitionStr_t stateTransMap[SBE_MAX_TRANSITIONS] = { + {SBE_STATE_UNKNOWN, SBE_FAILURE_EVENT, SBE_STATE_FAILURE}, + {SBE_STATE_UNKNOWN, SBE_RUNTIME_EVENT, SBE_STATE_RUNTIME}, + {SBE_STATE_UNKNOWN, SBE_ISTEP_EVENT, SBE_STATE_ISTEP}, + {SBE_STATE_UNKNOWN, SBE_PLCK_EVENT, SBE_STATE_IPLING}, + {SBE_STATE_IPLING, SBE_RUNTIME_EVENT, SBE_STATE_RUNTIME}, + {SBE_STATE_IPLING, SBE_DUMP_FAILURE_EVENT, SBE_STATE_DUMP}, + {SBE_STATE_IPLING, SBE_FAILURE_EVENT, SBE_STATE_FAILURE}, + {SBE_STATE_IPLING, SBE_QUIESCE_EVENT, SBE_STATE_QUIESCE}, + {SBE_STATE_ISTEP, SBE_RUNTIME_EVENT, SBE_STATE_RUNTIME}, + {SBE_STATE_ISTEP, SBE_FAILURE_EVENT, SBE_STATE_FAILURE}, + {SBE_STATE_ISTEP, SBE_QUIESCE_EVENT, SBE_STATE_QUIESCE}, + {SBE_STATE_MPIPL, SBE_RUNTIME_EVENT, SBE_STATE_RUNTIME}, + {SBE_STATE_MPIPL, SBE_DUMP_FAILURE_EVENT, SBE_STATE_DUMP}, + {SBE_STATE_MPIPL, SBE_QUIESCE_EVENT, SBE_STATE_QUIESCE}, + {SBE_STATE_RUNTIME, SBE_DUMP_FAILURE_EVENT, SBE_STATE_DUMP}, + {SBE_STATE_RUNTIME, SBE_ENTER_MPIPL_EVENT, SBE_STATE_MPIPL}, + {SBE_STATE_RUNTIME, SBE_DMT_ENTER_EVENT, SBE_STATE_DMT}, + {SBE_STATE_RUNTIME, SBE_FAILURE_EVENT, SBE_STATE_FAILURE}, + {SBE_STATE_RUNTIME, SBE_QUIESCE_EVENT, SBE_STATE_QUIESCE}, + {SBE_STATE_DMT, SBE_DMT_COMP_EVENT, SBE_STATE_RUNTIME}, + {SBE_STATE_DMT, SBE_QUIESCE_EVENT, SBE_STATE_QUIESCE}, + {SBE_STATE_DMT, SBE_DUMP_FAILURE_EVENT, SBE_STATE_DUMP}, +}; + +SbeRegAccess SbeRegAccess::cv_instance __attribute__((section (".sbss"))); + +/** + * @brief Initizlize the class + * + * @return An RC indicating success/failure + */ + +void SbeRegAccess::stateTransition(const sbeEvent &i_event) +{ + #define SBE_FUNC "SbeRegAccess::stateTransition " + //Fetch Current State + uint32_t l_state = (uint32_t)getSbeState(); + uint8_t l_startCnt = eventRangePerState[l_state].start; + SBE_INFO(SBE_FUNC "Event Received %d CurrState 0x%08X StartCnt%d EndCnt%d", + i_event, l_state, l_startCnt, eventRangePerState[l_state].end); + // Fetch the final State from the Map + while(l_startCnt < + (eventRangePerState[l_state].end + eventRangePerState[l_state].start)) + { + if(stateTransMap[l_startCnt].event == i_event) + { + SBE_INFO(SBE_FUNC "Updating State as %d", + (sbeState)stateTransMap[l_startCnt].finalState); + updateSbeState((sbeState)stateTransMap[l_startCnt].finalState); + break; + } + else + ++l_startCnt; + } + #undef SBE_FUNC +} + +uint32_t SbeRegAccess::init() +{ + #define SBE_FUNC "SbeRegAccess::SbeRegAccess " + static bool l_initDone = false; + uint32_t rc = 0; + uint64_t l_mbx8 = 0; + do + { + if(l_initDone) + { + break; + } + // Read SBE messaging register into iv_messagingReg + rc = getscom_abs(PERV_SB_MSG_SCOM, &iv_messagingReg); + if(PCB_ERROR_NONE != rc) + { + SBE_ERROR(SBE_FUNC"Failed reading sbe messaging reg., RC: 0x%08X. ", + rc); + break; + } + // Read Mailbox register 8 to check if the mailbox registers 3 and 6 are + // valid + rc = getscom_abs(PERV_SCRATCH_REGISTER_8_SCOM, &l_mbx8); + if(PCB_ERROR_NONE != rc) + { + SBE_ERROR(SBE_FUNC"Failed reading mailbox reg 7, RC: 0x%08X. ", + rc); + break; + } + if(l_mbx8 & SBE_MBX8_MBX3_VALID_MASK) + { + // Read MBX3 + rc = getscom_abs(PERV_SCRATCH_REGISTER_3_SCOM, &iv_mbx3); + if(PCB_ERROR_NONE != rc) + { + SBE_ERROR(SBE_FUNC"Failed reading mailbox reg 3, RC: 0x%08X. ", + rc); + break; + } + } + else + { + // Need to read the values off the attributes + uint32_t l_attr = 0; + FAPI_ATTR_GET(ATTR_BOOT_FLAGS, Target<TARGET_TYPE_SYSTEM>(), + l_attr); + iv_mbx3 = ((uint64_t) l_attr ) << 32; + } + if(l_mbx8 & SBE_MBX8_MBX6_VALID_MASK) + { + // Read MBX6 + rc = getscom_abs(PERV_SCRATCH_REGISTER_6_SCOM, &iv_mbx6); + if(PCB_ERROR_NONE != rc) + { + SBE_ERROR(SBE_FUNC"Failed reading mailbox reg 6, RC: 0x%08X. " + rc); + break; + } + } + + // If the master/slave bit is 0 (either default or read from mbx6), + // check the C4 board pin to determine role + // Read device ID register + uint64_t l_sbeDevIdReg = 0; + rc = getscom_abs(PERV_DEVICE_ID_REG, &l_sbeDevIdReg); + if(PCB_ERROR_NONE != rc) + { + SBE_ERROR(SBE_FUNC"Failed reading device id reg, RC: 0x%08X.",rc); + break; + } + + if(0 == iv_isSlave) + { + iv_isSlave = l_sbeDevIdReg & SBE_DEV_ID_C4_PIN_MASK; + SBE_INFO(SBE_FUNC"Overriding master/slave with data read from " + "C4 pin: HI: 0x%08X, LO: 0x%08X", + (uint32_t)(l_sbeDevIdReg >> 32), + (uint32_t)(l_sbeDevIdReg & 0xFFFFFFFF)); + } + } while(false); + + SBE_INFO(SBE_FUNC"Read mailbox registers: mbx8: 0x%08X, mbx3: 0x%08X, " + "mbx6: 0x%08X", (uint32_t)(l_mbx8 >> 32), + (uint32_t)(iv_mbx3 >> 32), (uint32_t)(iv_mbx6 >> 32)); + l_initDone = true; + return rc; + #undef SBE_FUNC +} + +/** + * @brief Update the SBE states into the SBE messaging register. The + * function does a read-modify-write, so any bits other than the state + * bits are preserved. The current state of the register is set to + * i_state, whereas the old current state is copied to previous state + * + * @param [in] i_state The current SBE state + * + * @return RC indicating success/failure. + * + */ +uint32_t SbeRegAccess::updateSbeState(const sbeState &i_state) +{ + #define SBE_FUNC "SbeRegAccess::updateSbeState " + uint32_t rc = 0; + + iv_prevState = iv_currState; + iv_currState = i_state; + rc = putscom_abs(PERV_SB_MSG_SCOM, iv_messagingReg); + if(PCB_ERROR_NONE != rc) + { + SBE_ERROR(SBE_FUNC"Failed to update state to messaging " + "register. RC: 0x%08X", rc); + } + return rc; + #undef SBE_FUNC +} + +/** + * @brief Update the SBE IPL steps into the SBE messaging register. The + * function does a read-modify-write, so any bits other than the IPL + * steps are retianed + * + * @param [in] i_major IPL major step number + * @param [in] i_minor IPL minor step number + * + * @return RC indicating success/failure. + * + */ +uint32_t SbeRegAccess::updateSbeStep(const uint8_t i_major, + const uint8_t i_minor) +{ + #define SBE_FUNC "SbeRegAccess::updateSbeStep " + uint32_t rc = 0; + + iv_majorStep = i_major; + iv_minorStep = i_minor; + + rc = putscom_abs(PERV_SB_MSG_SCOM, iv_messagingReg); + if(rc) + { + SBE_ERROR(SBE_FUNC"Failed to update SBE step to messaging " + "register. RC: 0x%08X", rc); + } + return rc; + #undef SBE_FUNC +} + +/** + * @brief Set the SBE ready bit into the SBE messaging register + * (meaning that SBE control loop is initialized) The function does a + * read-modify-write, so any bits other than the SBE ready bit remain + * unchanged. + * + * @return RC indicating success/failure. + * + */ +uint32_t SbeRegAccess::setSbeReady() +{ + #define SBE_FUNC "SbeRegAccess::setSbeReady " + uint32_t rc = 0; + + iv_sbeBooted = true; + rc = putscom_abs(PERV_SB_MSG_SCOM, iv_messagingReg); + if(rc) + { + SBE_ERROR(SBE_FUNC"Failed to update SBE ready state to " + "messaging register. RC: 0x%08X", rc); + } + return rc; + #undef SBE_FUNC +} + + +/** + * @brief Set the MPIPL mode bit into the mailbox scratch reg. 3 + * The function does a read-modify-write, so any bits other than the + * SBE ready bit remain unchanged. + * + * @param i_set [in] Whether to set or clear the MPIPL flag + * + * @return RC indicating success/failure. + * + */ +uint32_t SbeRegAccess::setMpIplMode(const bool i_set) +{ + #define SBE_FUNC "SbeRegAccess::setMpIplMode" + uint32_t rc = 0; + uint8_t l_set = i_set; + rc = getscom_abs(PERV_SCRATCH_REGISTER_3_SCOM, &iv_mbx3); + if(rc) + { + SBE_ERROR(SBE_FUNC"Failed read PERV_SCRATCH_REGISTER_3_SCOM " + "RC: 0x%08X", rc); + } + + iv_mpiplMode = i_set; + PLAT_ATTR_INIT(ATTR_IS_MPIPL, Target<TARGET_TYPE_SYSTEM>(), l_set); + rc = putscom_abs(PERV_SCRATCH_REGISTER_3_SCOM, iv_mbx3); + if(rc) + { + SBE_ERROR(SBE_FUNC"Failed to set/clear MPIPL flag in " + "mbx reg. 3. RC: 0x%08X", rc); + } + return rc; + #undef SBE_FUNC +} + +uint32_t SbeRegAccess::updateAsyncFFDCBit( bool i_on ) +{ + #define SBE_FUNC "SbeRegAccess::updateAsyncFFDCBit " + uint32_t rc = 0; + + iv_asyncFFDC = i_on; + + rc = putscom_abs(PERV_SB_MSG_SCOM, iv_messagingReg); + if(rc) + { + SBE_ERROR(SBE_FUNC"Failed to update SBE Aync bit in message " + "register. RC: 0x%08X", rc); + } + return rc; + #undef SBE_FUNC +} + diff --git a/src/sbefw/core/sberegaccess.H b/src/sbefw/core/sberegaccess.H new file mode 100644 index 00000000..420cf795 --- /dev/null +++ b/src/sbefw/core/sberegaccess.H @@ -0,0 +1,302 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sberegaccess.H $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* */ +/* */ +/* 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: ppe/sbe/sbefw/sberegaccess.H + * + * @brief This file contains interfaces to get/set FW flags either in the + * scratch registers and/or the FW attributes. + */ + +#ifndef __SBEFW_SBEREGACCESS_H +#define __SBEFW_SBEREGACCESS_H + +#include <stdint.h> +#include "sbestates.H" +#include "sbeevents.H" + +/** + * @brief Utility singleton that SBEFW can use to read write various scratch + * registers/FW attributes + * TODO: via RTC ??????: Need to change the read of scratch registers to FAPI + * attribute accesses once we have the attributes defined in the HWP code. + */ +class SbeRegAccess +{ + public: + // Disable copy construction and assignment operators + SbeRegAccess(const SbeRegAccess&) = delete; + SbeRegAccess& operator=(const SbeRegAccess&) = delete; + + /** + * @brief Returns the instance of this class + * + * @return A reference to SbeRegAccess + * + */ + static SbeRegAccess& theSbeRegAccess() + { + return cv_instance; + } + + /** + * @brief Initializes the class for use + * + * @return An RC indicating success/failure + * + */ + uint32_t init(); + + /** + * @brief Update the SBE states into the SBE messaging register. The + * function does a read-modify-write, so any bits other than the state + * bits are preserved. The current state of the register is set to + * i_state, whereas the old current state is copied to previous state + * + * @param [in] i_state The current SBE state + * + * @return RC indicating success/failure. + * + */ + uint32_t updateSbeState(const sbeState &i_state); + + /** + * @brief Update the SBE IPL steps into the SBE messaging register. The + * function does a read-modify-write, so any bits other than the IPL + * steps are retianed + * + * @param [in] i_major IPL major step number + * @param [in] i_minor IPL minor step number + * + * @return RC indicating success/failure. + * + */ + uint32_t updateSbeStep(const uint8_t i_major, const uint8_t i_minor); + + /** + * @brief Set the SBE ready bit into the SBE messaging register + * (meaning that SBE control loop is initialized) The function does a + * read-modify-write, so any bits other than the SBE ready bit remain + * unchanged. + * + * @return RC indicating success/failure. + * + */ + uint32_t setSbeReady(); + + /** + * @brief Set the MPIPL mode bit into the mailbox scratch reg. 3 + * The function does a read-modify-write, so any bits other than the + * SBE ready bit remain unchanged. It also updates the attribute + * ATTR_MPIPL + * + * @param i_set [in] true == set, false == clear + * + * @return RC indicating success/failure. + * + */ + uint32_t setMpIplMode(const bool i_set); + + /** + * @brief Check if we are on an FSP attached + * + * @return true if FSP attached system, false otherwise + * + */ + inline bool isFspSystem() const + { + return iv_fspAttached; + } + + /** + * @brief Check if we are in ISTEP IPL mode + * + * @return true if in istep mode, false otherwise + * + */ + inline bool isIstepMode() const + { + return iv_istepMode; + } + + /** + * @brief Check if SBE should directly go to runtime state + * + * @return true if SBE should go directly to runtime state, + * false otherwise + * + */ + inline bool isDestBitRuntime() const + { + return iv_sbeDestRuntime; + } + + /** + * @brief Check if SBE should collect FFDC + * + * @return true if in istep mode, false otherwise + * + */ + inline bool isCollectFFDCSet() const + { + return iv_collectFFDC; + } + + /** + * @brief Check if SBE should send internal FFDC for any chip op + * failures as a part of the response + * + * @return true if in istep mode, false otherwise + * + */ + inline bool isSendInternalFFDCSet() const + { + return iv_sendFFDC; + } + + /** + * @brief Check if SBE is slave/master + * + * @return true if SBE is slave, false if master + * + */ + inline bool isSbeSlave() const + { + return iv_isSlave; + } + + /** + * @brief Get the SBE current State + * + * @return SBE current State, sbeState enum + * + */ + uint64_t getSbeState() const + { + return iv_currState; + } + + /** + * @brief Get the SBE previous State + * + * @return SBE previous State, sbeState enum + * + */ + uint64_t getSbePrevState() const + { + return iv_prevState; + } + + + /** + * @brief Get the SBE major istep number + * + * @return SBE current major istep number + * + */ + uint8_t getSbeMajorIstepNumber() const + { + return iv_majorStep; + } + + /** + * @brief Update the SBE State as per the transition event + * + * @param [in] i_event Transition Event + */ + void stateTransition(const sbeEvent &i_event); + + /** + * @brief Update the async bit into the SBE messaging register. The + * function does a read-modify-write, so any bits other than the async + * bits are retained. + * + * @param [in] i_on True to turn on bit, false to turn off + * + * @return RC indicating success/failure. + * + */ + uint32_t updateAsyncFFDCBit( bool i_on ); + private: + + /** + * @brief Constructor + */ + SbeRegAccess() : iv_mbx3(0), iv_mbx6(0), iv_messagingReg(0) + {} + + union + { + struct + { + uint64_t iv_istepMode : 1; + uint64_t iv_sbeDestRuntime : 1; + uint64_t iv_mpiplMode : 1; + uint64_t iv_fspAttached : 1; + uint64_t iv_collectFFDC : 1; + uint64_t iv_sendFFDC : 1; + uint64_t iv_mbx3DontCare : 26; + uint64_t iv_mbx3Unused : 32; + }; + uint64_t iv_mbx3; + }; + + union + { + struct + { + uint64_t iv_mbx6DontCare : 24; + uint64_t iv_isSlave : 1; + uint64_t iv_mbx6DontCare2 : 7; + uint64_t iv_mbx6Unused : 32; + }; + uint64_t iv_mbx6; + }; + + union + { + struct + { + uint64_t iv_sbeBooted : 1; + uint64_t iv_asyncFFDC : 1; + uint64_t iv_reserved1 : 2; + uint64_t iv_prevState : 4; + uint64_t iv_currState : 4; + uint64_t iv_majorStep : 8; // Max major is 97 + uint64_t iv_minorStep : 6; // Max minor is 34 + uint64_t iv_reserved2 : 6; // Unused + uint64_t iv_unused : 32; + }; + uint64_t iv_messagingReg; + }; + + // Bit masks defining bits in the above registers that the SBE is + // interested in + static const uint64_t SBE_MBX8_MBX3_VALID_MASK = 0x2000000000000000ULL; + static const uint64_t SBE_MBX8_MBX6_VALID_MASK = 0x0400000000000000ULL; + static const uint64_t SBE_DEV_ID_C4_PIN_MASK = 0x0000000000800000ULL; + static const uint64_t SBE_PERV_DEVICE_ID_REG_BIT58_MASK = 0x0000000000000020ULL; + static SbeRegAccess cv_instance; +}; +#endif //__SBEFW_SBEREGACCESS_H + diff --git a/src/sbefw/core/sbescom.C b/src/sbefw/core/sbescom.C new file mode 100644 index 00000000..7c4105a0 --- /dev/null +++ b/src/sbefw/core/sbescom.C @@ -0,0 +1,221 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbescom.C $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* */ +/* */ +/* 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 <stdint.h> +#include "sbe_sp_intf.H" +#include "sbetrace.H" +#include "plat_hw_access.H" +#include "plat_target.H" +#include "sbescom.H" +#include "sbeSecurity.H" + +using namespace fapi2; +/** + * @brief Indirect SCOM Status + */ +union IndirectScom_t +{ + uint64_t data64; + struct + { + uint64_t :12; //0:11 + uint64_t addr:20; //12:31 + uint64_t done:1; //32 + uint64_t piberr:3; //33:35 + uint64_t userstat:4; //36:39 + uint64_t :8; //40:47 + uint64_t data:16; //48:63 + }; + +}; + +// Wait time slice to check indirect scom status register +static const uint32_t SBE_INDIRECT_SCOM_WAIT_TIME_NS = 10000; +// Indirect scom timeout +static const uint32_t MAX_INDSCOM_TIMEOUT_NS = 100000; //0.1 ns + +static const uint64_t DIRECT_SCOM_ADDR_MASK = 0x8000000000000000; +static const uint64_t INDIRECT_SCOM_NEW_ADDR_MASK = 0x9000000000000000; + +// Scom types +enum sbeScomType +{ + SBE_SCOM_TYPE_DIRECT = 0, // Direct scom + SBE_SCOM_TYPE_INDIRECT1 = 1, // Indirect scom. Old form + SBE_SCOM_TYPE_INDIRECT_2 = 2, // Indirect scom. New form +}; + +void checkIndirectAndDoScom( const bool i_isRead, + const uint64_t i_addr, + uint64_t & io_data, + sbeRespGenHdr_t *const o_hdr, + sbeResponseFfdc_t *const o_ffdc) +{ + + #define SBE_FUNC " checkIndirectAndDoScom " + uint32_t elapsedIndScomTimeNs = 0; + uint64_t tempBuffer = io_data; + sbeScomType scomType = SBE_SCOM_TYPE_DIRECT; + ReturnCode fapiRc = FAPI2_RC_SUCCESS; + do + { + // If the indirect scom bit is 0, then doing a regular scom + if( (i_addr & DIRECT_SCOM_ADDR_MASK) == 0) + { + plat_target_handle_t l_hndl; + SBE_INFO(SBE_FUNC "Performing Direct scom."); + CHECK_SBE_SECURITY_RC_AND_BREAK_IF_NOT_SUCCESS( + static_cast<uint32_t>(i_addr), + (i_isRead ? SBE_SECURITY::READ : SBE_SECURITY::WRITE), + o_hdr->primaryStatus, + o_hdr->secondaryStatus) + if( i_isRead ) + { + fapiRc = getscom_abs_wrap (&l_hndl, (uint32_t)i_addr, + & io_data); + } + else + { + fapiRc = putscom_abs_wrap (&l_hndl, (uint32_t)i_addr, + io_data); + } + break; + } + // We are performing an indirect scom. + if( ( i_addr & INDIRECT_SCOM_NEW_ADDR_MASK ) == + INDIRECT_SCOM_NEW_ADDR_MASK ) + { + scomType = SBE_SCOM_TYPE_INDIRECT_2; + if( i_isRead ) + { + // Not allowed write on new format. + SBE_ERROR(SBE_FUNC "Read not allowed in new form"); + o_hdr->primaryStatus = SBE_PRI_GENERIC_EXECUTION_FAILURE; + o_hdr->secondaryStatus = SBE_SEC_INVALID_ADDRESS_PASSED; + break; + } + // Zero out the indirect address location.. leave the 52bits of data + // Get the 12bit indirect scom address + // OR in the 20bit indirect address + tempBuffer = ( tempBuffer & 0x000FFFFFFFFFFFFF ) | + ( ( i_addr & 0x00000FFF00000000) << 20 ); + } + else + { + scomType = SBE_SCOM_TYPE_INDIRECT1; + // Zero out the indirect address location.. leave the 16bits of data + // Get the 20bit indirect scom address + // OR in the 20bit indirect address + tempBuffer = ( tempBuffer & 0x000000000000FFFF) | + ( i_addr & 0x000FFFFF00000000 ); + } + + SBE_INFO(SBE_FUNC "Performing Indirect scom. Type :%u", scomType); + + // zero out the indirect address from the buffer.. + // bit 0-31 - indirect area.. + // bit 32 - always 0 + // bit 33-47 - bcast/chipletID/port + // bit 48-63 - local addr + uint64_t tempAddr = i_addr & 0x000000007FFFFFFF; + plat_target_handle_t l_hndl; + CHECK_SBE_SECURITY_RC_AND_BREAK_IF_NOT_SUCCESS( + static_cast<uint32_t>(tempAddr), + (i_isRead ? SBE_SECURITY::READ : SBE_SECURITY::WRITE), + o_hdr->primaryStatus, + o_hdr->secondaryStatus) + + // If we are doing a read. We need to do a write first.. + if( i_isRead) + { + // turn the read bit on. + tempBuffer = tempBuffer | 0x8000000000000000; + } + else //write + { + // Turn the read bit off. + tempBuffer = tempBuffer & 0x7FFFFFFFFFFFFFFF; + + } // end of write + + // perform write before the read with the new + // IO_buffer with the imbedded indirect scom addr. + fapiRc = putscom_abs_wrap (&l_hndl, tempAddr, tempBuffer); + + if( ( fapiRc != FAPI2_RC_SUCCESS ) || + ( scomType == SBE_SCOM_TYPE_INDIRECT_2 )) + { + break; + } + + // Need to check loop on read until we see done, error, + // or we timeout + IndirectScom_t scomout; + do + { + // Now perform the op requested using the passed in + // IO_Buffer to pass the read data back to caller. + fapiRc = getscom_abs_wrap (&l_hndl, tempAddr, &(scomout.data64)); + + if( fapiRc != FAPI2_RC_SUCCESS) break; + // if bit 32 is on indicating a complete bit + // or we saw an error, then we're done + if (scomout.piberr) + { + + SBE_ERROR(SBE_FUNC "pib error reading status register"); + break; + } + if (scomout.done ) + { + io_data = scomout.data; + break; + } + + pk_sleep(PK_NANOSECONDS(SBE_INDIRECT_SCOM_WAIT_TIME_NS)); + elapsedIndScomTimeNs += SBE_INDIRECT_SCOM_WAIT_TIME_NS; + + }while ( elapsedIndScomTimeNs <= MAX_INDSCOM_TIMEOUT_NS); + + if( fapiRc != FAPI2_RC_SUCCESS ) break; + if( ! scomout.done) + { + SBE_ERROR(SBE_FUNC "Indirect scom timeout."); + o_hdr->primaryStatus = SBE_PRI_GENERIC_EXECUTION_FAILURE; + o_hdr->secondaryStatus = SBE_SEC_HW_OP_TIMEOUT; + break; + } + + }while(0); + + if (fapiRc != FAPI2_RC_SUCCESS) + { + o_hdr->primaryStatus = SBE_PRI_GENERIC_EXECUTION_FAILURE; + o_hdr->secondaryStatus = SBE_SEC_PCB_PIB_ERR; + if(o_ffdc) o_ffdc->setRc(fapiRc); + } + + SBE_DEBUG(SBE_FUNC "fapiRc:%u o_hdr->secondaryStatus:0x%08X", fapiRc, o_hdr->secondaryStatus); +} + diff --git a/src/sbefw/core/sbescom.H b/src/sbefw/core/sbescom.H new file mode 100644 index 00000000..5d242cdf --- /dev/null +++ b/src/sbefw/core/sbescom.H @@ -0,0 +1,40 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbescom.H $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* */ +/* */ +/* 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 "sbeSpMsg.H" +/** + * @brief check if scom address is Indirect scom and perform scom + * + * @param[in] i_isRead True if read operation, false otherwise + * @param[in] i_addr scom addess + * @param[in] io_data data for scom operation. For read, it is output operand. + * @param[out] o_hdr response header object + * @param[out] o_ffdc ffdc object + * + */ +void checkIndirectAndDoScom( const bool i_isRead, + const uint64_t i_addr, + uint64_t & io_data, + sbeRespGenHdr_t *const o_hdr, + sbeResponseFfdc_t *const o_ffdc); diff --git a/src/sbefw/core/sbestates.H b/src/sbefw/core/sbestates.H new file mode 100644 index 00000000..4f97c363 --- /dev/null +++ b/src/sbefw/core/sbestates.H @@ -0,0 +1,63 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbestates.H $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* */ +/* */ +/* 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: ppe/sbe/sbefw/sbestates.H + * + * @brief This file contains interfaces pertaining to SBE state/role management + * + */ + +#ifndef __SBEFW_SBESTATES_H +#define __SBEFW_SBESTATES_H + +/** + * @brief An enumeration of all SBE states + * + */ +enum sbeState +{ + SBE_STATE_UNKNOWN = 0x0, // Unkown, initial state + SBE_STATE_IPLING = 0x1, // IPL'ing - autonomous mode (transient) + SBE_STATE_ISTEP = 0x2, // ISTEP - Running IPL by steps (transient) + SBE_STATE_MPIPL = 0x3, // MPIPL + SBE_STATE_RUNTIME = 0x4, // SBE Runtime + SBE_STATE_DMT = 0x5, // Dead Man Timer State (transient) + SBE_STATE_DUMP = 0x6, // Dumping + SBE_STATE_FAILURE = 0x7, // Internal SBE failure + SBE_STATE_QUIESCE = 0x8, // Final state - needs SBE reset to get out + + // Max States, Always keep it at the last of the enum and sequential + SBE_MAX_STATE = 0x9, + // Don't count this in the state, just to intialize the state variables + SBE_INVALID_STATE = 0xF, +}; + +enum sbeRole +{ + SBE_ROLE_MASTER = 0, + SBE_ROLE_SLAVE = 1 +}; + +#endif //__SBEFW_SBESTATES_H + diff --git a/src/sbefw/core/sbetrace.H b/src/sbefw/core/sbetrace.H new file mode 100644 index 00000000..5c3ea7b5 --- /dev/null +++ b/src/sbefw/core/sbetrace.H @@ -0,0 +1,75 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbetrace.H $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2017 */ +/* */ +/* */ +/* 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 __SBEFW_SBE_TRACE_H +#define __SBEFW_SBE_TRACE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "pk_api.h" +#include "trac_interface.h" + +#ifdef __cplusplus +} +#endif + +#define SBE_ENTER_MRK ">>" +#define SBE_EXIT_MRK "<<" +#define SBE_ERR_MRK "E>" +#define SBE_INF_MRK "I>" +#define SBE_DEBUG_MRK "D>" + +#define SBE_ERROR(args...) +#define SBE_INFO(args...) +#define SBE_ENTER(args...) +#define SBE_EXIT(args...) +#define SBE_DEBUG(args...) + +// Levels of logging +// 0 - No tracing +// 1 - Error +// 2 - Error, info +// 3 - Error, info, entry/exit +// 4 - Error, info, entry/exit, debug +#if (SBE_TRACE_LEVEL >= 1) +#undef SBE_ERROR +#define SBE_ERROR(args...) PK_TRACE(SBE_ERR_MRK"" args) +#endif +#if (SBE_TRACE_LEVEL >= 2) +#undef SBE_INFO +#define SBE_INFO(args...) PK_TRACE(SBE_INF_MRK"" args) +#endif +#if (SBE_TRACE_LEVEL >= 3) +#undef SBE_ENTER +#undef SBE_EXIT +#define SBE_ENTER(args...) PK_TRACE(SBE_ENTER_MRK"" args) +#define SBE_EXIT(args...) PK_TRACE(SBE_EXIT_MRK"" args) +#endif +#if (SBE_TRACE_LEVEL >= 4) +#undef SBE_DEBUG +#define SBE_DEBUG(args...) PK_TRACE(SBE_DEBUG_MRK"" args) +#endif +#define SBE_TRACE(args...) PK_TRACE(args) +#endif // __SBEFW_SBE_TRACE_H diff --git a/src/sbefw/core/sbeutil.C b/src/sbefw/core/sbeutil.C new file mode 100644 index 00000000..bc53e7a4 --- /dev/null +++ b/src/sbefw/core/sbeutil.C @@ -0,0 +1,62 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbeutil.C $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* */ +/* */ +/* 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 "sbeutil.H" +#include "fapi2.H" +#include "sbetrace.H" +#include "sbeglobals.H" +// Nest frequency array +#include "p9_frequency_buckets.H" +namespace SBE +{ + bool isSimics() __attribute__((alias("__isSimicsRunning"))); + extern "C" void __isSimicsRunning() __attribute__ ((noinline)); + + void __isSimicsRunning() + { + asm volatile("li 3, 0"); + SBE_MAGIC_INSTRUCTION(MAGIC_SIMICS_CHECK); + } + + bool isSimicsRunning() + { + static bool simics = isSimics(); + return simics; + } + + void updatePkFreq() + { + #define SBE_FUNC "updatePkFreq " + using namespace fapi2; + Target<TARGET_TYPE_SYSTEM> sys; + uint8_t nestPllBkt = 0; + FAPI_ATTR_GET( ATTR_NEST_PLL_BUCKET, sys, nestPllBkt ); + assert( nestPllBkt && (nestPllBkt <= NEST_PLL_FREQ_BUCKETS )); + SBE_GLOBAL->sbefreq = ( NEST_PLL_FREQ_LIST[ nestPllBkt - 1 ] * 1000 * 1000 )/ + SBE::SBE_TO_NEST_FREQ_FACTOR; + SBE_INFO(SBE_FUNC"Setting new frequency:0x%08X", SBE_GLOBAL->sbefreq); + pk_timebase_freq_set(SBE_GLOBAL->sbefreq); + #undef SBE_FUNC + } +} + diff --git a/src/sbefw/core/sbeutil.H b/src/sbefw/core/sbeutil.H new file mode 100644 index 00000000..75ea07b5 --- /dev/null +++ b/src/sbefw/core/sbeutil.H @@ -0,0 +1,197 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbeutil.H $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2017 */ +/* */ +/* */ +/* 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 SBE_UTIL_H +#define SBE_UTIL_H +#ifdef __cplusplus +extern "C" { +#endif + +#include "pk.h" +#include "pk_api.h" + +#ifdef __cplusplus +} +#endif + +#define MASK_ZERO_L32B_UINT64(x) ((x) & 0xFFFFFFFF00000000ull) +#define MASK_ZERO_H32B_UINT64(x) ((x) & 0x00000000FFFFFFFFull) +#define SHIFT_RIGHT(x, bits) ((x) >> bits) + +// Macros Defined for Internal RC Check, Break if Error +#define CHECK_SBE_RC_AND_BREAK_IF_NOT_SUCCESS(l_rc) \ +if ((l_rc) != SBE_SEC_OPERATION_SUCCESSFUL) \ +{ \ + break; \ +} + +#define CHECK_SBE_SECURITY_RC_AND_BREAK_IF_NOT_SUCCESS(addr, op, prim, sec) \ +if (!SBE_SECURITY::isAllowed(addr, op)) \ +{ \ + prim = SBE_PRI_UNSECURE_ACCESS_DENIED; \ + sec = SBE_SEC_BLACKLISTED_REG_ACCESS; \ + /* TODO via RTC 180983:Enable this once the BL/WL registers are settled */ \ + /*break;*/ \ +} + +#define mfdec() \ + ({volatile uint32_t l_dec; \ + asm volatile ("mfdec %0" : "=r" (l_dec)); \ + l_dec;}) + +// To handle unused variables compilation error +static inline void UNUSED(int dummy, ...) {} + +// Magic instruction + +/** @brief This is a special assembler instruction that is a nop on + * regular hardware, but has special meaning to Simics. Code that + * executes this instruction in Simics will cause a "hap," a + * Simics term. If there is no hap handler registered, and magic + * breakpoints have not been enabled with + * simics> enable-magic-breakpoint + * then this instruction is also a nop in Simics. + * + * If magic breakpoints are enabled, and there is no hap handler, then + * when SBE code executes this instruction in Simics, Simics will + * stop the simulation. (Prompt changes from running> to simics> ) + * + * If a hap is registered, then Simics will call the hap handler. Hap + * handlers are written in Python, and the best place for them is + * + * src/tools/debug//simics-debug-framework.py + * + * Sample code to register the hap handler: + * # arg contains the integer parameter n passed to MAGIC_INSTRUCTION(n) + * def magic_instruction_callback(user_arg, cpu, arg): + * # print to console works... + * print "Hit magic instruction ", arg + * # Or else stop the simulation... + * SIM_break_simulation( "Stopped at magic instruction" ) + * + * # Register the magic instruction callback. + * SIM_hap_add_callback( "Core_Magic_Instruction", + * magic_instruction_callback, None ) + * + * # Better to register the SBE range 8000-8190 + * # so that PHYP and others won't be affected. + * SIM_hap_add_callback_range( "Core_Magic_Instruction", + * magic_instruction_callback, None, 8000, 8190 ) + * + * The argument n is an integer from 0..8191 which Simics passes to the hap + * handler in parameter 3, or "arg" in the sample code above. + */ +__attribute__((always_inline)) +inline void SBE_MAGIC_INSTRUCTION(int _n) +{ + register int n = _n; + asm volatile("rlwimi %0,%0,0,%1,%2" \ + :: "i" (((n) >> 8) & 0x1f), \ + "i" (((n) >> 4) & 0xf), \ + "i" ((((n) >> 0) & 0xf) | 16)); +} + +// Macro to execute HWP +#ifdef SEEPROM_IMAGE +#define SBE_EXEC_HWP_NOARG(...) SBE_EXEC_HWP(__VA_ARGS__) +#define SBE_EXEC_HWP(fapiRc, hwp, ...) \ +{ \ + fapiRc = hwp(__VA_ARGS__); \ +} +#else +#define SBE_EXEC_HWP_NOARG(fapiRc, hwp) \ +{ \ + SBE_INFO("Procedure not present in the image:No-Op"); \ + fapiRc = FAPI2_RC_SUCCESS; \ +} +#define SBE_EXEC_HWP(fapiRc, hwp, ...) \ +{ \ + /* handling unused variables */ \ + UNUSED(0, __VA_ARGS__); \ + SBE_INFO("Procedure not present in the image:No-Op"); \ + fapiRc = FAPI2_RC_SUCCESS; \ +} +#endif + +void sbeHandleFifoResponse (const uint32_t i_rc); + +void sbeHandlePsuResponse (const uint32_t i_rc); + +namespace SBE +{ + + // enum for magic instructions + enum + { + MAGIC_SIMICS_CHECK = 8000, // check if code is running on simics + }; + // Nest to SBE frequency ratio + static const uint8_t SBE_TO_NEST_FREQ_FACTOR = 4; + + // Currently PK does not define start range for app + // specifc panic code as enum. It is implicit understanding + // through code comments. Expectation is 0x1cxx range is for + // non-pk code. + static const uint32_t PK_APP_OFFSET_SBE_START = 0x1c00; + enum + { + // For defining new panic codes refer to pk/ppe42/pk_panic_codes.h + PANIC_ASSERT = PK_APP_OFFSET_SBE_START + }; + + /*@brief - Get higher 32bit number from uint64 + * + * @param[in] - i_lWord - 64bit long word + * + * @return - uint32_t word + */ + inline uint32_t higher32BWord(uint64_t i_lWord) + { + return (uint32_t)(SHIFT_RIGHT(MASK_ZERO_L32B_UINT64(i_lWord), 32)); + } + + /*@brief - Get lower 32bit number from uint64 + * + * @param[in] - i_lWord - 64bit long word + * + * @return - uint32_t word + */ + inline uint32_t lower32BWord(uint64_t i_lWord) + { + return (uint32_t)(MASK_ZERO_H32B_UINT64(i_lWord)); + } + + /*@brief - checks if sbe is running on simics + * + * @return - True if sbe is running on simics , false otherwise + */ + bool isSimicsRunning(); + + /*@brief - Update the pk frequcy as per NEST PLL bucket + * + * @return - void + */ + void updatePkFreq(); + +} // namespace SBE +#endif //SBE_UTIL_H diff --git a/src/sbefw/core/vector b/src/sbefw/core/vector new file mode 100644 index 00000000..bbb0818d --- /dev/null +++ b/src/sbefw/core/vector @@ -0,0 +1,397 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/vector $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* */ +/* */ +/* 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 stl_vector +#define stl_vector + +/** + * @file vector + * @brief simple stl vector template class declaration. + */ + +#include <stddef.h> + +#if !defined( __STDC_LIMIT_MACROS) +#define __STDC_LIMIT_MACROS +#endif +#include <stdint.h> +#include <pool.H> +#include <assert.h> +#include <new> +namespace std +{ + + /** + * @class vector + * subset of stl vector + * @note Does not support allocators, reverse iterators. + */ + template <class T> + class vector + { + public: + + typedef T * iterator; + typedef const T * const_iterator; + typedef T & reference; + typedef const T & const_reference; + typedef size_t size_type; + typedef T value_type; + typedef T * pointer; + typedef const T * const_pointer; + + protected: + + pointer iv_start __attribute__ ((aligned (8))); + pointer iv_finish; + SBEVECTORPOOL::vectorMemPool_t *iv_poolPtr; + public: + + /** + * Constructor default + * @post The vector is created with storage of + * G_BLOCKSIZE bytes. + */ + explicit vector(void) + { + iv_poolPtr = SBEVECTORPOOL::allocMem(); + assert ( NULL != iv_poolPtr) + iv_start = ( T* )iv_poolPtr->data; + iv_finish = iv_start; + } + + + /** + * MOVE COPY CTOR create a vector from another vector + * @param[in] x source vector + * @post Vector of x.size() is created from x with same + * memory. + * size() == capacity() == x.size() + * @note move Copy construtor willuse shallow copy. So input + * as well as output vector will point to same data + */ + vector(const vector<T>&& x) + { + iv_start = x.iv_start; + iv_finish = x.iv_finish; + iv_poolPtr = x.iv_poolPtr; + iv_poolPtr->refCount++; + } + + /** + * Reserve space for atleast n elements + * @param[in] n Number of elements + * @note We are having fixed size vectors in ppe. Defining + * this function to avoid compile issues in standard + * library. This function is noop for less than 512 + * bytes requirement. For more than 512 bytes, it will + * assert. + */ + void reserve(size_type n) + { + assert(n < max_size()); + return; + } + /** + * DTOR + * @post Storage released + */ + __attribute__ ((always_inline)) + ~vector() + { + clear(); // call dtors + SBEVECTORPOOL::releaseMem(iv_poolPtr); + } + + /** + * Move Assignment operator. + * @param[in] x A vector. + * @return A vector (for the purpose of multiple assigns). + * @pre None. + * @post *this == x, this->capacity() == x.size(). + * All previously obtained iterators are invalid. + */ + vector<T>& operator=(const vector<T>&& x) + { + // Just check here for pool to make sure + // input vector and current vector are not same; + if( iv_poolPtr != x.iv_poolPtr) + { + clear(); + SBEVECTORPOOL::releaseMem(iv_poolPtr); + iv_start = x.iv_start; + iv_finish = x.iv_finish; + iv_poolPtr = x.iv_poolPtr; + iv_poolPtr->refCount++; + } + return(*this); + } + + // Iterators -------------------- + + /** + * Get iterator to the first vector element + * @return iterator of rist vector element + * @pre None. + * @post None. + */ + __attribute__ ((always_inline)) + iterator begin() + { + return (iv_start); + } + + /** + * Get const_iterator to the first vector element + * @return const_iterator of rist vector element + * @pre None. + * @post None. + */ + __attribute__ ((always_inline)) + const_iterator begin() const + { + return (iv_start); + } + + /** + * Get iterator to the last vector element + 1 + * @return iterator + * @pre None. + * @post None. + */ + __attribute__ ((always_inline)) + iterator end() + { + return (iv_finish); + } + + /** + * Get const_iterator to the last vector element + 1 + * @return const_iterator + * @pre None. + * @post None. + */ + __attribute__ ((always_inline)) + const_iterator end() const + { + return (iv_finish); + } + + // Capacity ----------------------------------------------- + + /** + * Get the number of elements in the container + * @return number of elements in the container + */ + __attribute__ ((always_inline)) + size_type size() const + { + return(iv_finish - iv_start); + } + + /** + * Return the maximum potential size the container could reach. + * @return number of the maximum element count this container + * could reach + */ + __attribute__ ((always_inline)) + size_type max_size() const + { + return SBEVECTORPOOL::G_BLOCKSIZE/(sizeof(T)); + } + + /** + * Query for empty container + * @return bool, true if size()==0 else false. + * @pre none + * @post none + */ + __attribute__ ((always_inline)) + bool empty() const + { + return(size() == 0); + } + + // - Element Access ----------------------------------- + + /** + * Access a mutable reference to an element in the container + * @param An index into the vector + * @return A reference to an element + * @pre 0 <= n < size() + * @post None. + */ + __attribute__ ((always_inline)) + reference operator[](size_type n) + { + assert(n < size()); + return(*(iv_start + n)); + } + + /** + * Access a mutable reference to an element in the container + * @param[in] index An index into the vector + * @return A reference to an element + * @pre 0 <= n < size() + * @post None. + * @note no exception handling + */ + __attribute__ ((always_inline)) + reference at(size_type index) + { + assert(index < size()); + return(*(iv_start + index)); + } + + /** + * Get an immutable reference to an element in the container + * @param[in] index An index into the vector + * @return A const_reference to an object or type T + * @pre 0 <= n < size() + * @post None. + */ + __attribute__ ((always_inline)) + const_reference operator[](size_type index) const + { + assert(index < size()); + return(*(iv_start + index)); + } + + /** + * Get an immutable reference to an element in the container + * @param[in] index An index into the vector + * @return A const_reference to an object or type T + * @pre 0 <= n < size() + * @post None. + * @note no exception handling + */ + __attribute__ ((always_inline)) + const_reference at(size_type index) const + { + assert(index < size()); + return(*(iv_start + index)); + } + + /** + * Get a mutable reference to the first element in the container + * @return reference to first element + * @pre none + * @post None + */ + __attribute__ ((always_inline)) + reference front() + { + return *iv_start; + } + + /** + * Get an Immutable reference to the first element in the + * container + * @return const_reference to first element + * @pre none + * @post None + */ + __attribute__ ((always_inline)) + const_reference front() const + { + return *iv_start; + } + + /** + * Get a mutable reference to the last element in the container + * @return reference to last element + * @pre none + * @post None + */ + __attribute__ ((always_inline)) + reference back() + { + return *(iv_finish-1); + } + + /** + * Get an Immutable reference to the last element in the + * container + * @return reference to last element + * @pre none + * @post None + */ + __attribute__ ((always_inline)) + const_reference back() const + { + return *(iv_finish-1); + } + + /** + * Add element to the back of the container + * @param[in] x reference to object used to create new element + * @pre none + * @post All previously obtained iterators are invalid. + */ + __attribute__ ((always_inline)) + void push_back(const T& x) + { + assert(max_size() > size()); + new (iv_finish++) T(x); + } + + /** + * Clear the vector + * @pre none. + * @post size() = 0, All previously obtained iterators are + * invalid + * @note capacity unchanged + */ + void clear () + { + while(iv_finish != iv_start) + { + --iv_finish; + (iv_finish)->~T(); + } + } + + /* + * Assign new content to the vector object + * @param[in] n number of elements to assign + * @param[in] x reference to element to copy in + */ + void assign ( size_type n, const T& x) + { + assert(n < max_size()); + clear(); + for ( ; n> 0; n--) + push_back( x); + } + + private: + vector(const vector<T>& x); + vector<T>& operator=(const vector<T>& x); +}; + +}; // end namespace std + + +#endif +/* vim: set filetype=cpp : */ |