diff options
Diffstat (limited to 'src/usr')
-rw-r--r-- | src/usr/initservice/extinitsvc/extinitsvctasks.H | 14 | ||||
-rw-r--r-- | src/usr/makefile | 1 | ||||
-rw-r--r-- | src/usr/sbeio/makefile | 32 | ||||
-rw-r--r-- | src/usr/sbeio/sbe_coreStateControl.C | 110 | ||||
-rw-r--r-- | src/usr/sbeio/sbe_psudd.C | 409 | ||||
-rw-r--r-- | src/usr/sbeio/sbe_psudd.H | 414 |
6 files changed, 980 insertions, 0 deletions
diff --git a/src/usr/initservice/extinitsvc/extinitsvctasks.H b/src/usr/initservice/extinitsvc/extinitsvctasks.H index 8d1c44ab4..4cd06b868 100644 --- a/src/usr/initservice/extinitsvc/extinitsvctasks.H +++ b/src/usr/initservice/extinitsvc/extinitsvctasks.H @@ -168,6 +168,20 @@ const TaskInfo g_exttaskinfolist[] = { } }, #endif + + /** + * @brief SBE IO Device Driver + */ + { + "libsbeio.so", // taskname + NULL, // no ptr to fnct + { + + INIT_TASK, // init only + EXT_IMAGE, // Extended Module + } + }, + /** * @brief FSI SCOM Device Driver */ diff --git a/src/usr/makefile b/src/usr/makefile index f0ef233fe..a1e79fdd5 100644 --- a/src/usr/makefile +++ b/src/usr/makefile @@ -59,6 +59,7 @@ SUBDIRS += secureboot.d SUBDIRS += devtree.d #@TODO RTC:142091 #SUBDIRS += sbe.d +SUBDIRS += sbeio.d SUBDIRS += gpio.d SUBDIRS += lpc.d SUBDIRS += console.d diff --git a/src/usr/sbeio/makefile b/src/usr/sbeio/makefile new file mode 100644 index 000000000..421027557 --- /dev/null +++ b/src/usr/sbeio/makefile @@ -0,0 +1,32 @@ +# IBM_PROLOG_BEGIN_TAG +# This is an automatically generated prolog. +# +# $Source: src/usr/sbeio/makefile $ +# +# OpenPOWER HostBoot Project +# +# Contributors Listed Below - COPYRIGHT 2015,2016 +# [+] 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 +ROOTPATH = ../../.. + +MODULE = sbeio + +OBJS += sbe_psudd.o +OBJS += sbe_coreStateControl.o + +include ${ROOTPATH}/config.mk diff --git a/src/usr/sbeio/sbe_coreStateControl.C b/src/usr/sbeio/sbe_coreStateControl.C new file mode 100644 index 000000000..7d18d2c1a --- /dev/null +++ b/src/usr/sbeio/sbe_coreStateControl.C @@ -0,0 +1,110 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/sbeio/sbe_coreStateControl.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2012,2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +/** + * @file sbe_coreStateControl.C + * @brief Core State Control Messages to control the deadmap loop + */ + +#include <config.h> +#include <trace/interface.H> +#include <errl/errlmanager.H> +#include <sbeio/sbeioif.H> +#include "sbe_psudd.H" + +extern trace_desc_t* g_trac_sbeio; + +#define SBE_TRACD(printf_string,args...) \ + TRACDCOMP(g_trac_sbeio,"coreStateControl: " printf_string,##args) + +namespace SBEIO +{ + +/** + * @brief Start Deadman loop + * + * @param[in] i_waitTime Time to wait in milliseconds + * + * @return errlHndl_t Error log handle on failure. + * + */ + +errlHndl_t startDeadmanLoop(const uint64_t i_waitTime ) +{ + errlHndl_t errl = NULL; + + SBE_TRACD(ENTER_MRK "startDeadmanLoop waitTime=0x%x",i_waitTime); + + psuCommand l_psuCommand( + SBE_DMCONTROL_START | SBE_DMCONTROL_RESPONSE_REQUIRED, //control flags + SBE_PSU_CLASS_CORE_STATE, //command class + SBE_CMD_CONTROL_DEADMAN_LOOP); //comand + psuResponse l_psuResponse; + + // set up PSU command message + l_psuCommand.cdl_waitTime = i_waitTime; + + errl = performPsuChipOp(&l_psuCommand, + &l_psuResponse, + MAX_PSU_SHORT_TIMEOUT_NS, + SBE_DMCONTROL_START_REQ_USED_REGS, + SBE_DMCONTROL_START_RSP_USED_REGS); + + SBE_TRACD(EXIT_MRK "startDeadmanLoop"); + + return errl; +}; + + + +/** + * @brief Stop Deadman loop + * + * @return errlHndl_t Error log handle on failure. + * + */ +errlHndl_t stopDeadmanLoop() +{ + errlHndl_t errl = NULL; + + SBE_TRACD(ENTER_MRK "stopDeadmanLoop"); + + psuCommand l_psuCommand( + SBE_DMCONTROL_STOP + SBE_DMCONTROL_RESPONSE_REQUIRED, //control flags + SBE_PSU_CLASS_CORE_STATE, //command class + SBE_CMD_CONTROL_DEADMAN_LOOP); //comand + psuResponse l_psuResponse; + + errl = performPsuChipOp(&l_psuCommand, + &l_psuResponse, + MAX_PSU_SHORT_TIMEOUT_NS, + SBE_DMCONTROL_STOP_REQ_USED_REGS, + SBE_DMCONTROL_STOP_RSP_USED_REGS); + + SBE_TRACD(EXIT_MRK "stopDeadmanLoop"); + + return errl; +}; +} //end namespace SBEIO + diff --git a/src/usr/sbeio/sbe_psudd.C b/src/usr/sbeio/sbe_psudd.C new file mode 100644 index 000000000..bce5331f6 --- /dev/null +++ b/src/usr/sbeio/sbe_psudd.C @@ -0,0 +1,409 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/sbeio/sbe_psudd.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2012,2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +/** + * @file sbe_psudd.C + * @brief SBE PSU device driver + */ + +#include <sys/time.h> +#include <trace/interface.H> +#include <devicefw/driverif.H> +#include <errl/errlentry.H> +#include <errl/errlmanager.H> +#include <errl/errludtarget.H> +#include <targeting/common/target.H> +#include <targeting/common/targetservice.H> +#include <sbeio/sbeioreasoncodes.H> +#include "sbe_psudd.H" + +trace_desc_t* g_trac_sbeio; +TRAC_INIT(&g_trac_sbeio, SBEIO_COMP_NAME, 6*KILOBYTE, TRACE::BUFFER_SLOW); + +#define SBE_TRACF(printf_string,args...) \ + TRACFCOMP(g_trac_sbeio,"psudd: " printf_string,##args) +#define SBE_TRACD(printf_string,args...) \ + TRACDCOMP(g_trac_sbeio,"psudd: " printf_string,##args) + +using namespace ERRORLOG; + +//TODO RTC 144313 implement error recovery and ffdc. + +namespace SBEIO +{ + +/** + * @brief perform SBE PSU chip-op + * + * @param[in] i_pPsuRequest Pointer to PSU request commands + * @param[out] o_pPsuResponse Pointer to PSU response + * @param[in] i_timeout Time out for response + * @param[in] i_reqMsgs 4 bit mask telling which regs to write + * @param[in] i_rspMsgs 4 bit mask telling which regs to read + */ +errlHndl_t performPsuChipOp(psuCommand * i_pPsuRequest, + psuResponse * o_pPsuResponse, + const uint64_t i_timeout, + uint8_t i_reqMsgs, + uint8_t i_rspMsgs) + +{ + errlHndl_t errl = NULL; + TARGETING::Target * l_target = NULL; + static mutex_t l_psuOpMux = MUTEX_INITIALIZER; + + SBE_TRACD(ENTER_MRK "performPsuChipOp"); + + //Serialize access to PSU + mutex_lock(&l_psuOpMux); + + //Use master proc for SBE PSU access + (void)TARGETING::targetService().masterProcChipTargetHandle(l_target); + assert(l_target,"performPsuChipOp: master proc target is NULL"); + + do + { + // write PSU Request + errl = writeRequest(l_target, + i_pPsuRequest, + i_reqMsgs); + if (errl) break; // return with error + + // read PSU response and check results + errl = readResponse(l_target, + i_pPsuRequest, + o_pPsuResponse, + i_timeout, + i_rspMsgs); + if (errl) break; // return with error + + } + while (0); + + mutex_unlock(&l_psuOpMux); + + SBE_TRACD(EXIT_MRK "performPsuChipOp"); + + return errl; +} + +/** + * @brief write PSU Request message + */ +errlHndl_t writeRequest(TARGETING::Target * i_target, + psuCommand * i_pPsuRequest, + uint8_t i_reqMsgs) +{ + errlHndl_t errl = NULL; + static uint16_t l_seqID = 0; + + SBE_TRACD(ENTER_MRK "writeRequest"); + + do + { + // assign sequence ID and save to check that response matches + i_pPsuRequest->seqID = ++l_seqID; + + // Read SBE doorbell to confirm ready to accept command. + // Since the device driver single threads the requests, we should + // never see not being ready to send a request. + uint64_t l_addr = PSU_SBE_DOORBELL_REG_RW; + uint64_t l_data = 0; + errl = readScom(i_target,l_addr,&l_data); + if (errl) break; + if (l_data & SBE_DOORBELL) + { + SBE_TRACF(ERR_MRK "writeRequest: SBE not ready to accept cmd"); + SBE_TRACF(ERR_MRK " Control Flags,SeqID,Cmd,SubCmd=0x%016lx", + i_pPsuRequest->mbxReg0); + SBE_TRACF(ERR_MRK " Host to PSU door bell=0x%016lx", + l_data); + /*@ + * @errortype + * @moduleid SBEIO_PSU + * @reasoncode SBEIO_PSU_NOT_READY + * @userdata1[0:15] Reserved + * @userdata1[16:31] Request Control Flags + * @userdata1[32:47] Request Sequence ID + * @userdata1[48:55] Request Command Class + * @userdata1[56:63] Request Command + * @userdata2 Host to SBE door bell register + * + * @devdesc SBE PSU device driver not ready + * to receive next command. + * @custdesc Firmware error communicating with boot device + */ + errl = new ErrlEntry(ERRL_SEV_UNRECOVERABLE, + SBEIO_PSU, + SBEIO_PSU_NOT_READY, + i_pPsuRequest->mbxReg0, + l_data); + //TODO RTC 144313 review callouts and ffdc + errl->addProcedureCallout(HWAS::EPUB_PRC_HB_CODE, + HWAS::SRCI_PRIORITY_HIGH); + errl->collectTrace(SBEIO_COMP_NAME); + break; // return with error + } + + //write the command registers + uint64_t * l_pMessage = (uint64_t *)i_pPsuRequest; + l_addr = PSU_HOST_SBE_MBOX0_REG; + for (uint8_t i=0;i<4;i++) + { + if (0x01 & i_reqMsgs) // write register if non-reserved + { + errl = writeScom(i_target,l_addr,l_pMessage); + if (errl) break; + } + i_reqMsgs>>=1; + l_addr++; + l_pMessage++; + } + if (errl) break; + + //notify PSU command is ready + l_addr = PSU_SBE_DOORBELL_REG_OR; + l_data = SBE_DOORBELL; + errl = writeScom(i_target,l_addr,&l_data); + if (errl) break; + + } + while (0); + + SBE_TRACD(EXIT_MRK "writeRequest"); + + return errl; +} + +/** + * @brief Read PSU response messages + */ +errlHndl_t readResponse(TARGETING::Target * i_target, + psuCommand * i_pPsuRequest, + psuResponse * o_pPsuResponse, + const uint64_t i_timeout, + uint8_t i_rspMsgs) +{ + errlHndl_t errl = NULL; + + SBE_TRACD(ENTER_MRK "readResponse"); + + do + { + //wait for request to be completed + errl = pollForPsuComplete(i_target,i_timeout); + if (errl) break; // return with error + + //read the response registers + uint64_t * l_pMessage = (uint64_t *)o_pPsuResponse; + uint64_t l_addr = PSU_HOST_SBE_MBOX4_REG; + for (uint8_t i=0;i<4;i++) + { + if (0x01 & i_rspMsgs) // read register if non-reserved + { + errl = readScom(i_target,l_addr,l_pMessage); + break; + } + i_rspMsgs>>=1; + l_addr++; + l_pMessage++; + } + if (errl) break; + + //notify PSU response has been read + l_addr = PSU_HOST_DOORBELL_REG_AND; + uint64_t l_data = HOST_CLEAR_RESPONSE_WAITING; + errl = writeScom(i_target,l_addr,&l_data); + if (errl) break; + + //check status and seq ID in response messages + if ((SBE_PRI_OPERATION_SUCCESSFUL != o_pPsuResponse->primaryStatus) || + (SBE_SEC_OPERATION_SUCCESSFUL != o_pPsuResponse->secondaryStatus) || + (i_pPsuRequest->seqID != o_pPsuResponse->seqID) ) + { + SBE_TRACF(ERR_MRK "readResponse: failing response status " + " cmd=0x%08x prim=0x%08x secondary=0x%08x", + " expected seqID=%d actual seqID=%d", + i_pPsuRequest[1], + o_pPsuResponse->primaryStatus, + o_pPsuResponse->secondaryStatus, + i_pPsuRequest->seqID, + o_pPsuResponse->seqID); + /*@ + * @errortype + * @moduleid SBEIO_PSU + * @reasoncode SBEIO_PSU_RESPONSE_ERROR + * @userdata1[0:31] Indirect size or 9 for direct command + * @userdata1[32:47] Request Sequence ID + * @userdata1[48:55] Request Command Class + * @userdata1[56:63] Request Command + * @userdata2[0:15] Response Primary Status + * @userdata2[16:31] Response Secondary Status + * @userdata2[32:47] Response Sequence ID + * @userdata2[48:55] Response Command Class + * @userdata2[56:63] Response Command + * + * @devdesc Unexpected sequence number or non zero + * primary or secondary status + * @custdesc Firmware error communicating with boot device + */ + errl = new ErrlEntry(ERRL_SEV_UNRECOVERABLE, + SBEIO_PSU, + SBEIO_PSU_RESPONSE_ERROR, + i_pPsuRequest->mbxReg0, + o_pPsuResponse->mbxReg4); + //TODO RTC 144313 review callouts and ffdc + errl->addProcedureCallout(HWAS::EPUB_PRC_HB_CODE, + HWAS::SRCI_PRIORITY_HIGH); + errl->collectTrace(SBEIO_COMP_NAME); + break; + } + + } + while (0); + + SBE_TRACD(EXIT_MRK "readResponse"); + + return errl; +} + +/** + * @brief poll for PSU to complete command + */ +errlHndl_t pollForPsuComplete(TARGETING::Target * i_target, + const uint64_t i_timeout) +{ + errlHndl_t errl = NULL; + + SBE_TRACD(ENTER_MRK "pollForPsuComplete"); + + uint64_t l_elapsed_time_ns = 0; + uint64_t l_addr = PSU_HOST_DOORBELL_REG_RW; + uint64_t l_data = 0; + bool l_trace = true; //initialize so first call is traced + + do + { + // read response doorbell to see if ready + errl = readScom(i_target,l_addr,&l_data,l_trace); + if (errl) break; // return with error + + // check if response is now ready to be read + if (l_data & HOST_RESPONSE_WAITING) + { + break; // return with success + } + + // time out if wait too long + if (l_elapsed_time_ns > i_timeout ) + { + SBE_TRACF(ERR_MRK "pollForPsuComplete: " + "timeout waiting for PSU request to complete"); + + /*@ + * @errortype + * @moduleid SBEIO_PSU + * @reasoncode SBEIO_PSU_RESPONSE_TIMEOUT + * @userdata1 Timeout in NS + * @devdesc Timeout waiting for PSU command to complete + * @custdesc Firmware error communicating with boot device + */ + errl = new ErrlEntry(ERRL_SEV_UNRECOVERABLE, + SBEIO_PSU, + SBEIO_PSU_RESPONSE_TIMEOUT, + i_timeout, + 0); + //TODO RTC 144313 review callouts and ffdc + errl->addProcedureCallout(HWAS::EPUB_PRC_HB_CODE, + HWAS::SRCI_PRIORITY_HIGH); + errl->collectTrace(SBEIO_COMP_NAME); + break; + } + + // try later + nanosleep( 0, 10000 ); //sleep for 10,000 ns + l_elapsed_time_ns += 10000; + + // There will be many polls to check for the complete. If there + // is a problem, then there will be hundreds before timing out + // and giving up. Having one trace entry showing the poll request + // parameters is useful. Hundreds of identical entries is not. Hundreds + // with a non-continuous trace overruns the initial interaction. + l_trace = false; //only trace once to avoid flooding the trace + } + while (1); + + SBE_TRACD(EXIT_MRK "pollForPsuComplete"); + + return errl; +} + +/** + * @brief read Scom + */ +errlHndl_t readScom(TARGETING::Target * i_target, + uint64_t i_addr, + uint64_t * o_pData, + bool i_trace) +{ + errlHndl_t errl = NULL; + + size_t l_64bitSize = sizeof(uint64_t); + errl = deviceOp(DeviceFW::READ, + i_target, + o_pData, + l_64bitSize, + DEVICE_SCOM_ADDRESS(i_addr)); + + if (i_trace) + { + SBE_TRACD(" readScom addr=0x%08lx data=0x%016lx", + i_addr,*o_pData); + } + + return errl; +} + +/** + * @brief write Scom + */ +errlHndl_t writeScom(TARGETING::Target * i_target, + uint64_t i_addr, + uint64_t * i_pData) +{ + errlHndl_t errl = NULL; + + SBE_TRACD(" writeScom addr=0x%08lx data=0x%016lx", + i_addr,*i_pData); + size_t l_64bitSize = sizeof(uint64_t); + errl = deviceOp(DeviceFW::WRITE, + i_target, + i_pData, + l_64bitSize, + DEVICE_SCOM_ADDRESS(i_addr)); + + return errl; +} + +} //end of namespace SBEIO diff --git a/src/usr/sbeio/sbe_psudd.H b/src/usr/sbeio/sbe_psudd.H new file mode 100644 index 000000000..9b6228d89 --- /dev/null +++ b/src/usr/sbeio/sbe_psudd.H @@ -0,0 +1,414 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/sbeio/sbe_psudd.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2012,2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ + +#ifndef __SBE_PSUDD_H +#define __SBE_PSUDD_H + +/** + * @file sbe_psudd.H + * @brief SBE psu device driver specifics + */ + +#include <stdint.h> +#include <builtins.h> +#include <sys/time.h> + +#include <errl/errlentry.H> + +namespace SBEIO +{ + +//----------------------------------------------------------------------------- +// Interfaces to the SBE PSU device driver to be used by clients +// within this component. +//----------------------------------------------------------------------------- + + /** + * @brief enums for SBE command class + */ + enum psuCommandClass + { + SBE_PSU_CLASS_UNKNOWN = 0, + SBE_PSU_CLASS_CORE_STATE = 0xD1, + }; + + /** + * @brief enums for SBE core state control commands + */ + enum psuCoreStateControlCommands + { + SBE_CMD_CONTROL_DEADMAN_LOOP = 0x01, + }; + + /** + * @brief enums for SBE core state control commands + */ + enum psuDeadManControlFlags + { + SBE_DMCONTROL_START = 0x01, + SBE_DMCONTROL_STOP = 0x02, + SBE_DMCONTROL_RESPONSE_REQUIRED = 0x0100, + SBE_DMCONTROL_ACK_REQUIRED = 0x0200, + }; + + /** + * @brief non reserved word enums + * + * Shows which of the request and response msg registers are + * not reserved. Reserved registers do not need to be written + * or read. + * + * This is a 4 bit field: + * 0x1 - Reg 0 is non-reserved (read or write this reg) + * 0x2 - Reg 1 is non-reserved (read or write this reg) + * 0x4 - Reg 2 is non-reserved (read or write this reg) + * 0x8 - Reg 3 is non-reserved (read or write this reg) + */ + enum psuCoreStateControlNonReservedMsgs + { + SBE_DMCONTROL_START_REQ_USED_REGS = 0x03, + SBE_DMCONTROL_START_RSP_USED_REGS = 0x01, + SBE_DMCONTROL_STOP_REQ_USED_REGS = 0x01, + SBE_DMCONTROL_STOP_RSP_USED_REGS = 0x01, + }; + + /** + * @brief Struct for PSU command message format + * + */ + union psuCommand + { + struct //raw + { + uint64_t mbxReg0; + uint64_t mbxReg1; + uint64_t mbxReg2; + uint64_t mbxReg3; + } PACKED; + struct //common and direct fields + { + // mbxReg 0 + uint16_t reserved; + uint16_t controlFlags; + uint16_t seqID; + uint8_t commandClass; + uint8_t command; + // mbxReg 1 + uint32_t dataWord2; + uint32_t dataWord3; + // mbxReg 2 + uint32_t dataWord4; + uint32_t dataWord5; + // mbxReg 3 + uint32_t dataWord6; + uint32_t dataWord7; + } PACKED; + struct //indirect + { + // mbxReg 0 + uint16_t indirect_reserved; + uint16_t indirect_controlFlags; + uint16_t indirect_seqID; + uint8_t indirect_commandClass; + uint8_t indirect_command; + // mbxReg 1 + uint32_t indirect_dataWord2; + uint32_t indirect_dataWord3; + // mbxReg 2 + uint32_t indirect_dataWord4; + uint32_t indirect_dataWord5; + // mbxReg 3 + uint64_t indirect_address; // Data address (Mainstore/PBA) + } PACKED; + struct //controlDeadmanLoop + { + uint16_t cdl_reserved; + uint16_t cdl_controlFlags; + uint16_t cdl_seqID; + uint8_t cdl_commandClass; + uint8_t cdl_command; + uint64_t cdl_waitTime ; + uint64_t cdl_mbxReg2reserved; + uint64_t cdl_mbxReg3reserved; + } PACKED; + psuCommand(uint16_t i_controlFlags, + uint8_t i_commandClass, + uint8_t i_command) : + reserved (0), + controlFlags(i_controlFlags), + seqID(0), + commandClass(i_commandClass), + command(i_command), + dataWord2(0), + dataWord3(0), + dataWord4(0), + dataWord5(0), + dataWord6(0), + dataWord7(0) + { + } + }; + + /** + * @brief Struct for PSU response message format + * + */ + union psuResponse + { + struct //raw + { + uint64_t mbxReg4; + uint64_t mbxReg5; + uint64_t mbxReg6; + uint64_t mbxReg7; + } PACKED; + struct //common and direct fields + { + // mbxReg 4 + uint16_t primaryStatus; + uint16_t secondaryStatus; + uint16_t seqID; + uint8_t commandClass; + uint8_t command; + // mbxReg 5 + uint32_t respWord0; + uint32_t respWord1; + // mbxReg 6 + uint32_t respWord2; + uint32_t respWord3; + // mbxReg 7 + uint32_t respWord4; + uint32_t respWord5; + } PACKED; + struct // indirect fields + { + // mbxReg 4 + uint16_t indirect_primaryStatus; + uint16_t indirect_secondaryStatus; + uint16_t indirect_seqID; + uint8_t indirect_commandClass; + uint8_t indirect_command; + // mbxReg 5 + uint32_t indirect_respWord0; + uint32_t indirect_respWord1; + // mbxReg 6 + uint32_t indirect_respWord2; + uint32_t indirect_respWord3; + // mbxReg 7 + uint32_t indirect_reserved; + uint32_t indirect_size; //Size in dbl words for Indirect data + } PACKED; + psuResponse() : + primaryStatus (0xffff), //invalid status + secondaryStatus (0xffff), //invalid status + seqID (0xffff), //unlikely seq ID + commandClass (0xff), //invalid command class + command (0xff), //invalid command + respWord0 (0), + respWord1 (0), + respWord2 (0), + respWord3 (0), + respWord4 (0), + respWord5 (0) + { + } + }; + + /** + * @brief timeout values + * + */ + const uint64_t MAX_PSU_SHORT_TIMEOUT_NS = 100*NS_PER_MSEC; //=100ms + const uint64_t MAX_PSU_LONG_TIMEOUT_NS = 30000*NS_PER_MSEC; //=30 seconds + + /** + * @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_SEQUENCE_ERROR = 0x03, + SBE_PRI_INTERNAL_ERROR = 0x04, + SBE_PRI_GENERIC_EXECUTION_FAILURE = 0xFE, + }; + + /** + * @brief enums for secondary SBE response + * 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_TARGET_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_BACKLISTED_ACCESS = 0x0B, + SBE_SEC_OS_FAILURE = 0x0C, + SBE_SEC_HOST_MBX_REG_ACCESS_FAILURE = 0x0D, + SBE_SEC_INSUFFICIENT_DATA_PASSED = 0x0E, + SBE_SEC_EXCESS_DATA_PASSED = 0x0F, + SBE_SEC_SBE_BUSY_TO_HANDLE_COMMAND = 0x10, + }; + + /** + * @Brief perform SBE PSU chip-op + * + * @param[in] i_pPsuRequest Pointer to PSU request commands + * @param[out] o_pPsuResponse Pointer to PSU response + * @param[in] i_timeout Time out for response + * @param[in] i_reqMsgs 4 bit mask telling which regs to write + * @param[in] i_rspMsgs 4 bit mask telling which regs to read + */ + errlHndl_t performPsuChipOp(psuCommand * i_pPsuCommand, + psuResponse * o_pPsuResponse, + const uint64_t i_timeout, + uint8_t i_reqMsgs, + uint8_t i_rspMsgs); + +//----------------------------------------------------------------------------- +// Local definitions for the device driver +//----------------------------------------------------------------------------- + + /** + * @brief Write request to PSU + * + * @param[in] i_target Master proc to use for scoms + * @param[in] i_pPsuRequest Pointer to PSU request commands + * @param[in] i_reqMsgs 4 bit mask telling which regs to write + * + * @return errlHndl_t Error log handle on failure. + */ + errlHndl_t writeRequest(TARGETING::Target * i_target, + psuCommand * i_pPsuRequest, + uint8_t i_reqMsgs); + /** + * @brief Read response from PSU + * + * @param[in] i_target Master proc to use for scoms + * @param[in] i_pPsuRequest Pointer to PSU request commands + * @param[out] o_pPsuResponse Pointer to PSU response + * @param[in] i_timeout Time out for response + * @param[in] i_rspMsgs 4 bit mask telling which regs to read + * + * @return errlHndl_t Error log handle on failure. + */ + errlHndl_t readResponse(TARGETING::Target * i_target, + psuCommand * i_pPsuRequest, + psuResponse * o_pPsuResponse, + const uint64_t i_timeout, + uint8_t i_rspMsgs); + /** + * @brief Poll for response ready to be read + * + * @param[in] i_target Master proc to use for scoms + * @param[in] i_timeout Time out for response + * + * @return errlHndl_t Error log handle on failure. + */ + errlHndl_t pollForPsuComplete(TARGETING::Target * i_target, + const uint64_t i_timeout); + /** + * @brief Read Scom wrapper + * + * @param[in] i_target Master proc to use for scoms + * @param[in] i_addr Scom address + * @param[out] o_pData Pointer to returned data + * @param[in] i_trace Trace control to avoid overruning trace buffer + * when polling for response ready to be read + * + * @return errlHndl_t Error log handle on failure. + */ + errlHndl_t readScom(TARGETING::Target * i_target, + uint64_t i_addr, + uint64_t * o_pData, + bool i_trace=true); + + /** + * @brief Write Scom wrapper + * + * @param[in] i_target Master proc to use for scoms + * @param[in] i_addr Scom address + * @param[in] i_pData Pointer to data to write + * + * @return errlHndl_t Error log handle on failure. + */ + errlHndl_t writeScom(TARGETING::Target * i_target, + uint64_t i_addr, + uint64_t * i_pData); + + /** + * @brief SBE PSU register addresses + */ + enum psuRegs + { + PSU_HOST_SBE_MBOX0_REG = 0x000D0050, + PSU_HOST_SBE_MBOX1_REG = 0x000D0051, + PSU_HOST_SBE_MBOX2_REG = 0x000D0052, + PSU_HOST_SBE_MBOX3_REG = 0x000D0053, + PSU_HOST_SBE_MBOX4_REG = 0x000D0054, + PSU_HOST_SBE_MBOX5_REG = 0x000D0055, + PSU_HOST_SBE_MBOX6_REG = 0x000D0056, + PSU_HOST_SBE_MBOX7_REG = 0x000D0057, + PSU_SBE_DOORBELL_REG_RW = 0x000D0060, + PSU_SBE_DOORBELL_REG_AND = 0x000D0061, + PSU_SBE_DOORBELL_REG_OR = 0x000D0062, + PSU_HOST_DOORBELL_REG_RW = 0x000D0063, + PSU_HOST_DOORBELL_REG_AND = 0x000D0064, + PSU_HOST_DOORBELL_REG_OR = 0x000D0065, + }; + + /** + * @brief SBE PSU door bell register + */ + enum sbeDoorbellReg + { + // Doorbell Register to trigger SBE interrupt + // psu_sbe_interrupt_msg_available. Set by host firmware to inform + // the SBE about a waiting message in the Host/SBE Mailbox Registers + SBE_DOORBELL =0x8000000000000000, + }; + enum hostDoorbellReg + { + // Doorbell Register for Host Bridge interrupt. Set by the SBE to + // inform host firmware about a response message in the Host/SBE + // Mailbox Registers + HOST_RESPONSE_WAITING = 0x8000000000000000, + HOST_CLEAR_RESPONSE_WAITING = 0x7FFFFFFFFFFFFFFF, + }; + +} + +#endif |