diff options
Diffstat (limited to 'src/sbefw/core/sbecmdmemaccess.C')
-rw-r--r-- | src/sbefw/core/sbecmdmemaccess.C | 799 |
1 files changed, 799 insertions, 0 deletions
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__ |