diff options
Diffstat (limited to 'src/usr/hdat')
39 files changed, 18433 insertions, 0 deletions
diff --git a/src/usr/hdat/HBconfig b/src/usr/hdat/HBconfig new file mode 100644 index 000000000..7aa42ad40 --- /dev/null +++ b/src/usr/hdat/HBconfig @@ -0,0 +1,5 @@ + +config ENABLE_HDAT_IN_HOSTBOOT + default y + help + Enable Initialization of Hypervisor Memory Space diff --git a/src/usr/hdat/hdatbldda.C b/src/usr/hdat/hdatbldda.C new file mode 100755 index 000000000..4f940cf91 --- /dev/null +++ b/src/usr/hdat/hdatbldda.C @@ -0,0 +1,307 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hdat/hdatbldda.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 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 hdatbldda.C + * + * @brief This file contains the implementation of functions which drive the + * building of hypervisor data areas. + */ + + +/*----------------------------------------------------------------------------*/ +/* Includes */ +/*----------------------------------------------------------------------------*/ +#include "hdatbldda.H" // function prototypes and structures +#include <vpd/pvpdenums.H> +#include "hdatutil.H" +#include <sys/mm.h> +#include <sys/mmio.h> +#include <assert.h> +#include <attributeenums.H> +#include <util/align.H> +#include <limits.h> + +namespace HDAT +{ +/*----------------------------------------------------------------------------*/ +/* Global variables */ +/*----------------------------------------------------------------------------*/ + + + +/*----------------------------------------------------------------------------*/ +/* Constants */ +/*----------------------------------------------------------------------------*/ + +// Backplane keyword and record details +static vpdData pvpdData[] = +{ + { PVPD::VINI, PVPD::DR }, + { PVPD::VINI, PVPD::CE }, + { PVPD::VINI, PVPD::VZ }, + { PVPD::VINI, PVPD::FN }, + { PVPD::VINI, PVPD::SN }, + { PVPD::VINI, PVPD::CC }, + { PVPD::VINI, PVPD::HE }, + { PVPD::VINI, PVPD::CT }, + { PVPD::VINI, PVPD::B3 }, + { PVPD::VINI, PVPD::B4 }, + { PVPD::VINI, PVPD::B7 }, + { PVPD::VINI, PVPD::PF }, + { PVPD::OPFR, PVPD::VP }, + { PVPD::OPFR, PVPD::VS }, + { PVPD::OPFR, PVPD::DR }, + { PVPD::OPFR, PVPD::VN }, + { PVPD::OSYS, PVPD::MM }, + { PVPD::OSYS, PVPD::SS }, +}; +const HdatKeywordInfo l_pvpdKeywords[] = +{ + { PVPD::DR, "DR" }, + { PVPD::CE, "CE" }, + { PVPD::VZ, "VZ" }, + { PVPD::FN, "FN" }, + { PVPD::SN, "SN" }, + { PVPD::CC, "CC" }, + { PVPD::HE, "HE" }, + { PVPD::CT, "CT" }, + { PVPD::B3, "B3" }, + { PVPD::B4, "B4" }, + { PVPD::B7, "B7" }, + { PVPD::PF, "PF" }, + { PVPD::VP, "VP" }, + { PVPD::VS, "VS" }, + { PVPD::DR, "DR" }, + { PVPD::VN, "VN" }, + { PVPD::MM, "MM" }, + { PVPD::SS, "SS" }, +}; + + + +/** + * @brief See the prologue in hdatbldda.H + */ +errlHndl_t hdatProcessFru(const hdatMsAddr_t &i_msAddr, + const hdatSpiraDataAreas i_dataArea, + struct vpdData i_fetchVpd[], + const uint8_t i_size, + vpdType i_vpdtype, + uint32_t &o_count, + uint32_t &o_size) +{ + HDAT_ENTER(); + errlHndl_t l_errlHndl = NULL; + HdatVpd *l_vpdObj; + const char *l_strName; + TARGETING::TargetHandleList l_targList; + TARGETING::ATTR_SLCA_RID_type l_hdatRID = 0; + + // Get all the resource ids associated with this FRU type + hdatGetTarget(i_dataArea, l_targList); + + uint8_t l_cnt = 0; + o_count = 0; + o_size = 0; + + if (l_targList.size() == 0) + { + HDAT_DBG("got target list size as NULL"); + return NULL; + } + + + uint64_t l_base_addr = ((uint64_t) i_msAddr.hi << 32) | i_msAddr.lo; + uint64_t l_base_addr_down = ALIGN_PAGE_DOWN(l_base_addr); + // As we dont know the exact size, + //hence updating random size which is bigger + //than actual we write to MS memory. + void *l_virt_addr = mm_block_map ( reinterpret_cast<void*>(l_base_addr_down), + (ALIGN_PAGE(2048) + PAGESIZE)); + + //TODO HdatVpd and HdatHdif class should provide the total size + o_size = 2048; + o_count = 1; + + uint64_t l_final_addr = reinterpret_cast<uint64_t>(l_virt_addr); + + l_final_addr += l_base_addr - l_base_addr_down; + + l_virt_addr = reinterpret_cast<void *> (l_final_addr); + + uint8_t *l_addr = static_cast <uint8_t*>( l_virt_addr); + + if (HDAT_SYS_VPD == i_dataArea) + { + l_strName = HDAT_SYS_VPD_STRUCT_NAME; + } + else + { + l_strName = HDAT_FRU_VPD_STRUCT_NAME; + } + + // Build a VPD object for each FRU + while (l_cnt < l_targList.size()) + { + l_vpdObj = NULL; + + if (NULL == l_errlHndl) + { + uint32_t l_num = i_size/sizeof (i_fetchVpd[0]); + + assert((l_targList[l_cnt]->tryGetAttr<TARGETING::ATTR_SLCA_RID> + (l_hdatRID))); + + // Construct the VPD object and write the flat data to a file + l_vpdObj = new HdatVpd(l_errlHndl, + l_hdatRID, + l_targList[l_cnt], + l_strName, + l_cnt, + i_vpdtype, + i_fetchVpd, + l_num,l_pvpdKeywords); + + + if (NULL == l_errlHndl) + { + l_addr = l_vpdObj->setVpd(l_addr); + } + else + { + delete l_vpdObj; + break; + } + delete l_vpdObj; + } + l_cnt++; + } + + uint64_t l_addrData = reinterpret_cast<uint64_t> (l_virt_addr); + l_addrData = ALIGN_PAGE_DOWN(l_addrData); + + l_virt_addr = reinterpret_cast<void*>(l_addrData); + int rc = mm_block_unmap(l_virt_addr); + if( rc != 0) + { + errlHndl_t l_errl = NULL; + /*@ + * @errortype + * @moduleid HDAT::MOD_PROCESS_FRU + * @reasoncode HDAT::RC_DEV_UNMAP_FAIL + * @devdesc Unmap a mapped region failed + * @custdesc Firmware encountered an internal error. + */ + hdatBldErrLog(l_errl, + MOD_PROCESS_FRU, + RC_DEV_UNMAP_FAIL, + 0,0,0,0, + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + HDAT_VERSION1, + true); + } + + HDAT_EXIT(); + return l_errlHndl; +} + + +/** + * @brief See the prologue in hdatbldda.H + */ +errlHndl_t hdatBldSpecificVpd(hdatSpiraDataAreas i_dataArea, + const hdatMsAddr_t &i_msAddr, + uint32_t &o_count, + uint32_t &o_size) +{ + HDAT_ENTER(); + + errlHndl_t l_errlHndl = NULL; + struct vpdData *l_data = NULL; + vpdType l_type = BP; + uint8_t l_size = 0; + + // Determine which VPD structure to build. This assumes that i_dataArea + // is always a valid value. This is done to avoid more code bloat with + // a default leg to build an error log which should never occur. + switch (i_dataArea) + { + case HDAT_BACKPLANE_VPD: + case HDAT_SYS_VPD: + l_data = pvpdData; + l_size = sizeof(pvpdData); + l_type = BP; + break; + + case HDAT_CLOCK_VPD: + l_type = CLOCK; + break; + + case HDAT_ENCLOSURE_VPD: + l_type = ENCLOSURE; + break; + + case HDAT_ANCHOR_VPD: + l_type = ANCHOR; + break; + + case HDAT_MISC_CEC_VPD: + l_type = BP_EXT; + break; + + default: + break; + } + + // Build the VPD structure + l_errlHndl = hdatProcessFru(i_msAddr, i_dataArea,l_data,l_size,l_type, + o_count,o_size); + + if (NULL != l_errlHndl) + { + /*@ + * @errortype + * @moduleid HDAT::MOD_BUILD_SPECIFIED_VPD + * @reasoncode HDAT::RC_PROCESS_FRU_FAIL + * @userdata1 Spira data area + * @userdata2 Hdat fru type + * @devdesc process fru funciton failed + * @custdesc Firmware encountered an internal error. + */ + hdatBldErrLog(l_errlHndl, + MOD_BUILD_SPECIFIED_VPD, + RC_PROCESS_FRU_FAIL, + i_dataArea,l_type,0,0, + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + HDAT_VERSION1, + true); + } + + return l_errlHndl; +} + +} + diff --git a/src/usr/hdat/hdatbldda.H b/src/usr/hdat/hdatbldda.H new file mode 100755 index 000000000..84dc6a649 --- /dev/null +++ b/src/usr/hdat/hdatbldda.H @@ -0,0 +1,151 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hdat/hdatbldda.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 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 HDATBLDDA_H +#define HDATBLDDA_H + + +/** + * @file hdatbldda.H + * + * @brief This file contains the interfaces for building hypervisor data + * areas. + */ + +/*----------------------------------------------------------------------------*/ +/* Includes */ +/*----------------------------------------------------------------------------*/ +#include <stdint.h> // standard types +#include <hdat/hdat.H> // HDAT header type definitions +#include "hdatvpd.H" +#include <errl/errlentry.H> // ErrlEntry class definition +#include <hdat/hdat_reasoncodes.H> + +namespace HDAT +{ + +/** @brief Constant for the eye catcher for VPD structures + */ +const char HDAT_FRU_VPD_STRUCT_NAME[] = "FRUVPD"; +const char HDAT_SYS_VPD_STRUCT_NAME[] = "SYSVPD"; + + +/** @enum hdatSpiraDataAreas + * This enumeration defines the various data areas that must be built + T_MISC_VPD_FILE_NAME + * processor. + * This list must be kept in the same order as the 5-tuple entries in + * the SPIRA. + * + * If the order is changed, entries are added, or entries are deleted, + * update the HDAT_STR_NAME array in hdatPrtSpira(). + */ +enum hdatSpiraDataAreas +{ + HDAT_SPIRA_DA_FIRST = 0, + HDAT_SP_SUBSYS = 0, // service processor subsystem + HDAT_IPL_PARAMS = 1, // IPL parameters + HDAT_ENCLOSURE_VPD = 2, // enclosure vital product data + HDAT_SLCA = 3, // slot location code array + HDAT_BACKPLANE_VPD = 4, // backplane vital product data + HDAT_SYS_VPD = 5, // system vital product data + HDAT_CHIP_TOD = 6, // chip time-of-day + HDAT_PROC_INIT = 7, // phyp-supplied processor init data + HDAT_CLOCK_VPD = 8, // clock vital product data + HDAT_ANCHOR_VPD = 9, // anchor card vital product data + HDAT_OP_PNL_VPD = 10, // operator panel vital product data + HDAT_L3_VPD = 11, // level 3 cache vital product data + HDAT_MISC_CEC_VPD = 12, // miscellaneous FRU vital product data + HDAT_PACA = 13, // processor address communication area + HDAT_MDT = 14, // memory description tree + HDAT_IO_HUB = 15, // I/O hub FRU array + HDAT_CPU_CTRL = 16, // CPU controls + HDAT_MS_DUMP_SRC_TBL = 17, // mainstore dump source table (can change at run time) + HDAT_MS_DUMP_DST_TBL = 18, // mainstore dump destination table (can change at run time) + HDAT_MS_DUMP_RSLT_TBL = 19, // mainstore dump results table + HDAT_SPIRA_DA_GA1LAST = 20, // End of list for 1st eclipz release + HDAT_HEAP = 20, // Phyp allocated storage location for most of the data + HDAT_SPIRA_OLDPACA_LAST = 21, // This was last entry for old PACA format. //bs01a + + HDAT_PCIA = 21, // PCIA (Core information area) starting out on P7+ //bs01a + HDAT_PCRD = 22, // PCRD (Chip related data area) starting out on P7+ //bs01a + HDAT_HOSTSR = 23, // HOSTSR (Host service data) starting out on P8 //rij01A + HDAT_SPIRA_DA_LAST = 24 //bs01c +}; + +/** + * @brief The routines in this file drive the building of the various hypervisor + * data areas + * + * @pre + * + * @post + * + * @param[in] i_dataArea - An identifier for the specific data area + * @param[in] i_msAddr - The main store address where this data area + * will be written to. + * @param[out] o_count - number of instance of each area + * @param[out] o_size - actual size wrote to memory + * + * @return A null error log handle if successful, else the return code pointed + * to by errlHndl_t contains one of: + * + */ + +/* Build the specific VPD data areas */ +errlHndl_t hdatBldSpecificVpd(hdatSpiraDataAreas i_dataArea, + const hdatMsAddr_t &i_msAddr, + uint32_t &o_count, + uint32_t &o_size); + +/** + * @brief This function build vpd structure and write the data to MS memory. + * + * @pre + * + * @post + * + * @param[in] i_msAddr - The main store address where this data area + * @param[in] i_dataArea - An identifier for the specific data area + * will be written to. + * @param[in] i_fetchVpd - VPD record and keyword details + * @param[in] i_size - number of entries in VPD table + * @param[in] i_vpdtype - type of fru + * @param[out] o_count - number of instance of each area + * @param[out] o_size - actual size wrote to memory + * + * @return A null error log handle if successful, else the return code pointed + * to by errlHndl_t contains one of: + * + */ +errlHndl_t hdatProcessFru(const hdatMsAddr_t &i_msAddr, + const hdatSpiraDataAreas i_dataArea, + struct vpdData i_fetchVpd[], + const uint8_t i_size, + vpdType i_vpdtype, + uint32_t &o_count, + uint32_t &o_size); +}; +#endif //HDATBLDDA_H diff --git a/src/usr/hdat/hdathbrt.C b/src/usr/hdat/hdathbrt.C new file mode 100644 index 000000000..257fdce93 --- /dev/null +++ b/src/usr/hdat/hdathbrt.C @@ -0,0 +1,256 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hdat/hdathbrt.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 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 */ +#include <hdat/hdat.H> +#include "hdathbrt.H" +#include <targeting/common/util.H> +#include <sys/mm.h> +#include <sys/mmio.h> +#include <util/align.H> + +using namespace TARGETING; + + +namespace HDAT +{ + + + errlHndl_t loadHbrt(const hdatMsAddr_t &i_msAddr, + uint32_t &o_size , uint32_t &o_count) + { + HDAT_ENTER(); + errlHndl_t l_err = NULL; + HdatHbrt *l_hbrt = NULL; + + + //fetch the target attributes + do { + TARGETING::Target *l_pSysTarget = NULL; + (void) TARGETING::targetService().getTopLevelTarget(l_pSysTarget); + + if ( NULL == l_pSysTarget ) + { + HDAT_ERR("Error in getting Top Level Target"); + assert (l_pSysTarget != NULL); + } + TARGETING::ATTR_HDAT_HBRT_NUM_SECTIONS_type + l_numHbRuntimeDataSections = + l_pSysTarget->getAttr<TARGETING::ATTR_HDAT_HBRT_NUM_SECTIONS>(); + + TARGETING::ATTR_HDAT_HBRT_SECTION_SIZE_type + l_sizeHbRuntimeDataSections= {}; + + if(l_pSysTarget->tryGetAttr<TARGETING::ATTR_HDAT_HBRT_SECTION_SIZE>( + l_sizeHbRuntimeDataSections) == false ) + { + HDAT_ERR ("tryGetAttr of ATTR_HDAT_HBRT_SECTION_SIZE returned" + "false"); + + /*@ + * @errortype + * @moduleid HDAT::MOD_HBRT_LOAD_DATA + * @reasoncode HDAT::RC_TGT_ATTR_NOTFOUND + * @devdesc The target attribute not found + * @custdesc Firmware encountered an internal error + */ + hdatBldErrLog(l_err, + MOD_HBRT_LOAD_DATA, + RC_TGT_ATTR_NOTFOUND, + 0,0,0,0); + break; + } + + + l_hbrt = new HdatHbrt(l_err,i_msAddr, + (uint32_t)l_numHbRuntimeDataSections, + l_sizeHbRuntimeDataSections); + + + o_size = l_hbrt->size(); + o_count = HBRT_INSTANCE + 1; + + + l_err = l_hbrt->setHbrt(l_sizeHbRuntimeDataSections,o_size); + + HDAT_DBG("done building hbrt data, size = 0x%x, count= 0x%x", + o_size,o_count); + + + }while(0); + + + if ( l_hbrt ) + { + delete l_hbrt; + } + + HDAT_EXIT(); + return l_err; + }//end loadHbrt + + +HdatHbrt::HdatHbrt(errlHndl_t &o_errlHndl,const hdatMsAddr_t &i_msAddr, + const uint32_t i_numHbrtSections,uint64_t i_sizeHbrtSections[]) +:HdatHdif(o_errlHndl,HDAT_HBRT_STRUCT_NAME, i_numHbrtSections, + HBRT_INSTANCE, HDAT_HBRT_CHILD_COUNT, HDAT_HBRT_VERSION) +{ + HDAT_ENTER(); + + memcpy(&iv_msAddr, &i_msAddr, sizeof(hdatMsAddr_t)); + iv_numHbrtSections = i_numHbrtSections; + + for ( uint32_t l_loopCnt = 0; l_loopCnt < iv_numHbrtSections; l_loopCnt++ ) + { + this->addData(l_loopCnt, + (sizeof(hdatHbrtData_t) + i_sizeHbrtSections[l_loopCnt])); + } + this->align(); + + HDAT_EXIT(); +}//end constructor + + +HdatHbrt::~HdatHbrt() +{ + //free heap storage if any +} + + +errlHndl_t HdatHbrt::setHbrt( uint64_t i_sizeHbrtSections[],uint32_t i_size) +{ + errlHndl_t l_err = NULL; + hdatHbrtData_t *l_hdatHbrtData_t = NULL; + HDAT_ENTER(); + + + //first do block map + //total size reqd is size of hdif + (size of hbrt * number of hbrt sections) + uint64_t i_base_addr = ((uint64_t) iv_msAddr.hi << 32) | iv_msAddr.lo; + uint64_t i_base_addr_down = ALIGN_PAGE_DOWN(i_base_addr); + + + + void *l_virt_addr = mm_block_map ( + reinterpret_cast<void*>(i_base_addr_down), + ALIGN_PAGE(i_size) + PAGESIZE); + + + uint64_t l_vaddr = reinterpret_cast<uint64_t>(l_virt_addr); + l_vaddr += i_base_addr-i_base_addr_down; + + l_virt_addr = reinterpret_cast<void *>(l_vaddr); + + memset(l_virt_addr ,0x0, i_size); + uint8_t* io_virt_addr = reinterpret_cast<uint8_t *>(l_virt_addr); + + uint8_t* l_startAddr = io_virt_addr; + HDAT_DBG("io_virt_addr=0x%016llX, l_virt_addr=0x%016llX", + (uint64_t)io_virt_addr,(uint64_t)l_virt_addr); + + io_virt_addr = this->setHdif(io_virt_addr); + + HDAT_DBG("after writing HDIF header address now 0x%016llX", + (uint64_t)io_virt_addr); + + //now write the hbrt struct iv_numHbrtSections times + + uint32_t l_commonOffset = sizeof(hdatHDIF_t) + + (iv_numHbrtSections * sizeof(hdatHDIFDataHdr_t))+ + sizeof(hdatHbrtData_t); + + HDAT_DBG("common offset added to each is 0x%x",l_commonOffset); + + for (uint32_t i =0; i< iv_numHbrtSections; i++) + { + l_hdatHbrtData_t = reinterpret_cast<hdatHbrtData_t *> + (io_virt_addr); + l_hdatHbrtData_t->hdatHbrtBlobData.hdatSize = + i_sizeHbrtSections[i]; + + l_hdatHbrtData_t->hdatHbrtBlobData.hdatOffset = l_commonOffset; + + HDAT_DBG("hdatSize=0x%x, offset=0x%x",i_sizeHbrtSections[i], + l_hdatHbrtData_t->hdatHbrtBlobData.hdatOffset); + + l_commonOffset += i_sizeHbrtSections[i] + sizeof(hdatHbrtData_t); + + HDAT_DBG("next offset is 0x%x+0x%x=0x%x more",i_sizeHbrtSections[i], + sizeof(hdatHbrtData_t),(i_sizeHbrtSections[i]+sizeof(hdatHbrtData_t))); + + + io_virt_addr = reinterpret_cast<uint8_t *>(l_hdatHbrtData_t); + + io_virt_addr += sizeof(hdatHbrtData_t) + i_sizeHbrtSections[i]; + + }//end for + + + //add the pad after writing all the hbrt objects + uint32_t l_rem = i_size % 128; + uint32_t l_pad = l_rem ? (128 - l_rem) : 0; + + for (uint32_t i=0; i < l_pad; i++) + { + io_virt_addr[i] = '\0'; + } + HDAT_DBG("wrote pad of 0x%x size after hbrt object",l_pad); + + //unmap the region + int rc = 0; + + rc = mm_block_unmap(reinterpret_cast<void*>(ALIGN_PAGE_DOWN( + reinterpret_cast<uint64_t>(l_startAddr)))); + + if ( rc != 0 ) + { + HDAT_ERR("unmap of hbrt region failed"); + hdatMsAddr_t l_tmpaddr = {0}; + + if ( l_startAddr ) + { + memcpy(&l_tmpaddr,(void*)l_startAddr,sizeof(hdatMsAddr_t)); + } + /*@ + * @errortype + * @moduleid HDAT::MOD_HBRT_LOAD_DATA + * @reasoncode HDAT::RC_DEV_MAP_FAIL + * @devdesc Unmap a mapped region failed + * @custdesc Firmware encountered an internal error + */ + hdatBldErrLog(l_err, + MOD_HBRT_LOAD_DATA, + RC_DEV_MAP_FAIL, + l_tmpaddr.hi,l_tmpaddr.lo,0,0, + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + HDAT_VERSION1, + true); + + } + + + HDAT_EXIT(); + return l_err; +}//end setHbrt + +}//end namespace diff --git a/src/usr/hdat/hdathbrt.H b/src/usr/hdat/hdathbrt.H new file mode 100644 index 000000000..46d7b165e --- /dev/null +++ b/src/usr/hdat/hdathbrt.H @@ -0,0 +1,272 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hdat/hdathbrt.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 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 HDATHBRT_H +#define HDATHBRT_H + +/** + * @file hdathbrt.H + * + * @brief This file contains the class definition for the Host boot runtime + * data object. + * + */ + +/*----------------------------------------------------------------------------*/ +/* Includes */ +/*----------------------------------------------------------------------------*/ + +#include <stdint.h> +#include <errl/errlentry.H> +#include <hdat/hdat.H> +#include <hdat/hdat_reasoncodes.H> +#include "hdatutil.H" +#include "hdathdif.H" + +namespace HDAT +{ +/*----------------------------------------------------------------------------*/ +/* Constants */ +/*----------------------------------------------------------------------------*/ + +/** @brief eye catcher for the HDIF header for the Host boot runtime data + */ +const char HDAT_HBRT_STRUCT_NAME[] = "HBRT "; + +/** @enum hdatHbrtDataPtrs + * Constants for the internal data pointers that are added to the base + * class + */ +enum hdatHBrtDataPtrs +{ + HDAT_HBRT_ATTRIBUTE = 0 +}; + +/** @enum hdatHbrtChildPtrs + * Constants for the child structure pointers that are added to the base + * class + */ +enum hdatHbrtChildPtrs +{ + HDAT_HBRT_CHILD_COUNT = 0 +}; + +/** @brief Host boot runtime version number + * + */ +const uint16_t HDAT_HBRT_VERSION = 0x0010; + +/** @brief Host boot runtime string lablel size + * + */ +#define HDAT_HBRT_STRING_LABEL_SIZE 24 + +/** @brief HBRT structure instance + * */ +#define HBRT_INSTANCE 0 + + +/*----------------------------------------------------------------------------*/ +/* Type definitions */ +/*----------------------------------------------------------------------------*/ + + +/** @brief Host boot runtime data section. Host boot data updated will be + * populated in this structure format. + * + */ +struct hdatHbrtData_t +{ + uint8_t hdatHbrtStringLabel[HDAT_HBRT_STRING_LABEL_SIZE]; + //0x0000 : String Label + uint32_t hdatHbrtInstanceNum; //0x0018 : Instance Number + hdatHDIFDataHdr_t hdatHbrtBlobData; //0x001C : Pointer to Data Blob + uint32_t hdatHbrtReserved1; //0x0024 : Reserved1 + uint32_t hdatHbrtReserved2; //0x0028 : Reserved2 + uint32_t hdatHbrtReserved3; //0x002C : Reserved3 +} __attribute__ ((packed)); + + +/*----------------------------------------------------------------------------*/ +/* C++ class definition */ +/*----------------------------------------------------------------------------*/ + +/** Begin Class Description + * + * @brief The HdatHbrt class is used to construct Host boot runtime data + * objects. + * + * Description: This class defines a specialized object. It is not intended + * that any component can create an object of this type. In + * particular, the object is built only in the CEC Server process + * when requested by the hdat component. + * + * The real purpose of the object is to create the Host boot + * runtime data as defined by the PHYP Initialization + * architecture and is written to + * main memory. The class is not defined to be a general purpose + * interface for building this object by anyone other than the + * CEC Server process. + * + * Thread safety: An HdatHbrt object is not thread safe. That is, a single + * object cannot be shared and used concurrently by multiple + * threads at the same time. + * + * Signal handler usage: This class is not intended to be used in a signal + * handler and nothing has been done to try and make it + * safe to use in a signal handler. + * + * End Class Description + */ +class HdatHbrt : public HdatHdif +{ + public: + + + /** + * @brief Construct an HdatHbrt object. + * + * This is the constructor for the HdatHbrt object when that Host + * boot runtime data is not currently plugged but has been reserved + * for concurrent maintenance. + * + * If you are constructing this object on the heap by using new, + * then you must check the pointer returned from new to see if it + * is null. If it is null, new failed to allocate storage and the + * constructor was not called. If it is not null, then you must + * check o_errlHndl to see if the constructor ran successfully. If + * o_errlHndl indicates an error was reported by the constructor, + * new has already allocated heap storage and the object must be + * deleted in order to free the heap storage. + * + * @pre None + * + * @post An HdatHbrt object has been constructed. Heap storage has + * been allocated. + * + * @param[out] o_errlHndl + * If any errors occur, the HdatHbrt object is NOT constructed and + * errors are returned in this parameter + * @param[in] i_msAddr + * The main memory address that the Host boot runtime data that + * will be written to + * @param[in] i_numHbrtSections + * Number of host boot runtime sections + * @param[in] i_sizeHbrtSections + * HBRT section blob size array + * + * @return A null error log handle if successful, else the return code + * pointed to by o_errlHndl contains one of retval + * + * @retval HDAT_ALLOC_ERROR + */ + HdatHbrt(errlHndl_t &o_errlHndl, const hdatMsAddr_t &i_msAddr, + const uint32_t i_numHbrtSections,uint64_t i_sizeHbrtSections[]); + + + /** + * @brief HdatHbrt object destructor + * + * This is the destructor for an HdatHbrt object. Any heap storage + * allocated for the object is dallocated. + * + * @pre No preconditions exist + * + * @post The HdatHbrt object has been destroyed and can no longer be + * used. + * + */ + virtual ~HdatHbrt(); + + + /** + * @brief write an HdatHbrt object. + * + * This method must be called when the HdatHbrt object has been + * completed. That is, the object was constructed and all data has + * been added to object. + * + * + * @pre All informaton that is needed in the object must have been put + * there by the constructor or other methods. + * + * @post The object data is written to main memory + * + * @param[in] i_sizeHbrtSections + * Size of each of the host boot runtime sections + * @param[in] i_size + * The size of this and all previous objects.Needed to calculate + * the memory size which will be allocated. + * @param[out] o_count + * The count of all objects which have been committed. This value + * from the last object which is committed must be returned to the + * hdat component + * + * @return A null error log handle if successful, else the return code + * pointed to by errlHndl_t contains one of the retval + * + */ + errlHndl_t setHbrt(uint64_t i_sizeHbrtSections[],uint32_t i_size); + + private: + + /** Object Instance Data + * + * @li iv_msAddr - main memory address the final data structure + * is written to + * @li iv_numHbrtSections - number of hbrt data sections + */ + hdatMsAddr_t iv_msAddr; + uint32_t iv_numHbrtSections; + + +}; // end of HdatHbrt class + + +/* + * @brief main function to load an hbrt object into main memory. This + * function is called from Spiras while loading all the data areas. + * + * @pre All the previous data areas have been loaded to main memory + * + * @post HBRT is written to main memory + * + * @param[in] i_msAddr + * The main memory address where HBRT is written to + * + * @param[out] o_size + * Total size written + * + * @param[out] o_count + * Number of HBRT data structures + */ + +errlHndl_t loadHbrt(const hdatMsAddr_t &i_msAddr, + uint32_t &o_size , uint32_t &o_count); + + +}//end namespace + +#endif // HDATHBRT_H + diff --git a/src/usr/hdat/hdathdif.C b/src/usr/hdat/hdathdif.C new file mode 100755 index 000000000..1533ddbe2 --- /dev/null +++ b/src/usr/hdat/hdathdif.C @@ -0,0 +1,542 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hdat/hdathdif.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 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 hdathdif.C + * + * @brief This file contains the implementation of the HdatHdif class. + * + */ + + +/*----------------------------------------------------------------------------*/ +/* Includes */ +/*----------------------------------------------------------------------------*/ +#include "hdathdif.H" +#include "hdatutil.H" + + +namespace HDAT +{ + +/*----------------------------------------------------------------------------*/ +/* Global variables */ +/*----------------------------------------------------------------------------*/ +extern trace_desc_t * g_hdatTraceDesc; + + +/*----------------------------------------------------------------------------*/ +/* Constants */ +/*----------------------------------------------------------------------------*/ +const uint32_t HDAT_BOUNDARY = 16; // Pad structures to a 16 byte boundary +const char HDAT_PAD[15] = {'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', '\0', '\0', '\0'}; + + +/** @brief See the prologue in hdathdif.H + */ +HdatHdif::HdatHdif() +{ +} + + +/** @brief See the prologue in hdathdif.H + */ +HdatHdif::HdatHdif(errlHndl_t &o_errlHndl, + const char i_eyeCatcher[], + uint32_t i_dataPtrCnt, + uint32_t i_instance, + uint32_t i_childCnt, + uint32_t i_ver) +:iv_totalSize(0), iv_padSize(0),iv_siblingPadSize(0),iv_dataPtrSize(0), +iv_childPtrSize(0),iv_dataPtrs(NULL), iv_childPtrs(NULL) +{ + HDAT_ENTER(); + + const uint32_t HDAT_MULTIPLE = 16; + uint32_t l_mod; + + o_errlHndl = NULL; + + iv_hdr.hdatStructId = HDAT_HDIF_STRUCT_ID; + iv_hdr.hdatInstance = i_instance; + iv_hdr.hdatVersion = i_ver; + iv_hdr.hdatSize = sizeof(hdatHDIF_t); + iv_hdr.hdatHdrSize = sizeof(hdatHDIF_t); + iv_hdr.hdatDataPtrOffset = 0; + iv_hdr.hdatDataPtrCnt = 0; + iv_hdr.hdatChildStrOffset = 0; + iv_hdr.hdatChildStrCnt = 0; + + memcpy(iv_hdr.hdatStructName, i_eyeCatcher, sizeof(iv_hdr.hdatStructName)); + + if (i_dataPtrCnt > 0) + { + iv_hdr.hdatDataPtrOffset = iv_hdr.hdatSize; + iv_dataPtrSize = i_dataPtrCnt * sizeof(hdatHDIFDataHdr_t); + iv_dataPtrs = reinterpret_cast<hdatHDIFDataHdr_t *>(calloc(i_dataPtrCnt, + sizeof(hdatHDIFDataHdr_t))); + iv_hdr.hdatSize += iv_dataPtrSize; + } + + if (NULL == o_errlHndl && i_childCnt > 0) + { + iv_hdr.hdatChildStrOffset = iv_hdr.hdatSize; + + iv_childPtrSize = i_childCnt * sizeof(hdatHDIFChildHdr_t); + l_mod = iv_childPtrSize % HDAT_MULTIPLE; + if (l_mod > 0) + { + iv_childPtrSize += HDAT_MULTIPLE - l_mod; + } + + iv_childPtrs = reinterpret_cast<hdatHDIFChildHdr_t *> + (calloc(iv_childPtrSize, 1)); + iv_hdr.hdatSize += iv_childPtrSize; + } + + iv_totalSize = iv_hdr.hdatSize; + HDAT_EXIT(); +}//end constructor + +/** @brief See the prologue in hdathdif.H + */ +HdatHdif::~HdatHdif() +{ + HDAT_ENTER(); + free(iv_dataPtrs); + free(iv_childPtrs); + HDAT_EXIT(); +} + + +/** @brief See the prologue in hdathdif.H + */ +uint32_t HdatHdif::size() +{ + return iv_hdr.hdatSize; +} +uint32_t HdatHdif::getSize() +{ + uint32_t l_size = 0; + + l_size += sizeof(iv_hdr); + + if (NULL != iv_dataPtrs) + { + l_size += iv_dataPtrSize; + } + + if (NULL != iv_childPtrs) + { + l_size += iv_childPtrSize; + } + return l_size; +} +/** @brief See the prologue in hdathdif.H + */ +void HdatHdif::chgChildOffset(uint32_t i_whichChildEntry, + uint32_t i_offset) +{ + hdatHDIFChildHdr_t *l_hdr; + + // If there are child structures, change the offset of the selected triple + // entry + if (iv_hdr.hdatChildStrCnt > 0) + { + l_hdr = reinterpret_cast<hdatHDIFChildHdr_t *>(reinterpret_cast<char *> + (iv_childPtrs) + sizeof(hdatHDIFChildHdr_t) * + i_whichChildEntry); + l_hdr->hdatOffset = i_offset; + } + + return; +} + + + +/** @brief See the prologue in hdathdif.H + */ +void HdatHdif::addChild(uint32_t i_whichChildEntry, + uint32_t i_size, + uint32_t i_numChildStr) +{ + HDAT_ENTER(); + + hdatHDIFChildHdr_t *l_childHdr; + + iv_hdr.hdatChildStrCnt = i_whichChildEntry + 1; //(0 based index plus 1) + + // Address the child entry + l_childHdr = reinterpret_cast<hdatHDIFChildHdr_t *>(reinterpret_cast<char *> + (iv_childPtrs) + + sizeof(hdatHDIFChildHdr_t) * i_whichChildEntry); + + // Update child entry information + + // If not yet done, set offset to first child structure. Child structures + // are contiguous after the first and are all the same size. + if (0 == l_childHdr->hdatOffset) + { + l_childHdr->hdatOffset = iv_totalSize; + l_childHdr->hdatSize = i_size; + } + l_childHdr->hdatCnt++; + + // Increment total object size by child's size + iv_totalSize += i_size; + + HDAT_EXIT(); + return; +} + + +/** @brief See the prologue in hdathdif.H + */ +void HdatHdif::addGrandChild(uint32_t i_size) +{ + + // Increment total object size by the grandchild's size + iv_totalSize += i_size; + + return; +} + + +/** @brief See the prologue in hdathdif.H + */ +void HdatHdif::addData(uint32_t i_whichDataEntry, + uint32_t i_size) +{ + HDAT_ENTER(); + + hdatHDIFDataHdr_t *l_dataHdr; + + l_dataHdr = reinterpret_cast<hdatHDIFDataHdr_t *>(reinterpret_cast<char *> + (iv_dataPtrs) + + sizeof(hdatHDIFDataHdr_t) * i_whichDataEntry); + + // Update data entry information if there is any data + if (i_size > 0) + { + l_dataHdr->hdatOffset = iv_hdr.hdatSize; + l_dataHdr->hdatSize = i_size; + } + // Increment total object size by data's size and increment + // count of data entries + iv_hdr.hdatSize += i_size; + iv_totalSize += i_size; + iv_hdr.hdatDataPtrCnt++; + + HDAT_EXIT(); + return; +} + + +/** @brief See the prologue in hdathdif.H + */ +void HdatHdif::maxSiblingSize(uint32_t i_numBytes) +{ + + if (i_numBytes > iv_hdr.hdatSize) + { + iv_siblingPadSize = i_numBytes - iv_hdr.hdatSize; + iv_hdr.hdatSize += iv_siblingPadSize; + iv_totalSize += iv_siblingPadSize; + } + +} + + + + +/** @brief See the prologue in hdathdif.H + */ +void HdatHdif::align() +{ + uint32_t l_rem; + + // If the structure length is not a multiple of the boundary + // requirement, compute the number of pad bytes needed + l_rem = iv_hdr.hdatSize % HDAT_BOUNDARY; + + if (l_rem > 0) + { + iv_padSize = HDAT_BOUNDARY - l_rem; + iv_hdr.hdatSize += iv_padSize; + iv_totalSize += iv_padSize; + } + + return; +} + +uint8_t * HdatHdif::setHdif(uint8_t * io_virt_addr) +{ + HDAT_DBG("virtual address=0x%016llX", + (uint64_t)io_virt_addr); + + uint8_t *l_temp = NULL; + + // If no children were ever added, ensure offset to child pointers is 0 + if (0 == this->iv_hdr.hdatChildStrCnt) + { + HDAT_DBG(" no child information were addded"); + this->iv_hdr.hdatChildStrOffset = 0; + } + + //first write the hdatHDIF_t iv_hdr + hdatHDIF_t * l_hdatHDIF= reinterpret_cast<hdatHDIF_t *>(io_virt_addr); + + + l_hdatHDIF->hdatStructId = this->iv_hdr.hdatStructId; + l_hdatHDIF->hdatInstance = this->iv_hdr.hdatInstance; + l_hdatHDIF->hdatVersion = this->iv_hdr.hdatVersion; + l_hdatHDIF->hdatSize = this->iv_hdr.hdatSize; + l_hdatHDIF->hdatHdrSize = this->iv_hdr.hdatHdrSize; + l_hdatHDIF->hdatDataPtrOffset = this->iv_hdr.hdatDataPtrOffset; + l_hdatHDIF->hdatDataPtrCnt = this->iv_hdr.hdatDataPtrCnt; + l_hdatHDIF->hdatChildStrCnt = this->iv_hdr.hdatChildStrCnt; + l_hdatHDIF->hdatChildStrOffset = this->iv_hdr.hdatChildStrOffset; + + memcpy(l_hdatHDIF->hdatStructName,iv_hdr.hdatStructName, + sizeof(iv_hdr.hdatStructName)); + + //cast back to uint8_t and increment the pointer by size of + //hdatHDIF_t to point the next + + l_temp = reinterpret_cast<uint8_t *>(l_hdatHDIF); + l_temp += this->iv_hdr.hdatDataPtrOffset; + + HDAT_DBG("sizeof HDIF header=%x",sizeof(hdatHDIF_t)); + + //write data pointer array hdatHDIFDataHdr_t *iv_dataPtrs + hdatHDIFDataHdr_t *l_hdatHDIFDataHdr = + reinterpret_cast<hdatHDIFDataHdr_t *>(l_temp); + + HDAT_DBG("writing Data pointers array from address=0x%016llX", + (uint64_t)l_hdatHDIFDataHdr); + + //total number of data pointer header is HDAT_PARENT_LAST, + //actual filled up number is + //this->iv_hdr.hdatDataPtrCnt, but we should loop through the total number + //to fillup the memory and increment the pointer + + uint8_t l_totdataHdrCnt = this->iv_dataPtrSize / sizeof(hdatHDIFDataHdr_t); + + for (uint8_t l_cnt=0; l_cnt < l_totdataHdrCnt; l_cnt++) + { + l_hdatHDIFDataHdr->hdatOffset = this->iv_dataPtrs[l_cnt].hdatOffset; + l_hdatHDIFDataHdr->hdatSize = this->iv_dataPtrs[l_cnt].hdatSize; + + HDAT_DBG("wrote data array %d, at address 0x%016llX", + l_cnt,(uint64_t)l_hdatHDIFDataHdr); + l_hdatHDIFDataHdr++; + } + + + //write Child pointers array + hdatHDIFChildHdr_t *l_hdatHDIFChildHdr = + reinterpret_cast<hdatHDIFChildHdr_t *>(l_hdatHDIFDataHdr); + + //saving the start value + uint8_t *l_tempChildHdr = reinterpret_cast<uint8_t *>(l_hdatHDIFChildHdr); + + HDAT_DBG("writing Child pointers array from address=0x%016llX", + (uint64_t)l_hdatHDIFChildHdr); + //total count is HDAT_CHILD_LAST but actual data is hdatChildStrCnt + //but we need to copy the full to increase the memory pointer + uint8_t l_totChldHdrCnt = + this->iv_childPtrSize / sizeof(hdatHDIFChildHdr_t); + + + for(uint8_t l_cnt = 0; l_cnt < l_totChldHdrCnt; l_cnt++) + { + l_hdatHDIFChildHdr->hdatOffset = this->iv_childPtrs[l_cnt].hdatOffset; + l_hdatHDIFChildHdr->hdatSize = this->iv_childPtrs[l_cnt].hdatSize; + l_hdatHDIFChildHdr->hdatCnt = this->iv_childPtrs[l_cnt].hdatCnt; + + HDAT_DBG("wrote child array %d, at address 0x%016llX", + l_cnt,(uint64_t)l_hdatHDIFChildHdr); + l_hdatHDIFChildHdr++; + } + + + l_tempChildHdr += iv_childPtrSize; + + io_virt_addr = reinterpret_cast<uint8_t *>(l_tempChildHdr); + + return io_virt_addr; + +}//end setHdif + + +uint8_t * HdatHdif::setpadding(uint8_t * io_virt_addr, + uint32_t &o_size) +{ + + HDAT_DBG("address=0x%016llX", + (uint64_t)io_virt_addr); + uint32_t i = 0; + + if (this->iv_padSize > 0) + { + HDAT_DBG("adding iv_padSize=0x%x",iv_padSize); + for ( i = 0; i < iv_padSize; i++) + { + io_virt_addr[i] = '\0'; + } + } + + + if (iv_siblingPadSize > 0) + { + HDAT_DBG("adding iv_siblingPadSize=0x%x", + iv_siblingPadSize); + for ( i = 0; i < iv_siblingPadSize; i++) + { + io_virt_addr[i] = '\0'; + } + } + + io_virt_addr += iv_padSize + iv_siblingPadSize; + o_size = iv_totalSize; + + HDAT_DBG("exit address=0x%016llX", + (uint64_t)io_virt_addr); + + return io_virt_addr; +} + + + + +uint32_t HdatHdif::getChildOffset() +{ + if ( this->iv_childPtrs ) + { + return this->iv_childPtrs[0].hdatOffset; + } + else + { + return 0; + } + +}//end getChildOffset +/** @brief See the prologue in hdathdif.H + */ +void HdatHdif::startCommit(UtilMem &i_data) +{ + + // If no children were ever added, ensure offset to child pointers + // is 0. + if (0 == iv_hdr.hdatChildStrCnt) + { + iv_hdr.hdatChildStrOffset = 0; + } + i_data.write(&iv_hdr,sizeof(iv_hdr)); + + if ( NULL != iv_dataPtrs) + { + i_data.write(iv_dataPtrs ,iv_dataPtrSize); + } + + // Write the child pointers section. + if (NULL != iv_childPtrs) + { + i_data.write(iv_childPtrs,iv_childPtrSize); + } +} +void HdatHdif::print() +{ + HDAT_INF("****** HdatHdif base object ******"); + + HDAT_INF(" iv_totalSize = %u", iv_totalSize); + HDAT_INF(" iv_padSize = %u", iv_padSize); + HDAT_INF(" iv_dataPtrSize = %u", iv_dataPtrSize); + HDAT_INF(" iv_childPtrSize = %u", iv_childPtrSize); + + hdatPrintHdrs(&iv_hdr, + (const hdatHDIFDataHdr_t *)iv_dataPtrs, + NULL, + (const hdatHDIFChildHdr_t *)iv_childPtrs); + + + return; +} + +/** @brief See the prologue in hdathdif.H + */ +uint32_t HdatHdif::endCommitSize() +{ + uint32_t l_size = 0; + + // Write pad bytes if needed + if (iv_padSize > 0) + { + l_size += iv_padSize; + } + + if (iv_siblingPadSize > 0) + { + if (iv_siblingPadSize <= sizeof(HDAT_PAD)) + { + l_size += iv_siblingPadSize; + } + else + { + l_size += iv_siblingPadSize; + } + } + return l_size; + +} +void HdatHdif::endCommit(UtilMem &i_data) +{ + + char *l_buffer = NULL; + + // Write pad bytes if needed + if (iv_padSize > 0) + { + i_data.write(HDAT_PAD,iv_padSize); + } + + if (iv_siblingPadSize > 0) + { + if (iv_siblingPadSize <= sizeof(HDAT_PAD)) + { + i_data.write(HDAT_PAD,iv_siblingPadSize); + } + else + { + l_buffer = new char[iv_siblingPadSize](); + i_data.write(l_buffer,iv_siblingPadSize); + delete[] l_buffer; + } + } + +} + + +} //namespace HDAT diff --git a/src/usr/hdat/hdathdif.H b/src/usr/hdat/hdathdif.H new file mode 100755 index 000000000..a02f9a634 --- /dev/null +++ b/src/usr/hdat/hdathdif.H @@ -0,0 +1,398 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hdat/hdathdif.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 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 HDATHDIF_H +#define HDATHDIF_H + +/** + * @file hdathdif.H + * + * @brief This file contains the class definition for the object provding the + * HDIF header for most hypervisor data structures. + * + */ + + +/*----------------------------------------------------------------------------*/ +/* Includes */ +/*----------------------------------------------------------------------------*/ +#include <stdint.h> +#include <hdat/hdat.H> +#include <hdat/hdat_reasoncodes.H> +#include <errl/errlentry.H> +#include <util/utilmem.H> + + + +namespace HDAT +{ + +/*----------------------------------------------------------------------------*/ +/* C++ class definition */ +/*----------------------------------------------------------------------------*/ + +/** Begin Class Description + * + * @brief The HdatHdif class provides the base class for hypervisor data areas + * that have an HDIF header. Other C++ classes that build specific + * hypervisor data area structures are derived from this class. + * + * Description: This object is not intended to be constructed directly. Rather, + * it provides the base class upon which other derived classes are + * built. + * + * Thread safety: An HdatHdif object is not thread safe. That is, a single + * object cannot be shared and used concurrently by + * multiple threads at the same time. An object can be used by + * multiple threads if the threads serialize access. And of + * course, each thread can use its own object with no concerns + * about what other threads are doing. + * + * Signal handler usage: + * This class is not intended to be used in a signal handler + * and nothing has been done to try and make it safe to use + * in a signal handler. + * + * End Class Description + */ +class HdatHdif +{ + public: + + /** + * @brief Construct an HdatHdif base object. + * + * This is the constructor for the HdatHdif object + * + * If you are constructing this object on the heap by using new, + * you must check the pointer returned from new null value. + * If null, new failed to allocate storage and the constructor + * was not called. If not null, then you must check o_errlHndl + * to see if the constructor ran successfully.If o_errlHndl + * indicates an error was reported by the constructor, new has + * already allocated heap storage and the object must be deleted in + * order to free the heap storage. + * + * @pre None + * @param o_errlHndl output error handle + * + * @param i_eyeCatcher input the eyecatcher string + * @param i_dataPtrCnt input data array pointer count + * @param i_instance input object instance + * @param i_childCnt input child count + * @param i_ver input version number + * + * @post An HdatHdif object has been constructed. Heap storage has been + * allocated. + * + * @return A null error log handle if successful, else the return code + * pointed to by errlHndl_t contains one of: + * + * @retval HDAT_ALLOC_ERROR + */ + HdatHdif(); + + HdatHdif(errlHndl_t &o_errlHndl, + const char i_eyeCatcher[], + uint32_t i_dataPtrCnt, + uint32_t i_instance = 0, + uint32_t i_childCnt = 0, + uint32_t i_ver = 1); + + + /** + * @brief HdatHdif object destructor + * + * @pre None + * + * @post Heap storage is deallocated + * + */ + virtual ~HdatHdif(); + + + /** + * @brief Change the offset to the beginning of a set of children + * + * @pre i_childCnt from ctor must be greater than 0 (not checked) + * + * @post Total object size is updated. Child structure pointer entry is + * updated + * + * @param i_whichChildEntry - + * input parameter - An array index for the children being added. + * This is a 0 based array index so the first entry being added + * would specify 0 for this parameter. + * i_whichChildEntry < i_childCnt from ctor (not checked) + * @param i_size - + * input parameter - The size of the child structure(s) + * @param i_numChildStr - + * input parameter - The number of children being added. + * + */ + void addChild(uint32_t i_whichChildEntry, + uint32_t i_size, + uint32_t i_numChildStr); + + + /** + * @brief Add a grandchild structure entry to the base object. + * + * @pre None + * + * @post Total object size is updated. + * + * @param i_size - input parameter - The size of the grandchild structure + * + */ + void addGrandChild(uint32_t i_size); + + + /** + * @brief Add internal data pointer entry to the base object. + * When a hypervisor data structure has internal data , an array + * of data pointers(hdatHDIFDataHdr_t) is maintained to address + * the internal data areas. This method is used to maintain the + * array of data pointers. + * + * @pre i_dataPtrCnt from ctor must be greater than 0 (not checked) + * + * @post Total object size is updated. Internal data pointer entry is + * updated + * + * @param i_whichDataEntry - + * input parameter - An array index for the data entry being added + * This is a 0 based array index so the first entry being added + * would specify 0 for this parameter. + * i_whichDataEntry < i_dataPtrCnt from ctor (not checked) + * @param i_size - + * input parameter - The size of the internal data + * + */ + void addData(uint32_t i_whichDataEntry, + uint32_t i_size); + + /** + * @brief Some objects which have siblings must all be the same size + * so thatPHYP can traverse through them as elements of an array. Since + * the size of all the siblings is not known until the last sibling has + * been built, this method is used to ensure all objects are padded + * to the same size + * + * @pre None + * @post Total object size is updated. Pad size computed + * @param i_numBytes - input parameter - size, in bytes, of the + * maximum sized object + */ + + void maxSiblingSize(uint32_t i_numBytes); + + + + /** + * @brief After the derived object is constructed, all data pointers have + * been added,and the maximum number of child structures have been + * computed, this method must be called to "pad" the object to a + * nice byte boundary (currently 16 byte boundaries are used). + * + * @pre actual or maximum number of child structures were provided on + * the constructor + * all calls to addData() have been completed + * + * @post Total object size is updated. Pad size computed. + * + */ + void align(); + + /** + * @brief The current object size is returned. This is the size of + * an HDIF object. It does NOT include sizes of children or + * grandchildren + * + * @pre None + * + * @post None + * + * @return Object size + */ + uint32_t size(); + + /* + * @brief write Hdif header to memory + * + * @pre the object must have been constructed + * + * @param io_virt_addr input virtual address to write at + * + * @post data is written to host memory + * + * @return the next address to write at + * + */ + uint8_t * setHdif(uint8_t * io_virt_addr); + + + /* + * @brief write the required padding + * + * @pre the object must have been constructed + * + * @param io_virt_addr input virtual address to write at + * @param o_size output size of the object + * @post pad is written to host memory + * + * @return the next address to write at + */ + + uint8_t *setpadding(uint8_t * io_virt_addr, + uint32_t& o_size ); + + + /* + * @brief get the child offset + * + * daughter data must have been constructed + * + * return uint32_t offset value + */ + + uint32_t getChildOffset (); + /** + * @brief Update the offset to the beginning of a child structure(s) + * + * Complex strcutures which can have grandchilren (such as the + * HdatVpd object) may not be able to build the object pieces in + * the desired order. Thus offsets to chilren structures can be + * in error. When the objects are complete and are ready to be + * commited, they can be done so in the correct order but the + * offsets will have to be updated first. + * + * @pre None + * + * @post None + * + * @param[in] i_whichChildEntry - An array index for the child triple + * entry.This is a 0 based array index so the first entry would + * specify 0 for this parameter. i_whichChildEntry < i_childCnt + * from ctor (not checked) + * @param[in] i_offset - new offset value + * + * @return None + * + */ + void chgChildOffset(uint32_t i_whichChildEntry, + uint32_t i_offset); + /** + * @brief The object data is written to ms memory + * + * + * @pre The derived object must be complete. + * + * @post The base class data is flattened and written to a ms area + * + * @param[in]i_data - input memory that contains data + * + */ + void startCommit(UtilMem &i_data); + + /** + * @brief print out the HdatHdif object data + * + * @pre None + * + * @post output sent to stdout + * + */ + void print(); + + /** + * @brief Any padding that must be done to make the structure align + * properly is performed and the msarea containing the data structure is + * not closed. + * + * @pre None + * + * @post + * + * @param[in]i_data - input memory that contains data + * + */ + void endCommit(UtilMem &i_data); + + /** + * @brief Get endCommit size if there is any padding applied + * @pre None + * + * @post + * + * @return - size + */ + uint32_t endCommitSize(); + + /** + * @brief Get the complete size of base object that needs to be written + * to MS memory + * @pre None + * + * @post + * + * @return - size + */ + uint32_t getSize(); + + + + private: + + + /** Object Instance Data + * + * @li iv_totalSize - total number of bytes of structure and all + * its children and grandchildren + * @li iv_padSize - number of bytes to pad structure to a + * boundary (such as a nice 16 byte boundary) + * @li iv_siblingPadSize - the padding to be added + * @li iv_dataPtrSize - size of the internal data pointers array + * section + * @li iv_childPtrSize - size of the child pointers section + * @li iv_hdr - the basic HDIF header + * @li iv_dataPtrs - heap storage for the internal data pointers + * section + * @li iv_childPtrs - heap storage for the internal child structure + * pointers section + */ + uint32_t iv_totalSize; + uint32_t iv_padSize; + uint32_t iv_siblingPadSize; + uint32_t iv_dataPtrSize; + uint32_t iv_childPtrSize; + hdatHDIF_t iv_hdr; + hdatHDIFDataHdr_t *iv_dataPtrs; + hdatHDIFChildHdr_t *iv_childPtrs; + +}; // end of HdatHdif class + +}//end namespace + +#endif // HDATHDIF_H diff --git a/src/usr/hdat/hdathostservices.C b/src/usr/hdat/hdathostservices.C new file mode 100755 index 000000000..e96e863de --- /dev/null +++ b/src/usr/hdat/hdathostservices.C @@ -0,0 +1,308 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hdat/hdathostservices.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 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 hdathostservices.C + * + * @brief This file contains the implementation of the HdatHostsr class. + * + */ + + +/*-----------------------------------------------------------------------------*/ +/* Includes */ +/*-----------------------------------------------------------------------------*/ +#include <stdlib.h> // malloc & free +#include <sys/mm.h> +#include <sys/mmio.h> +#include <util/align.H> +#include "hdathostservices.H" +#include "hdatnodedata.H" // HdatNodedata class definition +#include "hdathdif.H" +#include "hdatutil.H" +#include "hdatvpd.H" +#include <targeting/common/util.H> + +using namespace TARGETING; +namespace HDAT +{ +/*-----------------------------------------------------------------------------*/ +/* Global variables */ +/*-----------------------------------------------------------------------------*/ +extern trace_desc_t *g_trac_hdat; +uint32_t HdatHostsr::cv_actualCnt; + +/** @brief See the prologue in hdathostservices.H + */ +HdatHostsr::HdatHostsr(errlHndl_t &o_errlHndl, + const hdatMsAddr_t &i_msAddr, + uint32_t &o_hostServiceTotalSize, + uint32_t &o_hostServiceTotalCnt) +: HdatHdif(o_errlHndl, HDAT_STRUCT_NAME, HDAT_HOSTSR_LAST, cv_actualCnt++, + HDAT_CHILD_LAST, HDAT_HOSTSR_VERSION),iv_actNodeCnt(0),iv_NodePtrs(NULL), + iv_virt_addr(NULL) +{ + HDAT_ENTER(); + + // Copy the passedin mainstore address in the local object variable + memcpy(&iv_msAddr, &i_msAddr, sizeof(hdatMsAddr_t)); + + // Total size for Host Service Data Structure + // including its internal data pointer size. + iv_size = sizeof(hdatHDIF_t) + + ( sizeof(hdatHDIFDataHdr_t) * + HDAT_HOSTSR_LAST)+ + ( HDAT_CHILD_LAST * sizeof(hdatHDIFChildHdr_t))+ + HDAT_HOSTSR_SIZE + 0x10; // Padding as per spec + // Find the virtual address to copy all the host service struct + uint64_t l_base_addr_down = ALIGN_PAGE_DOWN( iv_msAddr ); + iv_virt_addr = (uint8_t *) mm_block_map ( + reinterpret_cast<void*>(l_base_addr_down), + (ALIGN_PAGE(iv_size) + PAGESIZE)); + iv_hostServiceData = iv_virt_addr + (iv_msAddr - ALIGN_PAGE_DOWN(iv_msAddr)); + + // Add up the Service Data structure size to o/p var + o_hostServiceTotalSize += iv_size; + o_hostServiceTotalCnt = 1; // Only one host service Data structure + + // Calling the hdatHostServiceBuild + o_errlHndl= this->hdatHostServiceBuild(o_hostServiceTotalSize); + + HDAT_EXIT(); + return; +} + + + +/** @brief See the prologues in hdathostservices.H +*/ +errlHndl_t HdatHostsr::hdatHostServiceBuild(uint32_t &o_hostServiceTotalSize) +{ + errlHndl_t l_errlHndl = NULL; + HDAT_ENTER(); + + do{ + + /*** Add the parent Data pointer first ***/ + + this->addData(HDAT_SYSTEM_ATTRIBUTE, HDAT_HOSTSR_SIZE); + this->align(); + + /*** Create and Set the children ***/ + + // Lets build the node data child structures + // by looping into all nodes in bldNodeDataStruct + + uint32_t l_NodeDataSize = 0; + l_errlHndl = this->bldNodeDataStruct(l_NodeDataSize); + if(l_errlHndl == NULL) + { + // Done with node data.Add up the node data size to o/p var + o_hostServiceTotalSize += l_NodeDataSize; + } + else + { + HDAT_ERR("bldNodeDataStruct returned error"); + break; + } + /**** Creation of children done ******/ + + /*** Commit the Parent ***/ + + // set the header section of host services in the constructed memory space + iv_hostServiceData = this->setHdif(iv_hostServiceData); + + //Set the internal Data pointer Data of (parent) host services + memset(iv_hostServiceData,0, HDAT_HOSTSR_SIZE); + iv_hostServiceData += HDAT_HOSTSR_SIZE; + + /*** Parent commiting Done ***/ + + /*** Commit the children ***/ + + // Now lets commit the child structures. + l_errlHndl=this->setChildPtrs(); + + /*** Children commiting Done ***/ + + }while(0); + + HDAT_EXIT(); + return l_errlHndl; +} + +HdatHostsr::~HdatHostsr() +{ + errlHndl_t l_errlHndl = NULL; + HDAT_ENTER(); + + /*** Unmap the virtual address of parent ***/ + + uint32_t rc = mm_block_unmap(reinterpret_cast<void*>( + ALIGN_PAGE_DOWN((uint64_t)iv_virt_addr))); + if( rc != 0) + { + /*@ + * @errortype + * @moduleid HDAT::MOD_HDAT_SERVICEDATA_CTOR + * @reasoncode HDAT::RC_DEV_MAP_FAIL + * @devdesc Unmap a mapped region failed + * @custdesc Firmware encountered an internal error. + */ + hdatBldErrLog(l_errlHndl, + HDAT::MOD_HDAT_SERVICEDATA_CTOR, + RC_DEV_MAP_FAIL, + 0,0,0,0, + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + HDAT_VERSION1, + true); + } + /*** Unmap of parent addr done ***/ + + /*** Unmap the virtual address of children ***/ + + uint32_t l_cnt; + HdatNodedata *l_nodeDataObj, **l_curPtr; + + l_curPtr = iv_NodePtrs; + + for (l_cnt = 0; l_cnt < iv_actNodeCnt; l_cnt++) + { + l_nodeDataObj = *l_curPtr; + delete l_nodeDataObj; + l_curPtr = reinterpret_cast<HdatNodedata **>(reinterpret_cast<char *> + (l_curPtr) + sizeof(HdatNodedata *)); + } + + // Free heap storage + free(iv_NodePtrs); + + /*** Unmap of children addrresses done ***/ + + HDAT_EXIT(); +} +/** @brief See the prologue in hdathostservices.H + */ + +errlHndl_t HdatHostsr::bldNodeDataStruct(uint32_t &o_NodeDataSize) +{ + HDAT_ENTER(); + + errlHndl_t l_errlHndl = NULL; + + // Find the number of nodes on this machine + TARGETING::PredicateCTM l_nodeFilter(CLASS_ENC, TYPE_NODE); + TARGETING::PredicateHwas l_pred; + l_pred.present(true); + TARGETING::PredicatePostfixExpr l_presentNode; + l_presentNode.push(&l_nodeFilter).push(&l_pred).And(); + + TARGETING::TargetRangeFilter l_filter( + TARGETING::targetService().begin(), + TARGETING::targetService().end(), + &l_presentNode); + for( ; l_filter ; ++l_filter ) + { + iv_actNodeCnt++; + } + + // Looping and building the children + HdatNodedata *l_nodeDataObj, **l_arrayEntry; + const char HDAT_KID_STRUCT_NAME[] = "HS KID"; + uint32_t l_NodeStructSize = 0; + + if(iv_actNodeCnt > 0) + { + iv_NodePtrs = reinterpret_cast<HdatNodedata **>(calloc(iv_actNodeCnt, + sizeof(HdatNodedata *))); + } + else + { + HDAT_ERR("hdatHostsr : Hdat node data failed"); + } + + iv_msAddr += iv_size; // Leave a space for parent before creating children + + for(uint32_t l_nodeID = 0 ; l_nodeID < iv_actNodeCnt ; l_nodeID++) + { + l_NodeStructSize = 0; + l_nodeDataObj = new HdatNodedata(l_errlHndl ,iv_msAddr, + HDAT_KID_STRUCT_NAME,l_NodeStructSize); + + // Sum up the sizes for all the node data + o_NodeDataSize+= l_NodeStructSize; + + l_arrayEntry = reinterpret_cast<HdatNodedata **>( + reinterpret_cast<char *>(iv_NodePtrs) + + l_nodeID * sizeof(HdatNodedata *)); + + *l_arrayEntry = l_nodeDataObj; + + // Tell the base class about child structures and adjust size + if (NULL == l_errlHndl) + { + // 1st parm is 0 based + this->addChild(HDAT_CHILD_NODE_ATTRIBUTE, l_NodeStructSize, 0); + } + } + + HDAT_DBG("HdatHostSr::bldNodeDataStruct Done. Commit pending."); + + HDAT_EXIT(); + return l_errlHndl; +} + +/** @brief See the prologue in hdathostservices.H + */ + +errlHndl_t HdatHostsr::setChildPtrs() +{ + HDAT_ENTER(); + uint32_t l_cnt; + errlHndl_t l_errlHndl = NULL; + HdatNodedata *l_nodeDataObj, **l_curPtr; + + l_curPtr = iv_NodePtrs; + + for (l_cnt = 0; l_cnt < iv_actNodeCnt; l_cnt++) + { + l_nodeDataObj = *l_curPtr; + l_errlHndl = l_nodeDataObj->setNodeData(); + if(l_errlHndl) + { + HDAT_ERR(" Setting Node data failed"); + break; + } + } + + HDAT_EXIT(); + return l_errlHndl; + +} + + + +}// HDAT namespace diff --git a/src/usr/hdat/hdathostservices.H b/src/usr/hdat/hdathostservices.H new file mode 100755 index 000000000..e7bbce2d6 --- /dev/null +++ b/src/usr/hdat/hdathostservices.H @@ -0,0 +1,243 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hdat/hdathostservices.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 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 HDATHOSTSR_H +#define HDATHOSTSR_H + +/** + * @file hdathostservices.H + * + * @brief This file contains the class definition for the Host service data object. + * + */ + +/*-----------------------------------------------------------------------------*/ +/* Includes */ +/*-----------------------------------------------------------------------------*/ +#include <stdint.h> // standard types +#include <hdat/hdat.H> // HDAT header type definitions +#include "hdathdif.H" // HdatHdif base class definition +#include "hdatnodedata.H" //Host service node data + +/*-----------------------------------------------------------------------------*/ +/* Constants */ +/*-----------------------------------------------------------------------------*/ + +/** @brief eye catcher for the HDIF header for the Host service data + */ +const char HDAT_STRUCT_NAME[] = "HOSTSR"; + + +/** @enum hdatDataPtrs + * Constants for the internal data pointers that are added to the base + * class + */ +enum hdatHSDataPtrs +{ + HDAT_SYSTEM_ATTRIBUTE = 0, + HDAT_HOSTSR_LAST = 1 +}; + +/** @enum hdatChildPtrs + * Constants for the child structure pointers that are added to the base + * class + */ +enum hdatChildPtrs +{ + HDAT_CHILD_NODE_ATTRIBUTE = 0, + HDAT_CHILD_RESERVED1 = 1, + HDAT_CHILD_LAST = 2 +}; + +const uint16_t HDAT_HOSTSR_VERSION = 0x0010; + +const uint32_t HDAT_HOSTSR_SIZE = 4096; + + +/*-----------------------------------------------------------------------------*/ +/* Type definitions */ +/*-----------------------------------------------------------------------------*/ + + +namespace HDAT +{ +/*-----------------------------------------------------------------------------*/ +/* C++ class definition */ +/*-----------------------------------------------------------------------------*/ + +/** Begin Class Description + * + * @brief The HdatHostsr class is used to construct Host service data objects. + * + * Description: This class defines a specialized object. + * The real purpose of the object is to create the HostService data + * as defined by the PHYP Initialization + * architecture. + * + * End Class Description + */ +class HdatHostsr : public HdatHdif +{ +public: + + /** + * @brief Construct an HdatHostsr object. + * + * This is the constructor for the HdatHostsr object when that Host service data + * is not currently plugged but has been reserved for concurrent + * maintenance. + * + * If you are constructing this object on the heap by using new, then + * you must check the pointer returned from new to see if it is null. + * If it is null, new failed to allocate storage and the constructor + * was not called. If it is not null, then you must check o_errlHndl + * to see if the constructor ran successfully. If o_errlHndl indicates + * an error was reported by the constructor, new has already allocated + * heap storage and the object must be deleted in order to free the + * heap storage. + * + * @pre None + * + * @post An HdatHostsr object has been constructed. Heap storage has been allocated. + * + * @param o_errlHndl - output parameter - If any errors occur, the HdatHostsr object + * is NOT constructed and errors are returned in this parameter + * @param i_msAddr - input parameter - The main memory address that the Host service data + * that will be DMA'd to. + * + * @return A null error log handle if successful, else the return code pointed + * to by o_errlHndl contains one of: + * + * @retval HDAT_ALLOC_ERROR + */ + HdatHostsr(errlHndl_t &o_errlHndl, + const hdatMsAddr_t &i_msAddr, + uint32_t &o_hostServiceDataSize, + uint32_t &o_hostServiceDataCnt); + + + /** + * @brief HdatHostsr object destructor + * + * This is the destructor for an HdatHostsr object. Any heap storage + * allocated for the object is dallocated. + * + * @pre No preconditions exist + * + * @post The HdatHostsr object has been destroyed and can no longer be used. + * + */ + virtual ~HdatHostsr(); + /** + * @brief Build Host Service Data + * + * @pre Virtual mapping is done in constructor + * + * @post Host service(parent) and Node data(children) setting done + * + * @return A null error log handle if successful, else the return code pointed + * to by errlHndl_t + */ + + errlHndl_t hdatHostServiceBuild(uint32_t &o_hostServiceTotalSize); + + /** + * @brief Build the hypervisor data area structres for Node Data. + * + * @pre None + * + * @post A node data has been added to the object. Heap storage + * has been allocated. + * + * @return A null error log handle if successful, else the return code pointed + * to by errlHndl_t contains one of: + * + * @retval HDAT_ALLOC_ERROR + */ + errlHndl_t bldNodeDataStruct(uint32_t &o_NodeDataSize); + + /** + * @brief Add Host Service Node data description. + * + * @pre None + * + * @post Node data has been added to the object. Heap storage + * has been allocated. + * + * @param i_resourceId - input parameter - Node number + * + * @return A null error log handle if successful, else the return code pointed + * to by errlHndl_t contains one of: + * + * @retval HDAT_ALLOC_ERROR + * @retval HDAT_ARRAY_ERROR + */ + errlHndl_t addNodeData(uint32_t node); + + /** + * @brief Set node data child pointers. + * + * @pre Node data pointer should have built i.e., node data + * object should be instantiated + * + * @post Node data committed + */ + + errlHndl_t setChildPtrs(); + + /** Class (static) Data + * + * Only one copy of this data exists in a process. + * + * @li cv_actualCnt - a count of how many HdatServiceData objects are created + */ + static uint32_t cv_actualCnt; + +private: + + /** Object Instance Data + * + * @li iv_msAddr - main memory address + * @li iv_hostServiceData - Pointer to host service data + * @li iv_size - Size of the service Data structure + * @li iv_maxNodes - maximum number of Nodes + * @li iv_actNodeCnt - Actual Node Count + * @li iv_NodePtrs - Pointer to array of Node data pointers + * @li iv_virt_addr - Pointer to virtual mapped address + */ + uint64_t iv_msAddr; + uint8_t* iv_hostServiceData; + uint64_t iv_size; + uint32_t iv_maxNodes; + uint32_t iv_actNodeCnt; + HdatNodedata **iv_NodePtrs; + uint8_t* iv_virt_addr; + +}; // end of HdatHostSr class + + +} + +#endif // HDATHOSTSR_H + diff --git a/src/usr/hdat/hdathostslcadata.C b/src/usr/hdat/hdathostslcadata.C new file mode 100755 index 000000000..dae700e1b --- /dev/null +++ b/src/usr/hdat/hdathostslcadata.C @@ -0,0 +1,901 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hdat/hdathostslcadata.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 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 */ + +#include <devicefw/userif.H> +#include <hdat/hdat.H> +#include <targeting/common/target.H> +#include "hdatutil.H" +#include "hdathostslcadata.H" +#include <sys/mm.h> +#include <sys/mmio.h> +#include <vpd/vpd_if.H> + +#ifdef HDAT_DEBUG +#include <iostream> +#endif +#include <targeting/common/util.H> +#include <string.h> +#include <util/align.H> + +using namespace TARGETING; +using namespace std; +using namespace VPD; + +namespace HDAT +{ + +extern trace_desc_t *g_trac_hdat; + + +fru_id_rid_t g_fruIDRidMap[] = +{ + {0x0800 , "BP"}, + {0x1E00 , "EV"}, + {0x1C00 , "SV"}, + {0x1000 , "PF"}, + {0xD000 , "MS"}, + {0x3600 , "PI"}, + {0x0200 , "SP"}, + {0x3100 , "PS"}, + {0x3A00 , "AM"}, + {0x2900 , "CU"}, + {0x2800 , "CE"}, + {0x0300 , "OP"}, + {0x3900 , "RG"}, + {0xA100 , "SA"}, + {0xA200 , "EI"}, + {0xA300 , "EF"}, + {0x2A00 , "CS"}, + {0xD000 , "MS"}, + {0xA000 , "VV"}, + {0x1400 , "RI"}, +}; + + +/** + * @brief This helper routine returns VPD Collected status + * + * @pre None + * + * @post None + * + * @param i_Target - input parameter - Target of parent FRU + * + * @return True : VPD is collected + * False : VPD is not collected + * + * @retval HDAT_OTHER_COMP_ERROR + */ +bool getVPDCollectedStatus(TARGETING::Target *i_Target) +{ + bool l_vpdCollectedStatus = true; +//@TODO: RTC 149382: Method to get VPD collected status for Targets + + if((i_Target->getAttr<ATTR_TYPE>() != TYPE_PCI) && + (i_Target->getAttr<ATTR_TYPE>() != TYPE_SYS)) + { + l_vpdCollectedStatus = pvpdPresent(i_Target); + } + return l_vpdCollectedStatus; +} + +/** + * @brief This helper routine populates ordinal ids for Procs + * and cores + * + * @pre None + * + * @post None + * + * @param None + * + * @return None + * + * @retval HDAT_OTHER_COMP_ERROR + */ + +void hdatPopulateOrdinalId() +{ + TARGETING::Target *l_pSysTarget = NULL; + (void) TARGETING::targetService().getTopLevelTarget(l_pSysTarget); + + if(l_pSysTarget == NULL) + { + HDAT_ERR("hdatGetSystemParamters::Top Level Target not found"); + assert(l_pSysTarget != NULL); + } + + TARGETING::PredicateCTM l_procFilter(TARGETING::CLASS_CHIP, + TARGETING::TYPE_PROC); + + TARGETING::PredicateHwas l_predHwas; + l_predHwas.present(true); + + TARGETING::PredicatePostfixExpr l_presentProc; + l_presentProc.push(&l_procFilter).push(&l_predHwas).And(); + + TARGETING::TargetHandleList l_procList; + + //Get all Procs in the system + TARGETING::targetService(). + getAssociated(l_procList, l_pSysTarget, + TARGETING::TargetService::CHILD, + TARGETING::TargetService::ALL, &l_presentProc); + + uint32_t l_procOrdinalId = 0; + for (TargetHandleList::const_iterator pTarget_it = l_procList.begin(); + pTarget_it != l_procList.end(); + ++pTarget_it) + { + TargetHandle_t l_procTarget = *pTarget_it; + l_procTarget->setAttr<TARGETING::ATTR_ORDINAL_ID>(l_procOrdinalId++); + + TARGETING::PredicateCTM l_coreFilter(TARGETING::CLASS_UNIT, + TARGETING::TYPE_CORE); + + TARGETING::PredicatePostfixExpr l_presentCore; + l_presentCore.push(&l_coreFilter).push(&l_predHwas).And(); + + TARGETING::TargetHandleList l_coreList; + + //Get all Core in the Proc + TARGETING::targetService(). + getAssociated(l_coreList, l_procTarget, + TARGETING::TargetService::CHILD, + TARGETING::TargetService::ALL, &l_presentCore); + + uint32_t l_coreOrdinalId = 0; + for (TargetHandleList::const_iterator pcoreTarget_it = + l_coreList.begin(); + pcoreTarget_it != l_coreList.end(); + ++pcoreTarget_it) + { + TargetHandle_t l_coreTarget = *pcoreTarget_it; + l_coreTarget->setAttr<TARGETING::ATTR_ORDINAL_ID> + (l_coreOrdinalId++); + } + HDAT_DBG("Added Ordinal IDs for Core : %d",l_coreOrdinalId); + } + HDAT_DBG("Added Ordinal IDs Proc: %d ",l_procOrdinalId); +} + +/** + * @brief This routine adds a new SLCA entry for specified target + * + * @pre None + * + * @post None + * + * @param i_Target - input parameter - Target for which slca entry + * is added + * i_frutype - input parameter - FRU Type of the Target + * i_slcaParentIndex - input parameter - Index of parent FRU + * i_LocCodePrefix - input parameter - Location code prefix + * o_hdatslca - output parameter - Vector containing slca entries + * for DIMMs + * + * @return Index of Last SLCA entry added + * + * @retval HDAT_OTHER_COMP_ERROR + */ +uint16_t hdatAddSLCAEntry( TARGETING::Target *i_Target, + HDAT_FRUType_t i_frutype, + uint16_t i_slcaparentindex, + char *i_LocCodePrefix, + vector<HDAT_slcaEntry_t> &o_hdatslca ) +{ + //Values for the SLCA's collected and installed fields + #define HDAT_SLCA_COLLECTED 2 + #define HDAT_SLCA_NOT_COLLECTED 3 + #define HDAT_SLCA_NO_PD_INFO 1 + #define HDAT_SLCA_INSTALLED 2 + #define HDAT_SLCA_NOT_INSTALLED 3 + HDAT_slcaEntry_t l_hdatslcaentry; + + l_hdatslcaentry.fru_index = o_hdatslca.size(); + l_hdatslcaentry.fru_rid = g_fruIDRidMap[i_frutype].fru_rid++; + + strncpy(l_hdatslcaentry.fru_id, + (const char *)g_fruIDRidMap[i_frutype].fru_id, + sizeof(l_hdatslcaentry.fru_id)); + + l_hdatslcaentry.parent_index = i_slcaparentindex; + l_hdatslcaentry.first_child_rid = 0xFFFF; + l_hdatslcaentry.max_location_code_len = 64; + + memset(l_hdatslcaentry.location_code , 0 , + l_hdatslcaentry.max_location_code_len); + + hdatGetLocationCode(i_Target,i_LocCodePrefix,l_hdatslcaentry.location_code); + uint32_t l_length = strlen(l_hdatslcaentry.location_code); + l_hdatslcaentry.location_code[l_length]='\0'; + l_hdatslcaentry.actual_location_code_len = l_length + 1; + + l_hdatslcaentry.number_of_children = 0x0; + l_hdatslcaentry.first_child_index = 0xFFFF; + l_hdatslcaentry.first_redundant_index = 0xFFFF; + l_hdatslcaentry.number_redundant_copies = 0x0; + l_hdatslcaentry.number_of_children_2B = 0x0; + + l_hdatslcaentry.installed = HDAT_SLCA_INSTALLED; + if(getVPDCollectedStatus(i_Target)) + { + l_hdatslcaentry.collected = HDAT_SLCA_COLLECTED; + } + else + { + l_hdatslcaentry.collected = HDAT_SLCA_NOT_COLLECTED; + } + + o_hdatslca.push_back(l_hdatslcaentry); + + if(i_frutype != HDAT_SLCA_FRU_TYPE_EV && i_frutype != HDAT_SLCA_FRU_TYPE_VV) + { + if(!i_Target->trySetAttr<TARGETING::ATTR_SLCA_INDEX> + (o_hdatslca.size() - 1)) + { + HDAT_ERR("Error while setting SLCA_INDEX attribute for frutype: %d", + i_frutype); + } + if(!i_Target->trySetAttr<TARGETING::ATTR_SLCA_RID> + (l_hdatslcaentry.fru_rid)) + { + HDAT_ERR("Error while setting SLCA_RID attribute for frutype: %d", + i_frutype); + } + } + HDAT_DBG("Added SLCA Entry FI : %s loc_code : %s", + g_fruIDRidMap[i_frutype].fru_id, + l_hdatslcaentry.location_code); + return(o_hdatslca.size() - 1); +} + +/** + * @brief This routine adds Nodes and its children to SLCA table + * + * @pre None + * + * @post None + * + * @param i_Target - input parameter - Target of Node FRU being added + * i_slcaParentIndex - input parameter - Index of parent FRU + * i_LocCodePrefix - input parameter - Initial part of location code + * o_hdatslca - output parameter - Vector containing slca entries + * + * @return Number of DIMMs added + * + */ +static void hdatAddNodeToSLCATable(TARGETING::Target *i_Target, + uint16_t i_slcaParentIndex, + char *i_LocCodePrefix, + vector<HDAT_slcaEntry_t> &o_hdatslca) +{ + uint16_t l_slcaBPIndex = 0; + char l_nodeLocCode[64] = {0}; + uint16_t l_slcaEntryIndex = 0; + + l_slcaEntryIndex = hdatAddSLCAEntry(i_Target, HDAT_SLCA_FRU_TYPE_BP, + i_slcaParentIndex, + i_LocCodePrefix,o_hdatslca); + + if((o_hdatslca[i_slcaParentIndex].first_child_index == 0xFFFF) && + (l_slcaEntryIndex)) + { + o_hdatslca[i_slcaParentIndex].first_child_index = l_slcaEntryIndex; + + o_hdatslca[i_slcaParentIndex].first_child_rid = + o_hdatslca[l_slcaEntryIndex].fru_rid; + + o_hdatslca[i_slcaParentIndex].number_of_children++; + o_hdatslca[i_slcaParentIndex].number_of_children_2B++; + + } + + l_slcaBPIndex = l_slcaEntryIndex; + hdatGetLocationCode(i_Target, i_LocCodePrefix, l_nodeLocCode); + + TARGETING::PredicateHwas l_predHwas; + l_predHwas.present(true); + + TARGETING::PredicateCTM l_procFilter(TARGETING::CLASS_CHIP, + TARGETING::TYPE_PROC); + + TARGETING::PredicateCTM l_memFilter(TARGETING::CLASS_CHIP, + TARGETING::TYPE_MEMBUF); + + TARGETING::PredicateCTM l_pciFilter(TARGETING::CLASS_UNIT, + TARGETING::TYPE_PCI); + + TARGETING::PredicateCTM l_psFilter(TARGETING::CLASS_UNIT, + TARGETING::TYPE_PS); + + TARGETING::PredicateCTM l_vrmFilter(TARGETING::CLASS_UNIT, + TARGETING::TYPE_VRM); + + TARGETING::PredicateCTM l_fanFilter(TARGETING::CLASS_UNIT, + TARGETING::TYPE_FAN); + + TARGETING::PredicateCTM l_uartFilter(TARGETING::CLASS_UNIT, + TARGETING::TYPE_UART); + + TARGETING::PredicateCTM l_usbFilter(TARGETING::CLASS_UNIT, + TARGETING::TYPE_USB); + + TARGETING::PredicateCTM l_ethFilter(TARGETING::CLASS_UNIT, + TARGETING::TYPE_ETH); + + TARGETING::PredicateCTM l_dimmFilter(TARGETING::CLASS_LOGICAL_CARD, + TARGETING::TYPE_DIMM); + + TARGETING::PredicatePostfixExpr l_presentChildren; + l_presentChildren.push(&l_procFilter).push(&l_memFilter).Or(). + push(&l_pciFilter).Or().push(&l_psFilter).Or(). + push(&l_fanFilter).Or().push(&l_uartFilter).Or(). + push(&l_usbFilter).Or().push(&l_ethFilter).Or(). + push(&l_vrmFilter).Or().push(&l_dimmFilter).Or(). + push(&l_predHwas).And(); + + TARGETING::TargetHandleList l_childList; + + //Get all children of this node + TARGETING::targetService(). + getAssociated(l_childList, i_Target, + TARGETING::TargetService::CHILD, + TARGETING::TargetService::ALL, &l_presentChildren); + + for (TargetHandleList::const_iterator pTarget_it = l_childList.begin(); + pTarget_it != l_childList.end(); + ++pTarget_it) + { + TargetHandle_t l_childTarget = *pTarget_it; + TARGETING::ATTR_TYPE_type l_type; + HDAT_FRUType_t l_hdatFRUType = HDAT_SLCA_FRU_TYPE_UNKNOWN; + l_slcaEntryIndex = 0; + + if(l_childTarget->tryGetAttr<ATTR_TYPE>(l_type)) + { + switch(l_type) + { + case TYPE_PROC: + l_hdatFRUType = HDAT_SLCA_FRU_TYPE_PROC; + break; + + case TYPE_MEMBUF: + { + ATTR_FRU_ID_type l_childFRUId; + ATTR_FRU_ID_type l_encFRUId; + TARGETING::TargetHandleList targetList; + targetList.clear(); + getParentAffinityTargets(targetList,l_childTarget, + TARGETING::CLASS_ENC,TARGETING::TYPE_NODE); + if(!targetList.empty()) + { + TARGETING::Target* l_pNodeTarget = targetList[0]; + l_encFRUId = l_pNodeTarget->getAttr<ATTR_FRU_ID>(); + l_childFRUId = l_childTarget->getAttr<ATTR_FRU_ID>(); + if(l_encFRUId != l_childFRUId) + { + l_hdatFRUType = HDAT_SLCA_FRU_TYPE_RI; + } + } + else + { + //target list is empty for type membuf then FRU type + //would be set as HDAT_SLCA_FRU_TYPE_UNKNOWN + HDAT_ERR("Empty list returned while querying" + "for parents of membuf"); + } + } + break; + + case TYPE_DIMM: + l_hdatFRUType = HDAT_SLCA_FRU_TYPE_DIMM; + break; + + case TYPE_PCI: + l_hdatFRUType = HDAT_SLCA_FRU_TYPE_IOP; + break; + + case TYPE_PS: + l_hdatFRUType = HDAT_SLCA_FRU_TYPE_PS; + break; + + case TYPE_VRM: + l_hdatFRUType = HDAT_SLCA_FRU_TYPE_RG; + break; + + case TYPE_FAN: + l_hdatFRUType = HDAT_SLCA_FRU_TYPE_AM; + break; + + case TYPE_USB: + l_hdatFRUType = HDAT_SLCA_FRU_TYPE_CU; + break; + + case TYPE_ETH: + l_hdatFRUType = HDAT_SLCA_FRU_TYPE_CE; + break; + + case TYPE_UART: + l_hdatFRUType = HDAT_SLCA_FRU_TYPE_CS; + break; + +#ifdef BACKPLANE_EXTENSION_ENABLED + case TYPE_BX: + l_hdatFRUType = HDAT_SLCA_FRU_TYPE_BX; + hdatAddNodeToSLCATable(l_childTarget, l_slcaBPIndex, + l_nodeLocCode, o_hdatslca); + break; +#endif + + default: + l_hdatFRUType = HDAT_SLCA_FRU_TYPE_UNKNOWN; + break; + } + + if(l_hdatFRUType != HDAT_SLCA_FRU_TYPE_UNKNOWN) + { + l_slcaEntryIndex = hdatAddSLCAEntry(l_childTarget, + l_hdatFRUType, + l_slcaBPIndex, + l_nodeLocCode,o_hdatslca); + + o_hdatslca[l_slcaBPIndex].number_of_children++; + + o_hdatslca[l_slcaBPIndex].number_of_children_2B++; + + if((o_hdatslca[l_slcaBPIndex].first_child_index == 0xFFFF) && + (l_slcaEntryIndex)) + { + o_hdatslca[l_slcaBPIndex].first_child_index = + l_slcaEntryIndex; + + o_hdatslca[l_slcaBPIndex].first_child_rid = + o_hdatslca[l_slcaEntryIndex].fru_rid; + } + } + } + else + { + HDAT_ERR("Error reading ATTR_TYPE attribute"); + } + } +} + +/** + * @brief This routine adds Service Processors to SLCA table + * + * @pre None + * + * @post None + * + * @param i_Target - input parameter - Target of SP FRU + * i_slcaParentIndex - input parameter - Index of parent FRU + * o_hdatslca - output parameter - Vector containing slca entries + * for Service Processors + * + * @return Number of Service Processor FRUs added + * + * @retval HDAT_OTHER_COMP_ERROR + */ +static void hdatAddSPToSLCATable(TARGETING::Target *i_Target, + uint16_t i_slcaParentIndex, + char *i_LocCodePrefix, + vector<HDAT_slcaEntry_t> &o_hdatslca) +{ + TARGETING::PredicateCTM l_spPredicate(TARGETING::CLASS_CHIP, + TARGETING::TYPE_SP, + TARGETING::MODEL_BMC); + TARGETING::PredicateHwas l_predHwas; + l_predHwas.present(true); + + TARGETING::PredicatePostfixExpr l_presentSP; + l_presentSP.push(&l_spPredicate).push(&l_predHwas).And(); + + //Get all Service processors in the system + TARGETING::TargetRangeFilter l_spFilter( + TARGETING::targetService().begin(), + TARGETING::targetService().end(), + &l_presentSP); + + for (;l_spFilter;++l_spFilter) + { + TARGETING::Target *l_spTarget = (*l_spFilter); + + hdatAddSLCAEntry(l_spTarget, HDAT_SLCA_FRU_TYPE_SP, i_slcaParentIndex, + i_LocCodePrefix,o_hdatslca); + + o_hdatslca[i_slcaParentIndex].number_of_children++; + o_hdatslca[i_slcaParentIndex].number_of_children_2B++; + + HDAT_DBG("Added Service Processor to SLCA"); + } +} + +/** + * @brief This routine adds op-panel SLCA entry + * + * @pre None + * + * @post None + * + * @param i_Target - input parameter - Target of panel FRU + * i_slcaParentIndex - input parameter - Index of parent FRU + * i_LocCodePrefix - input parameter - Loc Code Prefix + * o_hdatslca - output parameter - Vector containing slca entries + * + * @return A null error log handle if successful, else the return code pointed + * to by errlHndl_t contains one of: + * + * @retval HDAT_OTHER_COMP_ERROR + */ +static void hdatAddOpPanelToSLCATable(TARGETING::Target *i_Target, + uint16_t i_slcaParentIndex, + char *i_LocCodePrefix, + vector<HDAT_slcaEntry_t> &o_hdatslca) +{ + TARGETING::PredicateCTM l_opPredicate(TARGETING::CLASS_UNIT, + TARGETING::TYPE_PANEL); + + TARGETING::PredicateHwas l_predHwas; + l_predHwas.present(true); + + TARGETING::PredicatePostfixExpr l_presentPanel; + l_presentPanel.push(&l_opPredicate).push(&l_predHwas).And(); + + //Get all op-panels in the system + TARGETING::TargetRangeFilter l_opFilter( + TARGETING::targetService().begin(), + TARGETING::targetService().end(), + &l_presentPanel); + + for (;l_opFilter;++l_opFilter) + { + TARGETING::Target *l_opTarget = (*l_opFilter); + + hdatAddSLCAEntry(l_opTarget, HDAT_SLCA_FRU_TYPE_OP, i_slcaParentIndex, + i_LocCodePrefix,o_hdatslca); + + o_hdatslca[i_slcaParentIndex].number_of_children++; + o_hdatslca[i_slcaParentIndex].number_of_children_2B++; + + HDAT_DBG("Added OpPanel to SLCA"); + } +} + +/** + * @brief This routine constructs SLCA table for all FRUs + * + * @pre None + * + * @post None + * + * @param o_hdatslcaentries - output parameter - Vector containing slca entries + * + * @return A null error log handle if successful, else the return code pointed + * to by errlHndl_t contains one of: + * + * @retval HDAT_OTHER_COMP_ERROR + */ +errlHndl_t hdatConstructslcaTable(std::vector<HDAT_slcaEntry_t> + &o_hdatslcaentries) +{ + + TARGETING::Target *l_pSystemTarget = NULL; + (void) TARGETING::targetService().getTopLevelTarget(l_pSystemTarget); + + if(l_pSystemTarget == NULL) + { + HDAT_ERR("Error in getting Top Level Target"); + assert(l_pSystemTarget != NULL); + } + + char l_locCode[64]={0}; + hdatGetLocationCodePrefix(l_locCode); + + uint16_t l_slcaVVIndex = hdatAddSLCAEntry(l_pSystemTarget, + HDAT_SLCA_FRU_TYPE_VV,0, + l_locCode, + o_hdatslcaentries); + + uint16_t l_slcaSVIndex = hdatAddSLCAEntry(l_pSystemTarget, + HDAT_SLCA_FRU_TYPE_SV,l_slcaVVIndex, + l_locCode, + o_hdatslcaentries); + + if((o_hdatslcaentries[0].first_child_index == 0xFFFF) && + (l_slcaSVIndex)) + { + o_hdatslcaentries[0].first_child_index = l_slcaSVIndex; + + o_hdatslcaentries[0].first_child_rid = + o_hdatslcaentries[l_slcaSVIndex].fru_rid; + + o_hdatslcaentries[0].number_of_children++; + o_hdatslcaentries[0].number_of_children_2B++; + + } + + TARGETING::PredicateCTM l_nodePredicate(TARGETING::CLASS_ENC, + TARGETING::TYPE_NODE); + TARGETING::PredicateHwas l_predHwas; + l_predHwas.present(true); + + TARGETING::PredicatePostfixExpr l_presentNode; + l_presentNode.push(&l_nodePredicate).push(&l_predHwas).And(); + + //Get all Nodes + TARGETING::TargetRangeFilter l_nodeFilter( + TARGETING::targetService().begin(), + TARGETING::targetService().end(), + &l_presentNode); + + TARGETING::Target *l_nodeTarget = (*l_nodeFilter); + if(l_nodeTarget != NULL) + { + l_nodeTarget->setAttr<TARGETING::ATTR_ORDINAL_ID>(0); + + //Add EV here and make SP, BP and OP as children of EV + uint16_t l_slcaEVIndex = hdatAddSLCAEntry(l_pSystemTarget, + HDAT_SLCA_FRU_TYPE_EV,l_slcaVVIndex, + l_locCode, + o_hdatslcaentries); + + o_hdatslcaentries[l_slcaEVIndex].first_child_index = 0xFFFF; + o_hdatslcaentries[l_slcaEVIndex].first_child_rid = 0xFFFF; + + o_hdatslcaentries[l_slcaVVIndex].number_of_children++; + o_hdatslcaentries[l_slcaVVIndex].number_of_children_2B++; + + hdatAddNodeToSLCATable(l_nodeTarget, l_slcaEVIndex, l_locCode, + o_hdatslcaentries); + + //Add Service Processor FRUs to SLCA table + hdatAddSPToSLCATable(l_nodeTarget,l_slcaEVIndex,l_locCode, + o_hdatslcaentries); + + //Add Op-Panel FRUs to SLCA table + hdatAddOpPanelToSLCATable(l_nodeTarget,l_slcaEVIndex,l_locCode, + o_hdatslcaentries); + + hdatPopulateOrdinalId(); + } + else + { + HDAT_ERR("Error retrieving nodes. There must be alteast one node"); + assert(l_nodeTarget != NULL); + } + return NULL; + +} + +/** + * @brief This routine sets SLCA structure header parameters + * + * @pre None + * + * @post None + * + * @param o_slcaStruct - output parameter - Structure containing SLCA header + * i_nrOfSLCAEntries - input parameter - Number of SLCA entries + * + * @return A null error log handle if successful, else the return code pointed + * to by errlHndl_t contains one of: + * + * @retval HDAT_OTHER_COMP_ERROR + */ +static errlHndl_t hdatSetSLCAStructHdrs(hdatSLCAStruct_t &o_slcaStruct, + uint32_t i_nrOfSLCAEntries) +{ + errlHndl_t l_errlHndl = NULL; + + uint32_t l_hdatslcastructsize = i_nrOfSLCAEntries * + sizeof(HDAT_slcaEntry_t); + + o_slcaStruct.hdatHdr.hdatStructId = HDAT_HDIF_STRUCT_ID; + o_slcaStruct.hdatHdr.hdatInstance = 0; + o_slcaStruct.hdatHdr.hdatVersion = HDAT_SLCA_STRUCT_VERSION; + o_slcaStruct.hdatHdr.hdatSize = sizeof(hdatSLCAStruct_t) + + l_hdatslcastructsize; + o_slcaStruct.hdatHdr.hdatHdrSize = sizeof(hdatHDIF_t); + o_slcaStruct.hdatHdr.hdatDataPtrOffset = sizeof(hdatHDIF_t); + o_slcaStruct.hdatHdr.hdatDataPtrCnt = 1; + o_slcaStruct.hdatHdr.hdatChildStrCnt = 0; + o_slcaStruct.hdatHdr.hdatChildStrOffset = 0; + + memcpy(o_slcaStruct.hdatHdr.hdatStructName, HDAT_SLCA_STRUCT_NAME, + sizeof(o_slcaStruct.hdatHdr.hdatStructName)); + + o_slcaStruct.hdatSLCAIntData[0].hdatOffset = + sizeof(hdatHDIF_t)+ sizeof(hdatHDIFDataHdr_t) + + sizeof(o_slcaStruct.hdatPadding); + + o_slcaStruct.hdatSLCAIntData[0].hdatSize = + sizeof(hdatSLCAArrayHdr_t) + l_hdatslcastructsize; + + memset(o_slcaStruct.hdatPadding, 0 , sizeof(o_slcaStruct.hdatPadding)); + + o_slcaStruct.hdatSLCAArrayHdr.hdatOffsetToSLCAArray = + sizeof(hdatSLCAArrayHdr_t); + + o_slcaStruct.hdatSLCAArrayHdr.hdatActualNrEntries = i_nrOfSLCAEntries; + + o_slcaStruct.hdatSLCAArrayHdr.hdatSizeOfEntryAllotted = + sizeof(HDAT_slcaEntry_t); + + o_slcaStruct.hdatSLCAArrayHdr.hdatActualSizeOfEntry = + sizeof(HDAT_slcaEntry_t); + + return l_errlHndl; +} + +/** + * @brief This routine builds the SLCA structure as per HDAT specifications + * + * @pre None + * + * @post None + * + * @param i_msAddr - Mainstore address where SLCA structure is loaded + * o_hdatslcaCount - output parameter - Number of SLCA structures + * o_hdatslcaSize - output paramster - Size of SLCA created + * + * @return errlHndl_t - Error Handle + * + * @retval HDAT_OTHER_COMP_ERROR + */ +errlHndl_t hdatBuildSLCA(const HDAT::hdatMsAddr_t &i_msAddr, + uint32_t &o_hdatslcaCount, + uint32_t &o_hdatslcaSize) + +{ + std::vector<HDAT_slcaEntry_t> l_hdatslcaentries; + hdatSLCAStruct_t l_hdatslcastruct; + errlHndl_t l_errl = NULL; + + hdatPopulateMTMAndSerialNumber(); + hdatConstructslcaTable(l_hdatslcaentries); + + uint32_t l_hdatslcastructsize = l_hdatslcaentries.size() * + sizeof(HDAT_slcaEntry_t); + + uint64_t l_base_addr = ((uint64_t) i_msAddr.hi << 32) | i_msAddr.lo; + + //Set SLCA Headers + hdatSetSLCAStructHdrs(l_hdatslcastruct, l_hdatslcaentries.size()); + + // Allocate space for SLCA Header + void *l_virt_addr_hdr = mm_block_map(reinterpret_cast<void*> + (ALIGN_PAGE_DOWN(l_base_addr)), + (ALIGN_PAGE(sizeof(hdatSLCAStruct_t) + + l_hdatslcastructsize) + PAGESIZE)); + l_virt_addr_hdr = reinterpret_cast<void *>( + reinterpret_cast<uint64_t>(l_virt_addr_hdr) + + (l_base_addr - ALIGN_PAGE_DOWN(l_base_addr))); + + HDAT_DBG("SLCA hdr addr 0x%016llX SLCA hdr size %d", + (uint64_t)l_virt_addr_hdr, sizeof(hdatSLCAStruct_t)); + + memcpy(reinterpret_cast<hdatSLCAStruct_t *>(l_virt_addr_hdr), + &l_hdatslcastruct, sizeof(hdatSLCAStruct_t)); + + HDAT_slcaEntry_t *l_hdatSLCA = reinterpret_cast<HDAT_slcaEntry_t *> + ((uint64_t)l_virt_addr_hdr + sizeof(hdatSLCAStruct_t)); + + HDAT_DBG("HDAT SLCA addr 0x%016llX SLCA struct size %d", + (uint64_t) l_base_addr, l_hdatslcastructsize); + + HDAT_DBG("HDAT SLCA addr 0x%016llX virtual addr 0x%016llX", + (uint64_t) l_hdatSLCA, (uint64_t)l_virt_addr_hdr); + + std::copy(l_hdatslcaentries.begin(), l_hdatslcaentries.end(), l_hdatSLCA); + + HDAT_DBG("HDAT:: Loaded SLCA structures: Size: 0x%X", + sizeof(hdatSLCAStruct_t) + + l_hdatslcastructsize); + + o_hdatslcaSize = sizeof(hdatSLCAStruct_t) + l_hdatslcastructsize; + o_hdatslcaCount = 1; + + int rc = mm_block_unmap(l_virt_addr_hdr); + + if( rc != 0) + { + errlHndl_t l_errl = NULL; + /*@ + * @errortype + * @moduleid HDAT::MOD_SLCA_DESTRUCTOR + * @reasoncode HDAT::RC_DEV_MAP_FAIL + * @devdesc Unmap a mapped region failed + * @custdesc Firmware encountered an internal error. + */ + hdatBldErrLog(l_errl, + MOD_PCIA_DESTRUCTOR, + RC_DEV_MAP_FAIL, + (uint32_t)((uint64_t)l_virt_addr_hdr >> 32), + (uint32_t)((uint64_t)l_virt_addr_hdr),0,0, + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + HDAT_VERSION1, false); + } + + return l_errl; +} + +/** + * @brief This routine copies the SLCA from a source address to a destination + * address + * + * @pre None + * + * @post None + * + * @param i_msAddrSource - input parameter - Source address of SLCA + * i_msAddrDest - input parameter - Destination address of SLCA + * i_slcaSize - input parameter - Size of SLCA to be copied + * + * @return None + * + * @retval HDAT_OTHER_COMP_ERROR + */ +void hdatMoveSLCA(const HDAT::hdatMsAddr_t &i_msAddrSource, + const HDAT::hdatMsAddr_t &i_msAddrDest, + uint32_t i_slcaSize) +{ + + uint64_t l_base_addr_source = ((uint64_t) i_msAddrSource.hi << 32) | + i_msAddrSource.lo; + uint64_t l_base_addr_dest = ((uint64_t) i_msAddrDest.hi << 32) | + i_msAddrDest.lo; + + HDAT_DBG("Move SLCA from 0x%016llX to 0x%016llX with size %d", + (uint64_t) l_base_addr_source, (uint64_t)l_base_addr_dest, + i_slcaSize); + // Allocate space for SLCA + void *l_virt_addr_source = mm_block_map(reinterpret_cast<void*> + (ALIGN_PAGE_DOWN(l_base_addr_source)), + (ALIGN_PAGE(i_slcaSize)+PAGESIZE)); + + l_virt_addr_source = reinterpret_cast<void *>( + reinterpret_cast<uint64_t>(l_virt_addr_source) + + (l_base_addr_source - ALIGN_PAGE_DOWN(l_base_addr_source))); + + // Allocate space for SLCA + void *l_virt_addr_dest = mm_block_map(reinterpret_cast<void*> + (ALIGN_PAGE_DOWN(l_base_addr_dest)), + (ALIGN_PAGE(i_slcaSize) + PAGESIZE)); + + l_virt_addr_dest = reinterpret_cast<void *>( + reinterpret_cast<uint64_t>(l_virt_addr_dest) + + (l_base_addr_dest - ALIGN_PAGE_DOWN(l_base_addr_dest))); + + memcpy(l_virt_addr_dest , reinterpret_cast<void*>(l_virt_addr_source), + i_slcaSize); + + mm_block_unmap(l_virt_addr_source); + mm_block_unmap(l_virt_addr_dest); +} + + +} diff --git a/src/usr/hdat/hdathostslcadata.H b/src/usr/hdat/hdathostslcadata.H new file mode 100644 index 000000000..4a0355546 --- /dev/null +++ b/src/usr/hdat/hdathostslcadata.H @@ -0,0 +1,144 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hdat/hdathostslcadata.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 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 HDATHOSTDATA_H_ +#define HDATHOSTDATA_H_ + +namespace HDAT +{ + +const uint16_t HDAT_SLCA_STRUCT_VERSION = 0x21; +const char HDAT_SLCA_STRUCT_NAME[7] = "SLCA "; + +struct HDAT_slcaEntry_t +{ + uint16_t fru_index; //slca_index_of_this_fru + uint16_t fru_rid; //vpd_resourece_id_of_this_fru + char fru_id[2]; //ASCII resource description + uint16_t parent_index; //slca_index_of_this_frus_parent + uint8_t slca_reserved:6, + non_functional_redundant_copy:1, //1 = not functional, 0 = functional + flag_embedded_pluggable:1; //1 = embedded. 0=pluggable + uint8_t number_of_children; //number_of_children + uint16_t first_child_index; //slca_index_of_this_frus_first_child + uint16_t first_child_rid; //resource_ID of this frus first child + uint8_t max_location_code_len; + uint8_t actual_location_code_len; //length_of_location_code + char location_code[80]; //location_code (NULL terminated) + uint16_t first_redundant_index; //slca index of the redundant copy + uint8_t number_redundant_copies; //total number of redundant copy + uint8_t reserved; + uint16_t number_of_children_2B; //number of children - 2 byte version + uint8_t installed; //Is FRU installed + uint8_t collected; //Is FRU VPD collected +}; + +enum HDAT_FRUType_t +{ + HDAT_SLCA_FRU_TYPE_BP = 0x00, + HDAT_SLCA_FRU_TYPE_EV = 0x01, + HDAT_SLCA_FRU_TYPE_SV = 0x02, + HDAT_SLCA_FRU_TYPE_PROC = 0x03, + HDAT_SLCA_FRU_TYPE_MEM = 0x04, + HDAT_SLCA_FRU_TYPE_IOP = 0x05, + HDAT_SLCA_FRU_TYPE_SP = 0x06, + HDAT_SLCA_FRU_TYPE_PS = 0x07, + HDAT_SLCA_FRU_TYPE_AM = 0x08, + HDAT_SLCA_FRU_TYPE_CU = 0x09, + HDAT_SLCA_FRU_TYPE_CE = 0x0A, + HDAT_SLCA_FRU_TYPE_OP = 0x0B, + HDAT_SLCA_FRU_TYPE_RG = 0x0C, + HDAT_SLCA_FRU_TYPE_SA = 0x0D, + HDAT_SLCA_FRU_TYPE_EI = 0x0E, + HDAT_SLCA_FRU_TYPE_EF = 0x0F, + HDAT_SLCA_FRU_TYPE_CS = 0x10, + HDAT_SLCA_FRU_TYPE_DIMM = 0x11, + HDAT_SLCA_FRU_TYPE_VV = 0x12, + HDAT_SLCA_FRU_TYPE_RI = 0x13, + HDAT_SLCA_FRU_TYPE_UNKNOWN = 0xFF, +}; + +struct fru_id_rid_t +{ + uint16_t fru_rid; + uint8_t fru_id[3]; +}; + +struct hdatSLCAArrayHdr_t +{ + uint32_t hdatOffsetToSLCAArray; + uint32_t hdatActualNrEntries; + uint32_t hdatSizeOfEntryAllotted; + uint32_t hdatActualSizeOfEntry; +}; + +struct hdatSLCAStruct_t +{ + hdatHDIF_t hdatHdr; + hdatHDIFDataHdr_t hdatSLCAIntData[1]; + uint8_t hdatPadding[8]; + hdatSLCAArrayHdr_t hdatSLCAArrayHdr; +}; + +/** + * @brief This routine builds the SLCA structure as per HDAT specifications + * + * @pre None + * + * @post None + * + * @param i_msAddr - Mainstore address where SLCA structure is loaded + * o_hdatslcaCount - output parameter - Number of SLCA structures + * o_hdatslcaSize - output paramster - Size of SLCA created + * + * @return errlHndl_t - Error Handle + * + * @retval HDAT_OTHER_COMP_ERROR + */ +errlHndl_t hdatBuildSLCA(const HDAT::hdatMsAddr_t &i_msAddr, + uint32_t &o_hdatslcaCount, + uint32_t &o_hdatslcaSize); + +/** + * @brief This routine copies the SLCA from a source address to a destination + * address + * + * @pre None + * + * @post None + * + * @param i_msAddrSource - input parameter - Source address of SLCA + * i_msAddrDest - input parameter - Destination address of SLCA + * i_slcaSize - input parameter - Size of SLCA to be copied + * + * @return None + * + * @retval HDAT_OTHER_COMP_ERROR + */ +void hdatMoveSLCA(const HDAT::hdatMsAddr_t &i_msAddrSource, + const HDAT::hdatMsAddr_t &i_msAddrDest, + uint32_t i_slcaSize); + +} +#endif diff --git a/src/usr/hdat/hdatiohub.C b/src/usr/hdat/hdatiohub.C new file mode 100644 index 000000000..b27cc471b --- /dev/null +++ b/src/usr/hdat/hdatiohub.C @@ -0,0 +1,899 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hdat/hdatiohub.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 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 */ +#include <sys/mm.h> +#include <sys/mmio.h> +#include "hdathdif.H" +#include "hdatvpd.H" +#include "hdatiohub.H" +#include <targeting/common/util.H> +#include<sys/time.h> +#include <util/align.H> + + +using namespace TARGETING; + +namespace HDAT +{ + +vpdData mvpdData[] = +{ + { PVPD::VINI, PVPD::DR }, + { PVPD::VINI, PVPD::CE }, + { PVPD::VINI, PVPD::VZ }, + { PVPD::VINI, PVPD::FN }, + { PVPD::VINI, PVPD::PN }, + { PVPD::VINI, PVPD::SN }, + { PVPD::VINI, PVPD::CC }, + { PVPD::VINI, PVPD::HE }, + { PVPD::VINI, PVPD::CT }, + { PVPD::VINI, PVPD::B3 }, + { PVPD::VINI, PVPD::B4 }, + { PVPD::VINI, PVPD::B7 }, + { PVPD::VINI, PVPD::PF }, + { PVPD::VINI, PVPD::LX }, +}; + +const HdatKeywordInfo l_pvpdKeywords[] = +{ + + { PVPD::DR, "DR" }, + { PVPD::CE, "CE" }, + { PVPD::VZ, "VZ" }, + { PVPD::FN, "FN" }, + { PVPD::PN, "PN" }, + { PVPD::SN, "SN" }, + { PVPD::CC, "CC" }, + { PVPD::HE, "HE" }, + { PVPD::CT, "CT" }, + { PVPD::B3, "B3" }, + { PVPD::B4, "B4" }, + { PVPD::B7, "B7" }, + { PVPD::PF, "PF" }, + { PVPD::LX, "LX" }, +}; + +extern trace_desc_t *g_trac_hdat; + +const uint32_t HDAT_MULTIPLE = 16; + + + +/******************************************************************************* + * IO HUB constructor +*******************************************************************************/ + +HdatIoHubFru::HdatIoHubFru(errlHndl_t &o_errlHndl, + uint32_t i_resourceId, + hdatCardType i_cardType, + uint32_t i_daughterCnt, + uint32_t i_index, + uint32_t i_slcaIdx) +:HdatHdif(o_errlHndl, "IO HUB", HDAT_PARENT_LAST,i_index,HDAT_CHILD_LAST, + HDAT_IO_VERSION), +iv_hubStatus(0),iv_kwdSize(0),iv_maxHubs(HDAT_MAX_IO_CHIPS), +iv_maxDaughters(i_daughterCnt),iv_hubArraySize(0),iv_actDaughterCnt(0), +iv_maxDaughterSize(0),iv_kwd(NULL),iv_hubArray(NULL),iv_daughterPtrs(NULL) +{ + HDAT_ENTER(); + + o_errlHndl = NULL; + + iv_hubId.hdatCardType = i_cardType; + iv_hubId.hdatReserved1 = 0; + iv_hubId.hdatReserved2 = 0; + iv_hubId.hdatReserved3 = 0; + iv_hubId.hdatReserved4 = 0; + iv_hubId.hdatReserved5 = 0; + iv_hubId.hdatReserved6 = 0; + + iv_hubArrayHdr.hdatOffset = sizeof(hdatHDIFDataArray_t); + iv_hubArrayHdr.hdatArrayCnt = 0; + iv_hubArrayHdr.hdatAllocSize = sizeof(hdatHubEntry_t); + iv_hubArrayHdr.hdatActSize = sizeof(hdatHubEntry_t); + + // Allocate space to build the I/O hub array + iv_hubArraySize = iv_maxHubs * sizeof(hdatHubEntry_t); + iv_hubArray = reinterpret_cast<hdatHubEntry_t *>(calloc(iv_maxHubs, + sizeof(hdatHubEntry_t))); + + iv_fru.hdatResourceId = i_resourceId; + + + if (NULL == o_errlHndl) + { + iv_fru.hdatSlcaIdx = i_slcaIdx; + this->addData(HDAT_FRU_ID, sizeof(hdatFruId_t)); + this->addData(HDAT_ASCII_KWD, iv_kwdSize); + this->addData(HDAT_HUB_ID, sizeof(hdatHubId_t)); + this->addData(HDAT_HUBS_ARRAY, iv_hubArraySize + + sizeof(iv_hubArrayHdr)); + this->align(); + } + + HDAT_EXIT(); +} + + +/******************************************************************************* + * * IO HUB destructor +*******************************************************************************/ +HdatIoHubFru::~HdatIoHubFru() +{ + uint32_t l_cnt; + HdatVpd *l_vpdObj, **l_curPtr; + HDAT_ENTER(); + + // Destroy daughter card objects + l_curPtr = iv_daughterPtrs; + for (l_cnt = 0; l_cnt < iv_actDaughterCnt; l_cnt++) + { + l_vpdObj = *l_curPtr; + delete l_vpdObj; + l_curPtr = reinterpret_cast<HdatVpd **>(reinterpret_cast<char *> + (l_curPtr) + sizeof(HdatVpd *)); + } + + free(iv_hubArray); + free(iv_daughterPtrs); + + HDAT_EXIT(); + +} + + + +//****************************************************************************** +// setIOHub +//****************************************************************************** + +//we enter the function each time with the starting address for the next +//object to write +uint8_t * HdatIoHubFru::setIOHub(uint8_t * io_virt_addr, + uint32_t& o_size) +{ + HDAT_DBG("virtual address=0x%016llX", + (uint64_t)io_virt_addr); + + uint8_t *l_temp = NULL, *l_ioMarker = NULL; + HdatVpd *l_vpdObj; + + //saving the starting offset as we need to add child pointer array offset + //to this location to start writing daughter cards which is often offset 820 + l_ioMarker = io_virt_addr; + + io_virt_addr = this->setHdif(io_virt_addr); + + HDAT_DBG("after writing HDIF header address now 0x%016llX", + (uint64_t)io_virt_addr); + + + //write FRU ID + //cast to hdatFruId_t + hdatFruId_t *l_hdatFruId = reinterpret_cast<hdatFruId_t *>(io_virt_addr); + + HDAT_DBG("writing FRU ID from address=0x%016llX", + (uint64_t)l_hdatFruId); + + l_hdatFruId->hdatSlcaIdx = this->iv_fru.hdatSlcaIdx; + l_hdatFruId->hdatResourceId = this->iv_fru.hdatResourceId; + + l_hdatFruId++; //increase by sizeof hdatFruId_t + + + //write HUB FRU id + //cast to hdatHubId_t * + hdatHubId_t *l_hdatHubId = reinterpret_cast<hdatHubId_t *>(l_hdatFruId); + + HDAT_DBG("writing HUB FRU id from address=0x%016llX", + (uint64_t)l_hdatHubId); + + l_hdatHubId->hdatCardType = this->iv_hubId.hdatCardType; + + l_hdatHubId++;//pass through reserved1..6 by incrementing the pointer + + + //write Data array header of iohub array hdatHDIFDataArray_t iv_hubArrayHdr + hdatHDIFDataArray_t *l_hdatHDIFDataArray = + reinterpret_cast<hdatHDIFDataArray_t *>(l_hdatHubId); + + HDAT_DBG("writing io hub Data array header at address=0x%016llX", + (uint64_t)l_hdatHDIFDataArray); + + l_hdatHDIFDataArray->hdatOffset = this->iv_hubArrayHdr.hdatOffset; + l_hdatHDIFDataArray->hdatArrayCnt = this->iv_hubArrayHdr.hdatArrayCnt; + l_hdatHDIFDataArray->hdatAllocSize = this->iv_hubArrayHdr.hdatAllocSize; + l_hdatHDIFDataArray->hdatActSize = this->iv_hubArrayHdr.hdatActSize; + + l_hdatHDIFDataArray++;//increase by sizeof hdatHDIFDataArray_t + + + //write io hub array entries + //number of entries are iv_hubArrayHdr.hdatArrayCnt + + hdatHubEntry_t *l_hdatHubEntry = + reinterpret_cast<hdatHubEntry_t *>(l_hdatHDIFDataArray); + + HDAT_DBG("writing io hub array from address=0x%016llX", + (uint64_t)l_hdatHubEntry); + + for ( uint8_t l_cnt = 0; l_cnt < this->iv_hubArrayHdr.hdatArrayCnt; l_cnt++) + { + l_hdatHubEntry->hdatIoHubId = + this->iv_hubArray[l_cnt].hdatIoHubId; + l_hdatHubEntry->hdatChipId = + this->iv_hubArray[l_cnt].hdatChipId; + l_hdatHubEntry->hdatEcLvl = + this->iv_hubArray[l_cnt].hdatEcLvl; + l_hdatHubEntry->hdatProcChipID = + this->iv_hubArray[l_cnt].hdatProcChipID; + l_hdatHubEntry->hdatHardwareTopology = + this->iv_hubArray[l_cnt].hdatHardwareTopology; + l_hdatHubEntry->hdatMRID = + this->iv_hubArray[l_cnt].hdatMRID; + l_hdatHubEntry->hdatMemMapVersion = + this->iv_hubArray[l_cnt].hdatMemMapVersion; + l_hdatHubEntry->hdatFlags = + this->iv_hubArray[l_cnt].hdatFlags; + l_hdatHubEntry->hdatFab0PresDetect = + this->iv_hubArray[l_cnt].hdatFab0PresDetect; + + for ( uint16_t l_phbcnt = 0 ; l_phbcnt < HDAT_PHB_LANES; l_phbcnt++) + { + l_hdatHubEntry->hdatLaneEqPHB[l_phbcnt] = + this->iv_hubArray[l_cnt].hdatLaneEqPHB[l_phbcnt]; + } + + l_hdatHubEntry++;//increase by size of hdatHubEntry_t + + HDAT_DBG("wrote io hub array %d",l_cnt); + } + + l_temp = reinterpret_cast<uint8_t *>(l_hdatHubEntry); + + + //doing padding for io hub + + io_virt_addr = this->setpadding(l_temp,o_size); + + + //next to write daughter card values + //this should go to offset 820 usually + uint32_t l_chldOffset = this->getChildOffset(); + l_ioMarker += l_chldOffset; + + io_virt_addr = reinterpret_cast<uint8_t *>(l_ioMarker); + + HDAT_DBG("start writing daughter cards from address 0x%016llX", + (uint64_t)io_virt_addr); + + if (iv_actDaughterCnt > 0) + { + l_vpdObj = *iv_daughterPtrs; + uint32_t l_daughterCount = 0; + while ( l_daughterCount < iv_actDaughterCnt) + { + HDAT_DBG("writing daughter from address 0x%016llX", + (uint64_t)io_virt_addr); + io_virt_addr = l_vpdObj->setVpd( io_virt_addr); + l_daughterCount++; + + if (l_daughterCount < iv_actDaughterCnt) + { + l_vpdObj = *(HdatVpd **)((char *)iv_daughterPtrs + + l_daughterCount * sizeof(HdatVpd *)); + } + } + } + else + { + HDAT_DBG("no daughter information to write"); + } + + HDAT_DBG("exiting with virtual address=0x%016llX", + (uint64_t)io_virt_addr); + return io_virt_addr; +} + + +/******************************************************************************/ +// hdatGetDaughterInfoFromTarget +/******************************************************************************/ + +errlHndl_t HdatIoHubFru::hdatGetDaughterInfoFromTarget( + const TARGETING::Target * i_target, + TARGETING::TargetHandleList& o_targetList, + std::vector <uint32_t>& o_DaughterRids) +{ + //i_target is the TARGET of proc + //add parent of this (sysnode) to list as BP + //get all pci slot children of the proc in a list + //for(start from the 1st slot; iterate through all the slots; ) + //add the pci slot to daughter list + //get all the pci card children of the slot + //for(start from the 1st card; iterate through all the cards; ) + //add the card to the daughter list + + //also add the vpdType enum here in this function and passover + //so we get the vpd type handy while calling vpd constructor + + HDAT_ENTER(); + errlHndl_t l_errl = NULL; + o_DaughterRids.clear(); + do + { + if ( NULL == i_target ) + { + HDAT_ERR("hdatGetDaughterInfoFromTarget:" + " input target pointer is NULL"); + + /*@ + * @errortype + * @moduleid HDAT::MOD_IOHUB_FETCH_DAUGHTER + * @reasoncode HDAT::RC_INVALID_OBJECT + * @devdesc input Target pointer is NULL + * @custdesc Firmware encountered an internal error + */ + hdatBldErrLog(l_errl, + MOD_IOHUB_FETCH_DAUGHTER, + RC_INVALID_OBJECT, + 0,0,0,0); + assert ( i_target != NULL); + } + if ((i_target->getAttr<ATTR_CLASS>() != CLASS_CARD)&& + (i_target->getAttr<ATTR_CLASS>() != CLASS_LOGICAL_CARD)&& + (i_target->getAttr<ATTR_CLASS>() != CLASS_CHIP)) + { + HDAT_ERR("hdatGetDaughterInfoFromTarget: input Target class " + "not supported"); + /*@ + * @errortype + * @moduleid HDAT::MOD_IOHUB_FETCH_DAUGHTER + * @reasoncode HDAT::RC_TARGET_UNSUPPORTED + * @devdesc Target class not supported + * @custdesc Firmware encountered an internal error + */ + hdatBldErrLog(l_errl, + MOD_IOHUB_FETCH_DAUGHTER, + RC_TARGET_UNSUPPORTED, + 0,0,0,0); + + break; + } + + o_targetList.clear(); + getParentAffinityTargets(o_targetList,i_target, + TARGETING::CLASS_ENC,TARGETING::TYPE_NODE); + if(o_targetList.empty()) + { + HDAT_ERR("hdatGetDaughterInfoFromTarget: node returned empty " + "Target list"); + /*@ + * @errortype + * @moduleid HDAT::MOD_IOHUB_FETCH_DAUGHTER + * @reasoncode HDAT::RC_EMPTY_TARGET_LIST + * @devdesc node returned empty Target list + * @custdesc Firmware encountered an internal error + */ + hdatBldErrLog(l_errl, + MOD_IOHUB_FETCH_DAUGHTER, + RC_EMPTY_TARGET_LIST, + 0,0,0,0); + assert ( !o_targetList.empty()); + + break; + } + //get the parent node id, this is BP of the proc + TARGETING::Target* l_pNodeTarget = o_targetList[0]; + o_DaughterRids.push_back(l_pNodeTarget->getAttr<ATTR_SLCA_RID>()); + + + //@TODO: RTC 148660 add the loop to fetch the pci slot and card + }while(0); + + + HDAT_EXIT(); + return l_errl; + +}//end hdatGetDaughterInfoFromTarget + +/******************************************************************************/ +// bldDaughterStruct +/******************************************************************************/ +errlHndl_t HdatIoHubFru::bldDaughterStruct(const TARGETING::Target * i_target, + uint32_t i_index) +{ + errlHndl_t l_errlHndl = NULL; + uint32_t l_InstalledEtRidCnt = 0; + uint32_t l_loopCnt = 0; + std::vector <uint32_t> l_etRidArray; + TARGETING::TargetHandleList l_targetList; + HdatVpd *l_daughter = NULL; + + HDAT_ENTER(); + + l_errlHndl = hdatGetDaughterInfoFromTarget(i_target, + l_targetList,l_etRidArray); + + if (NULL == l_errlHndl) + { + l_InstalledEtRidCnt = l_etRidArray.size(); + HDAT_DBG("daughter count %d",l_InstalledEtRidCnt); + iv_maxDaughters = l_InstalledEtRidCnt; + + iv_daughterPtrs = reinterpret_cast<HdatVpd **>(calloc( + l_InstalledEtRidCnt,sizeof(HdatVpd *))); + + if(iv_daughterPtrs) + { + for (uint32_t i=0; i<l_InstalledEtRidCnt; i++) + { + HDAT_DBG("adding daughter %d", + l_etRidArray[i]); + l_errlHndl = this->addDaughterCard(l_etRidArray[i], + l_targetList[i], i_index); + + if ( NULL != l_errlHndl ) + { + HDAT_DBG("error adding daughter card"); + break; + } + } + } + else + { + HDAT_DBG("error from calloc"); + + /*@ + * @errortype + * @moduleid HDAT::MOD_IOHUB_BUILD_DAUGHTER + * @reasoncode HDAT::RC_MEM_ALLOC_FAIL + * @devdesc memory alloc failed in calloc + * @custdesc Firmware encountered an internal error + */ + hdatBldErrLog(l_errlHndl, + MOD_IOHUB_BUILD_DAUGHTER, + RC_MEM_ALLOC_FAIL, + 0,0,0,0); + + } + } + else + { + HDAT_DBG("no daughter cards for RID:0x%04x", + iv_fru.hdatResourceId); + } + + // Tell the base class about child structures and adjust size of + // daughter card structures so they are all the same size + if (NULL == l_errlHndl && iv_daughterPtrs != NULL) + { + for(l_loopCnt = 0;l_loopCnt < iv_actDaughterCnt;l_loopCnt++) + { + /*l_daughter = *(HdatVpd **)((char *)iv_daughterPtrs + + l_loopCnt * sizeof(HdatVpd *));*/ + + l_daughter = *(reinterpret_cast<HdatVpd **> + (reinterpret_cast<char *>(iv_daughterPtrs) + + l_loopCnt * sizeof(HdatVpd *))); + + l_daughter->maxSiblingSize(iv_maxDaughterSize); + + HDAT_DBG("calling addChild"); + this->addChild(HDAT_DAUGHTER_CARD, iv_maxDaughterSize, 1); + } + } + + HDAT_EXIT(); + + return l_errlHndl; + +}//end bldDaughterStruct + + +/******************************************************************************/ +//getTotalIoKwdSize +/******************************************************************************/ + +uint64_t HdatIoHubFru::getTotalIoKwdSize() +{ + HDAT_ENTER(); + + return (iv_maxDaughterSize * iv_actDaughterCnt); + + HDAT_EXIT(); +} + +/******************************************************************************/ +// addDaughterCard +/******************************************************************************/ +errlHndl_t HdatIoHubFru::addDaughterCard(uint32_t i_resourceId, + TARGETING::Target * i_target, + uint32_t i_index) +{ + HDAT_ENTER(); + + //eye catcher + const char HDAT_KID_STRUCT_NAME[] = "IO KID"; + errlHndl_t l_errlHndl = NULL; + HdatVpd *l_vpdObj, **l_arrayEntry; + uint32_t l_size; + uint32_t l_vpdType = 0x0; + uint32_t FRU_BP = 0x8; + + l_vpdObj = NULL; + l_vpdType = i_resourceId >> 8; + HDAT_DBG("vpd type= %x",l_vpdType); + + // Ensure we are not trying to add more daughter cards than what we were + // told to allow for on the constructor + if (iv_actDaughterCnt < iv_maxDaughters) + { + if ( l_vpdType == FRU_BP ) + { + + uint32_t i_num = sizeof(mvpdData)/sizeof(mvpdData[0]); + l_vpdObj = new HdatVpd(l_errlHndl, i_resourceId,i_target, + HDAT_KID_STRUCT_NAME,i_index,BP, + mvpdData,i_num,l_pvpdKeywords); + } + //@TODO: RTC 148660 pci slots and cards + + if (NULL == l_errlHndl) + { + l_arrayEntry = reinterpret_cast<HdatVpd **>(reinterpret_cast<char *> + (iv_daughterPtrs) + + iv_actDaughterCnt * sizeof(HdatVpd *)); + *l_arrayEntry = l_vpdObj; + + // Keep track of the largest daughter card object + l_size = l_vpdObj->size(); + if (l_size > iv_maxDaughterSize) + { + iv_maxDaughterSize = l_size; + } + iv_actDaughterCnt++; + } + else + { + HDAT_DBG("could not create HdatVpd obj," + " got error"); + delete l_vpdObj; + } + } + else + { + HDAT_DBG("exceeded limit of number of daughter card" + " array entries"); + } + + HDAT_EXIT(); + + return l_errlHndl; +} + + + +/******************************************************************************/ +// hdatLoadIoData +/******************************************************************************/ + +errlHndl_t hdatLoadIoData(const hdatMsAddr_t &i_msAddr, + uint32_t& o_size,uint32_t& o_count) +{ + HDAT_ENTER(); + + errlHndl_t l_err = NULL; + uint32_t l_size = 0; + uint64_t l_totKwdSize = 0; + IO_MAP l_iomap; + + o_size = 0; + o_count = 0; + + + do + { + //For all present procs in the system + TARGETING::PredicateCTM l_ctm1(TARGETING::CLASS_CHIP, + TARGETING::TYPE_PROC); + TARGETING::PredicateHwas l_predHwas; + l_predHwas.present(true); + TARGETING::PredicatePostfixExpr l_presentProc; + l_presentProc.push(&l_ctm1).push(&l_predHwas).And(); + TARGETING::TargetRangeFilter l_proc( + TARGETING::targetService().begin(), + TARGETING::targetService().end(), + &l_presentProc); + + uint32_t l_numProcs = 0; //number of io entries + for (;l_proc;++l_proc,l_numProcs++) //so index will be same as l_proc + { + HDAT_DBG("for loop starting for index=%d",l_numProcs); + + TARGETING::Target *l_pProcTarget = *(l_proc); + + + uint32_t l_rid = 0,l_slcaIdx = 0; + + l_rid = l_pProcTarget->getAttr<ATTR_SLCA_RID>(); + l_slcaIdx = l_pProcTarget->getAttr<ATTR_SLCA_INDEX>(); + + HDAT_DBG("got RID value as %d",l_rid); + + uint32_t l_procOrdId = + l_pProcTarget->getAttr<TARGETING::ATTR_ORDINAL_ID>(); + HDAT_DBG("got ordinal id as %d",l_procOrdId); + + + TARGETING::PredicateCTM l_pciPredicate(TARGETING::CLASS_UNIT, + TARGETING::TYPE_PCI); + TARGETING::TargetHandleList l_pciList; + + + //Add support for finding the card type + //All values except HDAT_PROC_CARD is reverved + hdatCardType l_cardType = HDAT_PROC_CARD; + + uint32_t l_procEcLevel = 0; + uint32_t l_procChipId = 0; + l_err = hdatGetIdEc(l_pProcTarget, + l_procEcLevel, + l_procChipId); + if(NULL != l_err) + { + HDAT_ERR("Error in getting proc IdEc"); + break; + } + TARGETING::ATTR_MRU_ID_type l_mruId = 0; + + l_mruId = l_pProcTarget->getAttr<TARGETING::ATTR_MRU_ID>(); + HDAT_DBG("got mru id as %d",l_mruId); + + if(NULL != l_err) + { + HDAT_ERR("Error in getting MRU ID"); + break; + } + + HdatIoHubFru * fruData = new HdatIoHubFru(l_err, + l_rid, + l_cardType, + 0, + l_numProcs, + l_slcaIdx); + + hdatHubEntry_t *l_hub; + + l_hub = reinterpret_cast<hdatHubEntry_t *>(reinterpret_cast<char *> + (fruData->iv_hubArray) + + fruData->iv_hubArrayHdr.hdatArrayCnt * sizeof(hdatHubEntry_t)); + + // Save information about the I/O chip + l_hub->hdatIoHubId = l_procOrdId; + + if(isFunctional(l_pProcTarget)) + { + l_hub->hdatFlags = HDAT_HUB_USABLE; + } + else + { + l_hub->hdatFlags = HDAT_HUB_NOT_USABLE; + } + if (fruData->iv_hubStatus != 0) + { + // Replace status bits in hdatFlags with iv_hdatStatus + l_hub->hdatFlags &= ~HDAT_HUB_STATUS_MASK; + l_hub->hdatFlags |= fruData->iv_hubStatus; + } + HDAT_DBG("hdatFlags 1: %X",l_hub->hdatFlags); + + TARGETING::ATTR_MODEL_type l_model = + (l_pProcTarget->getAttr<TARGETING::ATTR_MODEL>()); + + if(l_model == TARGETING::MODEL_MURANO) + { + l_hub->hdatChipId = HDAT_MODULE_TYPE_ID_MURANO; + } + else if(l_model == TARGETING::MODEL_VENICE) + { + l_hub->hdatChipId = HDAT_MODULE_TYPE_ID_VENICE; + } + else + { + HDAT_ERR("Chip is not in Murano,Venice"); + } + + l_hub->hdatEcLvl = l_procEcLevel; + l_hub->hdatProcChipID = l_procOrdId; + l_hub->hdatHardwareTopology = l_pProcTarget-> + getAttr<TARGETING::ATTR_PROC_HW_TOPOLOGY>(); + l_hub->hdatMRID = l_mruId; + + //memory map version + l_hub->hdatMemMapVersion = 2; + + l_hub->hdatFab0PresDetect = l_pProcTarget-> + getAttr<TARGETING::ATTR_PROC_PCIE_PHB_ACTIVE>(); + + + TARGETING::ATTR_PROC_PCIE_LANE_EQUALIZATION_type l_laneEq = {{0}}; + + if(!l_pProcTarget-> + tryGetAttr<TARGETING::ATTR_PROC_PCIE_LANE_EQUALIZATION>( + l_laneEq)) + { + HDAT_ERR("ATTR_PROC_PCIE_LANE_EQUALIZATION" + " not found"); + /*@ + * @errortype + * @moduleid HDAT::MOD_IOHUB_LOAD_DATA + * @reasoncode HDAT::RC_TGT_ATTR_NOTFOUND + * @devdesc Target attribute not found + * @custdesc Firmware encountered an internal error + */ + hdatBldErrLog(l_err, + MOD_IOHUB_LOAD_DATA, + RC_TGT_ATTR_NOTFOUND, + 0,0,0,0); + break; + } + + //copying data from l_laneEq(which is 4x32 bytes) to + //uint16_t hdatLaneEqPHB[64] + memcpy( l_hub->hdatLaneEqPHB, l_laneEq, + (NUM_BYTES_PER_LANE * HDAT_PHB_LANES)); + + //increment counts + fruData->iv_hubArrayHdr.hdatArrayCnt++; + + //build the daughter structure + l_err = fruData->bldDaughterStruct(l_pProcTarget,l_numProcs); + + + if ( l_err ) + { + HDAT_ERR("error in building daughter structure"); + break; + } + + HDAT_DBG("fruData.bldDaughterStruct done, will insert to the map"); + + //insert the fru data to the map + l_iomap.insert(std::pair<uint32_t,HdatIoHubFru*> + (l_numProcs,fruData)); + HDAT_DBG("done inserting into the map"); + + l_totKwdSize = fruData->getTotalIoKwdSize(); + HDAT_DBG("got l_totKwdSize=%x",l_totKwdSize); + + }//end for loop + + o_count = l_numProcs; + HDAT_DBG("setting count same to index=%d,o_count=%d", + l_numProcs,o_count); + + + //calculate the virtual address to start writing at main memory + //allocate space for iohub data + + uint64_t i_base_addr = ((uint64_t) i_msAddr.hi << 32) | i_msAddr.lo; + uint64_t l_childPtrSize = HDAT_CHILD_LAST * sizeof(hdatHDIFChildHdr_t); + uint32_t l_mod = l_childPtrSize % HDAT_MULTIPLE; + + if ( l_mod > 0 ) + { + l_childPtrSize += HDAT_MULTIPLE - l_mod; + } + uint64_t l_totalsize = (HDAT_MAX_IO_CHIPS * sizeof(hdatHubEntry_t)) + + (HDAT_PARENT_LAST * sizeof(hdatHDIFDataHdr_t))+ + l_childPtrSize; + + uint64_t i_base_addr_down = ALIGN_PAGE_DOWN(i_base_addr); + + //l_numProcs carries the number of proc + //allocate the memory + HDAT_DBG("allocating memory (l_totalsize * l_numProcs)+l_totKwdSize=%x", + ((l_totalsize * l_numProcs)+ l_totKwdSize)); + + void *l_virt_addr = mm_block_map ( + reinterpret_cast<void*>(i_base_addr_down), + ALIGN_PAGE((l_totalsize * l_numProcs)+ l_totKwdSize) + + PAGESIZE); + + uint64_t l_vaddr = reinterpret_cast<uint64_t>(l_virt_addr); + l_vaddr += i_base_addr-i_base_addr_down; + l_virt_addr = reinterpret_cast<void *>(l_vaddr); + + uint8_t* l_virtAddr = reinterpret_cast<uint8_t *>(l_virt_addr); + + HDAT_DBG("l_virtAddr =0x%016llX, l_virt_addr=0x%016llX", + (uint64_t)l_virtAddr,(uint64_t)l_virt_addr); + + //Iterate thru each FRU data and write to mainstore + + IO_MAP::iterator l_itr; + for(l_itr = l_iomap.begin(); l_itr != l_iomap.end(); ++l_itr) + { + HDAT_DBG("writing to main memory"); + uint8_t* l_startAddr = l_virtAddr; + + //write to main memory + l_virtAddr= l_itr->second->setIOHub(l_virtAddr,l_size); + + if ( l_size > o_size ) + { + o_size = l_size; + } + + //add the required padding after each io object + uint32_t l_rem = o_size % 128; + uint32_t l_pad = l_rem ? (128 - l_rem) : 0; + l_virtAddr = l_startAddr + l_pad + o_size; + HDAT_DBG("wrote pad of 0x%x size after io object",l_pad); + + }//done writing to memory + + + //unmap the region + int rc = 0; + rc = mm_block_unmap(reinterpret_cast<void*>(ALIGN_PAGE_DOWN( + reinterpret_cast<uint64_t>(l_virt_addr)))); + + if( rc != 0) + { + HDAT_ERR("unmap of iohub region failed"); + errlHndl_t l_errl = NULL; + /*@ + * @errortype + * @moduleid HDAT::MOD_IOHUB_LOAD_DATA + * @reasoncode HDAT::RC_DEV_MAP_FAIL + * @devdesc Unmap a mapped region failed + * @custdesc Firmware encountered an internal error + */ + hdatBldErrLog(l_errl, + MOD_IOHUB_LOAD_DATA, + RC_DEV_MAP_FAIL, + 0,0,0,0, + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + HDAT_VERSION1, + true); + } + + //erase the map + for (l_itr = l_iomap.begin(); l_itr != l_iomap.end();) + { + //need to delete the object first + delete(l_itr->second); + + l_iomap.erase(l_itr++); + }//end erasing + + }while(0); + + + HDAT_EXIT(); + return l_err; +} //end hdatLoadIoData +} diff --git a/src/usr/hdat/hdatiohub.H b/src/usr/hdat/hdatiohub.H new file mode 100755 index 000000000..8e58d823a --- /dev/null +++ b/src/usr/hdat/hdatiohub.H @@ -0,0 +1,500 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hdat/hdatiohub.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 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 HDATIOHUB_H +#define HDATIOHUB_H + +/** + * @file hdatiohubfru.H + * + * @brief This file contains the class definition for the I/O hub FRU object. + * + */ + + +/*---------------------------------------------------------------------------*/ +/* Includes */ +/*---------------------------------------------------------------------------*/ +#include <stdint.h> +#include <hdat/hdat.H> +#include "hdatutil.H" +#include <hdat/hdat_reasoncodes.H> +#include "hdathdif.H" +#include "hdatvpd.H" +#include <errl/errlentry.H> +#include <vector> +#include<map> + + +namespace HDAT +{ + +#define HDAT_PHB_LANES 64 +#define NUM_BYTES_PER_LANE 2 +#define NUM_LANES_PER_PHB 16 + +const uint16_t HDAT_VPD_VERSION = 0x0020; +const uint16_t HDAT_IO_VERSION = 0x6A; + +const uint32_t HDAT_MAX_IO_CHIPS = 10; + +/*---------------------------------------------------------------------------*/ +/* Type definitions */ +/*---------------------------------------------------------------------------*/ + +/** @brief Structure definition for the hub ID data section of the CEC HUB FRU + * hypervisor data area. + * Reserved bytes are added to make the structure a multiple of 4 bytes. + * Adjust the reserved size as necessary if new members are added to this + * structure. + */ +struct hdatHubId_t +{ + uint32_t hdatCardType; // 0x0000 FRU card type + uint32_t hdatReserved1; // 0x0004 Formerly Processor Module Id + uint16_t hdatReserved2; // 0x0008 Total number of chips on this FRU + // and daughter card + uint8_t hdatReserved3; // 0x000A Various flags + uint8_t hdatReserved4; // 0x000B padding for alignment + uint16_t hdatReserved5; // 0x000C Hub ID whose passthru port + // this FRU is connected to + uint16_t hdatReserved6; // 0x000E padding for alignment. + //Reuse if another field is added to this structure +} __attribute__ ((packed)); + + +/** @brief Structure definition for the hub array entry data section of the CEC + * HUB FRU hypervisor data area + */ +struct hdatHubEntry_t +{ + hdatMsAddr_t hdatReserved1; // 0x0000 TCE address for I/O hub + uint32_t hdatReserved2; // 0x0008 Size of I/O hub's TCE + uint16_t hdatIoHubId; // 0x000C I/O hub chip instance number + uint8_t hdatFlags; // 0x000E Chip status + uint8_t hdatReserved3; // 0x000F Reserved + uint8_t hdatFab0PresDetect; // 0x0010 I/O hub chip fabric 0 + // presence detect bits + uint8_t hdatReserved4; // 0x0011 Reserved + uint16_t hdatChipId; // 0x0012 Module type Identification + uint32_t hdatEcLvl; // 0x0014 EC level + uint32_t hdatReserved5; // 0x0018 Affinity domain 2 + uint32_t hdatReserved6; // 0x001C Affinity Domain 3 + uint32_t hdatReserved7; // 0x0020 Reserved + uint32_t hdatReserved8; // 0x0024 Reserved + uint32_t hdatProcChipID; // 0x0028 Proc Chip ID associated with + // this HUB + uint32_t hdatReserved9; // 0x002C Reserved + uint32_t hdatReserved10; // 0x0030 Reserved + uint16_t hdatReserved11; // 0x0032 Reserved + uint16_t hdatHardwareTopology;// 0x0034 Hardware Topology + uint32_t hdatMRID; // 0x0038 MRU ID of Chip + uint32_t hdatMemMapVersion; // 0x003C Memory Map Version + uint16_t hdatLaneEqPHB[HDAT_PHB_LANES]; // 0x0040 Lane Equalization values + //from PHB0 to PHB3 + + + + hdatHubEntry_t() : hdatProcChipID(0), hdatHardwareTopology(0), + hdatMRID(0xDEADBEEF), hdatMemMapVersion(0xDEADBEEF), hdatLaneEqPHB() + { + } +} __attribute__ ((packed)); + + + +/** @enum hdatDataPtrs + * Constants for the internal data pointers that are added to the base + * class + */ +enum hdatioDataPtrs +{ + HDAT_FRU_ID = 0, + HDAT_ASCII_KWD = 1, + HDAT_HUB_ID = 2, + HDAT_HUBS_ARRAY = 3, + HDAT_PARENT_RESERVED1 = 4, + HDAT_PARENT_RESERVED2 = 5, + HDAT_PARENT_LAST = 6 +}; + +/** @enum hdatChildPtrs + * Constants for the child structure pointers that are added to the base + * class + */ +enum hdatioChildPtrs +{ + HDAT_DAUGHTER_CARD = 0, + HDAT_CHILD_RESERVED1 = 1, + HDAT_CHILD_LAST = 2 +}; + + +/*---------------------------------------------------------------------------*/ +/* Constants */ +/*---------------------------------------------------------------------------*/ + +/** @enum hdatCardType + * Enumeration of FRU card types used in the CEC HUB FRU identification + * structure + */ +enum hdatCardType +{ + HDAT_IO_HUB_CARD = 1, + HDAT_PROC_CARD = 2, + HDAT_CEC_BACK_PLANE_CARD = 3, + HDAT_BACK_PLANE_EXT_CARD = 4 +}; + + +/** @enum hdatHubStatus + * Status of an I/O hub chip. + */ +enum hdatHubStatus +{ + HDAT_HUB_USABLE = 0x00, // Usable, no failures + HDAT_HUB_FAILURES = 0x40, // Usable, failures encountered + HDAT_HUB_NOT_INSTALLED = 0x80, // Not installed + HDAT_HUB_NOT_USABLE = 0xC0 // Unusable +}; + + +// Bit definitions of the hdatFlags field of hdatHubEntry_t +// that are not included in hdatHubStatus enum. +#define HDAT_HUB_IS_MASTER 0x20 // HUB is the master I/O HUB +#define HDAT_HUB_GARDMASK_VALID 0x08 // for setting gardmask valid +#define HDAT_HUB_SWITCH_MASK_VALID 0x04 // Switch Mask field is valid +#define HDAT_HUB_FABRIC_0_VALID 0x02 // Fabric Bridge 0 Presence Detect + //field is valid +#define HDAT_HUB_FABRIC_1_VALID 0x01 // Fabric Bridge 1 Presence Detect + // field is valid +#define HDAT_HUB_STATUS_MASK 0xC0 // for masking status bits during logical + // and/or ops + + +// Bit definitions of the hdatFab0PresDetect & hdatFab1PresDetect +// fields of hdatHubEntry_t +#define HDAT_HUB_FAB_BRIDGE_PHB0 0x80 // HUB Fabric Bridge PHB0 + //presence detect bit +#define HDAT_HUB_FAB_BRIDGE_PHB1 0x40 // HUB Fabric Bridge PHB1 + //presence detect bit +#define HDAT_HUB_FAB_BRIDGE_PHB2 0x20 // HUB Fabric Bridge PHB2 + //presence detect bit +#define HDAT_HUB_FAB_BRIDGE_PHB3 0x10 // HUB Fabric Bridge PHB3 + //presence detect bit + + +#define HDAT_MODULE_TYPE_ID_MURANO 0x0001 +#define HDAT_MODULE_TYPE_ID_VENICE 0x0010 + + + +/*---------------------------------------------------------------------------*/ +/* C++ class definition */ +/*---------------------------------------------------------------------------*/ + +/** Begin Class Description + * + * @brief The HdatIoHubFru class is used to construct I/O hub FRU objects. + * For P8, the CEC Hub FRU refers to the DCM. + * + * Description: This class defines a specialized object. It is not intended + * that any component can create an object of this type. + * In particular,the object is built only in the + * CEC Server process when requested + * by the hdat component. + * + * The real purpose of the object is to create the CEC Hub FRU + * array structure as defined by the PHYP Initialization + * architecture. This data structure is eventually DMA'd to + * main memory. The class is not defined to be a general purpose + * interface for building this object by anyone other than the + * CEC Server process. + * + * Thread safety: An HdatIoHubFru object is not thread safe. That is, a single + * object cannot be shared and used concurrently by multiple + * threads at the same time. In fact, an object interface is + * used only as a better way to built a flat structure to DMA + * to main memory. + * + * Signal handler usage: This class is not intended to be used in a + * signal handler and nothing has been done + * to try and make it safe to use + * in a signal handler. + * + * End Class Description + */ +class HdatIoHubFru : public HdatHdif +{ +public: + + + /** + * @brief Construct an HdatIoHubFru object. + * + * This is the constructor for the HdatIoHubFru object when that I/O HUB + * is not currently plugged but has been reserved for concurrent + * maintenance. + * + * If you are constructing this object on the heap by using new, then + * you must check the pointer returned from new to see if it is null. + * If it is null, new failed to allocate storage and the constructor + * was not called. If it is not null, then you must check o_errlHndl + * to see if the constructor ran successfully. If o_errlHndl indicates + * an error was reported by the constructor, new has already allocated + * heap storage and the object must be deleted in order to free the + * heap storage. + * + * @pre None + * + * @post An HdatIoHubFru object has been constructed. + * Heap storage has been allocated. + * + * @param o_errlHndl - output parameter - If any errors occur, + * the HdatIoHubFru object is NOT constructed + * and errors are returned in this parameter + * + * @param i_resourceId - input parameter RID value for the FRU + * @param i_cardType - input parameter - FRU card type + * @param i_daughterCnt - input parameter - The count of the number of + * daughter cards + * @param i_index - input parameter - instance of the object created + * @param i_slcaIdx - input parameter - SLCA index of the FRU + * + * @return A null error log handle if successful,else the return code pointed + * to by o_errlHndl contains one of: + * + * @retval HDAT_ALLOC_ERROR + */ + + HdatIoHubFru(errlHndl_t &o_errlHndl, + uint32_t i_resourceId, + hdatCardType i_cardType, + uint32_t i_daughterCnt, + uint32_t i_index, + uint32_t i_slcaIdx); + + + /** + * @brief HdatIoHubFru object destructor + * + * This is the destructor for an HdatIoHubFru object. Any heap storage + * allocated for the object is dallocated. + * + * @pre No preconditions exist + * + * @post The HdatIoHubFru object has been destroyed and can no longer be used. + * + */ + ~HdatIoHubFru(); + + + + /** + * @brief write the data to main memory + * + * @param io_virt_addr - input parameter inputs the address to be + * written at. outputs the next iohub address + * + * @param o_size - output parameter - size of iohub data + * + * @return A null error log handle if successful,else the return code pointed + * to by errlHndl_t contains one of the error + */ + uint8_t * setIOHub(uint8_t * io_virt_addr, + uint32_t& o_size); + + /** + * @brief Add a daughter card description. + * + * Each I/O daughter card which provides part of the I/O path must be added + * to the HdatIoHubFru object. This method adds information about the card + * + * @pre None + * + * @post A card's VPD definiton has been added to the object. Heap storage + * has been allocated. + * + * @param i_resourceId - input parameter - + * VPD resource id for the daughter card FRU + * @param i_target - input parameter - TARGET value of the FRU + * @param i_index - input parameter - instance number to be added + * + * @return A null error log handle if successful, else the return code pointed + * to by errlHndl_t contains one of: + * + * @retval HDAT_ALLOC_ERROR + * @retval HDAT_ARRAY_ERROR + */ + errlHndl_t addDaughterCard( uint32_t i_resourceId, + TARGETING::Target * i_target, uint32_t i_index); + + + /** + * @brief Build the hypervisor data area structres for I/O hub daughter cards. + * + * Each I/O daughter card which provides part of the I/O path must have + * a data structure built for it. + * + * IMPLEMENTATION NOTE. This is not a generalized method. For the + * Squadrons program, no I/O hubs required daughter card structures + * so there was no good way to test the implementation. When P5IOC2 + * with Host Ethernet Adapter support came along in eClipz, there was + * a need for daughter card structures. But no other I/O hub type + * had this requirement. So again, no easy way to test a generalized + * implementation. So to simplify the code, this routine is specific + * to P5IOC2. If some other I/O card comes along with a need for + * daughter card structures, this rotuine will likely require changes. + * + * + * @pre None + * + * @param i_target - input parameter - TARGET value of the daughter + * @param i_index - input parameter - instance number to be added + * + * @post A card's VPD definiton has been added to the object. Heap storage + * has been allocated. + * + * + * @return A null error log handle if successful, else the return code pointed + * to by errlHndl_t contains one of: + * + * @retval HDAT_ALLOC_ERROR + */ + errlHndl_t bldDaughterStruct( const TARGETING::Target * i_target, + uint32_t i_index ); + + + /* + * @brief fetches all the daughter card information for a proc when the + * TARGET is passed + * + * @pre None + * + * @param i_target - input parameter - TARGET value of the FRU + * @param o_targetList - output parameter - daughter TARGET list + * @param o_DaughterRids - output parameter - daughter card RID list + * + * @post o_DaughterRids is populated with the daughter RID data + * + * @return A null error log handle if successful, else the error + * handle + */ + + errlHndl_t hdatGetDaughterInfoFromTarget(const TARGETING::Target * i_target, + TARGETING::TargetHandleList& o_targetList, + std::vector <uint32_t>& o_DaughterRids); + + + + /* @brief function to get the total keyword size for + * all the iohub objects + * @pre None + * @return the size + */ + + uint64_t getTotalIoKwdSize(); + + + + + /* @brief construct the iohub data. This function will be called from + * the interface. The constructor of iohub will be called inside this + * function + * + * @pre None + * + * @param i_msAddr - input parameter - MS address where the io hub data need + * to be written at + * + * @param o_size - output parameter - size of the iohub data + * @param o_count - output parameter - number of iohub + * + * @post The iohub data along with daughter card information is constructed + * and written to memory + * + * @return A null error log handle if successful, else the error + * handle + * + */ + friend errlHndl_t hdatLoadIoData(const hdatMsAddr_t &i_msAddr, + uint32_t &o_size, + uint32_t &o_count); + + + + private: + /** Object Instance Data + * + * @li iv_msAddr - main memory address the final data structure is + * DMA'd to + * @li iv_hubStatus - operational status of the IO Hub + * @li iv_kwdSize - size of the VPD ASCII keyword + * @li iv_maxHubs - maximum number of hub chips that can be added + * with addIoChip() + * @li iv_maxDaughters - maximum number of daughter cards that can be + * added with + * addDaughterCard() + * @li iv_hubArraySize - total size of the I/O hub array. + * @li iv_actDaughterCnt - number of daughter cards added to this object + * @li iv_maxDaughterSize - maximum size of a daughter card + * @li iv_kwd - ptr to the VPD ASCII keyword + * @li iv_fru - I/O hub FRU structure + * @li iv_hubId - hub FRU ID structure + * @li iv_hubArrayHdr - data header for the I/O hub array + * @li iv_hubArray - ptr to storage which holds the I/O hub array + * entries + * @li iv_daughterPtrs - ptr to one or more ptrs which in turn point to + * HdatVpd objects + */ + hdatMsAddr_t iv_msAddr; + uint8_t iv_hubStatus; + uint32_t iv_kwdSize; + uint32_t iv_maxHubs; + uint32_t iv_maxDaughters; + uint32_t iv_hubArraySize; + uint32_t iv_actDaughterCnt; + uint32_t iv_maxDaughterSize; + char *iv_kwd; + hdatFruId_t iv_fru; + hdatHubId_t iv_hubId; + hdatHDIFDataArray_t iv_hubArrayHdr; + hdatHubEntry_t *iv_hubArray; + HdatVpd **iv_daughterPtrs; + +}; // end of HdatIoHubFru class + + + +/* @brief + * map to store the pointers of iohub objects to write them to + * memory later + */ + + +typedef std::map<uint32_t,HdatIoHubFru*> IO_MAP; + +} //namespace HDAT + +#endif // HDATIOHUB_H diff --git a/src/usr/hdat/hdatiplparms.C b/src/usr/hdat/hdatiplparms.C new file mode 100755 index 000000000..01cffb564 --- /dev/null +++ b/src/usr/hdat/hdatiplparms.C @@ -0,0 +1,1148 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hdat/hdatiplparms.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 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 hdatiplparms.C + * + * @brief This file contains the implementation of the HdatIplParms class. + * + */ + +/*------------------------------------------------------------------------*/ +/* Includes */ +/*------------------------------------------------------------------------*/ +#include <ctype.h> // endian testing +#include "hdatiplparms.H" // HdatIplParms class definition +#include <attributeenums.H> +#include "hdatutil.H" +#include <sys/mm.h> +#include <sys/mmio.h> +#include <vpd/mvpdenums.H> +#include <pnor/pnorif.H> +#include <util/align.H> + +#include <devicefw/userif.H> +#include <targeting/common/util.H> + +using namespace TARGETING; + +namespace HDAT +{ + +extern trace_desc_t *g_trac_hdat; + + +/*------------------------------------------------------------------------*/ +/* Constants */ +/*------------------------------------------------------------------------*/ + +/** + * @brief This routine checks if a certain manufacturing flag is set + * + * @pre None + * + * @post None + * + * @param i_flag - input parameter - Specific mnfg flag to check + * + * @return true : The specified mnfg flag is set + * false : The specified mnfg flag is not set + * + * @retval HDAT_OTHER_COMP_ERROR + */ +static bool isMnfgFlagSet( uint32_t i_flag ) +{ + bool o_rc = false; + TARGETING::ATTR_MNFG_FLAGS_type l_attrValue = 0; + TARGETING::TargetHandle_t l_pTopTarget= NULL; + targetService().getTopLevelTarget(l_pTopTarget); + + if(l_pTopTarget) + { + l_attrValue = l_pTopTarget->getAttr<ATTR_MNFG_FLAGS>(); + o_rc = l_attrValue & i_flag; + } + else + { + HDAT_ERR("[isMnfgFlagSet] error finding l_pTopTarget"); + } + + return o_rc; +} + + +/** + * @brief This routine gets number of cores in each processor + * + * @pre None + * + * @post None + * + * @param o_numCores - output parameter - Number of cores + * + * @return None + * + * @retval HDAT_OTHER_COMP_ERROR + */ +static void hdatGetNumberOfCores(uint32_t &o_numCores) +{ + uint8_t l_prData[9]; + size_t l_prDataSz = 8; + errlHndl_t l_err = NULL; + + o_numCores = 0; + + + TARGETING::PredicateCTM l_procChipPredicate(TARGETING::CLASS_CHIP, + TARGETING::TYPE_PROC); + + TARGETING::PredicateHwas l_predHwas; + l_predHwas.present(true); + + TARGETING::PredicatePostfixExpr l_presentProc; + l_presentProc.push(&l_procChipPredicate).push(&l_predHwas).And(); + + TARGETING::TargetRangeFilter l_procFilter( + TARGETING::targetService().begin(), + TARGETING::targetService().end(), + &l_presentProc); + + TARGETING::Target *l_procTarget = (*l_procFilter); + + l_err = deviceRead(l_procTarget,l_prData,l_prDataSz, + DEVICE_MVPD_ADDRESS(MVPD::VINI,MVPD::PR)); + + if(l_err) + { + HDAT_ERR("Error during VPD PR keyword read"); + } + else + { + o_numCores = l_prData[2] >> 4; + HDAT_DBG("Number of Cores: %d",o_numCores); + } +} + +/** + * @brief This routine gets the information for Enlarged IO Slot Count + * + * @pre None + * + * @post None + * + * @param o_EnlargedSlotCount - output parameter - Enlarged IO Slot Count for + * all nodes + * + * @return None + * + * @retval HDAT_OTHER_COMP_ERROR + */ +static void hdatGetEnlargedIOCapacity(uint32_t &o_EnlargedSlotCount) +{ + TARGETING::PredicateCTM l_nodePredicate(TARGETING::CLASS_ENC, + TARGETING::TYPE_NODE); + TARGETING::PredicateHwas l_predHwas; + l_predHwas.present(true); + + TARGETING::PredicatePostfixExpr l_presentNode; + l_presentNode.push(&l_nodePredicate).push(&l_predHwas).And(); + + TARGETING::TargetRangeFilter l_nodeFilter( + TARGETING::targetService().begin(), + TARGETING::targetService().end(), + &l_presentNode); + + o_EnlargedSlotCount = 0; + uint8_t l_nodeindex = 3; + + for (;l_nodeFilter;++l_nodeFilter) + { + TARGETING::Target *l_nodeTarget = (*l_nodeFilter); + + TARGETING::ATTR_ENLARGED_IO_SLOT_COUNT_type l_enlargedIOSlotCount; + if(l_nodeTarget->tryGetAttr<TARGETING::ATTR_ENLARGED_IO_SLOT_COUNT> + (l_enlargedIOSlotCount)) + { + o_EnlargedSlotCount |= (uint32_t)l_enlargedIOSlotCount << + (8 * l_nodeindex); + } + else + { + HDAT_ERR("Error in getting ENLARGED_IO_SLOT_COUNT attribute"); + } + l_nodeindex--; + } +} + +/** + * @brief This routine gets the information for IPL Parameters + * + * @pre None + * + * @post None + * + * @param o_hdatOTA - output parameter - The structure to update with the + * other IPL attributes + * + * @return None + * + * @retval HDAT_OTHER_COMP_ERROR + */ +static void hdatPopulateOtherIPLAttributes(hdatOtherIPLAttributes_t &o_hdatOTA) +{ + TARGETING::Target *l_pSysTarget = NULL; + (void) TARGETING::targetService().getTopLevelTarget(l_pSysTarget); + + if(l_pSysTarget == NULL) + { + HDAT_ERR("Error in getting Top Level Target"); + assert(l_pSysTarget != NULL); + } + + TARGETING::ATTR_IPL_ATTRIBUTES_type l_iplAttributes; + l_iplAttributes = l_pSysTarget->getAttr<TARGETING::ATTR_IPL_ATTRIBUTES>(); + + o_hdatOTA.hdatCreDefPartition = l_iplAttributes.createDefaultPartition; + + o_hdatOTA.hdatCTAState = l_iplAttributes.clickToAcceptState; + + o_hdatOTA.hdatDisVirtIOConn = l_iplAttributes.disableVirtIO; + + o_hdatOTA.hdatResetPCINOs = l_iplAttributes.resetPCINumbers; + + o_hdatOTA.hdatClrPhypNvram = l_iplAttributes.clearHypNVRAM; + + TARGETING::ATTR_PRESERVE_MDC_PARTITION_VPD_type l_preserveMDCPartitionVPD; + if(l_pSysTarget->tryGetAttr<TARGETING::ATTR_PRESERVE_MDC_PARTITION_VPD> + (l_preserveMDCPartitionVPD)) + { + o_hdatOTA.hdatMDCLogPartVPD = l_preserveMDCPartitionVPD; + } + else + { + HDAT_ERR("Error in getting PRESERVE_MDC_PARTITION_VPD attribute"); + } + + //No CEC CM Capability on these systems + o_hdatOTA.hdatCECCMCapable = 0; + + //i5/OS not available on this system + o_hdatOTA.hdati5OSEnable = 0; + + o_hdatOTA.hdatSELFlagsValid = 1; + + o_hdatOTA.hdatDelSELFromHyp = 1; + + o_hdatOTA.hdatDelSELFromHB = 1; + + o_hdatOTA.hdatDelSELFromBMC = 1; + + //Lightpath support available on these systems + o_hdatOTA.hdatServiceIndMode = 1; + + //RPA AIX/Linux + o_hdatOTA.hdatDefPartitionType = 1; + +} + +/** + * @brief This routine gets the information for IPL Parameters + * + * @pre None + * + * @post None + * + * @param None + * + * @return None + * + * @retval HDAT_OTHER_COMP_ERROR + */ +void HdatIplParms::hdatGetIplParmsData() +{ + PNOR::SideInfo_t l_sideInfo; + errlHndl_t l_errl = NULL; + + TARGETING::Target *l_pSysTarget = NULL; + (void) TARGETING::targetService().getTopLevelTarget(l_pSysTarget); + if(l_pSysTarget == NULL) + { + HDAT_ERR("Error in getting Top Level Target"); + assert(l_pSysTarget != NULL); + } + + //IPL to hypervisor running + this->iv_hdatIPLParams->iv_iplParms.hdatIPLDestination = 0x02; + + l_errl = PNOR::getSideInfo(PNOR::WORKING, l_sideInfo); + if(!l_errl) + { + if(l_sideInfo.isGolden) + { + this->iv_hdatIPLParams->iv_iplParms.hdatIPLSide = + HDAT_FIRMWARE_SIDE_GOLDEN; + } + else + { + this->iv_hdatIPLParams->iv_iplParms.hdatIPLSide = + HDAT_FIRMWARE_SIDE_WORKING; + } + } + else + { + ERRORLOG::errlCommit(l_errl,HDAT_COMP_ID); + } + // Fast IPL Speed + this->iv_hdatIPLParams->iv_iplParms.hdatIPLSpeed = 0xFF; + + + TARGETING::ATTR_IS_MPIPL_HB_type l_mpiplHB; + if(l_pSysTarget->tryGetAttr<TARGETING::ATTR_IS_MPIPL_HB>(l_mpiplHB)) + { + if(l_mpiplHB) + { + this->iv_hdatIPLParams->iv_iplParms.hdatCECIPLAttributes = 0x2000; + this->iv_hdatIPLParams->iv_iplParms.hdatIPLMajorType = 0x01; + this->iv_hdatIPLParams->iv_iplParms.hdatIPLMinorType = 0x0D; + } + else + { + this->iv_hdatIPLParams->iv_iplParms.hdatCECIPLAttributes = 0x1000; + + this->iv_hdatIPLParams->iv_iplParms.hdatIPLMajorType = 0x00; + + TARGETING::ATTR_CEC_IPL_TYPE_type l_cecIPLType; + if(l_pSysTarget->tryGetAttr<TARGETING::ATTR_CEC_IPL_TYPE> + (l_cecIPLType)) + { + this->iv_hdatIPLParams->iv_iplParms.hdatIPLMinorType = + l_cecIPLType.MinorIPLType; + this->iv_hdatIPLParams->iv_iplParms.hdatIPLMinorType = 0xC; + HDAT_DBG("hdatGetIplParmsData: setting hdatIPLMinorType to 0xC0"); + } + else + { + HDAT_ERR("Error in getting CEC_IPL_TYPE attribute"); + } + } + } + else + { + this->iv_hdatIPLParams->iv_iplParms.hdatIPLMinorType = 0x0C; + HDAT_DBG("hdatGetIplParmsData: setting hdatIPLMinorType to 0xC0"); + HDAT_ERR("Error in getting IS_MPIPL_HB attribute"); + } + + TARGETING::ATTR_OS_IPL_MODE_type l_OSIPLMode; + if(l_pSysTarget->tryGetAttr<TARGETING::ATTR_OS_IPL_MODE>(l_OSIPLMode)) + { + this->iv_hdatIPLParams->iv_iplParms.hdatOSIPLMode = l_OSIPLMode; + } + else + { + HDAT_ERR("Error in getting OS_IPL_MODE attribute"); + } + + this->iv_hdatIPLParams->iv_iplParms.hdatKeyLockPosition = + HDAT_KEYLOCK_MANUAL; + + TARGETING::ATTR_LMB_SIZE_type l_lmbSize; + if(l_pSysTarget->tryGetAttr<TARGETING::ATTR_LMB_SIZE>(l_lmbSize)) + { + this->iv_hdatIPLParams->iv_iplParms.hdatLMBSize = 4; + } + else + { + HDAT_ERR("Error in getting LMB_SIZE attribute"); + } + + TARGETING::ATTR_MAX_HSL_OPTICONNECT_CONNECTIONS_type l_hslConnections; + if(l_pSysTarget->tryGetAttr + <TARGETING::ATTR_MAX_HSL_OPTICONNECT_CONNECTIONS> + (l_hslConnections)) + { + this->iv_hdatIPLParams->iv_iplParms.hdatMaxHSLConns = l_hslConnections; + } + else + { + HDAT_ERR("Error in getting MAX_HSL_OPTICONNECT_CONNECTIONS attribute"); + } + + hdatPopulateOtherIPLAttributes(this->iv_hdatIPLParams->iv_iplParms.hdatOIA); + + TARGETING::ATTR_HUGE_PAGE_COUNT_type l_hugePageCount; + if(l_pSysTarget->tryGetAttr<TARGETING::ATTR_HUGE_PAGE_COUNT> + (l_hugePageCount)) + { + this->iv_hdatIPLParams->iv_iplParms.hdatHugePageMemCount = + l_hugePageCount; + } + else + { + HDAT_ERR("Error in getting HUGE_PAGE_COUNT attribute"); + } + + TARGETING::ATTR_HUGE_PAGE_SIZE_type l_hugePageSize; + if(l_pSysTarget->tryGetAttr<TARGETING::ATTR_HUGE_PAGE_SIZE> + (l_hugePageSize)) + { + this->iv_hdatIPLParams->iv_iplParms.hdatHugePageMemSize = + l_hugePageSize; + } + else + { + HDAT_ERR("Error in getting HUGE_PAGE_SIZE attribute"); + } + + TARGETING::ATTR_VLAN_SWITCHES_type l_vlanSwitches; + if(l_pSysTarget->tryGetAttr<TARGETING::ATTR_VLAN_SWITCHES> + (l_vlanSwitches)) + { + this->iv_hdatIPLParams->iv_iplParms.hdatNumVlanSwitches = + l_vlanSwitches; + } + else + { + HDAT_ERR("Error in getting VLAN_SWITCHES attribute"); + } + + uint32_t hdatEnlargedIOCapacity = 0; + hdatGetEnlargedIOCapacity(hdatEnlargedIOCapacity); + this->iv_hdatIPLParams->iv_iplParms.hdatEnlargedIOCap = + hdatEnlargedIOCapacity; + +} + +/** + * @brief This routine gets the information for SP serial ports + * + * @pre None + * + * @post None + * + * @param o_portArrayHdr - output parameter - Array header + * @param o_ports - output parameter - The structure to update with the + * serial port information + * + * @return A null error log handle if successful, else the return code pointed + * to by errlHndl_t contains one of: + * + * @retval HDAT_OTHER_COMP_ERROR + */ +static errlHndl_t hdatGetPortInfo(HDAT::hdatHDIFDataArray_t &o_portArrayHdr, + hdatPortCodes_t o_ports[]) +{ + errlHndl_t l_errlHndl = NULL; + uint32_t l_loopCnt = 0; + + o_portArrayHdr.hdatOffset = sizeof(HDAT::hdatHDIFDataArray_t); + o_portArrayHdr.hdatAllocSize = sizeof(hdatPortCodes_t); + o_portArrayHdr.hdatActSize = sizeof(o_ports); + o_portArrayHdr.hdatArrayCnt = 0; + + TARGETING::PredicateCTM l_nodePredicate(TARGETING::CLASS_ENC, + TARGETING::TYPE_NODE); + + TARGETING::PredicateHwas l_predHwas; + l_predHwas.present(true); + + TARGETING::PredicatePostfixExpr l_presentNode; + l_presentNode.push(&l_nodePredicate).push(&l_predHwas).And(); + + //Get Node targets + TARGETING::TargetRangeFilter l_nodeFilter( + TARGETING::targetService().begin(), + TARGETING::targetService().end(), + &l_presentNode); + + TARGETING::Target *l_nodeTarget = (*l_nodeFilter); + + TARGETING::PredicateCTM l_serialPortPredicate(TARGETING::CLASS_UNIT, + TARGETING::TYPE_UART); + + TARGETING::PredicatePostfixExpr l_presentSerialPort; + l_presentSerialPort.push(&l_serialPortPredicate).push(&l_predHwas).And(); + + TARGETING::TargetHandleList l_serialPortList; + + //Get Serial Port targets associated with service processor + TARGETING::targetService().getAssociated(l_serialPortList, l_nodeTarget, + TARGETING::TargetService::CHILD, + TARGETING::TargetService::ALL, + &l_presentSerialPort); + + o_portArrayHdr.hdatArrayCnt = l_serialPortList.size(); + + for (uint32_t l_idx = 0; l_idx < l_serialPortList.size(); ++l_idx) + { + TARGETING::Target *l_serialportTarget = l_serialPortList[l_idx]; + char l_locCodePrefix[64]={0}; + char l_locCode[64]={0}; + + hdatGetLocationCodePrefix(l_locCodePrefix); + hdatGetLocationCode(l_serialportTarget,l_locCodePrefix,l_locCode); + HDAT_DBG(" Serial Port Loc Code :%s", l_locCode); + + strncpy((char *)(o_ports[l_loopCnt].hdatLocCode), + l_locCode, + sizeof(o_ports[l_loopCnt].hdatLocCode)); + + o_ports[l_loopCnt].hdatResourceId = l_serialportTarget->getAttr + <TARGETING::ATTR_SLCA_RID>(); + + // None of the ports are used for callhome + o_ports[l_loopCnt].hdatCallHome = 0; + l_loopCnt++; + } + + return l_errlHndl; +} + + +/** + * @brief This routine gets the information for System Parameters + * + * @pre None + * + * @post None + * + * @param None + * + * @return None + * + * @retval HDAT_OTHER_COMP_ERROR + **/ +void HdatIplParms::hdatGetSystemParamters() +{ + + TARGETING::Target *l_pSysTarget = NULL; + (void) TARGETING::targetService().getTopLevelTarget(l_pSysTarget); + + if(l_pSysTarget == NULL) + { + HDAT_ERR("hdatGetSystemParamters::Top Level Target not found"); + assert(l_pSysTarget != NULL); + } + + // Get system information - system model + uint32_t l_sysModel = 0; + + TARGETING::ATTR_RAW_MTM_type l_rawMTM = {0}; + if(l_pSysTarget->tryGetAttr<TARGETING::ATTR_RAW_MTM>(l_rawMTM)) + { + //we only want the last three bytes of the raw MTM, preceded by a 0x20 + l_sysModel = *((reinterpret_cast<uint32_t*>(l_rawMTM))+1); + l_sysModel &= 0x00FFFFFF; + l_sysModel |= 0x20000000; + this->iv_hdatIPLParams->iv_sysParms.hdatSysModel = l_sysModel; + } + else + { + HDAT_ERR("Error in getting RAW_MTM attribute"); + } + + // Get system information - processor feature code + // Processor Feature Code = CCIN of Anchor Card + // No Anchor Card in BMC systems + this->iv_hdatIPLParams->iv_sysParms.hdatProcFeatCode = 0; + + // Get system information - effective PVR + TARGETING::ATTR_EFFECTIVE_EC_type l_effectiveEc; + if(l_pSysTarget->tryGetAttr<TARGETING::ATTR_EFFECTIVE_EC>(l_effectiveEc)) + { + //Convert Ec format to PVR Ec format + uint32_t l_pvrEc = ( ((l_effectiveEc & 0xF0) << 4) | + (l_effectiveEc & 0xF) ); + + TARGETING::PredicateCTM l_procFilter(TARGETING::CLASS_CHIP, + TARGETING::TYPE_PROC); + + TARGETING::PredicateHwas l_predHwas; + l_predHwas.present(true); + + TARGETING::PredicatePostfixExpr l_presentProc; + l_presentProc.push(&l_procFilter).push(&l_predHwas).And(); + + TARGETING::TargetHandleList l_procList; + + //Get all Procs in the system + TARGETING::targetService(). + getAssociated(l_procList, l_pSysTarget, + TARGETING::TargetService::CHILD, + TARGETING::TargetService::ALL, &l_presentProc); + + if(l_procList.size() > 0) + { + TARGETING::Target *l_procTarget = l_procList[0]; + ATTR_MODEL_type l_procModel; + + if(l_procTarget->tryGetAttr<ATTR_MODEL>(l_procModel)) + { + //Effective Processor Version Register (PVR) + // bits 0-15: Processor version number + // bits 16-19: Reserved + // bits 20-23: Full RIT + // bits 24-27: Reserved + // bits 28-31: Minor revision level + + if(l_procModel == MODEL_MURANO) + { + this->iv_hdatIPLParams->iv_sysParms.hdatEffectivePvr = + 0x004B0000 | l_pvrEc; + } + else if(l_procModel == MODEL_VENICE) + { + this->iv_hdatIPLParams->iv_sysParms.hdatEffectivePvr = + 0x004D0200 ; + } + HDAT_DBG(" Effective PVR :0X%x", + this->iv_hdatIPLParams->iv_sysParms.hdatEffectivePvr); + } + else + { + HDAT_ERR("Error reading attribute ATTR_MODEL"); + } + } + else + { + HDAT_ERR("No Processors found in the system"); + assert(l_procList.size() > 0); + } + } + else + { + HDAT_ERR(" Error in getting attribute EFFECTIVE_EC"); + } + + // Get system type + iv_hdatIPLParams->iv_sysParms.hdatSysType = + (l_pSysTarget->getAttr<TARGETING::ATTR_PHYP_SYSTEM_TYPE>()); + + //Get ABC Bus Speed + TARGETING::ATTR_FREQ_A_MHZ_type l_ABCBusSpeed; + if(l_pSysTarget->tryGetAttr<TARGETING::ATTR_FREQ_A_MHZ>(l_ABCBusSpeed)) + { + this->iv_hdatIPLParams->iv_sysParms.hdatABCBusSpeed = l_ABCBusSpeed; + } + else + { + HDAT_ERR(" Error in getting attribute FREQ_A_MHZ"); + } + + //Get XYZ Bus Speed + TARGETING::ATTR_FREQ_X_MHZ_type l_WXYZBusSpeed; + if(l_pSysTarget->tryGetAttr<TARGETING::ATTR_FREQ_X_MHZ>(l_WXYZBusSpeed)) + { + this->iv_hdatIPLParams->iv_sysParms.hdatWXYZBusSpeed = l_WXYZBusSpeed; + } + else + { + HDAT_ERR(" Error in getting attribute FREQ_X_MHZ"); + } + + // NO ECO Support + this->iv_hdatIPLParams->iv_sysParms.hdatSystemECOMode = 0; + + this->iv_hdatIPLParams->iv_sysParms.hdatSystemAttributes = 0; + + //Populate SMM Enabled/Disabled attribute + TARGETING::ATTR_PAYLOAD_IN_MIRROR_MEM_type l_payLoadMirrorMem; + if(l_pSysTarget->tryGetAttr<TARGETING::ATTR_PAYLOAD_IN_MIRROR_MEM> + (l_payLoadMirrorMem)) + { + this->iv_hdatIPLParams->iv_sysParms.hdatSystemAttributes |= + ( static_cast<uint8_t>(l_payLoadMirrorMem) ? HDAT_SMM_ENABLED : 0); + } + else + { + HDAT_ERR(" Error in getting attribute PAYLOAD_IN_MIRROR_MEM"); + } + + this->iv_hdatIPLParams->iv_sysParms.hdatMemoryScrubbing = 0; + + // Get SPPL information + uint32_t l_numCores; + + TARGETING::ATTR_OPEN_POWER_TURBO_MODE_SUPPORTED_type l_turboModeSupported; + if(l_pSysTarget->tryGetAttr + <TARGETING::ATTR_OPEN_POWER_TURBO_MODE_SUPPORTED> + (l_turboModeSupported)) + { + HDAT::hdatGetNumberOfCores(l_numCores); + + if(l_turboModeSupported == true) + { + this->iv_hdatIPLParams->iv_sysParms.hdatCurrentSPPLValue = + HDAT_TURBO_CORE_MODE_PART_SIZE_128; + } + else if( l_numCores == 6 ) + { + this->iv_hdatIPLParams->iv_sysParms.hdatCurrentSPPLValue = + HDAT_NONTURBO_SIX_CORE_PART_SIZE_256; + } + else if( l_numCores == 8 ) + { + this->iv_hdatIPLParams->iv_sysParms.hdatCurrentSPPLValue = + HDAT_NONTURBO_EIGHT_CORE_PART_SIZE_256; + } + } + else + { + HDAT_ERR("Error in getting OPEN_POWER_TURBO_MODE_SUPPORTED attribute"); + } + + this->iv_hdatIPLParams->iv_sysParms.usePoreSleep = 0x01; + + TARGETING::ATTR_VTPM_ENABLED_type l_vTpmEnabled; + if(l_pSysTarget->tryGetAttr<TARGETING::ATTR_VTPM_ENABLED> + (l_vTpmEnabled)) + { + this->iv_hdatIPLParams->iv_sysParms.vTpmEnabled = l_vTpmEnabled; + } + else + { + HDAT_ERR("Error in getting VTPM_ENABLED attribute"); + } + + //HW Page Table Size : 0x07 : 1/128 + this->iv_hdatIPLParams->iv_sysParms.hdatHwPageTbl = 0x07; + + TARGETING::ATTR_HYP_DISPATCH_WHEEL_type l_hyperDispatchWheel; + if(l_pSysTarget->tryGetAttr<TARGETING::ATTR_HYP_DISPATCH_WHEEL> + (l_hyperDispatchWheel)) + { + if(!l_hyperDispatchWheel) + { + l_hyperDispatchWheel = 0x0a; + } + this->iv_hdatIPLParams->iv_sysParms.hdatDispWheel = + l_hyperDispatchWheel; + } + else + { + HDAT_ERR("Error in getting HYP_DISPATCH_WHEEL attribute"); + } + + TARGETING::ATTR_FREQ_PB_MHZ_type l_nestClockFreq; + if(l_pSysTarget->tryGetAttr<TARGETING::ATTR_FREQ_PB_MHZ> + (l_nestClockFreq)) + { + this->iv_hdatIPLParams->iv_sysParms.hdatNestFreq = + static_cast<uint32_t>(l_nestClockFreq); + } + else + { + HDAT_ERR("Error in getting FREQ_PB_MHZ"); + } + + this->iv_hdatIPLParams->iv_sysParms.hdatSplitCoreMode = 1; + + TARGETING::ATTR_SYSTEM_BRAND_NAME_type l_systemBrandName = {0}; + if(l_pSysTarget->tryGetAttr<TARGETING::ATTR_SYSTEM_BRAND_NAME> + (l_systemBrandName)) + { + strcpy(reinterpret_cast<char*> + (this->iv_hdatIPLParams->iv_sysParms.hdatSystemVendorName), + l_systemBrandName); + } + else + { + HDAT_ERR("Error in getting SYSTEM_BRAND_NAME"); + } +} + +/** + * @brief This routine gets the IPL Time Delta Structure + * + * @pre None + * + * @post None + * + * @param o_iplTime - output parameter - IPLTime Data + * + * @return None + * + * @retval HDAT_OTHER_COMP_ERROR + */ +void hdatGetIPLTimeData(hdatIplTimeData_t & o_iplTime) +{ + //RTC and Delta values marked as invalid + o_iplTime.hdatRTCValidFlags = 0; + + //Cumulative RTC Delta value is reset + o_iplTime.hdatCumulativeRTCDelta = 0; +} + + +/** + * @brief This routine gets the Manufacturing Flags + * + * @pre None + * + * @post None + * + * @param o_hdatManfFlags - output parameter - Manufacturing Flags + * + * @return None + * + * @retval HDAT_OTHER_COMP_ERROR + */ +void hdatGetMnfgFlags(hdatManf_t &o_hdatManfFlags) +{ + o_hdatManfFlags.hdatPolicyFlags[0] = HDAT_MFG_FLAGS_CELL_0; + o_hdatManfFlags.hdatPolicyFlags[1] = HDAT_MFG_FLAGS_CELL_1; + o_hdatManfFlags.hdatPolicyFlags[2] = HDAT_MFG_FLAGS_CELL_2; + o_hdatManfFlags.hdatPolicyFlags[3] = HDAT_MFG_FLAGS_CELL_3; + + if(HDAT::isMnfgFlagSet(TARGETING::MNFG_FLAG_AVP_ENABLE)) + o_hdatManfFlags.hdatPolicyFlags[1] |= HDAT_MFG_FLAG_AVP_ENABLED; + + if(HDAT::isMnfgFlagSet(TARGETING::MNFG_FLAG_HDAT_AVP_ENABLE)) + o_hdatManfFlags.hdatPolicyFlags[2] |= HDAT_MFG_FLAG_HDAT_AVP_ENABLED; + + if(HDAT::isMnfgFlagSet(TARGETING::MNFG_FLAG_SRC_TERM)) + o_hdatManfFlags.hdatPolicyFlags[0] |= HDAT_MNFG_FLAG_SRC_TERM; + + if(HDAT::isMnfgFlagSet(TARGETING::MNFG_FLAG_IPL_MEMORY_CE_CHECKING)) + o_hdatManfFlags.hdatPolicyFlags[2] |= + HDAT_MNFG_IPL_MEM_CE_CHECKING_ACTIVE; + + if(HDAT::isMnfgFlagSet(TARGETING::MNFG_FLAG_FAST_BACKGROUND_SCRUB)) + o_hdatManfFlags.hdatPolicyFlags[1] |= HDAT_MNFG_FAST_BKG_SCRUB_ACTIVE; + + if(isMnfgFlagSet(TARGETING::MNFG_FLAG_TEST_DRAM_REPAIRS)) + o_hdatManfFlags.hdatPolicyFlags[0] |= HDAT_MNFG_TEST_DRAM_REPAIRS; + + if(isMnfgFlagSet(TARGETING::MNFG_FLAG_DISABLE_DRAM_REPAIRS)) + o_hdatManfFlags.hdatPolicyFlags[0] |= HDAT_MNFG_DISABLE_DRAM_REPAIRS; + + if(isMnfgFlagSet(TARGETING::MNFG_FLAG_ENABLE_EXHAUSTIVE_PATTERN_TEST)) + o_hdatManfFlags.hdatPolicyFlags[2] |= + HDAT_MNFG_ENABLE_EXHAUSTIVE_PATTERN_TEST; + + if(isMnfgFlagSet(TARGETING::MNFG_FLAG_ENABLE_STANDARD_PATTERN_TEST)) + o_hdatManfFlags.hdatPolicyFlags[2] |= + HDAT_MNFG_ENABLE_STANDARD_PATTERN_TEST; + + if(isMnfgFlagSet(TARGETING::MNFG_FLAG_ENABLE_MINIMUM_PATTERN_TEST)) + o_hdatManfFlags.hdatPolicyFlags[2] |= HDAT_MNFG_ENABLE_MIN_PATTERN_TEST; + + if(isMnfgFlagSet(TARGETING::MNFG_FLAG_DISABLE_FABRIC_eREPAIR)) + o_hdatManfFlags.hdatPolicyFlags[1] |= HDAT_MNFG_DISABLE_FABRIC_ERPAIR; + + if(isMnfgFlagSet(TARGETING::MNFG_FLAG_DISABLE_MEMORY_eREPAIR)) + o_hdatManfFlags.hdatPolicyFlags[1] |= HDAT_MNFG_DISABLE_MEMORY_ERPAIR; + + if(isMnfgFlagSet(TARGETING::MNFG_FLAG_FABRIC_DEPLOY_LANE_SPARES)) + o_hdatManfFlags.hdatPolicyFlags[2] |= + HDAT_MNFG_FABRIC_DEPLOY_LANE_SPARES; + + if(isMnfgFlagSet(TARGETING::MNFG_FLAG_DMI_DEPLOY_LANE_SPARES)) + o_hdatManfFlags.hdatPolicyFlags[2] |= HDAT_MNFG_DMI_DEPLOY_LANE_SPARES; + + if(isMnfgFlagSet(TARGETING::MNFG_FLAG_PSI_DIAGNOSTIC)) + o_hdatManfFlags.hdatPolicyFlags[1] |= HDAT_MNFG_PSI_DIAGNOSTIC; + + if(isMnfgFlagSet(TARGETING::MNFG_FLAG_FSP_UPDATE_SBE_IMAGE)) + o_hdatManfFlags.hdatPolicyFlags[1] |= HDAT_MNFG_FSP_UPDATE_SBE_IMAGE; + + if(isMnfgFlagSet(TARGETING::MNFG_FLAG_UPDATE_BOTH_SIDES_OF_SBE)) + o_hdatManfFlags.hdatPolicyFlags[1] |= + HDAT_MNFG_UPDATE_BOTH_SIDES_OF_SBE; + +} + +/** + * @brief This routine populates dump data table + * + * @pre None + * + * @post None + * + * @param o_hdatDump + * + * @return None + * + * @retval HDAT_OTHER_COMP_ERROR + */ +void hdatGetPlatformDumpData(hdatDump_t &o_hdatDump) +{ + + o_hdatDump.hdatReserved2 = 0; + o_hdatDump.hdatHypDumpPolicy = 0; + memset(o_hdatDump.hdatReserved3, 0 , sizeof(o_hdatDump.hdatReserved3)); + o_hdatDump.hdatMaxHdwSize = 0; + o_hdatDump.hdatActHdwSize = 0; + o_hdatDump.hdatMaxSpSize = 0; + + o_hdatDump.hdatFlags = 0; + o_hdatDump.hdatDumpId = 0; + o_hdatDump.hdatActPlatformDumpSize = 0; + o_hdatDump.hdatPlid = 0; + +} + +/** + * @brief This routine sets the Header information for IPL + * Parameters structure + * + * @pre None + * + * @post None + * + * @param o_iplparams - Output Parameter - IPL Parameter headers + * + * @return None + * + * @retval HDAT_OTHER_COMP_ERROR + */ +static void hdatSetIPLParamsHdrs(hdatIPLParameters_t *o_iplparams) +{ + + o_iplparams->hdatHdr.hdatStructId = HDAT_HDIF_STRUCT_ID; + o_iplparams->hdatHdr.hdatInstance = 0; + o_iplparams->hdatHdr.hdatVersion = HDAT_IPL_PARAMS_VERSION; + o_iplparams->hdatHdr.hdatSize = sizeof(hdatIPLParameters_t); + o_iplparams->hdatHdr.hdatHdrSize = sizeof(hdatHDIF_t); + o_iplparams->hdatHdr.hdatDataPtrOffset = sizeof(hdatHDIF_t); + o_iplparams->hdatHdr.hdatDataPtrCnt = HDAT_IPL_PARAMS_DA_CNT; + o_iplparams->hdatHdr.hdatChildStrCnt = 0; + o_iplparams->hdatHdr.hdatChildStrOffset = 0; + + memcpy(o_iplparams->hdatHdr.hdatStructName, HDAT_IPLP_STRUCT_NAME, + sizeof(o_iplparams->hdatHdr.hdatStructName)); + + o_iplparams->hdatIPLParamsIntData[HDAT_IPL_PARAMS_SYS_PARAMS].hdatOffset = + offsetof(hdatIPLParameters_t,iv_sysParms); + + o_iplparams->hdatIPLParamsIntData[HDAT_IPL_PARAMS_SYS_PARAMS].hdatSize = + sizeof(hdatSysParms_t); + + o_iplparams->hdatIPLParamsIntData[HDAT_IPL_PARAMS_IPL_PARAMS].hdatOffset = + offsetof(hdatIPLParameters_t,iv_iplParms); + + o_iplparams->hdatIPLParamsIntData[HDAT_IPL_PARAMS_IPL_PARAMS].hdatSize = + sizeof(hdatIPLParams_t); + + o_iplparams->hdatIPLParamsIntData[HDAT_IPL_PARAMS_TIME_DATA].hdatOffset = + offsetof(hdatIPLParameters_t,iv_iplTime); + + o_iplparams->hdatIPLParamsIntData[HDAT_IPL_PARAMS_TIME_DATA].hdatSize = + sizeof(hdatIplTimeData_t); + + o_iplparams->hdatIPLParamsIntData[HDAT_IPL_PARAMS_SPPL_PARAMS].hdatOffset = + offsetof(hdatIPLParameters_t,iv_pvt); + + o_iplparams->hdatIPLParamsIntData[HDAT_IPL_PARAMS_SPPL_PARAMS].hdatSize = + sizeof(hdatIplSpPvt_t); + + o_iplparams->hdatIPLParamsIntData[HDAT_IPL_PARAMS_PDUMP_DATA].hdatOffset = + offsetof(hdatIPLParameters_t, iv_dump); + + o_iplparams->hdatIPLParamsIntData[HDAT_IPL_PARAMS_PDUMP_DATA].hdatSize = + sizeof(hdatDump_t); + + o_iplparams->hdatIPLParamsIntData[HDAT_IPL_PARAMS_HMC_CONNS].hdatOffset = + offsetof(hdatIPLParameters_t, iv_hmc); + + o_iplparams->hdatIPLParamsIntData[HDAT_IPL_PARAMS_HMC_CONNS].hdatSize = + sizeof(hdatHmc_t); + + o_iplparams->hdatIPLParamsIntData[HDAT_IPL_PARAMS_CUOD_DATA].hdatOffset = + offsetof(hdatIPLParameters_t, iv_cuod); + + o_iplparams->hdatIPLParamsIntData[HDAT_IPL_PARAMS_CUOD_DATA].hdatSize = + sizeof(hdatCuod_t); + + o_iplparams->hdatIPLParamsIntData[HDAT_IPL_PARAMS_MFG_DATA].hdatOffset = + offsetof(hdatIPLParameters_t, iv_manf); + + o_iplparams->hdatIPLParamsIntData[HDAT_IPL_PARAMS_MFG_DATA].hdatSize = + sizeof(hdatManf_t); + + o_iplparams->hdatIPLParamsIntData[HDAT_IPL_PARAMS_SERIAL_PORTS].hdatOffset = + offsetof(hdatIPLParameters_t, iv_portArrayHdr); + + o_iplparams->hdatIPLParamsIntData[HDAT_IPL_PARAMS_SERIAL_PORTS].hdatSize = + sizeof(hdatHDIFDataArray_t) + sizeof(hdatPortCodes_t); + +} + +/** + * @brief Constructor for IPL Parameters construction class + * + * @pre None + * + * @post None + * + * @param o_errlHndl - output parameter - Error Handlea + * i_msAddr - Mainstore address where IPL Params + * structure is loaded + * + * @return None + * + * @retval HDAT_OTHER_COMP_ERROR + */ +HdatIplParms::HdatIplParms(errlHndl_t &o_errlHndl, + const HDAT::hdatMsAddr_t &i_msAddr) +{ + o_errlHndl = NULL; + + // Copy the main store address for the pcia data + memcpy(&iv_msAddr, &i_msAddr, sizeof(hdatMsAddr_t)); + + uint64_t l_base_addr = ((uint64_t) i_msAddr.hi << 32) | i_msAddr.lo; + + void *l_virt_addr = mm_block_map ( + reinterpret_cast<void*>(ALIGN_PAGE_DOWN(l_base_addr)), + (ALIGN_PAGE(sizeof(hdatIPLParameters_t))+ PAGESIZE)); + + l_virt_addr = reinterpret_cast<void *>( + reinterpret_cast<uint64_t>(l_virt_addr) + + (l_base_addr - ALIGN_PAGE_DOWN(l_base_addr))); + + // initializing the space to zero + memset(l_virt_addr ,0x0, sizeof(hdatIPLParameters_t)); + + iv_hdatIPLParams = reinterpret_cast<hdatIPLParameters_t *>(l_virt_addr); + + HDAT_DBG("Ctr iv_hdatIPLParams addr 0x%016llX virtual addr 0x%016llX", + (uint64_t) this->iv_hdatIPLParams, (uint64_t)l_virt_addr); + +} + +/** + * @brief Load IPL Paramsters to Mainstore + * + * @pre None + * + * @post None + * + * @param o_size - output parameter - Size of IPL Parameters structure + * o_count - output parameter - Number of IPL Parameters structures + * + * @return None + * + * @retval HDAT_OTHER_COMP_ERROR + */ +errlHndl_t HdatIplParms::hdatLoadIplParams(uint32_t &o_size, uint32_t &o_count) +{ + errlHndl_t l_errl = NULL; + + //Set IPLParams Headers + hdatSetIPLParamsHdrs(this->iv_hdatIPLParams); + + //Get the FSP private IPL type + TARGETING::Target *l_pSysTarget = NULL; + (void) TARGETING::targetService().getTopLevelTarget(l_pSysTarget); + + if(l_pSysTarget == NULL) + { + HDAT_ERR("Error in getting Top Level target"); + assert(l_pSysTarget != NULL); + } + + //Initializing SP IPL Type to Power On Reset + this->iv_hdatIPLParams->iv_pvt.hdatIplType = 0x00000801; + + // Get the IPL parameters data + hdatGetIplParmsData(); + + // Get the IPL time data + hdatGetIPLTimeData(this->iv_hdatIPLParams->iv_iplTime); + + // Get the System Parameters + hdatGetSystemParamters(); + + // Get HMC information + memset(&this->iv_hdatIPLParams->iv_hmc, 0x00, + sizeof(this->iv_hdatIPLParams->iv_hmc)); + + // Get dump information + hdatGetPlatformDumpData(this->iv_hdatIPLParams->iv_dump); + + // Get CUOD information + this->iv_hdatIPLParams->iv_cuod.hdatCuodFlags = HDAT_POWER_OFF; + + // Get manufacturing mode information + memset(&this->iv_hdatIPLParams->iv_manf, 0x00, sizeof(hdatManf_t)); + hdatGetMnfgFlags(this->iv_hdatIPLParams->iv_manf); + + // Get serial port information + memset(&this->iv_hdatIPLParams->iv_portArrayHdr, 0x00, + sizeof(HDAT::hdatHDIFDataArray_t)); + memset(this->iv_hdatIPLParams->iv_ports, 0x00, sizeof(hdatPortCodes_t) * 2); + hdatGetPortInfo(this->iv_hdatIPLParams->iv_portArrayHdr, + this->iv_hdatIPLParams->iv_ports); + + HDAT_DBG("HDAT:: IPL Parameters Loaded :: Size : 0x%X", + sizeof(hdatIPLParameters_t)); + + o_count = 1; + o_size = sizeof(hdatIPLParameters_t); + + return l_errl; +} + +/** + * @brief Destructor for IPL Parameters construction class + * + * @pre None + * + * @post None + * + * @param None + * + * @return None + * + * @retval HDAT_OTHER_COMP_ERROR + */ +HdatIplParms::~HdatIplParms() +{ + int rc = 0; + rc = mm_block_unmap(iv_hdatIPLParams); + if( rc != 0) + { + errlHndl_t l_errl = NULL; + /*@ + * @errortype + * @moduleid HDAT::MOD_IPLPARMS_DESTRUCTOR + * @reasoncode HDAT::RC_DEV_MAP_FAIL + * @devdesc Unmap a mapped region failed + * @custdesc Firmware encountered an internal error. + */ + hdatBldErrLog(l_errl, + MOD_PCIA_DESTRUCTOR, + RC_DEV_MAP_FAIL, + 0,0,0,0, + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + HDAT_VERSION1, + true); + } + + return; +} +}; diff --git a/src/usr/hdat/hdatiplparms.H b/src/usr/hdat/hdatiplparms.H new file mode 100755 index 000000000..85729fb54 --- /dev/null +++ b/src/usr/hdat/hdatiplparms.H @@ -0,0 +1,475 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hdat/hdatiplparms.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 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 HDATIPLPARMS_H +#define HDATIPLPARMS_H + +/** + * @file hdatiplparms.H + * + * @brief This file contains the class definition for the IPL parms object + * constructed with data obtained from the registry and iplp component. + * + */ + +// Change Log *****************************************************************/ +// +// End Change Log *************************************************************/ + +/*----------------------------------------------------------------------------*/ +/* Includes */ +/*----------------------------------------------------------------------------*/ +#include <stdint.h> // standard types +#include <errl/errlentry.H> +#include <hdat/hdat_reasoncodes.H> +#include "hdatutil.H" +#include <hdat/hdat.H> + +namespace HDAT +{ + +/*----------------------------------------------------------------------------*/ +/* Typedefs */ +/*----------------------------------------------------------------------------*/ + +const uint16_t HDAT_IPL_PARAMS_VERSION = 0x5F; +const char HDAT_IPLP_STRUCT_NAME[7] = "IPLPMS"; + + + +/** @enum hdatDataPtrs + * Constants for the internal data pointers that are added to the base + * class + */ +enum hdatIplDataPtrs +{ + HDAT_IPL_SYS = 0, + HDAT_IPL_PARMS = 1, + HDAT_IPL_TIME = 2, + HDAT_IPL_PVT = 3, + HDAT_IPL_DUMP = 4, + HDAT_IPL_HMC = 5, + HDAT_IPL_CUOD = 6, + HDAT_IPL_MANF = 7, + HDAT_IPL_PORT_CODES = 8, + HDAT_IPL_LAST = 9 +}; + +/** @brief Structure definition for system model and feature code + */ +struct hdatSysParms_t +{ + uint32_t hdatSysModel; + uint32_t hdatProcFeatCode; + uint32_t hdatEffectivePvr; + uint32_t hdatSysType; + uint8_t hdatReserved3[8]; // Reserved + uint32_t hdatABCBusSpeed; // Speed in MHz + uint32_t hdatWXYZBusSpeed; // Speed in MHz + uint32_t hdatSystemECOMode; // System ECO Mode set by the user + uint32_t hdatSystemAttributes; // System supports multiple TPMDs + uint32_t hdatMemoryScrubbing; // Memory Scrubbing + uint16_t hdatCurrentSPPLValue; // The Current SPPL Value + uint8_t hdatReserved2; // Reserved + uint8_t usePoreSleep; // Use PORE Sleep + uint32_t hdatReserved1; // Reserved + uint8_t vTpmEnabled; // vTPM Enabled + uint8_t hdatHwPageTbl; // Hardware Page Table + uint16_t hdatDispWheel; // Hypervisor Dispatch Wheel + uint32_t hdatNestFreq; // Nest Clock Frequency in MHz + uint8_t hdatSplitCoreMode; // Split Core Mode + uint8_t hdatReserved4; // Reserved + uint16_t hdatReserved5; // Reserved + uint8_t hdatSystemVendorName[64]; // System Vendor Name +} __attribute__ ((packed)); + +/** @brief Structure definition for Other IPL Attributes within hdatIPLParams_t + * */ +struct hdatOtherIPLAttributes_t +{ + uint32_t hdatReserved1 : 1; // Reserved + uint32_t hdatCreDefPartition : 1; // Create Default Parititon + uint32_t hdatCTAState : 1; // Click To Accept State + uint32_t hdatDisVirtIOConn : 1; // Disable Virtual IO Connectivity + uint32_t hdatResetPCINOs : 1; // Reset PCI Numbers + uint32_t hdatClrPhypNvram : 1; // Clear PHYP NVRAM + uint32_t hdatMDCLogPartVPD : 1; // Preserve MDC Logical Paritition VPD + uint32_t hdatCECCMCapable : 1; // CEC Concurrent Maintanance Capable + uint32_t hdati5OSEnable : 1; // i5/OS enable + uint32_t hdatSELFlagsValid : 1; // SEL Flags Valid + uint32_t hdatDelSELFromHyp : 1; // Delete SELs originated from PHYP/OPAL + uint32_t hdatDelSELFromHB : 1; // Delete SELs originated from Hostboot + uint32_t hdatDelSELFromBMC : 1; // Delete SELs originated from BMC + uint32_t hdatReserved2 : 15; // Reserved + uint32_t hdatServiceIndMode : 2; // Platform Service Indicator Mode + uint32_t hdatDefPartitionType : 2; // Default Partition Type +}__attribute__ ((packed)); + +/** @brief Structure definition for IPL Parameters + * */ +struct hdatIPLParams_t +{ + uint8_t hdatReserved1; // Reserved + uint8_t hdatIPLDestination; // Hypervisor IPL Destination + uint8_t hdatIPLSide; // Platform IPL Side + uint8_t hdatIPLSpeed; // Platform IPL Speed for Current IPL + uint16_t hdatCECIPLAttributes; // CEC IPL Attributes + uint8_t hdatIPLMajorType; // CEC IPL Major Type + uint8_t hdatIPLMinorType; // CEC IPL Minor Type + uint8_t hdatOSIPLMode; // Operating System IPL Mode + uint8_t hdatKeyLockPosition; // Key Lock Position + uint8_t hdatLMBSize; // Logical Memory Block Size + uint8_t hdatReserved2; // Reserved + uint32_t hdatMaxHSLConns; // Max number of HSL Opticonnect + // connections + hdatOtherIPLAttributes_t hdatOIA; // Other IPL Attributes + uint16_t hdatHugePageMemCount; // Huge Page Memory Count + uint8_t hdatHugePageMemSize; // Huge Page Memory Size + uint8_t hdatNumVlanSwitches; // Number of VLAN Switches + uint32_t hdatReserved3; // Reserved + uint32_t hdatEnlargedIOCap; // Enlarged IO Capacity +}__attribute__ ((packed)); + + +/** @brief Structure definition for IPL Time Data + * */ +struct hdatIplTimeData_t +{ + uint32_t hdatReserved1; // Reserved + uint32_t hdatReserved2; // Reserved + uint32_t hdatReserved3; // Reserved + union {uint32_t hdatRTCValidFlags; // Real Time Clock and Delta Valid Flags + uint32_t hdatReserved4 :27, + hdatFSPTimeRef : 1, + hdatHYPSetTOD : 1, + hdatReserved5 : 1, + hdatCumRTCDeltaValid : 1, + hdatIPLStartRTCValid : 1;}; + uint64_t hdatCumulativeRTCDelta; // Cumulative RTC Delta + uint32_t hdatReserved6; // Reserved + uint32_t hdatReserved7; // Reserved +} __attribute__ ((packed)); + +/** @brief Structure definition for service processor private IPL type + */ +struct hdatIplSpPvt_t +{ + uint32_t hdatIplType; +} __attribute__ ((packed)); + + +/** @brief Structure definition for dump information + */ +struct hdatDump_t +{ + union {uint16_t hdatFlags; // word view unioned with bit view + uint16_t hdatRptPending : 1, // 1 = A dump exists and is + // waiting to be extracted + hdatHdwDumpExists : 1, // 1 = Hardware dump exists + hdatMemDumpExists : 1, // 1 = Memory dump exists + hdatHdwDumpErrs : 1, // 1 = Errors occurred during + // hardware dump collection + hdatMemDumpErrs : 1, // 1 = Errors occurred during + // memory dump collection + hdatHdwDumpReq : 1, // 1 = Hardware dump requested + hdatMemDumpReq : 1, // 1 = Memory dump requested + hdatUserReq : 1, // 1 = User requested the dump + hdatErrReq : 1, // 1 = Hardware or software + // error caused the dump + hdatReserved1 : 7;}; // Reserved for future use + uint8_t hdatReserved2; + uint8_t hdatHypDumpPolicy; + uint32_t hdatDumpId; + uint8_t hdatReserved3[8]; + uint64_t hdatActPlatformDumpSize; + uint32_t hdatMaxHdwSize; + uint32_t hdatActHdwSize; + uint32_t hdatMaxSpSize; + uint32_t hdatPlid; +} __attribute__ ((packed)); + + +/** @brief Structure definition for hardware management console information + */ +struct hdatHmc_t +{ + uint8_t hdatHmcFlags; + uint8_t hdatReserved1[3]; +} __attribute__ ((packed)); + +const uint8_t HDAT_HMC_MANAGED = 0x80; + + +/** @brief Structure definition for capacity upgrade on demand information + */ +struct hdatCuod_t +{ + uint8_t hdatCuodFlags; + uint8_t hdatReserved1[3]; +} __attribute__ ((packed)); + + +const uint32_t HDAT_POWER_LOST = 0x80; +const uint32_t HDAT_POWER_OFF = 0x40; + + +const uint32_t HDAT_MNFG_MAX_CELLS = 0x04; + +/** @brief Structure definition for manufacturing mode information + */ +struct hdatManf_t +{ + uint32_t hdatPolicyFlags[HDAT_MNFG_MAX_CELLS]; // 4 cells of mfg mode data +} __attribute__ ((packed)); + + +/** @brief Structure definition for SP serial port information + */ +const uint32_t hdatMaxPorts = 2; // maximum number of serial ports + +struct hdatPortCodes_t +{ + char hdatLocCode[80]; // serial port location code + uint16_t hdatResourceId; // serial port resource id + uint16_t hdatCallHome : 1, // 1 = designated as the "Call Home" port + hdatReserved1 : 15;// Reserved for future use +} __attribute__ ((packed)); + + +#define HDAT_CHIP_TYPE_MURANO "MURANO" +#define HDAT_CHIP_TYPE_VENICE "VENICE" +#define HDAT_CHIP_TYPE_NIMBUS "NIMBUS" +#define HDAT_CHIP_TYPE_CUMULUS "CUMULUS" + +#define HDAT_SYSTEM_TYPE_BASE_FIRENZE 0x30000000 +#define HDAT_SYSTEM_TYPE_PLUS_FIRENZE 0x30000001 +#define HDAT_SYSTEM_TYPE_MISC_OPENPOWER 0x00150000 + +#define HDAT_FIRMWARE_SIDE_GOLDEN 0x00 +#define HDAT_FIRMWARE_SIDE_WORKING 0x22 + +#define HDAT_KEYLOCK_MANUAL 0x02 +#define HDAT_KEYLOCK_NORMAL 0x04 + +#define HDAT_MULT_TPMDS 0x80000000 +#define HDAT_SMM_ENABLED 0x40000000 +#define HDAT_CRYPTO_DISABLED_BIT 0x20000000 + +#define HDAT_ECO_ENABLED 0x80000000 +#define HDAT_ECO_CAPABLE 0x40000000 + +#define HDAT_TURBO_CORE_MODE_PART_SIZE_128 0x0080 +#define HDAT_NONTURBO_EIGHT_CORE_PART_SIZE_32 0x0020 +#define HDAT_NONTURBO_EIGHT_CORE_PART_SIZE_256 0x8020 +#define HDAT_NONTURBO_SIX_CORE_PART_SIZE_24 0x0018 +#define HDAT_NONTURBO_SIX_CORE_PART_SIZE_256 0x8018 + + +#define HDAT_MFG_FLAGS_CELL_0 0x00000000 +#define HDAT_MFG_FLAGS_CELL_1 0x00020000 +#define HDAT_MFG_FLAGS_CELL_2 0x00040000 +#define HDAT_MFG_FLAGS_CELL_3 0x00080000 + +#define HDAT_MFG_FLAG_AVP_ENABLED 0x00000100 +#define HDAT_MFG_FLAG_HDAT_AVP_ENABLED 0x00000010 +#define HDAT_MNFG_FLAG_SRC_TERM 0x00000200 +#define HDAT_MNFG_IPL_MEM_CE_CHECKING_ACTIVE 0x00000008 +#define HDAT_MNFG_FAST_BKG_SCRUB_ACTIVE 0x00000080 +#define HDAT_MNFG_TEST_DRAM_REPAIRS 0x00000200 +#define HDAT_MNFG_DISABLE_DRAM_REPAIRS 0x00000008 +#define HDAT_MNFG_ENABLE_EXHAUSTIVE_PATTERN_TEST 0x00000001 +#define HDAT_MNFG_ENABLE_STANDARD_PATTERN_TEST 0x00000002 +#define HDAT_MNFG_ENABLE_MIN_PATTERN_TEST 0x00000004 +#define HDAT_MNFG_DISABLE_FABRIC_ERPAIR 0x00000010 +#define HDAT_MNFG_DISABLE_MEMORY_ERPAIR 0x00000020 +#define HDAT_MNFG_FABRIC_DEPLOY_LANE_SPARES 0x00000200 +#define HDAT_MNFG_DMI_DEPLOY_LANE_SPARES 0x00000100 +#define HDAT_MNFG_PSI_DIAGNOSTIC 0x00000001 +#define HDAT_MNFG_FSP_UPDATE_SBE_IMAGE 0x00000004 +#define HDAT_MNFG_UPDATE_BOTH_SIDES_OF_SBE 0x00000008 + +enum hdatIPLParamsDataPtrs +{ + HDAT_IPL_PARAMS_SYS_PARAMS = 0, + HDAT_IPL_PARAMS_IPL_PARAMS = 1, + HDAT_IPL_PARAMS_TIME_DATA = 2, + HDAT_IPL_PARAMS_SPPL_PARAMS = 3, + HDAT_IPL_PARAMS_PDUMP_DATA = 4, + HDAT_IPL_PARAMS_HMC_CONNS = 5, + HDAT_IPL_PARAMS_CUOD_DATA = 6, + HDAT_IPL_PARAMS_MFG_DATA = 7, + HDAT_IPL_PARAMS_SERIAL_PORTS = 8, + HDAT_IPL_PARAMS_DA_CNT = 9, + HDAT_IPL_PARAMS_DA_LAST = 10 +}; + +struct hdatIPLParameters_t{ + /** Object Instance Data + * + * @li iv_sysParms - system model/feature code + * @li iv_iplParms - IPL parameter information + * @li iv_iplTime - IPL time information + * @li iv_pvt - SP private IPL information + * @li iv_dump - dump information + * @li iv_hmc - hardware management console information + * @li iv_cuod - Capacity upgrade on demand information + * @li iv_manf - manufacturing flags + * @li iv_portArrayHdr - serial port array header + * @li iv_ports - serial port location codes and resource ids + */ + hdatHDIF_t hdatHdr; + hdatHDIFDataHdr_t hdatIPLParamsIntData[HDAT_IPL_PARAMS_DA_LAST]; + hdatSysParms_t iv_sysParms; + hdatIPLParams_t iv_iplParms; + hdatIplTimeData_t iv_iplTime; + hdatIplSpPvt_t iv_pvt; + hdatDump_t iv_dump; + hdatHmc_t iv_hmc; + hdatCuod_t iv_cuod; + hdatManf_t iv_manf; + hdatHDIFDataArray_t iv_portArrayHdr; + hdatPortCodes_t iv_ports[hdatMaxPorts]; +}; + +/*----------------------------------------------------------------------------*/ +/* C++ class definition */ +/*----------------------------------------------------------------------------*/ + +/** Begin Class Description + * + * @brief The HdatIplParms class is used to construct the IPL Parameters + * hypervisor data area. + * + * Description: This class defines a specialized object. It is not intended + * that any component can create an object of this type. + * In particular, the object is built only by the hdat component. + * + * The real purpose of the object is to create the IPL parameters + * data structure as defined by the PHYP Initialization + * architecture. This data structure is eventually copied to + * main memory. The class is not defined to be a general purpose + * interface for building this object by anyone other than the + * hdat process. + * + * Thread safety: An HdatIplParms object is not thread safe. That is, a + * single object cannot be shared and used concurrently by + * multiple threads at the same time. An object can be used by + * multiple threads if the threads serialize access. And of + * course, each thread can use its own object with no concerns + * about what other threads are doing. + * + * Signal handler usage: This class is not intended to be used in a signal + * handler and nothing has been done to try and make + * it safe to use in a signal handler. + * + * End Class Description + */ +class HdatIplParms +{ + public: + +/* + * @brief Construct an HdatIplParms object. + * + * This is the constructor for the HdatIplParms object. + * + * If you are constructing this object on the heap by using new, + * then you must check the pointer returned from new to see if + * it is null. + * If it is null, new failed to allocate storage and the + * constructor was not called. If it is not null, then you must + * check o_errlHndl to see if the constructor ran successfully. + * If o_errlHndl indicates an error was reported by the + * constructor, new has already allocated heap storage and the + * object must be deleted in order to free the heap storage. + * + * @pre None + * + * @post An HdatIplParms object has been constructed. + * Heap storage has been allocated. + * + * @param o_errlHndl - output parameter - If any errors occur, the + * HdatIplParms object is NOT + * constructed and errors are + * returned in this parameter + * @param i_msAddr - input parameter - The main memory address that + * the service processor subsystem + * structure will be DMA'd to. + * + * @return A null error log handle if successful, else the return + * code pointed to by o_errlHndl contains one of: + * + * @retval HDAT_REGISTRY_ERROR + */ + HdatIplParms(errlHndl_t &o_errlHndl, + const HDAT::hdatMsAddr_t &i_msAddr); + + + /** + * @brief HdatIplParms object destructor + * + * This is the destructor for an HdatIplParms object. + * Any heap storage allocated for the object is dallocated. + * + * @pre No preconditions exist + * + * @post The HdatIplParms object has been destroyed and can + * no longer be used. + * + */ + ~HdatIplParms(); + + /** + * @brief Load IPL Paramsters to Mainstore + * + * @pre None + * + * @post None + * + * @param o_size - output parameter - Size of IPL Parameters structure + * o_count - output parameter - Number of IPL Parameters + * structures + * + * @return None + * + * @retval HDAT_OTHER_COMP_ERROR + */ + + errlHndl_t hdatLoadIplParams(uint32_t &o_size,uint32_t &o_count); + private: + + void hdatGetSystemParamters(void); + + void hdatGetIplParmsData(void); + + HDAT::hdatMsAddr_t iv_msAddr; + + hdatIPLParameters_t *iv_hdatIPLParams; + + +}; // end of HdatIplParms class + +} +#endif // HDATIPLPARMS_H diff --git a/src/usr/hdat/hdatmsarea.C b/src/usr/hdat/hdatmsarea.C new file mode 100755 index 000000000..f2031c08d --- /dev/null +++ b/src/usr/hdat/hdatmsarea.C @@ -0,0 +1,720 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hdat/hdatmsarea.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 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 hdatmsarea.C + * + * @brief This file contains the implementation of the HdatMsArea class. + * + */ + + +/*----------------------------------------------------------------------------*/ +/* Includes */ +/*----------------------------------------------------------------------------*/ +#include <stdlib.h> // malloc & free +#include <hdat/hdat.H> // debug compile control variables +#include "hdatmsarea.H" // HdatMsArea class definition +#include "hdatutil.H" // utility functions +#include "hdatmsvpd.H" + +#include <stdio.h> + +namespace HDAT +{ +/*----------------------------------------------------------------------------*/ +/* Global variables */ +/*----------------------------------------------------------------------------*/ +uint32_t HdatMsArea::cv_actualCnt; + +static vpdData cvpdData[] = +{ +// { CVPD::VINI, CVPD::RT }, + { CVPD::VINI, CVPD::DR }, + { CVPD::VINI, CVPD::FN }, + { CVPD::VINI, CVPD::PN }, + { CVPD::VINI, CVPD::SN }, + { CVPD::VINI, CVPD::CC }, +// { CVPD::VINI, CVPD::PR }, + //{ CVPD::VINI, CVPD::SZ }, + { CVPD::VINI, CVPD::HE }, + { CVPD::VINI, CVPD::CT }, + { CVPD::VINI, CVPD::HW }, + // { CVPD::VINI, CVPD::B3 }, + // { CVPD::VINI, CVPD::B4 }, + // { CVPD::VINI, CVPD::B7 }, + { CVPD::VINI, CVPD::PF }, +}; + +const HdatKeywordInfo l_cvpdKeywords[] = +{ + { CVPD::DR, "DR" }, + { CVPD::FN, "FN" }, + { CVPD::PN, "PN" }, + { CVPD::SN, "SN" }, + { CVPD::CC, "CC" }, + { CVPD::HE, "HE" }, + { CVPD::CT, "CT" }, + { CVPD::HW, "HW" }, + { CVPD::PF, "PF" }, +}; + + + +/** @brief See the prologue in hdatmsarea.H + */ +HdatMsArea::HdatMsArea(errlHndl_t &o_errlHndl, + TARGETING::Target * i_target, + uint16_t i_msAreaId, + uint32_t i_ramCnt, + uint32_t i_chipEcCnt, + uint32_t i_addrRngCnt, + uint32_t i_resourceId, + uint32_t i_slcaIdx, + uint32_t i_kwdSize, + char *&i_kwd) + +: HdatHdif(o_errlHndl,HDAT_MSAREA_STRUCT_NAME,HDAT_MS_AREA_LAST,cv_actualCnt++, + HDAT_MS_AREA_CHILD_LAST,HDAT_MS_AREA_VERSION), + iv_kwdSize(i_kwdSize), + iv_maxAddrRngCnt(HDAT_MAX_ADDR_RNG_ENTRIES), iv_maxEcCnt(HDAT_MAX_EC_ENTRIES), + iv_maxRamCnt(i_ramCnt), iv_actRamCnt(0), iv_maxRamObjSize(0), iv_kwd(NULL), + iv_ramPadReq(false),iv_addrRange(NULL), iv_ecLvl(NULL), iv_ramPtrs(NULL) +{ + HDAT_ENTER( ); + + uint32_t l_slcaIdx = 0; + + o_errlHndl = NULL; + iv_fru.hdatResourceId = i_resourceId; + + memset(&iv_msId, 0x00, sizeof(hdatMsAreaId_t)); + memset(&iv_msSize, 0x00, sizeof(hdatMsAreaSize_t)); + memset(&iv_aff, 0x00, sizeof(hdatMsAreaAffinity_t)); + + iv_msId.hdatMsAreaId = i_msAreaId; + + iv_addrRngArrayHdr.hdatOffset = sizeof(hdatHDIFDataArray_t); + iv_addrRngArrayHdr.hdatArrayCnt = 0; + iv_addrRngArrayHdr.hdatAllocSize = sizeof(hdatMsAreaAddrRange_t); + iv_addrRngArrayHdr.hdatActSize = sizeof(hdatMsAreaAddrRange_t); + + iv_ecArrayHdr.hdatOffset = sizeof(hdatHDIFDataArray_t); + iv_ecArrayHdr.hdatArrayCnt = 0; + iv_ecArrayHdr.hdatAllocSize = sizeof(hdatMsAreaEcLvl_t); + iv_ecArrayHdr.hdatActSize = sizeof(hdatMsAreaEcLvl_t); + l_slcaIdx = i_slcaIdx; + + + // If the ASCII keyword data and related info has been passed to us as a + // parm, use it and avoid calling into svpd. This is an IPL performance + // improvement since all mainstore areas for an MCM will have the same + // resource id and thus the same keyword VPD. + if (i_kwdSize > 0) + { + l_slcaIdx = i_slcaIdx; + iv_kwd = new char[i_kwdSize]; + memcpy(iv_kwd, i_kwd, i_kwdSize); + } + else + { + // Get the SLCA index and ASCII keyword for this resource id + uint32_t l_num = sizeof(cvpdData)/sizeof(cvpdData[0]); + size_t theSize[l_num]; + hdatGetAsciiKwdForMvpd(i_target,iv_kwdSize,iv_kwd,cvpdData, + l_num,theSize); + do + { + char *o_fmtKwd; + uint32_t o_fmtkwdSize; + o_errlHndl = hdatformatAsciiKwd(cvpdData , l_num , theSize, iv_kwd, + iv_kwdSize, o_fmtKwd, o_fmtkwdSize, l_cvpdKeywords); + if( o_fmtKwd != NULL ) + { + delete[] iv_kwd; + //padding extra 8 bytes to keep data sync as FSP + iv_kwd = new char [o_fmtkwdSize + 8]; + memcpy(iv_kwd,o_fmtKwd,o_fmtkwdSize); + iv_kwdSize = o_fmtkwdSize + 8; + delete[] o_fmtKwd; + } + }while(0); + } + + // Allocate space for the address range array + if (NULL == o_errlHndl) + { + iv_addrRange = new hdatMsAreaAddrRange_t[iv_maxAddrRngCnt]; + memset(iv_addrRange,0, + (sizeof(hdatMsAreaAddrRange_t) * iv_maxAddrRngCnt)); + } + + // Allocate space for the EC level array + if (NULL == o_errlHndl) + { + iv_fru.hdatSlcaIdx = l_slcaIdx; + iv_ecLvl = new hdatMsAreaEcLvl_t[iv_maxEcCnt]; + } + // Allocate space for the RAM entries + if (NULL == o_errlHndl) + { + iv_ramPtrs = new HdatRam*[i_ramCnt]; + } + + HDAT_EXIT(); + return; +} + + +/** @brief See the prologue in hdatmsarea.H + */ +HdatMsArea::~HdatMsArea() +{ + HDAT_ENTER( ); + + uint32_t l_cnt; + HdatRam *l_ramObj, **l_curPtr; + + // Delete RAM Objects + l_curPtr = iv_ramPtrs; + for (l_cnt = 0; l_cnt < iv_actRamCnt; l_cnt++) + { + l_ramObj = *l_curPtr; + delete l_ramObj; + l_curPtr = reinterpret_cast<HdatRam **>(reinterpret_cast<char*>(l_curPtr) + + sizeof(HdatRam *)); + } + + delete[] iv_kwd; + delete[] iv_addrRange; + delete[] iv_ecLvl; + delete [] iv_ramPtrs; + + HDAT_EXIT(); + return; +} + + +/** @brief See the prologue in hdatmsarea.H + */ +void HdatMsArea::setParentType(uint16_t i_type) +{ + iv_msId.hdatMsAreaParentType = i_type; + return; +} + + +/** @brief See the prologue in hdatmsarea.H + */ +void HdatMsArea::setStatus(uint16_t i_status) +{ + iv_msId.hdatMsAreaStatus = i_status; + + return; +} + + +/** @brief See the prologue in hdatmsarea.H + */ +void HdatMsArea::setInterleavedId(uint16_t i_id) +{ + iv_msId.hdatInterleavedId = i_id; + + return; +} + + +/** @brief See the prologue in hdatmsarea.H + */ +void HdatMsArea::setSize(uint32_t i_size) +{ + iv_msSize.hdatReserved1 = 0; + iv_msSize.hdatMsAreaSize = i_size; + + return; +} + + +/** @brief See the prologue in hdatmsarea.H + */ +void HdatMsArea::setModuleId(uint32_t i_moduleId) +{ + iv_aff.hdatMsAreaModuleId = i_moduleId; + + return; +} + + +/** @brief See the prologue in hdatmsarea.H + */ +void HdatMsArea::setAffinityDomain(uint32_t i_affinityDomain) +{ + iv_aff.hdatMsAffinityDomain = i_affinityDomain; + + return; +} + + +/** @brief See the prologue in hdatmsarea.H + */ +void HdatMsArea::getKwdInfo(uint32_t &o_resourceId, + uint32_t &o_slcaIdx, + uint32_t &o_kwdSize, + char *&o_kwd) +{ + o_resourceId = iv_fru.hdatResourceId; + o_slcaIdx = iv_fru.hdatSlcaIdx; + o_kwdSize = iv_kwdSize; + o_kwd = iv_kwd; + + return; +} + + +/** @brief See the prologue in hdatmsarea.H + */ +errlHndl_t HdatMsArea::addAddrRange(hdatMsAddr_t &i_start, + hdatMsAddr_t &i_end, + uint32_t i_procChipId, + bool i_rangeIsMirrorable, + uint8_t i_mirroringAlgorithm, + hdatMsAddr_t &i_startMirrAddr) +{ + HDAT_ENTER(); + errlHndl_t l_errlHndl = NULL; + hdatMsAreaAddrRange_t *l_addr; + + if (iv_addrRngArrayHdr.hdatArrayCnt < iv_maxAddrRngCnt) + { + l_addr = reinterpret_cast<hdatMsAreaAddrRange_t*>( + reinterpret_cast<char*>(iv_addrRange) + iv_addrRngArrayHdr.hdatArrayCnt* + sizeof(hdatMsAreaAddrRange_t)); + + l_addr->hdatMsAreaStrAddr = i_start; + l_addr->hdatMsAreaEndAddr = i_end; + l_addr->hatMsAreaProcChipId = i_procChipId; + l_addr->hdatSMMAttributes.hdatRangeIsMirrorable = + i_rangeIsMirrorable ? 1 : 0; + l_addr->hdatSMMAttributes.hdatMirroringAlgorithm = i_mirroringAlgorithm; + l_addr->hdatStartMirrAddr = i_startMirrAddr; + iv_addrRngArrayHdr.hdatArrayCnt++; + } + else + { + /*@ + * @errortype + * @refcode LIC_REFCODE + * @subsys EPUB_FIRMWARE_SP + * @reasoncode RC_ERC_MAX_EXCEEDED + * @moduleid MOD_ADD_ADDR_RANGE + * @userdata1 current number of array entries + * @userdata2 maximum number of array entries + * @userdata3 ID number of mainstore area + * @userdata4 none + * @devdesc Failed trying to add another entry to a mainstore area + * address range array + */ + hdatBldErrLog(l_errlHndl, + MOD_ADD_ADDR_RANGE, // SRC module ID + RC_ERC_MAX_EXCEEDED, // SRC extended reference code + iv_addrRngArrayHdr.hdatArrayCnt, // SRC hex word 1 + iv_maxAddrRngCnt, // SRC hex word 2 + iv_msId.hdatMsAreaId); // SRC hex word 3 + } + HDAT_EXIT(); + return l_errlHndl; +} + + +/** @brief See the prologue in hdatmsarea.H + */ +errlHndl_t HdatMsArea::addEcEntry(uint32_t i_manfId, + uint32_t i_ecLvl) +{ + HDAT_ENTER(); + errlHndl_t l_errlHndl = NULL; + hdatMsAreaEcLvl_t *l_ec; + + + if (iv_ecArrayHdr.hdatArrayCnt < iv_maxEcCnt) + { + l_ec = reinterpret_cast<hdatMsAreaEcLvl_t*>(reinterpret_cast<char*> + (iv_ecLvl) + iv_ecArrayHdr.hdatArrayCnt * sizeof(hdatMsAreaEcLvl_t)); + l_ec->hdatChipManfId = i_manfId; + l_ec->hdatChipEcLvl = i_ecLvl; + iv_ecArrayHdr.hdatArrayCnt++; + } + + HDAT_EXIT(); + return l_errlHndl; +} + + +/** @brief See the prologue in hdatmsarea.H + */ +errlHndl_t HdatMsArea::addRam(HdatRam &i_ram) +{ + HDAT_ENTER(); + errlHndl_t l_errlHndl = NULL; + HdatRam **l_arrayEntry; + uint32_t l_ramSize; + + if (iv_actRamCnt < iv_maxRamCnt) + { + l_arrayEntry = reinterpret_cast<HdatRam**>(reinterpret_cast<char*> + (iv_ramPtrs) + iv_actRamCnt * sizeof(HdatRam *)); + + *l_arrayEntry = &i_ram; + + //Determine if the size of this RAM is larger than any other RAM objects + // associated with this mainstore area + l_ramSize = i_ram.size(); + if (l_ramSize != iv_maxRamObjSize) + { + // If not the first RAM object, then we have to pad some shorter + // RAM object(s) + if (iv_maxRamObjSize != 0) + { + iv_ramPadReq = true; + } + if (l_ramSize > iv_maxRamObjSize) + { + iv_maxRamObjSize = l_ramSize; + } + } + + iv_actRamCnt++; + } + else + { + /*@ + * @errortype + * @refcode LIC_REFCODE + * @subsys EPUB_FIRMWARE_SP + * @reasoncode RC_ERC_MAX_EXCEEDED + * @moduleid MOD_ADD_RAM + * @userdata1 current number of array entries + * @userdata2 maximum number of array entries + * @userdata3 ID number of mainstore area + * @userdata4 none + * @devdesc Failed trying to add another entry to a mainstore area + * RAM array + */ + + HDAT_INF("Failed trying to add another entry to a mainstore area RAM " + "array %d",iv_actRamCnt); + + hdatBldErrLog(l_errlHndl, + MOD_ADD_RAM, // SRC module ID + RC_ERC_MAX_EXCEEDED, // SRC extended reference code + iv_actRamCnt, // SRC hex word 1 + iv_maxRamCnt, // SRC hex word 2 + iv_msId.hdatMsAreaId); // SRC hex word 3 + } + HDAT_EXIT(); + return l_errlHndl; +} + + +/** @brief See the prologue in hdatmsarea.H + */ +uint32_t HdatMsArea::ramObjSizes() +{ + HDAT_ENTER(); + uint32_t l_size, l_cnt; + HdatRam *l_ramObj; + + l_size = 0; + + // Process the RAM objects + for (l_cnt = 0; l_cnt < iv_actRamCnt; l_cnt++) + { + l_ramObj = *(reinterpret_cast<HdatRam **>(reinterpret_cast<char*> + (iv_ramPtrs) + l_cnt * sizeof(HdatRam *))); + l_size += l_ramObj->size(); + } + + HDAT_EXIT(); + return l_size; +} + + +/** @brief See the prologue in hdatmsarea.H + */ +void HdatMsArea::finalizeObjSize() +{ + HDAT_ENTER(); + uint32_t l_idx; + HdatRam **l_ramEntry; + + // Update the base class internal data pointers + // When the data is written to the file by commit(), it must be done in the + // same order as these addData() calls + this->addData(HDAT_MS_AREA_FRU_ID, sizeof(hdatFruId_t)); + this->addData(HDAT_MS_AREA_KWD, iv_kwdSize); + this->addData(HDAT_MS_AREA_ID, sizeof(hdatMsAreaId_t)); + this->addData(HDAT_MS_AREA_SIZE, sizeof(hdatMsAreaSize_t)); + this->addData(HDAT_MS_AREA_ADDR_RNG, sizeof(hdatHDIFDataArray_t) + + iv_maxAddrRngCnt * sizeof(hdatMsAreaAddrRange_t)); + + this->addData(HDAT_MS_AREA_AFF, sizeof(hdatMsAreaAffinity_t)); + this->addData(HDAT_MS_AREA_EC_ARRAY, sizeof(hdatHDIFDataArray_t) + + iv_maxEcCnt * sizeof(hdatMsAreaEcLvl_t)); + + this->align(); + + // If we have RAM objects of different sizes, the smaller ones have to be + // padded to the size of the largest one so that PHYP can traverse through + // the RAM objects as elements of an array. + if (iv_ramPadReq) + { + for (l_idx = 0; l_idx < iv_actRamCnt; l_idx++) + { + l_ramEntry = (reinterpret_cast<HdatRam **>(reinterpret_cast<char*> + (iv_ramPtrs) + l_idx * sizeof(HdatRam *))); + + if (iv_maxRamObjSize > (*l_ramEntry)->size()) + { + (*l_ramEntry)->maxSiblingSize(iv_maxRamObjSize); + } + } + } + + // Update the base class for children that have been added + for (l_idx = 0; l_idx < iv_actRamCnt; l_idx++) + { + l_ramEntry = (reinterpret_cast<HdatRam **>(reinterpret_cast<char*> + (iv_ramPtrs) + l_idx * sizeof(HdatRam *))); + this->addChild(HDAT_MS_AREA_RAM_AREAS, (*l_ramEntry)->size(), 1); + // 1st parm is 0 based + } + + HDAT_EXIT(); + return; +} + + +/** @brief See the prologue in hdatmsarea.H + */ +uint32_t HdatMsArea::getMsAreaSize() +{ + uint32_t l_size = 0; + + // Start committing the base class data + l_size += this->getSize(); + + // Write the various pieces of data from this derived class + l_size += sizeof(hdatFruId_t); + + if ( iv_kwdSize > 0) + { + l_size += iv_kwdSize; + } + + l_size += sizeof(hdatMsAreaId_t); + + l_size += sizeof(hdatMsAreaSize_t); + + l_size += sizeof(hdatHDIFDataArray_t); + + l_size += (iv_maxAddrRngCnt * sizeof(hdatMsAreaAddrRange_t)); + + l_size += sizeof(hdatMsAreaAffinity_t); + + l_size += sizeof(hdatHDIFDataArray_t); + + l_size += (iv_maxEcCnt * sizeof(hdatMsAreaEcLvl_t)); + + l_size += this->endCommitSize(); + return l_size; +} + + +/** @brief See the prologue in hdatmsarea.H + */ +uint32_t HdatMsArea::getRamAreaSize() +{ + uint32_t l_size = 0, l_cnt = 0; + HdatRam *l_ramObj; + + // Write the RAM structures + if (iv_actRamCnt > 0) + { + l_cnt = 0; + while (l_cnt < iv_actRamCnt) + { + l_ramObj = *(reinterpret_cast<HdatRam **>(reinterpret_cast<char*> + (iv_ramPtrs) + l_cnt * sizeof(HdatRam *))); + + l_size += l_ramObj->getRamSize(); + l_cnt++; + + } + } + + return l_size; +} +/** @brief See the prologue in hdatmsarea.H + */ +void HdatMsArea::commit(UtilMem &i_data) +{ + + // Start committing the base class data + this->startCommit(i_data); + + + i_data.write(&iv_fru,sizeof(hdatFruId_t)); + + if (iv_kwdSize > 0) + { + i_data.write(iv_kwd,iv_kwdSize); + } + + + i_data.write(&iv_msId,sizeof(hdatMsAreaId_t)); + + + i_data.write(&iv_msSize, sizeof(hdatMsAreaSize_t)); + + i_data.write(&iv_addrRngArrayHdr,sizeof(hdatHDIFDataArray_t)); + + i_data.write(iv_addrRange,iv_maxAddrRngCnt * sizeof(hdatMsAreaAddrRange_t)); + + i_data.write(&iv_aff, sizeof(hdatMsAreaAffinity_t)); + + i_data.write(&iv_ecArrayHdr, sizeof(hdatHDIFDataArray_t)); + + i_data.write(iv_ecLvl,iv_maxEcCnt * sizeof(hdatMsAreaEcLvl_t)); + + this->endCommit(i_data); +} +/** @brief See the prologue in hdatmsarea.H + */ +void HdatMsArea::commitRamAreas(UtilMem &i_data) +{ + + uint32_t l_cnt; + HdatRam *l_ramObj; + + // Write the RAM structures + if (iv_actRamCnt > 0) + { + l_cnt = 0; + while (l_cnt < iv_actRamCnt) + { + l_ramObj = *(reinterpret_cast<HdatRam **>(reinterpret_cast<char*> + (iv_ramPtrs) + l_cnt * sizeof(HdatRam *))); + + l_ramObj->commit(i_data); + l_cnt++; + + } + } +} + + + +/** @brief See the prologue in hdatmsarea.H + */ +void HdatMsArea::prt() +{ + uint32_t l_cnt; + hdatMsAreaEcLvl_t *l_ec; + hdatMsAreaAddrRange_t *l_addr; + HdatRam *l_ramObj; + + HDAT_INF(" **** HdatMsArea start ****"); + HDAT_INF(" cv_actualCnt = %u", cv_actualCnt); + HDAT_INF(" iv_kwdSize = %u", iv_kwdSize); + HDAT_INF(" iv_maxAddrRngCnt = %u", iv_maxAddrRngCnt); + HDAT_INF(" iv_maxEcCnt = %u", iv_maxEcCnt); + HDAT_INF(" iv_maxRamCnt = %u", iv_maxRamCnt); + HDAT_INF(" iv_actRamCnt = %u", iv_actRamCnt); + this->print(); + //hdatPrintFruId(&iv_fru); + hdatPrintKwd(iv_kwd, iv_kwdSize); + + HDAT_INF(" **hdatMsAreaId_t**"); + HDAT_INF(" hdatMsAreaId = %u", iv_msId.hdatMsAreaId); + HDAT_INF(" hdatMsAreaParentType = %u", iv_msId.hdatMsAreaParentType); + HDAT_INF(" hdatMsAreaStatus %u", iv_msId.hdatMsAreaStatus); + + HDAT_INF(" **hdatMsAreaSize_t**"); + HDAT_INF(" hdatMsAreaSize = %u", iv_msSize.hdatMsAreaSize); + + HDAT_INF(" **hdatMsAreaAddrRange_t**"); + hdatPrintHdrs(NULL, NULL, &iv_addrRngArrayHdr, NULL); + l_addr = iv_addrRange; + for (l_cnt = 0; l_cnt < iv_ecArrayHdr.hdatArrayCnt; l_cnt++) + { + HDAT_INF(" hdatMsAreaStrAddr = 0X %08X %08X ", + l_addr->hdatMsAreaStrAddr.hi, + l_addr->hdatMsAreaStrAddr.lo); + HDAT_INF(" hdatMsAreaEndAddr = 0X %08X %08X ", + l_addr->hdatMsAreaEndAddr.hi, + l_addr->hdatMsAreaEndAddr.lo); + HDAT_INF(" hatMsAreaProcChipId = %u", l_addr->hatMsAreaProcChipId); + HDAT_INF(" hdatSMMAttributes.hdatRangeIsMirrorable = %u", + l_addr->hdatSMMAttributes.hdatRangeIsMirrorable); + HDAT_INF(" hdatSMMAttributes.hdatMirroringAlgorithm = %u", + l_addr->hdatSMMAttributes.hdatMirroringAlgorithm); + HDAT_INF(" hdatStartMirrAddr = 0X %08X %08X ", + l_addr->hdatStartMirrAddr.hi, l_addr->hdatStartMirrAddr.lo); + l_addr++; + l_cnt++; + } + HDAT_INF(""); + + + HDAT_INF(" **hdatMsAreaAffinity_t**"); + HDAT_INF(" hdatMsAreaModuleId = %u", iv_aff.hdatMsAreaModuleId); + HDAT_INF(" hdatMsAffinityDomain = %u", iv_aff.hdatMsAffinityDomain); + + HDAT_INF(" **hdatMsAreaEcLvl_t**"); + hdatPrintHdrs(NULL, NULL, &iv_ecArrayHdr, NULL); + l_ec = iv_ecLvl; + for (l_cnt = 0; l_cnt < iv_ecArrayHdr.hdatArrayCnt; l_cnt++) + { + HDAT_INF(" hdatChipManfId = %u", l_ec->hdatChipManfId); + HDAT_INF(" hdatChipEcLvl = %u", l_ec->hdatChipEcLvl); + l_ec++; + } + + HDAT_INF(" **** HdatMsArea end ****"); + + // Write the RAM structures + if (iv_actRamCnt > 0) + { + HDAT_INF(" **associated RAM objects**"); + for(l_cnt = 0; l_cnt < iv_actRamCnt; l_cnt++) + { + l_ramObj = *(HdatRam **)((char *)iv_ramPtrs + l_cnt + * sizeof(HdatRam *)); + l_ramObj->prt(); + } + } + + return; +} +} diff --git a/src/usr/hdat/hdatmsarea.H b/src/usr/hdat/hdatmsarea.H new file mode 100755 index 000000000..79fa04a10 --- /dev/null +++ b/src/usr/hdat/hdatmsarea.H @@ -0,0 +1,609 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hdat/hdatmsarea.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 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 HDATMSAREA_H +#define HDATMSAREA_H + +/** + * @file hdatmsarea.H + * + * @brief This file contains the class definition for the mainstore areas. + * This structure is part of the larger mainstore VPD structure + * which describes the various chips which make up the memory subsystem. + * + */ + +/*----------------------------------------------------------------------------*/ +/* Includes */ +/*----------------------------------------------------------------------------*/ +#include <stdint.h> // standard types +#include <hdat/hdat.H> // HDAT header type definitions +#include "hdathdif.H" // HdatHdif base class definition +#include "hdatram.H" // HdatRam class definition +#include <errl/errlentry.H> // ErrlEntry class + +namespace HDAT +{ + +/*----------------------------------------------------------------------------*/ +/* Constants */ +/*----------------------------------------------------------------------------*/ + +const uint16_t HDAT_MS_AREA_VERSION = 0x30; +const char HDAT_MSAREA_STRUCT_NAME[] = "MSAREA"; + +/** @brief Since the size of each MS Area must the same as all others, the + * total size of the EC level array and the address range array must + * be the same in each MS area. The constants below are the result of + * a bug found during initial PHYP bringup when several MS areas were + * built with different sizes. We always reserve enough space for the + * maximum number of array entries since we don't know in advance how + * many entries will actually be added. + */ +const uint32_t HDAT_MAX_EC_ENTRIES = 5; +const uint32_t HDAT_MAX_ADDR_RNG_ENTRIES = 4; + + /** @enum hdatDataPtrs + * Constants for the internal data pointers that are added to the base class + */ +enum hdatMsAreaDataPtrs +{ + HDAT_MS_AREA_FRU_ID = 0, + HDAT_MS_AREA_KWD = 1, + HDAT_MS_AREA_ID = 2, + HDAT_MS_AREA_SIZE = 3, + HDAT_MS_AREA_ADDR_RNG = 4, + HDAT_MS_AREA_AFF = 5, + HDAT_MS_AREA_EC_ARRAY = 6, + HDAT_MS_AREA_RESERVED1 = 7, + HDAT_MS_AREA_RESERVED2 = 8, + HDAT_MS_AREA_RESERVED3 = 9, + HDAT_MS_AREA_LAST = 10 +}; + + +/*----------------------------------------------------------------------------*/ +/* Typedefs */ +/*----------------------------------------------------------------------------*/ + +/** @brief Structure definition for the main store area id and status. + Reserved bytes are added to make the structure a multiple of 4 bytes. + Adjust the reserved size as necessary if new members are added to this + structure. + */ +struct hdatMsAreaId_t +{ + uint16_t hdatMsAreaId; // 0x0000 Identifier for this mainstore area + uint16_t hdatMsAreaParentType; // 0x0002 Memory parent type + uint16_t hdatMsAreaStatus; // 0x0004 Status + uint16_t hdatInterleavedId; // 0x0006 Id for MS areas which are interleaved +} __attribute__ ((packed)); + + +/** @brief Structure definition for the size of the main store area + */ +struct hdatMsAreaSize_t +{ + uint32_t hdatReserved1; // 0x0000 Reserved to make hdatMsAreaSize 8 bytes + // in future + uint32_t hdatMsAreaSize; // 0x0004 Total size of the configured main store + // in mega-bytes +} __attribute__ ((packed)); + +/** @brief Structure definition for Selective Memory Mirroring attributes field + */ +struct hdatSMMAttributes_t +{ + uint8_t hdatRangeIsMirrorable; // 0x0000 Memory range is mirrorable + uint8_t hdatMirroringAlgorithm; // 0x0001 Hardware mirroring algorithm to + // use + uint16_t hdatReserved; // 0x0002 +} __attribute__ ((packed)); + + +/** @brief Structure definition for an array of main store area address ranges + */ +struct hdatMsAreaAddrRange_t +{ + hdatMsAddr_t hdatMsAreaStrAddr; // 0x0000 Range starting address + hdatMsAddr_t hdatMsAreaEndAddr; // 0x0008 Range ending address+1 + uint32_t hatMsAreaProcChipId; // 0x0010 Processor physical chip id + // associated with this address range + hdatSMMAttributes_t hdatSMMAttributes; // 0x0014 SMM Attributes + hdatMsAddr_t hdatStartMirrAddr; // 0x0018 Starting Mirrorable Address + // for range +} __attribute__ ((packed)); + + +/** @brief Structure definition for the processor affinity + */ +struct hdatMsAreaAffinity_t +{ + uint32_t hdatMsAreaModuleId; // 0x0000 Processor Module ID associated + // with this mainstore area + uint32_t hdatMsAffinityDomain; // 0x0004 Affinity Domain +} __attribute__ ((packed)); + + +/** @brief Structure definition for an entry in the chip's engineering change + * level array + */ +struct hdatMsAreaEcLvl_t +{ + uint32_t hdatChipManfId; // 0x0000 Memory interface chip manufacturing id + uint32_t hdatChipEcLvl; // 0x0004 Memory interface chip EC level +} __attribute__ ((packed)); + + + +/*----------------------------------------------------------------------------*/ +/* Constants */ +/*----------------------------------------------------------------------------*/ + +/** @enum hdatMsAreaChildPtrs + * Constants for the child structure pointers that are added to the base + * class + */ +enum hdatMsAreaChildPtrs +{ + HDAT_MS_AREA_RAM_AREAS = 0, + HDAT_MS_AREA_CHILD_RESERVED1 = 1, + HDAT_MS_AREA_CHILD_LAST = 2 +}; + + +/*----------------------------------------------------------------------------*/ +/* C++ class definition */ +/*----------------------------------------------------------------------------*/ + +/** Begin Class Description + * + * @brief The HdatMsArea class is used to construct objects which describe + * main store areas. + * + * Description: This class defines a specialized object. It is not intended + * that anyone can create an object of this type. In particular, + * the object is built only in the hdatstep process when the step + * that builds hypervisor data structures is run. + * + * The real purpose of the object is to create the various main store + * area structures as defined by the PHYP Initialization architecture + * This data structure is eventually DMA'd to main memory. The + * class is not defined to be a general purpose interface for + * building this object by anyone other than the hdatstep process. + * + * Thread safety: An HdatMsArea object is not thread safe. That is, a single + * object cannot be shared and used concurrently by + * multiple threads at the same time. An object can be used by + * multiple threads if the threads serialize access. And of + * course, each thread can use its own object with no concerns + * about what other threads are doing. + * + * Signal handler usage: This class is not intended to be used in a signal + * handler and nothing has been done to try and make it safe to use + * in a signal handler. + * + * End Class Description + */ +class HdatMsArea : public HdatHdif +{ +public: + + /** + * @brief Construct an HdatMsArea object. + * + * This is the constructor for the HdatMsArea object. + * + * If you are constructing this object on the heap by using new, then + * you must check the pointer returned from new to see if it is null. + * If it is null, new failed to allocate storage and the constructor + * was not called. If it is not null, then you must check o_errlHndl + * to see if the constructor ran successfully. If o_errlHndl indicates + * an error was reported by the constructor, new has already allocated + * heap storage and the object must be deleted in order to free the + * heap storage. + * + * @pre None + * + * @post An HdatMsArea object has been constructed. + * Heap storage has been allocated. + * + * @param[out] o_errlHndl - If any errors occur, the HdatMsArea object + * is NOT constructed and errors are returned in this + * parameter + * @param[in]i_msAreaId - input parameter - A unique id for each main store + * area associated with a mainstore VPD object. The id + * starts at 0 and is incremented by 1 for each new + * mainstore area. + * @param[in] i_ramCnt - The number of RAM objects that will be + * added to the mainstore area. If an exact count cannot + * be computed, a maximum number can be provided. + * @param[in] i_chipEcCnt - The number of EC entries that will be + * added to the mainstore area. If an exact count + * cannot be computed, a maximum number can be provided. + * @param[in] i_addrRngCnt - The number of address range entries that + * will be added to the mainstore area. If an exact + * count cannot be computed, a maximum number can be + * provided. + * @param[in] i_resourceId - The FRU's resource id + * @param[in] i_slcaIdx - SLCA index for this FRU (only meaningful + * if keyword size > 0). + * @param[in] i_kwdSize - Size of the ASCII keyword data if available, + * otherwise 0. + * @param[in] i_kwd - ASCII keyword data if available, otherwise + * NULL. + * + * @return A null error log handle if successful, else the return code point + * to by o_errlHndl contains one of: + * + * @retval HDAT_ALLOC_ERROR + */ + HdatMsArea(errlHndl_t &o_errlHndl, + TARGETING::Target* i_target, + uint16_t i_msAreaId, + uint32_t i_ramCnt, + uint32_t i_chipEcCnt, + uint32_t i_addrRngCnt, + uint32_t i_resourceId, + uint32_t i_slcaIdx, + uint32_t i_kwdSize, + char *&i_kwd); + + + /** + * @brief HdatMsArea object destructor + * + * This is the destructor for an HdatMsArea object. Any heap storage + * allocated for the object is dallocated. + * + * @pre No preconditions exist + * + * @post The HdatMsArea object has been destroyed and can no longer be used. + * + */ + virtual ~HdatMsArea(); + + + /** + * @brief Add a RAM area to this main store area + * + * A RAM object is added. + * + * @pre The number of RAM objects added cannot exceed the RAM count specified + * on the HdatMsArea constructor + * + * @post None + * + * @param[in] i_ram - input parameter - A RAM object + * + * @return A null error log handle if successful, else the return code pointed + * to by o_errlHndl contains one of: + * + * @retval HDAT_ARRAY_ERROR + */ + errlHndl_t addRam(HdatRam &i_ram); + + + /** + * @brief Update the mainstore area to specify the type of memory. + * + * @pre None + * + * @post None + * + * @param[in] i_type - input parameter - This specifies the type of memory + * card for this mainstore area. + */ + void setParentType(uint16_t i_type); + + + /** + * @brief Update the mainstore area to specify the status of the memory DIMMS + * + * @pre None + * + * @post None + * + * @param[in] i_status - input parameter - See the hdatMsAreaStatus enum. + * The value specified here can be a bitwise OR of the enum values. + */ + void setStatus(uint16_t i_status); + + + /** + * @brief Update the mainstore area with a unique ID for interleaved areas + * + * The call to setStatus must also turn on the HDAT_MEM_SHARED flag. + * + * @pre None + * + * @post None + * + * @param[in] i_status - A unique ID. All MS areas which are + * interleaved will have the same ID. + */ + void setInterleavedId(uint16_t i_id); + + + /** + * @brief Update the mainstore area to specify the total size of the mainstore + * area. + * + * @pre None + * + * @post None + * + * @param[in] i_size - The total size of the configured mainstore + * area in megabytes. It is the (high address of the mainstore + * area + 1 minus the low address of the mainstore area) divided + * by 1 megabyte. + */ + void setSize(uint32_t i_size); + + + /** + * @brief Update the mainstore area to specify associated processor id + * + * @pre None + * + * @post None + * + * @param[in] i_moduleId - The Module Id of the processor + * associated with this mainstore area. + */ + void setModuleId(uint32_t i_moduleId); + + /** + * @brief Update the mainstore area to specify its affinity domain + * + * @pre None + * + * @post None + * + * @param[in] i_affinityDomain - The Affinity Domain + * associated with this mainstore area. + */ + void setAffinityDomain(uint32_t i_affinityDomain); + + /** + * @brief Get the SLCA index, the keyword size, and the ASCII keyword + * + * @pre None + * + * @post None + * + * @param[out] o_resourceId - The resource ID for this FRU + * @param[out] o_slcaIdx - The SLCA index for this FRU + * @param[out] o_kwdSize The size of the ASCII keyword data + * @param[out] o_kwd - A pointer to the ASCII keyword + * + */ + void getKwdInfo(uint32_t &o_resourceId, + uint32_t &o_slcaIdx, + uint32_t &o_kwdSize, + char *&o_kwd); + + + /** + * @brief Update the mainstore area to specify a memory address range. + * More than one address range can be added. + * + * @pre One cannot add any more address range entries than was specified by + * the i_addrRngCnt parameter on the HdatMsArea constructor. + * + * @post An address range entry has been added. + * + * @param[in] i_start - The starting address of the range + * @param[in] i_end - The ending address of the range + 1 + * @param[in] i_procChipId - which is the chip id of the physical processor + * @param[in] i_rangeIsMirrorable - Specifies whether the range is + * mirrorable + * @param[in] i_mirroringAlgorithm - Specifies hardware mirroring + * algorithm to use + * @param[in] i_startMirrAddr - Specifies the starting mirrorable + * address for range + * + * @return A null error log handle if successful, else the return code pointed + * to by o_errlHndl contains one of: + * + * @retval HDAT_ARRAY_ERROR + */ + errlHndl_t addAddrRange(hdatMsAddr_t &i_start, + hdatMsAddr_t &i_end, + uint32_t i_procChipId, + bool i_rangeIsMirrorable, + uint8_t i_mirroringAlgorithm, + hdatMsAddr_t &i_startMirrAddr); + + + /** + * @brief Add engineering change information for memory interface chips + * + * @pre The first EC entry added must be for the memory controller + * + * @post One cannot add any more engineering change entries than was specified + * by the i_chipEcCnt parameter on the HdatMsArea constructor. + * + * @param[in] i_manfId - input parameter - Chip's manufacturing id + * @param[in] i_ecLvl - input parameter - Chip's engineering change level + * + * @return A null error log handle if successful, else the return code pointed + * to by o_errlHndl contains one of: + * + * @retval HDAT_ARRAY_ERROR + */ + errlHndl_t addEcEntry(uint32_t i_manfId, + uint32_t i_ecLvl); + + + /** + * @brief This routine returns the length of all RAM objects associated + * with this mainstore area + * + * @pre None + * + * @post None + * + */ + uint32_t ramObjSizes(); + + + /** + * @brief This routine finalizes the object's size and updates header + * information + * + * + * @pre All data must have been added to the object and it must be ready to + * commit. + * + * @post This method must be called first before the inherited size() method + * can be called and return correct results. + * + */ + void finalizeObjSize(); + + + /** + * @brief Print an HdatMsArea object. + * + * This method is a debug mthod which prints out a mainstore area object. + * + * @pre None + * + * @post None + * + */ + void prt(); + + /** + * @brief Get MS area size + * + * This method is to retreive complete MS area size + * + * @pre None + * + * @post None + * + * @return - returns size value + * + */ + uint32_t getMsAreaSize(); + + /** + * @brief Get Ram area size + * + * This method invokes ram getSize routine for all the child pointers + * and gets the size. + * + * @pre None + * + * @post None + * + * @return - returns size value + * + */ + uint32_t getRamAreaSize(); + /** + * @brief Writes the MS area data in main store memory + * + * @pre None + * + * @post None + * + * @param[inout] i_data - memory used to write the data + * + * + */ + void commit(UtilMem &i_data); + /** + * @brief Iterates all the child pointers to invoke function that writes ram + * area data + * + * @pre None + * + * @post None + * + * @param[inout] i_data - memory used to write the data + * + * + */ + void commitRamAreas(UtilMem &i_data); +private: + + + /** Object Instance Data + * + * @li iv_kwdSize - size of the ASCII keyword + * @li iv_maxAddrRngCnt - maximum number of address range entries that + * can be added + * @li iv_maxEcCnt - maximum number of EC entries that can be added + * @li iv_maxRamCnt - maximum number of RAM objects that can be added + * @li iv_actRamCnt - actual number of RAM objects that were added + * @li iv_maxRamObjSize - maximum size of any RAM object associated with + * this mainstore area + * @li iv_kwd - ptr to storage which holds the ASCII keyword + * @li iv_ramPadReq - padding will be required for one or more RAM + * objects to make them all the same size + * @li iv_fru - FRU Id information + * @li iv_msId - mainstore area id information + * @li iv_msSize - mainstore size information + * @li iv_AddrRngArrayHdr - data array header + * @li iv_addrRange - mainstore addresses + * @li iv_aff - CPU affinity information + * @li iv_ecArrayHdr - data array header + * @li iv_ecLvl - EC level array + * @li iv_ramPtrs - ptr to storage which contains one of more ptrs + * to RAM objects + */ + uint32_t iv_kwdSize; + uint32_t iv_maxAddrRngCnt; + uint32_t iv_maxEcCnt; + uint32_t iv_maxRamCnt; + uint32_t iv_actRamCnt; + uint32_t iv_maxRamObjSize; + char *iv_kwd; + bool iv_ramPadReq; + hdatFruId_t iv_fru; + hdatMsAreaId_t iv_msId; + hdatMsAreaSize_t iv_msSize; + hdatHDIFDataArray_t iv_addrRngArrayHdr; + hdatMsAreaAddrRange_t *iv_addrRange; + hdatMsAreaAffinity_t iv_aff; + hdatHDIFDataArray_t iv_ecArrayHdr; + hdatMsAreaEcLvl_t *iv_ecLvl; + HdatRam **iv_ramPtrs; + + + /** Class (static) Data + * + * Only one copy of this data exists in a process. + * + * @li cv_actualCnt - a count of how many HdatMsArea objects are created + */ + static uint32_t cv_actualCnt; + +}; // end of HdatMsArea class + +} +#endif // HDATMSAREA_H diff --git a/src/usr/hdat/hdatmsvpd.C b/src/usr/hdat/hdatmsvpd.C new file mode 100755 index 000000000..a83669a71 --- /dev/null +++ b/src/usr/hdat/hdatmsvpd.C @@ -0,0 +1,2015 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hdat/hdatmsvpd.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 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 hdatmsvpd.C + * + * @brief This file contains the implementation of the HdatMsVpd class. + * + */ + +/*----------------------------------------------------------------------------*/ +/* Includes */ +/*----------------------------------------------------------------------------*/ +#include "hdatmsvpd.H" // HdatMsVpd class definition +#include "hdathdif.H" +#include <sys/mm.h> +#include <sys/mmio.h> +#include <assert.h> +#include <util/align.H> +#include <limits.h> + + +namespace HDAT +{ +/*----------------------------------------------------------------------------*/ +/* Global variables */ +/*----------------------------------------------------------------------------*/ + + +/*----------------------------------------------------------------------------*/ +/* Macros */ +/*----------------------------------------------------------------------------*/ +// macro to compute the address of a main store area +#define HDAT_MS_AREA(_i_idx_) *((HdatMsArea **)((char *)iv_msAreaPtrs + \ +_i_idx_ * sizeof(HdatMsArea *))) + + + + +/** @brief See the prologue in hdatmsvpd.H + */ +HdatMsVpd::HdatMsVpd(errlHndl_t &o_errlHndl, + const hdatMsAddr_t &i_msAddr + ):HdatHdif(o_errlHndl, + HDAT_MSVPD_STRUCT_NAME, HDAT_MS_VPD_LAST, HDAT_START_INSTANCE, + HDAT_MS_CHILD_LAST, HDAT_MS_VPD_VERSION), + iv_actMsAreaCnt(0), iv_maxMsAreaCnt(0), iv_msAreaPtrs(NULL), + iv_IMTaddrRangeArray(NULL), iv_maxIMTAddrRngCnt(0), + iv_UEaddrRangeArray(NULL), iv_maxUEAddrRngCnt(0) +{ + memcpy(&iv_msAddr, &i_msAddr, sizeof(hdatMsAddr_t)); +} + + + +void HdatMsVpd::hdatInit(hdatMsAddr_t &i_maxMsAddr, + hdatMsAddr_t &i_maxMsCcmAddr, + uint32_t i_msSize, + uint32_t i_msAreaCnt, + uint32_t i_MostSigAffinityDomain, + uint32_t i_ueAreaCnt, + uint64_t i_MirrMemStartAddr) +{ + iv_maxUEAddrRngCnt = i_ueAreaCnt; + iv_maxMsAreaCnt = i_msAreaCnt; + iv_maxIMTAddrRngCnt = i_msAreaCnt; + memcpy(&iv_maxAddr.hdatMaxAddr, &i_maxMsAddr, sizeof(hdatMsAddr_t)); + memcpy(&iv_maxAddr.hdatMaxCcmAddr, &i_maxMsCcmAddr, sizeof(hdatMsAddr_t)); + iv_maxAddr.hdatMstSigAffntyDom = i_MostSigAffinityDomain; + memcpy(&iv_maxAddr.hdatMirrMemStartAddr, &i_MirrMemStartAddr, + sizeof(hdatMsAddr_t)); + iv_maxSize.hdatReserved1 = 0; + iv_maxSize.hdatTotSize = i_msSize; + memset(&iv_mover, 0x00, sizeof(hdatMsVpdPageMover_t)); + iv_IMTaddrRngArrayHdr.hdatOffset = sizeof(hdatHDIFDataArray_t); + iv_IMTaddrRngArrayHdr.hdatArrayCnt = 0; + iv_IMTaddrRngArrayHdr.hdatAllocSize = sizeof(hdatMsVpdImtAddrRange_t); + iv_IMTaddrRngArrayHdr.hdatActSize = sizeof(hdatMsVpdImtAddrRange_t); + iv_UEaddrRngArrayHdr.hdatOffset = sizeof(hdatHDIFDataArray_t); + iv_UEaddrRngArrayHdr.hdatArrayCnt = 0; + iv_UEaddrRngArrayHdr.hdatAllocSize = sizeof(hdatMsVpdUEAddrRange_t); + iv_UEaddrRngArrayHdr.hdatActSize = sizeof(hdatMsVpdUEAddrRange_t); + iv_RHBaddrRngArrayHdr.hdatOffset = sizeof(hdatHDIFDataArray_t); + iv_RHBaddrRngArrayHdr.hdatArrayCnt = 0; + iv_RHBaddrRngArrayHdr.hdatAllocSize = sizeof(hdatMsVpdRhbAddrRange_t); + iv_RHBaddrRngArrayHdr.hdatActSize = sizeof(hdatMsVpdRhbAddrRange_t); + + iv_maxRHBAddrRngCnt = hdatGetMaxCecNodes(); + + // Allocate space for the mainstore area entries and IMT Addr Range array + iv_msAreaPtrs = new HdatMsArea*[iv_maxMsAreaCnt]; + iv_IMTaddrRangeArray = new hdatMsVpdImtAddrRange_t[iv_maxIMTAddrRngCnt]; + iv_UEaddrRangeArray = new hdatMsVpdUEAddrRange_t[iv_maxUEAddrRngCnt]; + // Allocate space for the host boot memory reserve range + iv_RHBaddrRangeArray = new hdatMsVpdRhbAddrRange_t[iv_maxRHBAddrRngCnt]; + + // Update the base class internal data pointers. + // When the data is written to the file by commit(), it must be done in the + // same order as these addData() calls + this->addData(HDAT_MS_VPD_MAX_ADDR, sizeof(hdatMsVpdAddr_t)); + this->addData(HDAT_MS_VPD_MAX_SIZE, sizeof(hdatMsVpdSize_t)); + this->addData(HDAT_MS_VPD_PAGE_MOVER, sizeof(hdatMsVpdPageMover_t)); + + this->addData(HDAT_MS_VPD_IMT_ADDR_RNG, (sizeof(hdatHDIFDataArray_t) + + (iv_maxIMTAddrRngCnt * sizeof(hdatMsVpdImtAddrRange_t)))); + this->addData(HDAT_MS_VPD_UE_ADDR_RNG, (sizeof(hdatHDIFDataArray_t) + + (iv_maxUEAddrRngCnt * sizeof(hdatMsVpdUEAddrRange_t)))); + + this->addData(HDAT_MS_VPD_HB_ADDR_RNG, (sizeof(hdatHDIFDataArray_t) + + (iv_maxRHBAddrRngCnt * sizeof(hdatMsVpdRhbAddrRange_t)))); + this->align(); + + return; +} + + +/** @brief See the prologue in hdatmsvpd.H + */ +HdatMsVpd::~HdatMsVpd() +{ + + uint32_t l_cnt; + HdatMsArea *l_obj, **l_curPtr; + + // Delete mainstore area objects (which in turn delete RAM objects) + l_curPtr = iv_msAreaPtrs; + for (l_cnt = 0; l_cnt < iv_actMsAreaCnt; l_cnt++) + { + l_obj = *l_curPtr; + delete l_obj; + l_curPtr = reinterpret_cast<HdatMsArea**>(reinterpret_cast<char*> + (l_curPtr) + sizeof(HdatMsArea *)); + } + + delete[] iv_msAreaPtrs; + + // Delete IMT Address Range Array + delete[] iv_IMTaddrRangeArray; + + // Delete UE Address Range Array + delete[] iv_UEaddrRangeArray; + + delete[] iv_RHBaddrRangeArray; + + uint64_t l_addr = reinterpret_cast<uint64_t> (iv_virtAddr); + l_addr = ALIGN_PAGE_DOWN(l_addr); + + iv_virtAddr = reinterpret_cast<void*>(l_addr); + + int rc = mm_block_unmap(iv_virtAddr); + if( rc != 0) + { + errlHndl_t l_errl = NULL; + /*@ + * @errortype + * @moduleid HDAT::MOD_MSVPD_DESTRUCTOR + * @reasoncode HDAT::RC_DEV_MAP_FAIL + * @devdesc Unmap a mapped region failed + * @custdesc Firmware encountered an internal error. + */ + hdatBldErrLog(l_errl, + MOD_MSVPD_DESTRUCTOR, + RC_DEV_MAP_FAIL, + 0,0,0,0, + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + HDAT_VERSION1, + true); + } + + return; +} + +/** @brief See the prologue in hdatmsvpd.H + */ +errlHndl_t HdatMsVpd::addIMTAddrRange(hdatMsAddr_t &i_start, + hdatMsAddr_t &i_end) +{ + + errlHndl_t l_errlHndl = NULL; + hdatMsVpdImtAddrRange_t *l_addr; + + if (iv_IMTaddrRngArrayHdr.hdatArrayCnt < iv_maxIMTAddrRngCnt) + { + l_addr = reinterpret_cast<hdatMsVpdImtAddrRange_t*>(reinterpret_cast + <char*>(iv_IMTaddrRangeArray) + (iv_IMTaddrRngArrayHdr.hdatArrayCnt * + sizeof(hdatMsVpdImtAddrRange_t))); + + l_addr->hdatImtAddrRngStrAddr = i_start; + l_addr->hdatImtAddrRngEndAddr = i_end; + iv_IMTaddrRngArrayHdr.hdatArrayCnt++; + } + else + { + /*@ + * @errortype + * @refcode LIC_REFCODE + * @subsys EPUB_FIRMWARE_SP + * @reasoncode RC_ERC_MAX_EXCEEDED + * @moduleid MOD_ADD_IMT_ADDR_RANGE + * @userdata1 current number of array entries + * @userdata2 maximum number of array entries + * @userdata3 none + * @userdata4 none + * @devdesc Exceeded limit of number of mainstore VPD + * In Memory Trace array entries + */ + hdatBldErrLog(l_errlHndl, + MOD_ADD_IMT_ADDR_RANGE, // SRC module ID + RC_ERC_MAX_EXCEEDED, // SRC extended reference code + iv_IMTaddrRngArrayHdr.hdatArrayCnt, // SRC hex word 1 + iv_maxIMTAddrRngCnt); // SRC hex word 2 + } + + return l_errlHndl; +} + + +/** @brief See the prologue in hdatmsvpd.H + */ +errlHndl_t HdatMsVpd::addUEAddrRange(hdatMsAddr_t &i_addr) +{ + + errlHndl_t l_errlHndl = NULL; + hdatMsVpdUEAddrRange_t *l_addr; + + if (iv_UEaddrRngArrayHdr.hdatArrayCnt < iv_maxUEAddrRngCnt) + { + l_addr = reinterpret_cast<hdatMsVpdUEAddrRange_t*>(reinterpret_cast + <char*>(iv_UEaddrRangeArray) + (iv_UEaddrRngArrayHdr.hdatArrayCnt * + sizeof(hdatMsVpdUEAddrRange_t))); + + l_addr->hdatUEAddr = i_addr; + iv_UEaddrRngArrayHdr.hdatArrayCnt++; + } + else + { + /*@ + * @errortype + * @refcode LIC_REFCODE + * @subsys EPUB_FIRMWARE_SP + * @reasoncode RC_ERC_MAX_EXCEEDED + * @moduleid MOD_ADD_UE_ADDR_RANGE + * @userdata1 current number of array entries + * @userdata2 maximum number of array entries + * @userdata3 none + * @userdata4 none + * @devdesc Exceeded limit of number of mainstore + * VPD In Memory Trace array entries + */ + hdatBldErrLog(l_errlHndl, + MOD_ADD_UE_ADDR_RANGE, // SRC module ID + RC_ERC_MAX_EXCEEDED, // SRC extended reference code + iv_UEaddrRngArrayHdr.hdatArrayCnt, // SRC hex word 1 + iv_maxUEAddrRngCnt); // SRC hex word 2 + } + + return l_errlHndl; +} + + +errlHndl_t HdatMsVpd::addRHBAddrRange(uint32_t i_dbob_id, hdatMsAddr_t &i_start, + hdatMsAddr_t &i_end, uint32_t i_labelSize, + uint8_t* &i_labelStringPtr) +{ + errlHndl_t l_errlHndl = NULL; + hdatMsVpdRhbAddrRange_t *l_addr; + + if (iv_RHBaddrRngArrayHdr.hdatArrayCnt < iv_maxRHBAddrRngCnt) + { + l_addr = reinterpret_cast<hdatMsVpdRhbAddrRange_t*>(reinterpret_cast + <char*>(iv_RHBaddrRangeArray) + (iv_RHBaddrRngArrayHdr.hdatArrayCnt * + sizeof(hdatMsVpdRhbAddrRange_t))); + + l_addr->hdatDbobID = i_dbob_id; + l_addr->hdatRhbAddrRngStrAddr = i_start; + l_addr->hdatRhbAddrRngEndAddr = i_end; + //TODO : : RTC Story 159684 + //Need to verify the correct data for label size and string + if (i_labelSize <= HDAT_MS_RHB_LABEL_LEN) + { + l_addr->hdatRhbLabelSize = i_labelSize; + } + else + { + l_addr->hdatRhbLabelSize = HDAT_MS_RHB_LABEL_LEN; + } + + memset(l_addr->hdatRhbLabelString, 0x00, HDAT_MS_RHB_LABEL_LEN); + + if (i_labelStringPtr != NULL) + { + for(uint8_t l_idx = 0; l_idx < l_addr->hdatRhbLabelSize; l_idx++) + { + l_addr->hdatRhbLabelString[l_idx] = i_labelStringPtr[l_idx]; + } + } + else + { + HDAT_INF("hdatmsvpd:addRHBAddrRange " + "i_labelStringPtr is NULL"); + } + iv_RHBaddrRngArrayHdr.hdatArrayCnt++; + } + else + { + /*@ + * @errortype + * @refcode LIC_REFCODE + * @subsys EPUB_FIRMWARE_SP + * @reasoncode RC_ERC_MAX_EXCEEDED + * @moduleid MOD_ADD_RES_HB_ADDR_RANGE + * @userdata1 current number of array entries + * @userdata2 maximum number of array entries + * @userdata3 none + * @userdata4 none + * @devdesc Exceeded limit of number of mainstore VPD Reserved + * Hostboot array entries + */ + hdatBldErrLog(l_errlHndl, + MOD_ADD_RES_HB_ADDR_RANGE, // SRC module ID + RC_ERC_MAX_EXCEEDED, // SRC extended reference code + iv_RHBaddrRngArrayHdr.hdatArrayCnt, // SRC hex word 1 + iv_maxRHBAddrRngCnt); // SRC hex word 2 + } + + return l_errlHndl; + +} + +/** @brief See the prologue in hdatmsvpd.H + */ +void HdatMsVpd::setBSR(const hdatMsAddr_t &i_bsrAddr, + hdatBsrMode i_bsrMode) +{ + const uint32_t HDAT_BSR_ENABLED = 0x20000000; + + iv_mover.hdatFlags |= (HDAT_BSR_ENABLED | i_bsrMode); + + memcpy(&iv_mover.hdatBSRAddr, &i_bsrAddr, sizeof(hdatMsAddr_t)); + + return; +} + + +/** @brief See the prologue in hdatmsvpd.H + */ +void HdatMsVpd::setXSCOM(const hdatMsAddr_t &i_xscomAddr) +{ + + const uint32_t HDAT_XSCOM_ENABLED = 0x10000000; + + iv_mover.hdatFlags |= HDAT_XSCOM_ENABLED; + + memcpy(&iv_mover.hdatXSCOMAddr, &i_xscomAddr, sizeof(hdatMsAddr_t)); + + return; +} + + +/** @brief See the prologue in hdatmsvpd.H + */ +errlHndl_t HdatMsVpd::addMsAreaFru(uint32_t i_resourceId, + uint32_t i_slcaIndex, + TARGETING::Target * i_target, + uint16_t i_msAreaId, + uint32_t i_ramCnt, + uint32_t i_chipEcCnt, + uint32_t i_addrRngCnt) +{ + errlHndl_t l_errlHndl = NULL; + HdatMsArea *l_msArea, *l_prevMsArea, **l_arrayEntry; + uint32_t l_slcaIdx, l_kwdSize, l_resourceId, l_prevIdx; + char *l_kwd; + + l_msArea = NULL; + l_kwd = NULL; + l_slcaIdx = i_slcaIndex; + l_kwdSize = 0; + + // Ensure we are not over max mainstore areas that we were told this object + // could handle on the constructor. + if (iv_actMsAreaCnt < iv_maxMsAreaCnt) + { + + // Determine if the resource ID associated with this mainstore area is + // the same as the resoruce id of the previous mainstore area.If it is, + // we can gain a performance advantage (translates into a smaller IPL + // time for the builddata step) by using the ASCII keyword data we + // already have rather than going to svpd to get it again. + if (iv_actMsAreaCnt > 0) + { + l_prevIdx = iv_actMsAreaCnt - 1; + l_prevMsArea = HDAT_MS_AREA(l_prevIdx); + l_prevMsArea->getKwdInfo(l_resourceId, l_slcaIdx, l_kwdSize, l_kwd); + if (l_resourceId != i_resourceId) + { + l_kwd = NULL; + l_slcaIdx = 0; + l_kwdSize = 0; + } + } + + // Create a mainstore area object and add it to the array of objects we + // are managing + l_msArea = new HdatMsArea(l_errlHndl, + i_target, + i_msAreaId, + i_ramCnt, + i_chipEcCnt, + i_addrRngCnt, + i_resourceId, + l_slcaIdx, + l_kwdSize, + l_kwd); + if (NULL == l_errlHndl) + { + l_arrayEntry = reinterpret_cast<HdatMsArea**>(reinterpret_cast + <char*>(iv_msAreaPtrs) + iv_actMsAreaCnt * sizeof(HdatMsArea *)); + + *l_arrayEntry = l_msArea; + iv_actMsAreaCnt++; + } + else + { + delete l_msArea; + } + } + else + { + /*@ + * @errortype + * @refcode LIC_REFCODE + * @subsys EPUB_FIRMWARE_SP + * @reasoncode RC_ERC_MAX_EXCEEDED + * @moduleid MOD_ADD_MS_AREA_FRU + * @userdata1 current array entry count + * @userdata2 maximum array entry count + * @userdata3 ID number of mainstore area that wasn't added + * @userdata4 none + * @devdesc Exceeded limit of number of mainstore area array entries + */ + hdatBldErrLog(l_errlHndl, + MOD_ADD_MS_AREA_FRU, // SRC module ID + RC_ERC_MAX_EXCEEDED, // SRC extended reference code + iv_actMsAreaCnt, // SRC hex word 1 + iv_maxMsAreaCnt, // SRC hex word 2 + i_msAreaId); // SRC hex word 3 + } + + return l_errlHndl; +} + + +/** @brief See the prologue in hdatmsvpd.H + */ +void HdatMsVpd::setMsAreaType(uint16_t i_msAreaId, + hdatMemParentType i_type) +{ + HdatMsArea *l_obj; + + if (i_msAreaId < iv_actMsAreaCnt) + { + l_obj = HDAT_MS_AREA(i_msAreaId); + l_obj->setParentType(i_type); + } + + return; +} + + +/** @brief See the prologue in hdatmsvpd.H + */ +void HdatMsVpd::setMsAreaStat(uint16_t i_msAreaId, + uint16_t i_status) +{ + + HdatMsArea *l_obj; + + if (i_msAreaId < iv_actMsAreaCnt) + { + l_obj = HDAT_MS_AREA(i_msAreaId); + l_obj->setStatus(i_status); + } + else + { + HDAT_ERR( "hdatmsvpd:setMsAreaStat - invalid i_msAreadId parameter"); + } + + return; +} + + +/** @brief See the prologue in hdatmsvpd.H + */ +void HdatMsVpd::setMsAreaInterleavedId(uint16_t i_msAreaId, + uint16_t i_id) +{ + HdatMsArea *l_obj; + + if (i_msAreaId < iv_actMsAreaCnt) + { + l_obj = HDAT_MS_AREA(i_msAreaId); + l_obj->setInterleavedId(i_id); + } + else + { + HDAT_ERR( "hdatmsvpd:setMsAreaInterleavedId-invalid i_msAreadId " + "parameter"); + } + + return; +} + + +/** @brief See the prologue in hdatmsvpd.H + */ +void HdatMsVpd::setMsAreaSize(uint16_t i_msAreaId, + uint32_t i_size) +{ + HdatMsArea *l_obj; + + if (i_msAreaId < iv_actMsAreaCnt) + { + l_obj = HDAT_MS_AREA(i_msAreaId); + l_obj->setSize(i_size); + } + else + { + HDAT_ERR( "hdatmsvpd:setMsAreaSize - invalid i_msAreadId parameter"); + } + + return; +} + + +/** @brief See the prologue in hdatmsvpd.H + */ +void HdatMsVpd::setMsAreaModuleId(uint16_t i_msAreaId, + uint32_t i_moduleId) +{ + HdatMsArea *l_obj; + + if (i_msAreaId < iv_actMsAreaCnt) + { + l_obj = HDAT_MS_AREA(i_msAreaId); + l_obj->setModuleId(i_moduleId); + } + else + { + HDAT_ERR( "hdatmsvpd:setMsAreaModuleId - invalid i_msAreadId" + " parameter"); + } + + return; +} + + +/** @brief See the prologue in hdatmsvpd.H + */ +void HdatMsVpd::setMsAreaAffinityDomain(uint16_t i_msAreaId, + uint32_t i_affinityDomain) +{ + HdatMsArea *l_obj; + + if (i_msAreaId < iv_actMsAreaCnt) + { + l_obj = HDAT_MS_AREA(i_msAreaId); + l_obj->setAffinityDomain(i_affinityDomain); + } + else + { + HDAT_ERR("hdatmsvpd:setMsAreaAffinityDomain-invalid " + "i_msAreadId parameter"); + } + + return; +} + + +/** @brief See the prologue in hdatmsvpd.H + */ +errlHndl_t HdatMsVpd::addMsAreaAddr(uint16_t i_msAreaId, + hdatMsAddr_t &i_start, + hdatMsAddr_t &i_end, + uint32_t i_procChipId, + bool i_rangeIsMirrorable, + uint8_t i_mirroringAlgorithm, + uint64_t i_startMirrAddr) +{ + errlHndl_t l_errlHndl = NULL; + HdatMsArea *l_obj; + hdatMsAddr_t l_startMirrAddr; + + memcpy(&l_startMirrAddr, &i_startMirrAddr, sizeof(hdatMsAddr_t)); + + if (i_msAreaId < iv_actMsAreaCnt) + { + l_obj = HDAT_MS_AREA(i_msAreaId); + l_errlHndl = l_obj->addAddrRange(i_start, i_end, i_procChipId, + i_rangeIsMirrorable, i_mirroringAlgorithm, l_startMirrAddr); + } + else + { + HDAT_INF( "hdatmsvpd:addMsAreaAddr - invalid i_msAreadId parameter"); + } + + return l_errlHndl; +} + + +/** @brief See the prologue in hdatmsvpd.H + */ +errlHndl_t HdatMsVpd::addEcEntry(uint16_t i_msAreaId, + uint32_t i_manfId, + uint32_t i_ecLvl) +{ + errlHndl_t l_errlHndl = NULL; + HdatMsArea *l_obj; + + if (i_msAreaId < iv_actMsAreaCnt) + { + l_obj = HDAT_MS_AREA(i_msAreaId); + l_errlHndl = l_obj->addEcEntry(i_manfId, i_ecLvl); + } + else + { + HDAT_ERR( "hdatmsvpd:addEcEntry - invalid i_msAreadId parameter"); + } + + return l_errlHndl; +} + + +/** @brief See the prologue in hdatmsvpd.H + */ +errlHndl_t HdatMsVpd::addRamFru(uint16_t i_msAreaId, + TARGETING::Target * i_target, + uint32_t i_resourceId, + uint32_t i_slcaIndex, + uint16_t i_ramId, + uint16_t i_status, + uint32_t i_size) +{ + errlHndl_t l_errlHndl = NULL; + + HdatMsArea *l_msArea;; + HdatRam *l_ram; + + // Ensure we are not over the current mainstore area count + if (i_msAreaId < iv_actMsAreaCnt) + { + l_ram = NULL; + l_msArea = HDAT_MS_AREA(i_msAreaId); + + // Create a RAM object + l_ram = new HdatRam(l_errlHndl, i_target, i_resourceId,i_slcaIndex); + if (NULL == l_errlHndl) + { + l_ram->iv_ramArea.hdatRamAreaId = i_ramId; + l_ram->iv_ramArea.hdatRamStatus = i_status; + l_ram->iv_ramSize.hdatRamTotalSize = i_size; + + // Add the RAM object to the mainstore area object + if (l_msArea) + { + l_errlHndl = l_msArea->addRam(*l_ram); + } + } + + if (NULL != l_errlHndl) + { + delete l_ram; + } + } + else + { + /*@ + * @errortype + * @refcode LIC_REFCODE + * @subsys EPUB_FIRMWARE_SP + * @reasoncode RC_ERC_NO_PARENT + * @moduleid MOD_ADD_RAM_FRU + * @userdata1 main store area id + * @userdata2 current count of main store areas + * @userdata3 none + * @userdata4 none + * @devdesc Attempted to add a RAM FRU for an invalid mainstore area + */ + HDAT_INF("Attempted to add a RAM FRU for an invalid mainstore area %d", + i_msAreaId); + + hdatBldErrLog(l_errlHndl, + MOD_ADD_RAM_FRU, // SRC module ID + RC_ERC_NO_PARENT, // SRC extended reference code + i_msAreaId, // SRC hex word 1 + iv_actMsAreaCnt); // SRC hex word 2 + } + + return l_errlHndl; +} + + +/** @brief See the prologue in hdatmsvpd.H + */ +void HdatMsVpd::adjustMsAreaObjects() +{ + HdatMsArea *l_msEntry; + uint32_t l_idx, l_maxSize, l_tempSize; + bool l_adjust; + + l_maxSize = 0; + l_adjust = false; + + // Finalize the object size for each MS area object. Also, determine if + // the objects differ in size. If they do, an extra step is needed to make + // them all the same size. + for (l_idx = 0; l_idx < iv_actMsAreaCnt; l_idx++) + { + l_msEntry = *(reinterpret_cast<HdatMsArea**>(reinterpret_cast + <char*>(iv_msAreaPtrs) + l_idx * sizeof(HdatMsArea *))); + + l_msEntry->finalizeObjSize(); // Get the MS area sizes updated before + // size() method is used + l_tempSize = l_msEntry->size(); + if (l_maxSize != l_tempSize) + { + if (l_maxSize != 0) + { + l_adjust = true; + } + if (l_maxSize < l_tempSize) + { + l_maxSize = l_tempSize; + } + } + } + + // Do we need to adjust some of the MS area objects to make them all the + // same size? + if (l_adjust) + { + for (l_idx = 0; l_idx < iv_actMsAreaCnt; l_idx++) + { + l_msEntry = *(reinterpret_cast<HdatMsArea**>(reinterpret_cast + <char*>(iv_msAreaPtrs) + l_idx * sizeof(HdatMsArea *))); + + // If too small, adjust its size + if (l_msEntry->size() < l_maxSize) + { + l_msEntry->maxSiblingSize(l_maxSize); + } + } + } + + // Tell the base class about child and grandchild structures. + for (l_idx = 0; l_idx < iv_actMsAreaCnt; l_idx++) + { + l_msEntry = *(reinterpret_cast<HdatMsArea**>(reinterpret_cast + <char*>(iv_msAreaPtrs) + l_idx * sizeof(HdatMsArea *))); + + this->addChild(HDAT_MS_AREAS, l_msEntry->size(),1);//1st parm is 0 based + this->addGrandChild(l_msEntry->ramObjSizes()); + } + + return; +} + +/** @brief See the prologue in hdatmsvpd.H + */ +void HdatMsVpd::getTotalSize(uint32_t &o_size) +{ + + HdatMsArea *l_msEntry; + // Since MS area objects could be different sizes at this point (different + // size for the VPD, for example) and since PHYP traverses the MS areas + // as an array, we may need to adjust the MS areas so they are all the same + // size. + this->adjustMsAreaObjects(); + + o_size = this->getSize(); + + o_size += sizeof(hdatMsVpdAddr_t); + + o_size += sizeof(hdatMsVpdSize_t); + + o_size += sizeof(hdatMsVpdPageMover_t); + + o_size += sizeof(hdatHDIFDataArray_t); + + o_size += (iv_maxIMTAddrRngCnt * sizeof(hdatMsVpdImtAddrRange_t)); + + o_size += sizeof(hdatHDIFDataArray_t); + + o_size += (iv_maxUEAddrRngCnt * sizeof(hdatMsVpdUEAddrRange_t)); + + o_size += sizeof(hdatHDIFDataArray_t); + + o_size += (iv_maxRHBAddrRngCnt * sizeof(hdatMsVpdRhbAddrRange_t)); + + o_size += this->endCommitSize(); + + // Write the MS area structures and RAM structures + if (iv_actMsAreaCnt > 0) + { + // All of the mainstore areas must be written first so that can be + // processed as an array of mainstore areas. + uint32_t l_ramSizes = 0; + uint8_t l_cnt = 0; + uint8_t l_currOffset = 0; + + while (l_cnt < iv_actMsAreaCnt) + { + l_msEntry = *(reinterpret_cast<HdatMsArea**>(reinterpret_cast + <char*>(iv_msAreaPtrs) + l_cnt * sizeof(HdatMsArea *))); + + // Since we don't know what order mainstore areas and RAM + // areas were created, update the offset in the HdatMsArea + // child structure triple so it points to the first RAM area. + + l_currOffset = (iv_actMsAreaCnt - l_cnt) * l_msEntry->size() + + l_ramSizes; + l_msEntry->chgChildOffset(HDAT_MS_AREA_RAM_AREAS, l_currOffset); + o_size += l_msEntry->getMsAreaSize(); + + // Now compute the size of the RAM areas associated with this + // mainstore area. These will have to be added to the child offset + // for the next mainstore area to skip over them. + l_ramSizes += l_msEntry->ramObjSizes(); + + l_cnt++; + } + + // Now the children (RAM areas) of each mainstore area must be committed + l_cnt = 0; + + while (l_cnt < iv_actMsAreaCnt) + { + l_msEntry = *(reinterpret_cast<HdatMsArea**>(reinterpret_cast + <char*>(iv_msAreaPtrs) + l_cnt * sizeof(HdatMsArea *))); + + o_size += l_msEntry->getRamAreaSize(); + l_cnt++; + } + } + +} + + +/** @brief See the prologue in hdatmsvpd.H + */ +void HdatMsVpd::prt() +{ + uint32_t l_cnt; + HdatMsArea *l_obj; + + HDAT_INF(" **** HdatMsVpd start ****"); + HDAT_INF(" iv_msAddr = 0X %08X %08X ", iv_msAddr.hi, iv_msAddr.lo); + HDAT_INF(" iv_actMsAreaCnt = %u", iv_actMsAreaCnt); + HDAT_INF(" iv_maxMsAreaCnt = %u", iv_maxMsAreaCnt); + this->print(); + + HDAT_INF(" **hdatMsVpdAddr_t**"); + HDAT_INF(" hdatMaxAddr = 0X %08X %08X ", iv_maxAddr.hdatMaxAddr.hi, + iv_maxAddr.hdatMaxAddr.lo); + HDAT_INF(" hdatMaxCcmAddr = 0X %08X %08X ", iv_maxAddr.hdatMaxCcmAddr.hi, + iv_maxAddr.hdatMaxCcmAddr.lo); + HDAT_INF(" hdatMstSigAffntyDom = 0X %08X ", iv_maxAddr.hdatMstSigAffntyDom); + + HDAT_INF(" **hdatMsVpdSize_t**"); + HDAT_INF(" hdatReserved1 = %u", iv_maxSize.hdatReserved1); + HDAT_INF(" hdatTotSize = %u", iv_maxSize.hdatTotSize); + + HDAT_INF(" **hdatMsVpdPageMover_t**"); + HDAT_INF(" hdatFlags = %u", iv_mover.hdatFlags); + HDAT_INF(" hdatLockCnt = %u", iv_mover.hdatLockCnt); + HDAT_INF(" hdatLockAddr = 0X %08X %08X ", iv_mover.hdatLockAddr.hi, + iv_mover.hdatLockAddr.lo); + HDAT_INF(" hdatMoverAddr = 0X %08X %08X ", iv_mover.hdatMoverAddr.hi, + iv_mover.hdatMoverAddr.lo); + HDAT_INF(" hdatBSRAddr = 0X %08X %08X ", iv_mover.hdatBSRAddr.hi, + iv_mover.hdatBSRAddr.lo); + + HDAT_INF(" **hdatMsVpdImtAddrRange_t**"); + hdatPrintHdrs(NULL, NULL, &iv_IMTaddrRngArrayHdr, NULL); +{ + hdatMsVpdImtAddrRange_t *l_addr = iv_IMTaddrRangeArray; + for (l_cnt = 0; l_cnt < iv_IMTaddrRngArrayHdr.hdatArrayCnt; l_cnt++) + { + HDAT_INF(" hdatImtAddrRngStrAddr = 0X %08X %08X ", + l_addr->hdatImtAddrRngStrAddr.hi, + l_addr->hdatImtAddrRngStrAddr.lo); + HDAT_INF(" hdatImtAddrRngEndAddr = 0X %08X %08X ", + l_addr->hdatImtAddrRngEndAddr.hi, + l_addr->hdatImtAddrRngEndAddr.lo); + l_addr++; + l_cnt++; + } +} + HDAT_INF(" **hdatMsVpdUEAddrRange_t**"); + hdatPrintHdrs(NULL, NULL, &iv_UEaddrRngArrayHdr, NULL); + { + hdatMsVpdUEAddrRange_t *l_addr = iv_UEaddrRangeArray; + for (l_cnt = 0; l_cnt < iv_UEaddrRngArrayHdr.hdatArrayCnt; l_cnt++) + { + HDAT_INF(" hdatUEAddrRngStrAddr = 0X %08X %08X ", + l_addr->hdatUEAddr.hi, + l_addr->hdatUEAddr.lo); + l_addr++; + l_cnt++; + } + } + HDAT_INF(" **hdatMsVpdRhbAddrRange_t**"); + hdatPrintHdrs(NULL, NULL, &iv_RHBaddrRngArrayHdr, NULL); + { + hdatMsVpdRhbAddrRange_t *l_addr = iv_RHBaddrRangeArray; + for (l_cnt = 0; l_cnt < iv_RHBaddrRngArrayHdr.hdatArrayCnt; l_cnt++) + { + HDAT_INF(" hdatRhbAddrRngStrAddr = 0X %08X %08X ", + l_addr->hdatRhbAddrRngStrAddr.hi, + l_addr->hdatRhbAddrRngStrAddr.lo); + HDAT_INF(" hdatRhbAddrRngEndAddr = 0X %08X %08X ", + l_addr->hdatRhbAddrRngEndAddr.hi, + l_addr->hdatRhbAddrRngEndAddr.lo); + l_addr++; + l_cnt++; + } + + } + HDAT_INF("");; + + HDAT_INF(" **** HdatMsVpd end ****"); + + HDAT_INF(" **main store areas and their associated RAM areas**"); + for (l_cnt = 0; l_cnt < iv_actMsAreaCnt; l_cnt++) + { + l_obj = *(HdatMsArea **)((char *)iv_msAreaPtrs + l_cnt * + sizeof(HdatMsArea *)); + l_obj->prt(); + } + + return; +} + + + + +/******************************************************************************* +* hdatLoadMsData +*******************************************************************************/ +errlHndl_t HdatMsVpd::hdatLoadMsData(uint32_t &o_size, uint32_t &o_count) +{ + errlHndl_t l_err = NULL; + HDAT_ENTER(); + + do + { + //Find the system target + TARGETING::Target *l_pSysTarget = NULL; + (void) TARGETING::targetService().getTopLevelTarget(l_pSysTarget); + + assert(l_pSysTarget != NULL); + + hdatMsAddr_t l_addr_range; + hdatMsAddr_t l_end; + l_addr_range.hi = 0x0; + l_addr_range.lo = 0x0; + l_end = l_addr_range; + + uint32_t l_sizeConfigured = 0; + uint64_t l_maxMsAddr = hdatGetMaxMemConfiguredAddress(); + + hdatMsAddr_t l_tmpMaxMsAddr; + l_tmpMaxMsAddr.hi = (l_maxMsAddr & 0xFFFFFFFF00000000ull) >> 32; + l_tmpMaxMsAddr.lo = l_maxMsAddr & 0x00000000FFFFFFFFull; + + HDAT_INF("MaxMsAddr high:0x%.8X 0x%.8X", + l_tmpMaxMsAddr.hi,l_tmpMaxMsAddr.lo); + + uint32_t l_mostSigAffinityDomain_x = 0; + uint32_t l_ueCount = 1; + + TARGETING::ATTR_MIRROR_BASE_ADDRESS_type l_mirroringBaseAddress_x = + l_pSysTarget->getAttr<TARGETING::ATTR_MIRROR_BASE_ADDRESS>(); + l_mirroringBaseAddress_x |= HDAT_REAL_ADDRESS_MASK64; + + TARGETING::ATTR_MAX_MCS_PER_SYSTEM_type l_maxMsAreas = + l_pSysTarget->getAttr<TARGETING::ATTR_MAX_MCS_PER_SYSTEM>(); + + // Initialize the MS vpd class + hdatInit(l_tmpMaxMsAddr,l_tmpMaxMsAddr,l_sizeConfigured,l_maxMsAreas, + l_mostSigAffinityDomain_x,l_ueCount,l_mirroringBaseAddress_x); + + TARGETING::ATTR_XSCOM_BASE_ADDRESS_type l_xscomAddr = + l_pSysTarget->getAttr<TARGETING::ATTR_XSCOM_BASE_ADDRESS>(); + assert(l_xscomAddr != 0); + { + hdatMsAddr_t l_hdatXscomAddr; + l_hdatXscomAddr.hi = (l_xscomAddr & 0xFFFFFFFF00000000ull) >> 32; + l_hdatXscomAddr.lo = l_xscomAddr & 0x00000000FFFFFFFFull; + + l_hdatXscomAddr.hi |= HDAT_REAL_ADDRESS_MASK; + + setXSCOM(l_hdatXscomAddr); + } + + uint32_t l_index = 0; + //for each proc/ memory controller in the system + TARGETING::PredicateCTM l_procPred(TARGETING::CLASS_CHIP, + TARGETING::TYPE_PROC); + TARGETING::PredicateHwas l_predHwasPresent; + l_predHwasPresent.present(true); + TARGETING::PredicateHwas l_predHwasFunc; + l_predHwasFunc.functional(true); + TARGETING::PredicatePostfixExpr l_funcProc; + l_funcProc.push(&l_procPred).push(&l_predHwasFunc).And(); + + TARGETING::TargetRangeFilter l_procs( + TARGETING::targetService().begin(), + TARGETING::targetService().end(), + &l_funcProc); + + uint32_t l_nxtSharingGroupId = 0; + + for(;l_procs;++l_procs) + { + TARGETING::Target *l_pProcTarget = *(l_procs); + TARGETING::ATTR_ORDINAL_ID_type l_procChipId + = l_pProcTarget->getAttr<TARGETING::ATTR_ORDINAL_ID>(); + + // TODO : RTC Story 159682 + // Further CHTM support needs to be added which contains the trace + // array for 24 cores + hdatMsAddr_t l_hdatNhtmStartAddr; + hdatMsAddr_t l_hdatNhtmEndAddr; + + TARGETING::ATTR_PROC_NHTM_BAR_BASE_ADDR_type l_nhtmStartAddr = + l_pProcTarget->getAttr<TARGETING::ATTR_PROC_NHTM_BAR_BASE_ADDR>(); + TARGETING::ATTR_PROC_NHTM_BAR_SIZE_type l_nhtmSize = + l_pProcTarget->getAttr<TARGETING::ATTR_PROC_NHTM_BAR_SIZE>(); + + if( 0 != l_nhtmSize ) + { + l_hdatNhtmStartAddr.hi = + (l_nhtmStartAddr & 0xFFFFFFFF00000000ull) >> 32; + l_hdatNhtmStartAddr.lo = + l_nhtmStartAddr & 0x00000000FFFFFFFFull; + l_hdatNhtmStartAddr.hi |= HDAT_REAL_ADDRESS_MASK; + + l_nhtmSize = l_nhtmStartAddr + l_nhtmSize; + l_hdatNhtmEndAddr.hi = + (l_nhtmSize & 0xFFFFFFFF00000000ull) >> 32; + l_hdatNhtmEndAddr.lo = l_nhtmSize & 0x00000000FFFFFFFFull; + l_hdatNhtmEndAddr.hi |= HDAT_REAL_ADDRESS_MASK; + + HDAT_INF("hdatNhtmStartAddr = 0x%08X 0x%08X ", + l_hdatNhtmStartAddr.hi, l_hdatNhtmStartAddr.lo); + HDAT_INF("hdatNhtmEndAddr = 0x%08X 0x%08X ", + l_hdatNhtmEndAddr.hi, l_hdatNhtmEndAddr.lo); + + addIMTAddrRange(l_hdatNhtmStartAddr, l_hdatNhtmEndAddr); + } + else + { + HDAT_INF("NHTM Bar size value = 0x%016llX", + l_nhtmSize); + } + + TARGETING::ATTR_PROC_MEM_BASES_type l_procMemBases = {0}; + assert(l_pProcTarget-> + tryGetAttr<TARGETING::ATTR_PROC_MEM_BASES>(l_procMemBases)); + + //Sharing count for each group + TARGETING::ATTR_MSS_MEM_MC_IN_GROUP_type l_mcsSharingCount = {0}; + + //Group ID for each group, group id will be assigned only + //if the group is shared + TARGETING::ATTR_MSS_MEM_MC_IN_GROUP_type l_mcsSharingGrpIds = {0}; + + //Size configured under each group + TARGETING::ATTR_PROC_MEM_SIZES_type l_procMemSizesBytes = {0}; + + assert(l_pProcTarget->tryGetAttr<TARGETING::ATTR_PROC_MEM_SIZES> + (l_procMemSizesBytes)); + + TARGETING::PredicateCTM l_mcbistPredicate(TARGETING::CLASS_UNIT, + TARGETING::TYPE_MCBIST); + + TARGETING::PredicatePostfixExpr l_presentMcbist; + l_presentMcbist.push(&l_mcbistPredicate). + push(&l_predHwasFunc).And(); + + TARGETING::TargetHandleList l_mcbistList; + + // Find Associated MCBIST list + TARGETING::targetService().getAssociated(l_mcbistList, + l_pProcTarget, + TARGETING::TargetService::CHILD_BY_AFFINITY, + TARGETING::TargetService::ALL, + &l_presentMcbist); + + //scan all mcbist in this proc + for(uint32_t l_mcbistIdx =0; + l_mcbistIdx < l_mcbistList.size(); + ++l_mcbistIdx) + { + TARGETING::Target *l_pMcbistTarget = l_mcbistList[l_mcbistIdx]; + + TARGETING::PredicateCTM l_mcsPredicate(TARGETING::CLASS_UNIT, + TARGETING::TYPE_MCS); + + TARGETING::PredicatePostfixExpr l_funcMcs; + l_funcMcs.push(&l_mcsPredicate).push(&l_predHwasFunc).And(); + + TARGETING::TargetHandleList l_mcsList; + + // Find Associated memory controllers + TARGETING::targetService().getAssociated(l_mcsList, + l_pMcbistTarget, + TARGETING::TargetService::CHILD, + TARGETING::TargetService::ALL, + &l_funcMcs); + + //scan all mcs in this proc to get sharing counit + for(uint32_t l_idx = 0; l_idx<l_mcsList.size(); ++l_idx) + { + TARGETING::Target *l_pMcsTarget = l_mcsList[l_idx]; + + uint32_t l_mcsInGrp = 0; + if(!hdatFindGroupForMc(l_pProcTarget, + l_pMcsTarget, + l_mcsInGrp)) + { + //Skip this MCS is not in any group + continue; + } + + //Increment sharing count if mem configured under group. + if(l_procMemSizesBytes[l_mcsInGrp] > 0) + { + l_mcsSharingCount[l_mcsInGrp]++; + + //Assign sharing group id only if shared + //And only when first instance of sharing is found + if(l_mcsSharingCount[l_mcsInGrp] == + HDAT_MIN_NUM_FOR_SHARING) + { + l_mcsSharingGrpIds[l_mcsInGrp] = + l_nxtSharingGroupId; + l_nxtSharingGroupId++; + } + } + } + + for(uint32_t l_mcsIdx = 0; l_mcsIdx<l_mcsList.size(); + ++l_mcsIdx) + { + TARGETING::Target *l_pMcsTarget = + l_mcsList[l_mcsIdx]; + + //Group which this MCS is belonging + uint32_t l_mcsInGrp = 0; + + if(!hdatFindGroupForMc(l_pProcTarget, + l_pMcsTarget, + l_mcsInGrp)) + { + HDAT_INF("No group found for MCS"); + //Skip this MCS is not under any group + continue; + } + + uint32_t l_mcaFruId = 0; + hdatMemParentType l_parentType = HDAT_MEM_PARENT_CEC_FRU; + + std::list<hdatRamArea> l_areas; + l_areas.clear(); + uint32_t l_areaSizeInMB = 0; + bool l_areaFunctional = false; + uint32_t l_numDimms =0; + + l_err = hdatScanDimms(l_pMcsTarget, + l_mcaFruId, + l_areas, + l_areaSizeInMB, + l_numDimms, + l_areaFunctional, + l_parentType); + + if(NULL != l_err) + { + HDAT_ERR("Error in calling Scan Dimms"); + break; + } + + HDAT_INF("l_areaSizeInMB:0x%.8X l_numDimms:0x%.8X" + " l_areas.size():0x%.8X", l_areaSizeInMB, l_numDimms, + l_areas.size()); + + //Skip if no memory configured under this MCS + if(l_areaSizeInMB == 0) + { + continue; + } + + uint32_t l_maxMemBlocks = 0; + l_err = hdatGetMaxMemoryBlocks(l_pMcsTarget,l_maxMemBlocks); + if(NULL != l_err) + { + HDAT_ERR("Error error in get max blocks"); + break; + } + + TARGETING::ATTR_SLCA_RID_type l_procRid = + l_pProcTarget->getAttr<TARGETING::ATTR_SLCA_RID>(); + + TARGETING::ATTR_SLCA_INDEX_type l_procSlcaIndex = + l_pProcTarget->getAttr<TARGETING::ATTR_SLCA_INDEX>(); + + l_err = addMsAreaFru(l_procRid, + l_procSlcaIndex, + l_pProcTarget, + l_index, + l_numDimms, + MAX_CHIP_EC_CNT_PER_MSAREA, + l_maxMemBlocks); + + if(NULL != l_err) + { + HDAT_ERR("Error adding MSArea %d" + "Number of Dimms: %d Max Blocks: %d", + l_index, + l_numDimms,l_maxMemBlocks); + break; + } + + uint32_t l_memStatus = 0; + //If group is shared with more than one area + if(l_mcsSharingCount[l_mcsInGrp] >= + HDAT_MIN_NUM_FOR_SHARING) + { + l_memStatus = HDAT_MEM_SHARED; + setMsAreaInterleavedId(l_index, + l_mcsSharingGrpIds[l_mcsInGrp]); + } + + setMsAreaType(l_index,l_parentType); + setMsAreaSize(l_index,l_areaSizeInMB); + + iv_maxSize.hdatTotSize += l_areaSizeInMB; + + l_memStatus |= l_areaFunctional ? + (HDAT_MEM_INSTALLED | HDAT_MEM_FUNCTIONAL) : + HDAT_MEM_INSTALLED; + + setMsAreaStat(l_index, l_memStatus); + + //Add MCS ec level + uint32_t l_mcsEcLevel = 0; + uint32_t l_mcsChipId = 0; + l_err = hdatGetIdEc(l_pMcsTarget, + l_mcsEcLevel, + l_mcsChipId); + if(NULL != l_err) + { + HDAT_ERR("Error in getting MCS ID " + "and EC HUID:[0x%08X]", + l_pMcsTarget->getAttr<TARGETING::ATTR_HUID>()); + break; + } + + l_err = addEcEntry(l_index, + l_mcsChipId, + l_mcsEcLevel); + if(NULL != l_err) + { + HDAT_ERR("Error in adding" + " ID[0x%08X] and EC[0x%08X] to ms area" + " HUID:[0x%08X]",l_mcsChipId, + l_mcsEcLevel, + l_pMcsTarget->getAttr<TARGETING::ATTR_HUID>()); + break; + } + + std::list<hdatRamArea>::iterator l_area = l_areas.begin(); + + for (uint32_t l_ramId = 0; + l_area != l_areas.end(); + ++l_ramId, ++l_area) + { + uint32_t l_status = (l_area)->ivFunctional ? + (HDAT_RAM_INSTALLED | HDAT_RAM_FUNCTIONAL) + : HDAT_RAM_INSTALLED; + + TARGETING::Target *l_pDimmTarget = + TARGETING::Target::getTargetFromHuid(l_area->ivHuid); + + TARGETING::ATTR_SLCA_RID_type l_dimmRid = + l_pDimmTarget->getAttr<TARGETING::ATTR_SLCA_RID>(); + + TARGETING::ATTR_SLCA_INDEX_type l_dimmSlcaIndex = + l_pDimmTarget->getAttr<TARGETING::ATTR_SLCA_INDEX>(); + + l_err = addRamFru(l_index, + l_pDimmTarget, + l_dimmRid, + l_dimmSlcaIndex, + l_ramId, + l_status, + (l_area)->ivSize); + + if (l_err) // Failed to add ram fru information + { + HDAT_ERR("Error in adding RAM FRU" + "Index:%d Rid:[0x%08X] status:[0x%08X]" + "Size:[0x%08X] RamID:[0x%08X]", + l_index,(l_area)->ivHuid, + l_status,(l_area)->ivSize,l_ramId); + ERRORLOG::errlCommit(l_err,HDAT_COMP_ID); + + delete l_err; + l_err = NULL; + continue; + } + }//end of RAM list + + l_addr_range.hi = (l_procMemBases[l_mcsInGrp] & + 0xFFFFFFFF00000000ull) >> 32; + l_addr_range.lo = l_procMemBases[l_mcsInGrp] & + 0x00000000FFFFFFFFull; + + l_end = l_addr_range; + + //Update the range + l_end.hi += (l_procMemSizesBytes[l_mcsInGrp] & + 0xFFFFFFFF00000000ull) >> 32; + l_end.lo += l_procMemSizesBytes[l_mcsInGrp] & + 0x00000000FFFFFFFFull; + + HDAT_INF("MCS:0x%08X l_addr_range:0x%08X 0x%08X" + " l_end:0x%08X 0x%08X", + l_pMcsTarget->getAttr<TARGETING::ATTR_HUID>(), + l_addr_range.hi, l_addr_range.lo, + l_end.hi,l_end.lo); + + uint64_t l_hdatMirrorAddr_x = 0x0ull; + uint64_t l_hdatMirrorAddr = 0x0ull; + uint8_t l_hdatMirrorAlogrithm = 0xFF; + bool l_rangeIsMirrorable = false; + + TARGETING::ATTR_PROC_MIRROR_BASES_type l_MirrorAddr = {0}; + assert(l_pProcTarget->tryGetAttr< + TARGETING::ATTR_PROC_MIRROR_BASES>(l_MirrorAddr)); + + TARGETING::ATTR_PROC_MIRROR_SIZES_type l_MirrorSize = {0}; + assert(l_pProcTarget->tryGetAttr< + TARGETING::ATTR_PROC_MIRROR_SIZES>(l_MirrorSize)); + + TARGETING::ATTR_MIRROR_BASE_ADDRESS_type l_mirrorBaseAddress_x = + l_pSysTarget->getAttr<TARGETING::ATTR_MIRROR_BASE_ADDRESS>(); + + uint64_t l_startAddr = (((uint64_t)(l_addr_range.hi) << 32 ) + | (uint64_t)(l_addr_range.lo)); + l_hdatMirrorAddr_x = (l_startAddr / 2) + l_mirrorBaseAddress_x; + + TARGETING::ATTR_PAYLOAD_IN_MIRROR_MEM_type l_payLoadMirrorMem = + l_pSysTarget->getAttr<TARGETING::ATTR_PAYLOAD_IN_MIRROR_MEM>(); + + HDAT_INF( + "Start add : 0x%016llX MirrorBase : 0x%016llX" + " MirrorAddr : 0x%016llX PayLoadMirrorMem : 0x%X", + l_startAddr, l_mirrorBaseAddress_x, + l_hdatMirrorAddr_x, l_payLoadMirrorMem); + + if ( 0 != l_payLoadMirrorMem ) + { + for ( int idx=0 ; idx < + (int)(sizeof(TARGETING::ATTR_PROC_MIRROR_SIZES_type) + / sizeof(uint64_t)) ; idx++ ) + { + HDAT_INF("Mirror size : 0x%016llX" + " MirrorAddr[idx] : 0x%016llX" + " hdatMirrorAddr_x : 0x%016llX", + l_MirrorSize[idx], l_MirrorAddr[idx], + l_hdatMirrorAddr_x); + + if( (0 != l_MirrorSize[idx]) && + (l_MirrorAddr[idx] == l_hdatMirrorAddr_x) ) + { + l_rangeIsMirrorable = true; + l_hdatMirrorAddr = l_MirrorAddr[idx] + | HDAT_REAL_ADDRESS_MASK64; + break; + } + } + } + l_err = addMsAreaAddr(l_index, + l_addr_range, + l_end, + l_procChipId, + l_rangeIsMirrorable, + l_hdatMirrorAlogrithm, + l_hdatMirrorAddr); + if(NULL != l_err) + { + HDAT_ERR("Error in adding addMsAreaAddr" + " to ms area index[%d]", + l_index); + break; + } + + // TODO : RTC Story 159682 + // Further CHTM support needs to be added which contains the + // trace array for 24 cores + // Reinitializing the NHTM size + l_nhtmSize = + l_pProcTarget->getAttr + <TARGETING::ATTR_PROC_NHTM_BAR_SIZE>(); + + uint64_t l_end_addr = + (((uint64_t)(l_end.hi) << 32 ) | (uint64_t)(l_end.lo)); + uint64_t l_start_addr = (((uint64_t)(l_addr_range.hi) << 32 ) + | (uint64_t)(l_addr_range.lo)); + uint64_t l_size_bytes = (l_areaSizeInMB) * 1024 * 1024; + + if((0 != l_nhtmSize) && + (l_size_bytes != (l_end_addr - l_start_addr))) + { + HDAT_INF("NHTM Bar size = 0x%016llX " + " MS area size = 0x%016llX" + " l_end_addr = 0x%016llX" + " l_start_addr = 0x%016llX", + l_nhtmSize,l_size_bytes, l_end_addr, l_start_addr); + + l_addr_range.lo = l_hdatNhtmStartAddr.lo; + l_addr_range.hi = l_hdatNhtmStartAddr.hi; + + l_end.lo = l_hdatNhtmEndAddr.lo; + l_end.hi = l_hdatNhtmEndAddr.hi; + + l_err = addMsAreaAddr(l_index, + l_addr_range, + l_end, + l_procChipId, + false, 0, 0); + if(NULL != l_err) + { + HDAT_ERR("Error in adding " + " addMsAreaAddr to ms area index[%d]", + l_index); + break; + } + l_nhtmSize=0; //only add 1 entry + } + l_addr_range = l_end; + l_index++; + } //end of MCS list + } //end of MCBIST list + if(l_err) + { + // Error message recorded above + break; + } + } //end of proc list + + TARGETING::PredicateCTM l_nodePred(TARGETING::CLASS_ENC, + TARGETING::TYPE_NODE); + TARGETING::PredicateHwas l_predFunctional; + l_predFunctional.functional(true); + TARGETING::PredicatePostfixExpr l_functionalnode; + l_functionalnode.push(&l_nodePred).push(&l_predFunctional).And(); + + TARGETING::TargetRangeFilter l_nodes(TARGETING::targetService().begin(), + TARGETING::targetService().end(), + &l_functionalnode); + + TARGETING::ATTR_HB_RSV_MEM_SIZE_MB_type l_rhbSize = + l_pSysTarget->getAttr<TARGETING::ATTR_HB_RSV_MEM_SIZE_MB>(); + if( 0 != l_rhbSize ) + { + for(;l_nodes;++l_nodes) + { + TARGETING::ATTR_HB_HRMOR_NODAL_BASE_type l_rhbStartAddr = + l_pSysTarget->getAttr<TARGETING::ATTR_HB_HRMOR_NODAL_BASE>(); + + TARGETING::Target *l_pNodeTarget = *(l_nodes); + uint32_t l_dbobId = + l_pNodeTarget->getAttr<TARGETING::ATTR_ORDINAL_ID>(); + + hdatMsAddr_t l_hdatRhbStartAddr; + hdatMsAddr_t l_hdatRhbEndAddr; + + l_rhbStartAddr = l_rhbStartAddr * l_dbobId; + l_hdatRhbStartAddr.hi = + (l_rhbStartAddr & 0xFFFFFFFF00000000ull) >> 32; + l_hdatRhbStartAddr.lo = l_rhbStartAddr & 0x00000000FFFFFFFFull; + l_hdatRhbStartAddr.hi |= HDAT_REAL_ADDRESS_MASK; + + // need to store a 64 bit range + uint64_t l_hbSize=0; + // in bytes + uint64_t l_size_bytes = (l_rhbSize * 1024 * 1024) -1; + l_hbSize = l_rhbStartAddr + l_size_bytes; + l_hdatRhbEndAddr.hi = (l_hbSize & 0xFFFFFFFF00000000ull) >> 32; + l_hdatRhbEndAddr.lo = l_hbSize & 0x00000000FFFFFFFFull; + l_hdatRhbEndAddr.hi |= HDAT_REAL_ADDRESS_MASK; + + //TODO : : RTC Story 159684 + //Need to populate correct label size and label string + uint32_t l_rhbLabelSize = 0; + uint8_t* l_rhbLabelStringPtr = NULL; + + addRHBAddrRange(l_dbobId, l_hdatRhbStartAddr, + l_hdatRhbEndAddr, l_rhbLabelSize, + l_rhbLabelStringPtr); + } + } + else + { + HDAT_INF("Reserve HB mem size 0x%08X",l_rhbSize); + } + + if(l_err) + { + // Error message recorded above + break; + } + + o_size = 0; + o_count = 1; // Only 1 of these structures is ever built + + getTotalSize (o_size); + + + uint64_t l_base_addr = ((uint64_t) iv_msAddr.hi << 32) | iv_msAddr.lo; + uint64_t l_base_addr_down = ALIGN_PAGE_DOWN(l_base_addr); + iv_virtAddr = mm_block_map ( reinterpret_cast<void*>(l_base_addr_down), + (ALIGN_PAGE(o_size) + PAGESIZE)); + + uint64_t l_final_addr = reinterpret_cast<uint64_t>(iv_virtAddr); + + l_final_addr += l_base_addr - l_base_addr_down; + + + iv_virtAddr = reinterpret_cast<void *> (l_final_addr); + + + commit(iv_virtAddr,o_size); + + prt(); + } + while(0); + + HDAT_EXIT(); + + return l_err; +} + +/** @brief See the prologue in hdatmsvpd.H + */ +void HdatMsVpd::commit(void * i_addr, + uint32_t i_size) +{ + + uint32_t l_cnt,l_currOffset, l_ramSizes; + HdatMsArea *l_msEntry; + UtilMem l_data(i_addr, i_size); + + // Start committing the base class data + this->startCommit(l_data); + + l_data.write(&iv_maxAddr, sizeof(hdatMsVpdAddr_t)); + + l_data.write(&iv_maxSize, sizeof(hdatMsVpdSize_t)); + + // Page mover is called 'Misc Addr Structure' on OPAL but still exists + l_data.write(&iv_mover, sizeof(hdatMsVpdPageMover_t)); + + l_data.write(&iv_IMTaddrRngArrayHdr,sizeof(hdatHDIFDataArray_t)); + + l_data.write(iv_IMTaddrRangeArray, + iv_maxIMTAddrRngCnt * sizeof(hdatMsVpdImtAddrRange_t)); + + l_data.write(&iv_UEaddrRngArrayHdr, sizeof(hdatHDIFDataArray_t)); + + l_data.write(iv_UEaddrRangeArray, + iv_maxUEAddrRngCnt * sizeof(hdatMsVpdUEAddrRange_t)); + + l_data.write(&iv_RHBaddrRngArrayHdr,sizeof(hdatHDIFDataArray_t)); + + l_data.write (iv_RHBaddrRangeArray,iv_maxRHBAddrRngCnt + * sizeof(hdatMsVpdRhbAddrRange_t)); + + this->endCommit(l_data); + + + // Write the MS area structures and RAM structures + if (iv_actMsAreaCnt > 0) + { + // All of the mainstore areas must be written first so that can be + // processed as an array of mainstore areas. + l_ramSizes = 0; + l_cnt = 0; + + while (l_cnt < iv_actMsAreaCnt) + { + l_msEntry = *(reinterpret_cast<HdatMsArea **>( + reinterpret_cast<char *>(iv_msAreaPtrs) + l_cnt + * sizeof(HdatMsArea *))); + + // Since we don't know what order mainstore areas and RAM + // areas were created, update the offset in the HdatMsArea + // child structure triple so it points to the first RAM area. + + l_currOffset = (iv_actMsAreaCnt - l_cnt) * l_msEntry->size() + + l_ramSizes; + l_msEntry->chgChildOffset(HDAT_MS_AREA_RAM_AREAS, l_currOffset); + l_msEntry->commit(l_data); + + // Now compute the size of the RAM areas associated with this + // mainstore area. These will have to be added to the child + // offset for the next mainstore area to skip over them. + l_ramSizes += l_msEntry->ramObjSizes(); + + l_cnt++; + } + + // Now the children (RAM areas) of each mainstore area must be committed + l_cnt = 0; + + while (l_cnt < iv_actMsAreaCnt) + { + l_msEntry = *(reinterpret_cast<HdatMsArea **>(reinterpret_cast<char *> + (iv_msAreaPtrs) + l_cnt + * sizeof(HdatMsArea *))); + l_msEntry->commitRamAreas(l_data); + l_cnt++; + } + } +} + +/******************************************************************************* +* hdatGetMaxMemConfiguredAddress +*******************************************************************************/ +uint64_t HdatMsVpd::hdatGetMaxMemConfiguredAddress() +{ + //For each processor in the system + TARGETING::PredicateCTM l_procChipPred(TARGETING::CLASS_CHIP, + TARGETING::TYPE_PROC); + + TARGETING::PredicateHwas l_predFunctional; + l_predFunctional.functional(true); + TARGETING::PredicatePostfixExpr l_functionalProc; + l_functionalProc.push(&l_procChipPred).push(&l_predFunctional).And(); + + TARGETING::TargetRangeFilter l_procs( + TARGETING::targetService().begin(), + TARGETING::targetService().end(), + &l_functionalProc); + + uint64_t l_maxBase = 0x0ull; + uint64_t l_maxMsAddress = 0x0ull; + bool l_processedAnyGroup = false; + uint64_t l_hdatMaxImtAddr = 0x0ull; + + for(;l_procs;++l_procs) + { + TARGETING::Target *l_pProcTarget = (*l_procs); + + TARGETING::ATTR_PROC_MEM_BASES_type l_procMemBases = {0}; + TARGETING::ATTR_PROC_MEM_SIZES_type l_procMemSizesBytes = {0}; + + assert(l_pProcTarget->tryGetAttr<TARGETING::ATTR_PROC_MEM_SIZES> + (l_procMemSizesBytes)); + + assert(l_pProcTarget-> + tryGetAttr<TARGETING::ATTR_PROC_MEM_BASES>(l_procMemBases)); + + //For each MCS + TARGETING::PredicateCTM l_allMcs(TARGETING::CLASS_UNIT, + TARGETING::TYPE_MCS); + TARGETING::PredicateHwas l_funcMcs; + l_funcMcs.functional(true); + TARGETING::PredicatePostfixExpr l_allFuncMcs; + l_allFuncMcs.push(&l_allMcs).push(&l_funcMcs).And(); + + TARGETING::TargetHandleList l_mcsList; + + TARGETING::targetService(). + getAssociated(l_mcsList, l_pProcTarget, + TARGETING::TargetService::CHILD, + TARGETING::TargetService::ALL, &l_allFuncMcs); + + for(uint32_t i=0; i < l_mcsList.size(); i++) + { + + TARGETING::Target *l_pMcsTarget = l_mcsList[i]; + + uint32_t l_mcsInGroup = 0; + if(!hdatFindGroupForMc(l_pProcTarget, + l_pMcsTarget, + l_mcsInGroup)) + { + //Skip this MC not part of any group + continue; + } + + if(!l_processedAnyGroup || + (l_procMemBases[l_mcsInGroup] > l_maxBase)) + { + l_maxBase = l_procMemBases[l_mcsInGroup]; + l_processedAnyGroup = true; + l_maxMsAddress = l_maxBase + l_procMemSizesBytes[l_mcsInGroup]; + } + } + + // TODO : RTC Story 159682 + // Further CHTM support needs to be added which contains the trace array + // for 24 cores + hdatMsAddr_t l_hdatNhtmStartAddr; + hdatMsAddr_t l_hdatNhtmEndAddr; + + TARGETING::ATTR_PROC_NHTM_BAR_BASE_ADDR_type l_nhtmStartAddr = + l_pProcTarget->getAttr<TARGETING::ATTR_PROC_NHTM_BAR_BASE_ADDR>(); + TARGETING::ATTR_PROC_NHTM_BAR_SIZE_type l_nhtmSize = + l_pProcTarget->getAttr<TARGETING::ATTR_PROC_NHTM_BAR_SIZE>(); + + if( 0 != l_nhtmSize ) + { + l_hdatNhtmStartAddr.hi = + (l_nhtmStartAddr & 0xFFFFFFFF00000000ull) >> 32; + l_hdatNhtmStartAddr.lo = l_nhtmStartAddr & 0x00000000FFFFFFFFull; + l_hdatNhtmStartAddr.hi |= HDAT_REAL_ADDRESS_MASK; + + l_nhtmSize = l_nhtmStartAddr + l_nhtmSize; + l_hdatNhtmEndAddr.hi = + (l_nhtmSize & 0xFFFFFFFF00000000ull) >> 32; + l_hdatNhtmEndAddr.lo = l_nhtmSize & 0x00000000FFFFFFFFull; + l_hdatNhtmEndAddr.hi |= HDAT_REAL_ADDRESS_MASK; + + if( l_hdatMaxImtAddr < + (((uint64_t)l_hdatNhtmEndAddr.hi << 32) |l_hdatNhtmEndAddr.lo)) + { + l_hdatMaxImtAddr = + (((uint64_t)l_hdatNhtmEndAddr.hi << 32) |l_hdatNhtmEndAddr.lo); + HDAT_INF("NHTM Max Addr: = 0x%016llX", l_hdatMaxImtAddr); + } + } + else + { + HDAT_INF("NHTM Bar size value = 0x%016llX ", l_nhtmSize); + } + } + // Set MSB to 1 for PHYP + l_maxMsAddress |= HDAT_REAL_ADDRESS_MASK64; + + if(l_hdatMaxImtAddr > l_maxMsAddress) + { + l_maxMsAddress = l_hdatMaxImtAddr; + HDAT_INF("IMT Max MS Addr: = 0x%016llX",l_maxMsAddress); + } + // We now have to subtract 1 since the address range starts at 0 + if(l_maxMsAddress != 0) + { + l_maxMsAddress -= 1; + } + + return l_maxMsAddress; +} + +//****************************************************************************** +//* hdatFindGroupForMc +//****************************************************************************** +bool HdatMsVpd::hdatFindGroupForMc(const TARGETING::Target *i_pProcTarget, + const TARGETING::Target *i_pMcsTarget, + uint32_t& o_groupOfMc) +{ + bool l_foundGroup = false; + TARGETING::ATTR_MSS_MEM_MC_IN_GROUP_type l_mcsGroups = {0}; + assert(i_pProcTarget != NULL || i_pMcsTarget != NULL); + + assert(!(i_pProcTarget->getAttr<TARGETING::ATTR_TYPE>() + != TARGETING::TYPE_PROC)|| + !(i_pProcTarget->getAttr<TARGETING::ATTR_CLASS>() + != TARGETING::CLASS_CHIP)); + + assert(i_pProcTarget-> + tryGetAttr<TARGETING::ATTR_MSS_MEM_MC_IN_GROUP>(l_mcsGroups)); + + assert(!(i_pMcsTarget->getAttr<TARGETING::ATTR_TYPE>() + != TARGETING::TYPE_MCS)|| + !(i_pMcsTarget->getAttr<TARGETING::ATTR_CLASS>() + != TARGETING::CLASS_UNIT)); + TARGETING::ATTR_CHIP_UNIT_type l_chipUnit = + i_pMcsTarget->getAttr<TARGETING::ATTR_CHIP_UNIT>(); + uint32_t l_sizeOfArray = sizeof(l_mcsGroups)/sizeof(l_mcsGroups[0]); + + assert(!(sizeof( l_mcsGroups[0] ) != sizeof(uint8_t))); + + + assert(!( l_chipUnit >= ( sizeof( l_mcsGroups[0] ) * HDAT_BITS_PER_BYTE ))); + + + const uint8_t MC_IN_GROUP_MCS_0 = 0x80; + for(uint32_t l_idx =0; l_idx < l_sizeOfArray;++l_idx) + { + //Attribute ATTR_MSS_MEM_MC_IN_GROUP is an array of bitmask + //bit 0 of bitmask corresponds to mcs 0, bit 7 to mcs7 + if((l_mcsGroups[l_idx] & (MC_IN_GROUP_MCS_0 >> l_chipUnit)) == + (MC_IN_GROUP_MCS_0 >> l_chipUnit)) + { + HDAT_INF("hdatFindGroupForMc::: Found group : %d",l_idx); + o_groupOfMc = l_idx; + l_foundGroup = true; + break; + } + } + + return l_foundGroup; +} +/******************************************************************************* +* hdatScanDimms +*******************************************************************************/ +errlHndl_t HdatMsVpd::hdatScanDimms(const TARGETING::Target *i_pTarget, + uint32_t i_mcaFruid, + std::list<hdatRamArea>& o_areas, + uint32_t& o_areaSize, + uint32_t& o_dimmNum, + bool& o_areaFunctional, + hdatMemParentType& o_parentType) +{ + errlHndl_t l_err = NULL; + + do + { + if(i_pTarget->getAttr<TARGETING::ATTR_TYPE>() != TARGETING::TYPE_MCS) + { + HDAT_ERR("Input Target is type not supported."); + break; + } + + TARGETING::ATTR_EFF_DIMM_SIZE_type l_dimSizes = {{0}}; + //Get configured memory size + if(!i_pTarget-> + tryGetAttr<TARGETING::ATTR_EFF_DIMM_SIZE>(l_dimSizes)) + { + HDAT_ERR("DIMM size should be available with MCS"); + } + + //for each MCA connected to this this MCS + TARGETING::PredicateCTM l_mcaPredicate(TARGETING::CLASS_UNIT, + TARGETING::TYPE_MCA); + + TARGETING::PredicateHwas l_predMca; + l_predMca.present(true); + TARGETING::PredicatePostfixExpr l_presentMca; + l_presentMca.push(&l_mcaPredicate).push(&l_predMca).And(); + TARGETING::TargetHandleList l_mcaList; + + // Get associated MCAs + TARGETING::targetService(). + getAssociated(l_mcaList, i_pTarget, + TARGETING::TargetService::CHILD_BY_AFFINITY, + TARGETING::TargetService::ALL, &l_presentMca); + + o_dimmNum = 0; + for (uint32_t i = 0; i < l_mcaList.size(); ++i) + { + + TARGETING::Target *l_pMcaTarget = l_mcaList[i]; + + //for each DIMM connected to this this MCA + TARGETING::PredicateCTM l_dimmPredicate(TARGETING:: + CLASS_LOGICAL_CARD, + TARGETING::TYPE_DIMM); + TARGETING::PredicateHwas l_predDimm; + l_predDimm.present(true); + TARGETING::PredicatePostfixExpr l_presentDimm; + l_presentDimm.push(&l_dimmPredicate).push(&l_predDimm).And(); + + TARGETING::TargetHandleList l_dimmList; + + // Get associated dimms + TARGETING::targetService(). + getAssociated(l_dimmList, l_pMcaTarget, + TARGETING::TargetService::CHILD_BY_AFFINITY, + TARGETING::TargetService::ALL, &l_presentDimm); + + + for(uint32_t j=0; j < l_dimmList.size(); ++j) + { + //fetch each dimm + TARGETING::Target *l_pDimmTarget = l_dimmList[j]; + + uint32_t l_dimmfru = 0; + l_dimmfru = l_pDimmTarget->getAttr<TARGETING::ATTR_FRU_ID>(); + + uint8_t l_mcaDimm = 0; + uint8_t l_mcaPort = 0; + TARGETING::ATTR_REL_POS_type l_dimmRelPos = 0; + + if(l_pDimmTarget-> + tryGetAttr<TARGETING::ATTR_REL_POS>(l_dimmRelPos)) + { + l_mcaDimm = l_dimmRelPos%2; //2 DIMMs per MCA + l_dimmRelPos = 0; + if(!l_pMcaTarget-> + tryGetAttr<TARGETING::ATTR_REL_POS>(l_dimmRelPos)) + { + HDAT_ERR("Attribute REL_POS in MCA is not " + "present"); + } + else + { + l_mcaPort = l_dimmRelPos%2; //2 MCAs per MCS + } + } + else + { + HDAT_ERR("Attribute REL_POS in DIMM " + "is not present"); + } + + //Convert GB to MB + uint32_t l_dimmSizeInMB = + l_dimSizes[l_mcaPort][l_mcaDimm] * HDAT_MB_PER_GB; + uint32_t l_huid = TARGETING::get_huid(l_pDimmTarget); + + + bool foundArea = false; + for (std::list<hdatRamArea>::iterator l_area = o_areas.begin(); + l_area != o_areas.end(); + ++l_area) + { + //we do not need to compare each dimm fru id with mca fru id + //to create ram area, by the below logic + //dimms with same fruid will fall into same ram area + //even if they have fru id same with mca + if (l_area->ivfruId == l_dimmfru)//this means soldered dimms + { + foundArea = true; + l_area->ivFunctional = (l_area)->ivFunctional || + isFunctional(l_pDimmTarget); + (l_area)->ivFunctional = true; + (l_area)->ivSize += l_dimmSizeInMB; + break; + } + } + + //Search in the list of RAM Areas if not + //present create a new ram area + if (!foundArea) + { + o_dimmNum++; + o_areas.push_back(hdatRamArea(l_huid, + isFunctional(l_pDimmTarget), + l_dimmSizeInMB,l_dimmfru)); + } + o_areaSize += l_dimmSizeInMB; + o_areaFunctional = o_areaFunctional || + isFunctional(l_pDimmTarget); + } + if(l_err != NULL) + { + //Break of error + break; + } + } + o_parentType = HDAT_MEM_PARENT_CEC_FRU; + + if(l_err != NULL) + { + //break if error + break; + } + } + while(0); + return l_err; +} +/******************************************************************************* +* hdatGetMaxMemoryBlocks +*******************************************************************************/ +errlHndl_t HdatMsVpd::hdatGetMaxMemoryBlocks(const TARGETING::Target *i_pTarget, + uint32_t &o_maxMemoryBlocks) +{ + errlHndl_t l_err = NULL; + do + { + //One Memctrl connected to only one membuf in P8 + o_maxMemoryBlocks = 1; + } + while(0); + return l_err; +} +} //namespace HDAT diff --git a/src/usr/hdat/hdatmsvpd.H b/src/usr/hdat/hdatmsvpd.H new file mode 100755 index 000000000..ade185b41 --- /dev/null +++ b/src/usr/hdat/hdatmsvpd.H @@ -0,0 +1,936 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hdat/hdatmsvpd.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 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 HDATMSVPD_H +#define HDATMSVPD_H + +/** + * @file hdatmsvpd.H + * + * @brief This file contains the class definition for the main store + * VPD object. + * + */ + +/*----------------------------------------------------------------------------*/ +/* Includes */ +/*----------------------------------------------------------------------------*/ +#include <stdint.h> // standard types +#include <hdat/hdat.H> // HDAT header type definitions +#include "hdathdif.H" // HdatHdif base class definition +#include "hdatmsarea.H" // HdatMsArea class definition +#include <errl/errlentry.H> // ErrlEntry class +#include <vpd/cvpdenums.H> +#include "hdatutil.H" + +namespace HDAT +{ + +/*----------------------------------------------------------------------------*/ +/* Constants */ +/*----------------------------------------------------------------------------*/ + +/** @brief eye catcher for the HDIF header for the mainstore VPD data area + */ +const char HDAT_MSVPD_STRUCT_NAME[] = "MS VPD"; +const uint32_t HDAT_NO_MEMORY = 0; +const uint32_t HDAT_MIN_NUM_FOR_SHARING = 2; +const uint32_t HDAT_BITS_PER_BYTE = 8; +const uint32_t HDAT_MB_PER_GB = 1024; +const uint32_t MAX_CHIP_EC_CNT_PER_MSAREA = 2; +const uint32_t HDAT_START_INSTANCE = 0; + + +/** @brief Structure version number + */ +const uint16_t HDAT_MS_VPD_VERSION = 0x24; + +/** @brief Other constants + */ +const uint16_t HDAT_MS_RHB_LABEL_LEN = 64; //Reserved HB length + +/** @enum hdatDataPtrs + * Constants for the internal data pointers that are added to the base class + */ +enum hdatMsVpdDataPtrs +{ + HDAT_MS_VPD_MAX_ADDR = 0, + HDAT_MS_VPD_MAX_SIZE = 1, + HDAT_MS_VPD_PAGE_MOVER = 2, + HDAT_MS_VPD_IMT_ADDR_RNG = 3, + HDAT_MS_VPD_UE_ADDR_RNG = 4, + HDAT_MS_VPD_HB_ADDR_RNG = 5, + HDAT_MS_VPD_LAST = 6 +}; + + +/** @enum hdatChildPtrs + * Constants for the child structure pointers that are added to the base + * class + */ +enum hdatMsVpdChildPtrs +{ + HDAT_MS_AREAS = 0, + HDAT_MS_CHILD_RESERVED1 = 1, + HDAT_MS_CHILD_LAST = 2 +}; + + +/*----------------------------------------------------------------------------*/ +/* Typedefs */ +/*----------------------------------------------------------------------------*/ + +/** +* @brief structure for RAM AREA Information +* +*/ +struct hdatRamArea +{ + uint32_t ivHuid; + bool ivFunctional; + uint32_t ivSize; + uint32_t ivfruId; + hdatRamArea(uint32_t i_huid, + bool status, + uint32_t dimmSize,uint32_t i_fruId) : + ivHuid(i_huid), + ivFunctional(status), + ivSize(dimmSize), + ivfruId(i_fruId) { + } +}; + +/** @brief Main store address information + */ +struct hdatMsVpdAddr_t +{ + hdatMsAddr_t hdatMaxAddr; // 0x0000 Maximum configured mainstore address + hdatMsAddr_t hdatMaxCcmAddr; // 0x0008 Maximum mainstore address that could + // be configured if memory is added with + // concurrent maintenance + uint32_t hdatMstSigAffntyDom; // 0x0010 The affinity domain considered + //most important when making affinity decisions + hdatMsAddr_t hdatMirrMemStartAddr;//0x0014 Mirrorable MemoryStarting Address +} __attribute__ ((packed)); + + +/** @brief Main store size information + */ +struct hdatMsVpdSize_t +{ + uint32_t hdatReserved1; // 0x0000 reserved to make hdatTotSize 8 bytes + // in future + uint32_t hdatTotSize; // 0x0004 Total configured mainstore size in + // mega-bytes +} __attribute__ ((packed)); + + +/** @brief Page mover information + */ +struct hdatMsVpdPageMover_t +{ + uint32_t hdatFlags; // 0x0000 Flags + uint32_t hdatLockCnt; // 0x0004 Count of hardware locks per page + hdatMsAddr_t hdatLockAddr; // 0x0008 Hardware lock address + hdatMsAddr_t hdatMoverAddr; // 0x0010 Page mover address + hdatMsAddr_t hdatBSRAddr; // 0x0018 Barrier sync register address + hdatMsAddr_t hdatXSCOMAddr; // 0x0020 address of XSCOM address range +} __attribute__ ((packed)); + + +/** @brief In Memory Trace address range array element information + */ +struct hdatMsVpdImtAddrRange_t +{ + hdatMsAddr_t hdatImtAddrRngStrAddr; // 0x0000 Range starting address + hdatMsAddr_t hdatImtAddrRngEndAddr; // 0x0008 Range ending address+1 +} __attribute__ ((packed)); + + +/** @brief In UE address range array element information - added for bi01 + */ +struct hdatMsVpdUEAddrRange_t +{ + hdatMsAddr_t hdatUEAddr; // 0x0000 UE area starting address +} __attribute__ ((packed)); + +/** @brief In Reserved Hostboot Memory iaddress range array element information- + */ +struct hdatMsVpdRhbAddrRange_t +{ + uint32_t hdatDbobID; // 0x0000 Node instance + // number + hdatMsAddr_t hdatRhbAddrRngStrAddr; // 0x0004 Range starting + // address + hdatMsAddr_t hdatRhbAddrRngEndAddr; // 0x000C Range ending + // address+1 + uint32_t hdatRhbLabelSize; // 0x0014 Label size + uint8_t hdatRhbLabelString[HDAT_MS_RHB_LABEL_LEN];// 0x0019 Label string Ptr +} __attribute__ ((packed)); + + +struct hdatMsVpd_t +{ + hdatMsVpdAddr_t hdatMsAddr; + hdatMsVpdSize_t hdatMsSize; + hdatMsVpdPageMover_t hdatPageMover; + hdatMsVpdImtAddrRange_t hdatImtAddrRange; + hdatMsVpdUEAddrRange_t hdatUEAddrRange; + hdatMsVpdRhbAddrRange_t hdatRhbAddrRange; +}__attribute__ ((packed)); +/*----------------------------------------------------------------------------*/ +/* Constants */ +/*----------------------------------------------------------------------------*/ + +/* @enum hdatMsAreaStatus + * Status of an MS area. + */ +enum hdatMsAreaStatus +{ + HDAT_MEM_INSTALLED = 0x8000, // DIMMs are installed + HDAT_MEM_FUNCTIONAL = 0x4000, // DIMMs are functional + HDAT_MEM_SHARED = 0x2000 // Memory is shared +}; + +/* @enum hdatRamStatus + * Status of a RAM FRU. + */ +enum hdatRamStatus +{ + HDAT_RAM_NOT_INSTALLED = 0x0000, // RAM is NOT installed + HDAT_RAM_INSTALLED = 0x8000, // RAM is installed + HDAT_RAM_FUNCTIONAL = 0x4000 // RAM is functional +}; + +/* @enum hdatMemParentType + * + */ +enum hdatMemParentType +{ + HDAT_MEM_PARENT_RISER = 0x8000, // RISER card + HDAT_MEM_PARENT_MEMCARD = 0x4000, // Memory card + HDAT_MEM_PARENT_CEC_FRU = 0x2000, // Other CEC FRU + HDAT_MEM_PARENT_HYB_RISER = 0x1000, // Hybrid RISER card +}; + +/* @enum hdatBsrMode + * + */ +enum hdatBsrMode +{ + HDAT_BSR_16_BYTE = 0x00000000, // 16 byte BSR mode + HDAT_BSR_64_BYTE = 0x02000000, // 64 byte BSR mode + HDAT_BSR_128_BYTE = 0x04000000, // 128 byte BSR mode + + // P7 values + HDAT_BSR_1M_BYTE = 0x00000000, // 1MB BSR mode + HDAT_BSR_2M_BYTE = 0x02000000, // 2MB BSR mode + HDAT_BSR_4M_BYTE = 0x04000000, // 4MB BSR mode + HDAT_BSR_8M_BYTE = 0x06000000 // 8MB BSR mode +}; + + + + +/*----------------------------------------------------------------------------*/ +/* C++ class definition */ +/*----------------------------------------------------------------------------*/ + +/** Begin Class Description + * + * @brief The HdatMsVpd class is used to construct a main store VPD object. + * + * Description: This class defines a specialized object. It is not intended + * that any component can create an object of this type. + * In particular,the object is built only in the CEC Server process + * when requested by the hdat component. And only 1 HdatMsVpd + * object can be built.These restrictions are not checked or + * enforced by HDAT. + * + * The real purpose of the object is to create the main store + * VPD structure as defined by the PHYP Initialization + * architecture. This data structure is eventually DMA'd to + * main memory. The class is not defined to be a general purpose + * interface for building this object by anyone other than the + * CEC Server process. + * + * Contained within the mainstore VPD object are mainstore area + * objects and RAM objects. + * + * Thread safety: An HdatMsVpd object is not thread safe. That is, a single + * object cannot be shared and used concurrently by multiple + * threads at the same time. In fact, an object interface is + * used only as a better way to built a flat structure to DMA + * to main memory. + * + * Signal handler usage: This class is not intended to be used in a signal + * handler and nothing has been done to try and make it safe + * to use in a signal handler. + * + * End Class Description + */ +class HdatMsVpd : public HdatHdif +{ + public: + + /** + * @brief Construct an HdatMsVpd object. + * + * This is the constructor for the HdatMsVpd object. + * + * If you are constructing this object on the heap by using new, then + * you must check the pointer returned from new to see if it is null. + * If it is null, new failed to allocate storage and the constructor + * was not called. If it is not null, then you must check o_errlHndl + * to see if the constructor ran successfully. If o_errlHndl indicates + * an error was reported by the constructor, new has already allocated + * heap storage and the object must be deleted in order to free the + * heap storage. + * + * @pre None + * + * @post An HdatMsVpd object has been constructed.Heap storage has been + * allocated. + * + * @param[out] o_errlHndl - If any errors occur, the HdatMsVpd object + * is NOT constructed and errors are returned in + * this parameter + * @param[in] i_msAddr - The main memory address that the main + * store VPD structure will be DMA'd to. + * + * @return A null error log handle if successful, else the return code + * pointed to by o_errlHndl. + * + */ + HdatMsVpd(errlHndl_t &o_errlHndl,const hdatMsAddr_t &i_msAddr); + + /** + * @brief HdatMsVpd object destructor + * + * This is the destructor for an HdatMsVpd object. Any heap storage + * allocated for the object is dallocated. + * + * @pre No preconditions exist + * + * @post The HdatMsVpd object has been destroyed and can no longer be + * used. + * + */ + virtual ~HdatMsVpd(); + + /** + * @brief Update the mainstore VPD to specify a memory address range for + * the In Memory Trace tool. More than one address range can be added. + * + * @post An address range entry has been added. + * + * @param[in] i_start - The starting address of the range + * @param[in] i_end - The ending address of the range + 1 + * + * @return A null error log handle if successful, else the return code + * pointed to by o_errlHndl contains one of: + * + * @retval HDAT_ARRAY_ERROR + */ + errlHndl_t addIMTAddrRange(hdatMsAddr_t &i_start, + hdatMsAddr_t &i_end); + + /** + * @brief Update the mainstore VPD to specify a memory address range for + * UE areas. More than one address range can be added. Added for + * bi01. + * + * @post An address range entry has been added. + * + * @param[in] i_addr - The starting address of the range + * + * @return A null error log handle if successful, else the return code + * pointed to by o_errlHndl contains one of: + * + * @retval HDAT_ARRAY_ERROR + */ + errlHndl_t addUEAddrRange(hdatMsAddr_t &i_addr); + + /** + * @brief Update the mainstore VPD to specify a memory address range for + * host boot reserver. + * + * @post An address range entry has been added. + * + * @param[in] i_dbobId - DBOB ID + * @param[in] i_start - The starting address of the range + * @param[in] i_end - The end address of the range + * @param[in] i_labelSize - RHB Label Size + * @param[in] i_labelStringPtr - RHB Label String + * + * @return A null error log handle if successful, else the return code + * pointed to by o_errlHndl contains one of: + * + * @retval HDAT_ARRAY_ERROR + */ + + errlHndl_t addRHBAddrRange( uint32_t i_dbob_id, hdatMsAddr_t &i_start, + hdatMsAddr_t &i_end, uint32_t i_labelSize, + uint8_t* &i_labelStringPtr); + + /** + * @brief Update the mainstore VPD with Barrier Synchronization Register + * information + * + * Note: If the Barrier Synchronization Register is NOT enabled, this + * method does not have to be called. + * + * @pre None + * + * @post None + * + * @param[in] i_bsrAddr - Address of memory mapped BSR + * @param[in] i_bsrMode - Mode the BSR is initialized to + */ + void setBSR(const hdatMsAddr_t &i_bsrAddr, + hdatBsrMode i_bsrMode = HDAT_BSR_128_BYTE); + + + /** + * @brief Update the mainstore VPD with address of XSCOM + * + * Note: If the XSCOM address is NOT supported, this + * method does not have to be called. + * + * @pre None + * + * @post None + * + * @param[in] i_xscomAddr - Address of XSCOM address range + */ + void setXSCOM(const hdatMsAddr_t &i_xscomAddr); + + + /** + * @brief Add a main store area FRU. + * + * Each main store area FRU which contains memory must be added to the + * HdatMsVpd object. This method adds information about the FRU. + * + * @pre One cannot add any more mainstore area FRUs than was specified + * by the i_msAreaCnt parameter on the HdatMsVpd constructor. + * + * @post A main store area FRU has been added to the object. + * Heap storage has been allocated. + * + * @param[in] i_resourceId - The FRU's resource id + * @param[in] i_msAreaId - A unique id for each main store area + * associated with a mainstore VPD object. The id starts at + * 0 and is incremented by 1 for each new + * mainstore area. + * @param[in] i_ramCnt - The number of RAM objects that will be + * added to the mainstore area. If an exact count + * cannot be computed, a maximum number can be + * provided. + * @param[in] i_chipEcCnt - The number of EC entries that will be + * added to the mainstore area. If an exact count cannot be + * computed, a maximum number can be provided. + * @param[in] i_addrRngCnt - The number of address range entries that + * will be added to the mainstore area. If an + * exact count cannot be computed, a maximum + * number can be provided. + * + * @return A null error log handle if successful, else the return code + * pointed to by errlHndl_t contains one of: + * + * @retval HDAT_ALLOC_ERROR + * @retval HDAT_ARRAY_ERROR + */ + errlHndl_t addMsAreaFru(uint32_t i_resourceId, + uint32_t i_slcaIndex, + TARGETING::Target * i_target, + uint16_t i_msAreaId, + uint32_t i_ramCnt, + uint32_t i_chipEcCnt, + uint32_t i_addrRngCnt); + + + /** + * @brief Update the mainstore area to specify the type of memory. + * + * @pre The i_msAreaId parameter must be for a valid mainstore area that + * was added with the addMsAreaFru() method. HDAT does not check or + * enforce that this is a valid main store area ID. + * + * @post None + * + * @param[in] i_msAreaId - A unique id for each main store area + * associated with a mainstore VPD object. The id + * identifies the mainstore area that is to be + * updated. + * @param[in] i_type - This specifies the type of memory card + * for this mainstore area. + */ + void setMsAreaType(uint16_t i_msAreaId, + hdatMemParentType i_type); + + + /** + * @brief Update the mainstore area to specify the status of the memory + * DIMMS + * + * @pre The i_msAreaId parameter must be for a valid mainstore area that + * was added with the addMsAreaFru() method.HDAT does not check or + * enforce that this is a valid main store area ID. + * + * @post None + * + * @param[in] i_msAreaId - A unique id for each main store area + * associated with a mainstore VPD object. The id + * identifies the mainstore area that is to be updated. + * @param[in] i_status - See the hdatMsAreaStatus enum. The value + * specified here can be a bitwise OR of the enum + * values. + */ + void setMsAreaStat(uint16_t i_msAreaId, + uint16_t i_status); + + + /** + * @brief Update the mainstore area with an id for interleaved memory + * + * @pre The i_msAreaId parameter must be for a valid mainstore area that + * was added with the addMsAreaFru() method.HDAT does not check or + * enforce that this is a valid main store area ID. + * + * @post None + * + * @param[in] i_msAreaId - A unique id for each main store area + * associated with a mainstore VPD object. The id + * identifies the mainstore area that is to be updated + * @param[in] i_id - An identifier from 0 to N which is the same + * for each MS area which is interleaved. In + * addition, the HDAT_MEM_SHARED status attribute + * must have been used for this + * MS area when setMsAreaStat() was called. + */ + void setMsAreaInterleavedId(uint16_t i_msAreaId, + uint16_t i_id); + + + /** + * @brief Update the mainstore area to specify the total size of the + * mainstore area. + * + * @pre The i_msAreaId parameter must be for a valid mainstore area that + * was added with the addMsAreaFru() method. HDAT does not check or + * enforce that this is a valid main store area ID. + * + * @post None + * + * @param[in] i_msAreaId - A unique id for each main store area + * associated with a mainstore VPD object. The id + * identifies the mainstore area that is to be + * updated. + * @param[in] i_size - The total size of the configured mainstore + * area in megabytes. It is the (high address of + * the mainstore area + 1 minus the low address of + * the mainstore area) divided by 1 megabyte. + */ + void setMsAreaSize(uint16_t i_msAreaId, + uint32_t i_size); + + + /** + * @brief Update the mainstore area to specify associated processor id + * + * @pre The i_msAreaId parameter must be for a valid mainstore area that + * was added with the addMsAreaFru() method. HDAT does not check or + * enforce that this is a valid main store area ID. + * + * @post None + * + * @param[in] i_msAreaId - A unique id for each main store area + * associated with a mainstore VPD object. + * The id identifies the mainstore area that is + * to be updated. + * @param[in] i_moduleId - The Module Id of the processor + * associated with this mainstore area. + */ + void setMsAreaModuleId(uint16_t i_msAreaId, + uint32_t i_moduleId); + + + /** + * @brief Update the mainstore area to specify the affinity domain + * + * @pre The i_msAreaId parameter must be for a valid mainstore area that + * was added with the addMsAreaFru() method. HDAT does not check or + * enforce that this is a valid main store area ID. + * + * @post None + * + * @param[in] i_msAreaId - A unique id for each main store area + * associated with a mainstore VPD object. + * The id identifies the mainstore area that is + * to be updated. + * @param[in] i_affinityDomain - The affinity domain + * associated with this mainstore area. + */ + void setMsAreaAffinityDomain(uint16_t i_msAreaId, + uint32_t i_affinityDomain); + + + /** + * @brief Update the mainstore area to specify the memory address range + * More than one address range can be added. + * + * @pre The i_msAreaId parameter must be for a valid mainstore area that + * was added with the addMsAreaFru() method. HDAT does not check or + * enforce that this is a valid main store area ID. + * + * @post None + * + * @param[in] i_msAreaId - A unique id for each main store area + * associated with a mainstore VPD object. The id + * identifies the mainstore area that is to be + * updated. + * @param[in] i_start - The starting address of the range + * @param[in] i_end - The ending address of the range + 1 + * @param[in] i_procChipId - which is the chip id of the physical + * processor + * @param[in] i_rangeIsMirrorable - Specifies whether the range is + * mirrorable + * @param[in] i_mirroringAlgorithm - Specifies hardware mirroring + * algorithm to use + * @param[in] i_startMirrAddr - Specifies the starting mirrorable + * address for range + * + * @return A null error log handle if successful, else the return code + * pointed to by errlHndl_t contains one of: + * + * @retval HDAT_ARRAY_ERROR + */ + errlHndl_t addMsAreaAddr(uint16_t i_msAreaId, + hdatMsAddr_t &i_start, + hdatMsAddr_t &i_end, + uint32_t i_procChipId, + bool i_rangeIsMirrorable = false, + uint8_t i_mirroringAlgorithm = 0, + uint64_t i_startMirrAddr = 0); + + + /** + * @brief Add engineering change information for memory interface chips + * + * @pre The first EC entry added must be for the memory controller. + * HDAT has no way of validating or enforcing this so it is up to the + * user of the method to do this correctly. + * + * The i_msAreaId parameter must be for a valid mainstore area that + * was added with the addMsAreaFru() method.HDAT does not check or + * enforce that this is a valid main store area ID. + * + * @post One cannot add any more engineering change entries than was + * specified by the i_chipEcCnt parameter on the addMsAreaFru method. + * + * @param[in] i_msAreaId -A unique id for each main store area + * associated with a mainstore VPD object. The id + * identifies the mainstore area that is to be + * updated. + * @param[in] i_manfId - Chip's manufacturing id + * @param[in] i_ecLvl - Chip's engineering change level + * + * @return A null error log handle if successful, else the return code + * pointed to by errlHndl_t contains one of: + * + * @retval HDAT_ARRAY_ERROR + */ + errlHndl_t addEcEntry(uint16_t i_msAreaId, + uint32_t i_manfId, + uint32_t i_ecLvl); + + + /** + * @brief Add a RAM area FRU. + * + * After a mainstore area has been added to the mainstore VBPD object, + * one or more RAM FRUs must be added to the mainstore area. + * + * @pre A mainstore area must have been previously created so this RAM + * area can be added to it. + * + * The i_msAreaId parameter must be for a valid mainstore area that + * was added with the addMsAreaFru() method. HDAT does not check + * or enforce that this is a valid main store area ID. + * + * @post A RAM card's VPD definiton has been added to the object. Heap + * storage has been allocated. + * + * @param[in] i_msAreaId - The id of the mainstore area this + * RAM is associated with + * @param[in] i_resourceId - VPD resource ID for the RAM FRU. + * @param[in] i_slcaIndex - SLCA index of ms area + * @param[in] i_ramId - RAM area identifier; a number from 0 to N + * @param[in] i_status - staus of the DIMMS and is the bitwise OR of + * values from hdatRamStatus defined above + * @param[in] i_size -the total size of configured mainstore in this + * RAM area + * + * @return A null error log handle if successful, else the return code + * pointed to by errlHndl_t contains one of: + * + * @retval HDAT_ALLOC_ERROR + * @retval HDAT_ARRAY_ERROR + */ + errlHndl_t addRamFru(uint16_t i_msAreaId, + TARGETING::Target * i_target, + uint32_t i_resourceId, + uint32_t i_slcaIndex, + uint16_t i_ramId, + uint16_t i_status, + uint32_t i_size); + /** + * @brief Initialization of HdatMsVpd object. + * + * If you are constructing this object on the heap by using new, then + * you must check the pointer returned from new to see if it is null. + * If it is null, new failed to allocate storage and the constructor + * was not called. If it is not null, then you must check o_errlHndl + * to see if the constructor ran successfully. If o_errlHndl indicates + * an error was reported by the constructor, new has already allocated + * heap storage and the object must be deleted in order to free the + * heap storage. + * + * @pre None + * + * @post An HdatMsVpd object has been initialized. Heap storage has + * been allocated. + * + * @param[in] i_maxMsAddr - maximum configured main store address + * @param[in] i_maxMsCcmAddr - maximum main store address that could be + * configured if memory was added with + * concurrent maintenance.If concurrent + * maintenance cannot be performed on this + * machine,this parameter has the same value as + * i_maxMsAddr. + * @param[in] i_msSize - total size of configured main store in + * mega-bytes. (number of mega-bytes from lowest + * main store address to highest main store + * address minus the number of mega-bytes of a + * ddress holes) + * @param[in] i_msAreaCnt The count of the number of main store areas + * that will be defined by using the + * addMsAreaFru() method below.If the actual + * count cannot be derived when this object is + * constructed, a maximum count can be supplied. + * @param[in] i_MostSigAffinityDomain -most significant affinity domain. + * The affinity domain considered most important + * when making affinity decisions. The value is + * model dependent. + * @param[in] i_ueAreaCnt - Maximum number of UE Address ranges + * @param[in] i_MirrMemStartAddr - The address of the start of + * mirrorable memory + * + */ + void hdatInit(hdatMsAddr_t &i_maxMsAddr, + hdatMsAddr_t &i_maxMsCcmAddr, + uint32_t i_msSize, + uint32_t i_msAreaCnt, + uint32_t i_MostSigAffinityDomain, + uint32_t i_ueAreaCnt, + uint64_t i_MirrMemStartAddr); + + /** + * @brief Gather MS data for HDAT + * @par Description: + * This function collects various MS attributes and fills MS Data area + * + * @param[in] o_size - total size written + * @param[in] o_count - total count of ms vpd instance + * + * @return A null error log handle if successful, else the return code + * pointed to by o_errlHndl contains one of: + * + * @retval HDAT_ARRAY_ERROR + */ + errlHndl_t hdatLoadMsData(uint32_t &o_size, uint32_t &o_count); + + /** + * @brief Gets maximum configured memory address + * + * + * @return value of ms address + */ + uint64_t hdatGetMaxMemConfiguredAddress(); + + /** + * @brief Fetches the group of MC + * + * @param[in] i_pTarget Proc target + * @param[in] i_pMcsTarget MCS target + * @param[out] o_groupOfMc MC group value + * + * @return Success or failure + */ + bool hdatFindGroupForMc(const TARGETING::Target *i_pProcTarget, + const TARGETING::Target *i_pMcsTarget, + uint32_t& o_groupOfMc); + + /** + * @brief Get the DIMMS list present on the system + * + * @param[in] i_pTarget Mcs target + * @param[in] i_membufFruid - membuf fruid decides the parent type + * @param[out] o_areas list of ram area structure based on the DIMM + * present. + * @param[out] o_areaSize - Total DIMM size + * @param[out] o_dimmNum - Total DIMM number + * @param[out] o_areaFunctional - DIMM functional status + * @param[out] o_parentType - memory parent type based on whether + * the dimms are pluggable or soldered + * + * @return A null error log handle if successful, else the return the + * error handle + */ + errlHndl_t hdatScanDimms(const TARGETING::Target *i_pTarget, + uint32_t i_membufFruid, + std::list<hdatRamArea>& o_areas, + uint32_t& o_areaSize, + uint32_t& o_dimmNum, + bool& o_areaFunctional, + hdatMemParentType& i_parentType); + + /** + * @brief Get max memory blocks connected to membuf + * + * @param[in] i_pTarget Mcs target + * @param[out] o_maxMemoryBlocks - max memory block value + * + * @return A null error log handle if successful, else the return the + * error handle + */ + errlHndl_t hdatGetMaxMemoryBlocks(const TARGETING::Target *i_pTarget, + uint32_t &o_maxMemoryBlocks); + + /** + * @brief Write the data to Mainstore area space + * + * @param[in] i_addr - MS address + * @param[in] i_size - total size to be written + * + */ + void commit(void * i_addr,uint32_t i_size); + + /** + * @brief Get total size of MS data to be written + * + * @param[out] o_size - total size value + * + */ + void getTotalSize(uint32_t &o_size); + + /** + * @brief Print an HdatMsVpd object. + * + * This method is a debug mthod which prints out a mainstore VPD object. + * + * @pre None + * + * @post None + * + */ + void prt(); + + protected: + + /** + * @brief After all MS area objects have been created, this routine must + * be called to see if they are all the same size.If they are not, the + * smaller one(s) will be adjusted with padding so they are all + * the same size. + * + * This is required because PHYP traverses through the MS areas + * as entries in an array. + * + * @pre All MS area objects must have been created + * + * @post Some objects' size may be adjusted + * + */ + void adjustMsAreaObjects(); + + + private: + + + /** Object Instance Data + * + * @li iv_msAddr - main memory address the final data structure is + * DMA'd to + * @li iv_actMsAreaCnt - actual count of main store areas that are added + * @li iv_maxMsAreaCnt - maximum count of main store areas that can be + * added + * @li iv_maxAddr - maximum main store addresses + * @li iv_maxSize - maximum main store size + * @li iv_mover - page mover information + * @li iv_msAreaPtrs - ptr to one or more ptrs which in turn point to + * HdatMsArea objects + * @li iv_IMTaddrRngArrayHdr - In memory trace address range header + * @li iv_IMTaddrRangeArray - In memory trace address range array + * @li iv_UEaddrRngArrayHdr - UE address range header + * @li iv_UEaddrRangeArray - UE address range array + * @li iv_maxUEAddrRngCnt - Max UE address range count + * @li iv_RHBaddrRngArrayHdr - Reserved host boot address range header + * @li iv_RHBaddrRangeArray - Reserved host boot address range array + * @li iv_maxRHBAddrRngCnt - Max RHB address range count + * @li iv_virtAddr - virtual address + */ + hdatMsAddr_t iv_msAddr; + uint32_t iv_actMsAreaCnt; + uint32_t iv_maxMsAreaCnt; + hdatMsVpdAddr_t iv_maxAddr; + hdatMsVpdSize_t iv_maxSize; + hdatMsVpdPageMover_t iv_mover; + HdatMsArea **iv_msAreaPtrs; + hdatHDIFDataArray_t iv_IMTaddrRngArrayHdr; + hdatMsVpdImtAddrRange_t *iv_IMTaddrRangeArray; + uint32_t iv_maxIMTAddrRngCnt; + hdatHDIFDataArray_t iv_UEaddrRngArrayHdr; + hdatMsVpdUEAddrRange_t *iv_UEaddrRangeArray; + uint32_t iv_maxUEAddrRngCnt; + hdatHDIFDataArray_t iv_RHBaddrRngArrayHdr; + hdatMsVpdRhbAddrRange_t *iv_RHBaddrRangeArray; + uint32_t iv_maxRHBAddrRngCnt; + void *iv_virtAddr; + + + /** Class (static) Data + * + * Only one copy of this data exists in a process. + * + * @li cv_actualCnt - a count of how many HdatMsVpd objects are created + */ + static uint32_t cv_actualCnt; + +}; // end of HdatMsVpd class + +} + +#endif // HDATMSVPD_H diff --git a/src/usr/hdat/hdatnaca.C b/src/usr/hdat/hdatnaca.C new file mode 100644 index 000000000..6ad0e9307 --- /dev/null +++ b/src/usr/hdat/hdatnaca.C @@ -0,0 +1,228 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hdat/hdatnaca.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 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 */ +#include <hdat/hdatnaca.H> +#include "hdatspiraH.H" +#include <hdat/hdat.H> +#include "hdatspiraS.H" +#include "hdatutil.H" +#include <sys/mm.h> +#include <sys/mmio.h> +#include <targeting/common/util.H> +#include <initservice/initserviceif.H> + +using namespace TARGETING; + +namespace HDAT +{ +extern trace_desc_t *g_trac_hdat; + +errlHndl_t hdatGetNacaFromMem(hdatNaca_t &o_naca) +{ + HDAT_ENTER(); + errlHndl_t l_errl = NULL; + void* l_virtualAddress = NULL; + do + { + // Get Target Service, and the system target. + TargetService& l_targetService = targetService(); + TARGETING::Target* l_sysTarget = NULL; + (void) l_targetService.getTopLevelTarget(l_sysTarget); + + assert(l_sysTarget != NULL); + + uint64_t l_hrmor = l_sysTarget->getAttr<ATTR_PAYLOAD_BASE>() * MEGABYTE; + + // Mapping the uncompressed region. HDAT areas are at the hrmor address + // + the naca offset so we are reading the entire area of 256 MB. + l_virtualAddress = mm_block_map(reinterpret_cast<void*>(l_hrmor), + l_hrmor ); + + // Reading the data at hrmor + Naca offset + hdatNaca_t* l_naca = reinterpret_cast<hdatNaca_t*>( + reinterpret_cast<uint64_t>(l_virtualAddress) + + HDAT_NACA_OFFSET); + + if( l_naca == NULL) + { + /*@ + * @errortype + * @moduleid HDAT::MOD_NACA_GET_MEM + * @reasoncode HDAT::RC_INVALID_NACA + * @devdesc map a mapped region failed + * @custdesc Firmware encountered an internal error. + */ + hdatBldErrLog(l_errl, + MOD_NACA_GET_MEM, + RC_INVALID_NACA, + 0,0,0,0, + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + HDAT_VERSION1, + true); + break; + } + + memcpy(&o_naca, l_naca, sizeof(hdatNaca_t)); + }while(0); + + if ( l_virtualAddress != NULL ) + { + int rc = 0; + rc = mm_block_unmap(l_virtualAddress); + if( rc != 0) + { + + errlHndl_t l_errl = NULL; + /*@ + * @errortype + * @moduleid HDAT::MOD_NACA_GET_MEM + * @reasoncode HDAT::RC_DEV_MAP_FAIL + * @devdesc Unmap a mapped region failed + * @custdesc Firmware encountered an internal error. + */ + hdatBldErrLog(l_errl, + MOD_NACA_GET_MEM, + RC_DEV_MAP_FAIL, + 0,0,0,0, + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + HDAT_VERSION1, + true); + } + } + return l_errl; +} + +/**************************************************************/ +//hdatGetCpuCtrlFromMem +/**************************************************************/ + +void hdatGetCpuCtrlFromMem(hdatMsAddr_t i_msAddr, uint32_t i_size) +{ + HDAT_ENTER(); + hdatMsAddr_t l_addr; + hdatCpuCtrlArea_t l_cpuCtrl; + hdatSvcRoutines_t l_svcRtn; + + uint64_t l_baddr = ((uint64_t) i_msAddr.hi << 32) | i_msAddr.lo; + + memcpy(&l_cpuCtrl, &l_baddr,i_size); + + TRACFBIN(g_trac_hdat,"Read Cpu Ctrl area",&l_cpuCtrl,i_size); + + l_addr.hi = l_cpuCtrl.hdatSR[HDAT_SVC_RTNS].hdatSsrPtr.hi; + l_addr.lo = l_cpuCtrl.hdatSR[HDAT_SVC_RTNS].hdatSsrPtr.lo; + + l_baddr = ((uint64_t) l_addr.hi << 32) | l_addr.lo; + + memcpy(&l_svcRtn,&l_baddr,sizeof(hdatSvcRoutines_t)); + + TRACFBIN(g_trac_hdat,"Read Svc Routine Area",&l_svcRtn, + sizeof(hdatSvcRoutines_t)); + + HDAT_EXIT(); +} + +/**************************************************************/ +//call_hdat_steps +/**************************************************************/ +void * call_hdat_steps( void *io_pArgs ) +{ + HDAT_ENTER(); + + errlHndl_t l_errlHndl=NULL; + hdatMsAddr_t i_msAddr,l_cpuAddr; + hdat5Tuple_t l_spirasHostEntry, l_spirhCpuCtrlEntry; + do { + + //true => FSP present. OR ! running on PHYP mode + if(INITSERVICE::spBaseServicesEnabled() || !(is_phyp_load())) + { + break; + } + + hdatNaca_t l_naca; + l_errlHndl = hdatGetNacaFromMem(l_naca); + + if ( l_errlHndl ) + { + HDAT_ERR("could not get NACA from memory"); + l_errlHndl->addFFDC(HDAT_COMP_ID,AT,sizeof(AT), + HDAT_VERSION1,HDAT_NACA_FFDC_SUBSEC1); + break; + } + + i_msAddr.lo = l_naca.nacaOpalMasterThreadEntry.lo; + i_msAddr.hi = l_naca.nacaOpalMasterThreadEntry.hi; + + HDAT_DBG("creating SPIRA-H with address hi=%x, lo=%x", + i_msAddr.hi,i_msAddr.lo); + HdatSpiraH l_spirah(l_errlHndl, i_msAddr); + + l_spirah.getSpiraHEntry(HDAT_SEC_CPU_CTRL,l_spirhCpuCtrlEntry); + l_cpuAddr.hi = l_spirhCpuCtrlEntry.hdatAbsAddr.hi; + l_cpuAddr.lo = l_spirhCpuCtrlEntry.hdatAbsAddr.lo; + + HDAT_DBG("CPU controls structures at 0x%08x",l_cpuAddr.lo); + hdatGetCpuCtrlFromMem(l_cpuAddr,sizeof(hdatCpuCtrlArea_t)); + + //add for dump header later + + l_spirah.getSpiraHEntry(HDAT_SEC_HOST_DATA_AREA,l_spirasHostEntry); + HDAT_DBG("got spiras addrss from SPIRAH hi=%x,lo=%x", + l_spirasHostEntry.hdatAbsAddr.hi, + l_spirasHostEntry.hdatAbsAddr.lo); + HDAT_DBG("creating all data areas through spiras"); + + + HDAT_DBG("l_spirasHostEntry.hdatAbsAddr.lo=0x%x", + l_spirasHostEntry.hdatAbsAddr.lo); + + HdatSpiraS l_spiras (l_spirasHostEntry.hdatAbsAddr); + + uint32_t l_hostAreaCnt=0, l_hostAreaSize=0; + + l_errlHndl = l_spiras.loadDataArea(l_spirasHostEntry, + l_hostAreaCnt,l_hostAreaSize); + HDAT_DBG("got back total size from spiras=0x%x",l_hostAreaSize); + + if ( l_errlHndl ) + { + HDAT_ERR("could not create all data areas"); + l_errlHndl->addFFDC(HDAT_COMP_ID,AT,sizeof(AT), + HDAT_VERSION1,HDAT_NACA_FFDC_SUBSEC2); + break; + } + + l_spirah.chgSpiraHEntry(HDAT_SEC_HOST_DATA_AREA, + l_hostAreaCnt,l_hostAreaSize); + + HDAT_DBG("loaded all data areas successfully"); + + }while(0); + + HDAT_EXIT(); + return NULL; +} + +} //namespace HDAT diff --git a/src/usr/hdat/hdatnodedata.C b/src/usr/hdat/hdatnodedata.C new file mode 100755 index 000000000..6e735b9f4 --- /dev/null +++ b/src/usr/hdat/hdatnodedata.C @@ -0,0 +1,144 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hdat/hdatnodedata.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 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 hdatnodedata.C + * + * @brief This file contains the implementation of the HdatNodedata class. + * + */ + +/*-----------------------------------------------------------------------------*/ +/* Includes */ +/*-----------------------------------------------------------------------------*/ + +#include <stdlib.h> // malloc & free +#include <sys/mm.h> +#include <sys/mmio.h> +#include <util/align.H> +#include "hdatnodedata.H" // HdatNodedata class definition +#include "hdathdif.H" +#include "hdatutil.H" +#include "hdatvpd.H" +#include <targeting/common/util.H> + +using namespace HDAT; +namespace HDAT +{ +/*-----------------------------------------------------------------------------*/ +/* Global variables */ +/*-----------------------------------------------------------------------------*/ +extern trace_desc_t *g_trac_hdat; +uint32_t HdatNodedata::cv_actualCnt; + +/** @brief See the prologue in hdatnodedata.H + */ +HdatNodedata::HdatNodedata(errlHndl_t &o_errlHndl, + uint64_t &io_msAddr, + const char *i_eyeCatcher, + uint32_t &o_NodeStructSize) +: HdatHdif(o_errlHndl, i_eyeCatcher, HDAT_NODE_DATA_LAST, +cv_actualCnt++, HDAT_NO_CHILD, HDAT_NODE_DATA_VERSION) +{ + HDAT_ENTER(); + o_errlHndl = NULL; + + // Copy the mainstore address to object variable + iv_msAddr = io_msAddr; + + // Total size of Node Data + iv_size = sizeof(hdatHDIF_t) + + ( sizeof(hdatHDIFDataHdr_t) * + HDAT_NODE_DATA_LAST)+ + HDAT_NODE_ATTR_DATA_SIZE + 0x08; // padding as per spec + + // Create a virtual address mapping + uint64_t l_base_addr_down = ALIGN_PAGE_DOWN((uint64_t)iv_msAddr); + iv_virt_addr =(uint8_t *) mm_block_map ( + reinterpret_cast<void*>(l_base_addr_down), + (ALIGN_PAGE(iv_size) + PAGESIZE)); + iv_hdatNodeData = iv_virt_addr + + ((uint64_t)iv_msAddr - ALIGN_PAGE_DOWN((uint64_t)iv_msAddr)); + + o_NodeStructSize = iv_size; + + // Copy the end adress back to input pointer for next node use + io_msAddr += iv_size; + + HDAT_EXIT(); + return; +} + + +/** @brief See the prologue in HdatNodedata.H + */ +errlHndl_t HdatNodedata::setNodeData() +{ + HDAT_ENTER(); + errlHndl_t o_errlHndl=NULL; + + // Add the internal pointer Data + this->addData(HDAT_NODE_ATTRIBUTE, HDAT_NODE_ATTR_DATA_SIZE); + this->align(); + + // initializing the space to zero + memset(iv_hdatNodeData ,0x0, iv_size ); + + iv_hdatNodeData = this->setHdif(iv_hdatNodeData); + + iv_hdatNodeData += HDAT_NODE_ATTR_DATA_SIZE; + + HDAT_EXIT(); + return o_errlHndl; +} + +HdatNodedata::~HdatNodedata() +{ + HDAT_ENTER(); + + errlHndl_t o_errlHndl=NULL; + uint32_t rc = mm_block_unmap(reinterpret_cast<void*>( + ALIGN_PAGE_DOWN((uint64_t)iv_virt_addr))); + if( rc != 0) + { + /*@ + * @errortype + * @moduleid HDAT::MOD_HDAT_NODEDATA_DTOR + * @reasoncode HDAT::RC_DEV_MAP_FAIL + * @devdesc Unmap a mapped region failed + * @custdesc Firmware encountered an internal error. + */ + hdatBldErrLog(o_errlHndl, + HDAT::MOD_HDAT_NODEDATA_DTOR, + RC_DEV_MAP_FAIL, + 0,0,0,0, + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + HDAT_VERSION1, + true); + } + HDAT_EXIT(); + +} + +}// HDAT namespace diff --git a/src/usr/hdat/hdatnodedata.H b/src/usr/hdat/hdatnodedata.H new file mode 100755 index 000000000..58adb1256 --- /dev/null +++ b/src/usr/hdat/hdatnodedata.H @@ -0,0 +1,179 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hdat/hdatnodedata.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 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 HDATNODEDATA_H +#define HDATNODEDATA_H + +/** + * @file hdatvpd.H + * + * @brief This file contains the class definition for the Host service node data object constructed + * + */ + +/*-----------------------------------------------------------------------------*/ +/* Includes */ +/*-----------------------------------------------------------------------------*/ +#include <stdint.h> // standard types +#include "hdathdif.H" // HdatHdif base class definition +#include <hdat/hdat.H> + +/*-----------------------------------------------------------------------------*/ +/* Constants +*/ +/*-----------------------------------------------------------------------------*/ +#define HDAT_NODE_ATTR_DATA_SIZE 256000 + +const uint16_t HDAT_NODE_DATA_VERSION = 0x0010; + + +/** @enum hdatDataPtrs + * Constants for the internal data pointers that are added to the base + * class + */ +enum hdatDataPtrs +{ + HDAT_NODE_ATTRIBUTE = 0, + HDAT_NODE_DATA_LAST = 1 +}; + +/*-----------------------------------------------------------------------------*/ +/* Type definitions */ +/*-----------------------------------------------------------------------------*/ + +using namespace HDAT; + +/*-----------------------------------------------------------------------------*/ +/* C++ class definition */ +/*-----------------------------------------------------------------------------*/ +namespace HDAT +{ + + /** Begin Class Description + * + * @brief The HdatNodedata class + * + * Description: This class defines a specialized object. It is not intended + * that anyone can create an object of this type. In particular, + * the object is built only in the hdatstep process when the step + * that builds hypervisor data structures is run. + * + * Thread safety: An HdatNodedata object is not thread safe. That is, a single + * object cannot be shared and used concurrently by + * multiple threads at the same time. An object can be used by + * multiple threads if the threads serialize access. And of + * course, each thread can use its own object with no concerns + * about what other threads are doing. + * + * Signal handler usage: This class is not intended to be used in a signal handler + * and nothing has been done to try and make it safe to use + * in a signal handler. + * + * End Class Description + */ + class HdatNodedata : public HdatHdif + { + public: + + /** + * @brief Construct an HdatNodedata object. + * + * This is the constructor for the HdatNodedata object. + * + * If you are constructing this object on the heap by using new, then + * you must check the pointer returned from new to see if it is null. + * If it is null, new failed to allocate storage and the constructor + * was not called. If it is not null, then you must check o_errlHndl + * to see if the constructor ran successfully. If o_errlHndl indicates + * an error was reported by the constructor, new has already allocated + * heap storage and the object must be deleted in order to free the + * heap storage. + * + * @pre None + * + * @post An HdatNodedata object has been constructed. Heap storage has been allocated. + * + * @param o_errlHndl - output parameter - If any errors occur, the HdatNodedata object + * is NOT constructed and errors are returned in this parameter + * @param io_msAddr - input output parameter - The main memory address + * @param i_eyeCatcher - input parameter - A character string to put in the structure's + * eye catcher field. + * @param o_NodeStructSize- Whole Node Data structure size + * + * @return A null error log handle if successful, else the return code pointed + * to by o_errlHndl contains one of: + * + * @retval HDAT_OTHER_COMP_ERROR + */ + HdatNodedata(errlHndl_t &o_errlHndl, + uint64_t &io_msAddr, + const char *i_eyeCatcher, + uint32_t &o_NodeStructSize); + + + /** + * @brief HdatNodedata object destructor + * + * This is the destructor for an HdatNodedata object. Any heap storage + * allocated for the object is dallocated. + * + * @pre No preconditions exist + + * @post The HdatNodedata object has been destroyed and can no longer be used. + * + */ + virtual ~HdatNodedata(); + errlHndl_t setNodeData(); + + /** Class (static) Data + * + * Only one copy of this data exists in a process. + * + * @li cv_actualCnt - a count of how many HdatNodedata objects are created + */ + static uint32_t cv_actualCnt; + + private: + + /** Object Instance Data + * + * @li iv_msAddr - main store address the structure need to be copied to + * @li iv_hdatNodeData - Pointer to Node Data + * @li iv_virt_addr - Pointr to hold virtual address post mem map. + * @li iv_nodeAttritbuteData - Pointer to internal Data pointer + * @li iv_size - Size of the Node data + */ + uint64_t iv_msAddr; + uint8_t * iv_hdatNodeData; + uint8_t * iv_virt_addr; + uint8_t *iv_nodeAttritbuteData; + uint64_t iv_size; + +}; // end of HdatNodedata class + + +}//HDAT + +#endif // HDATNODEDATA_H + diff --git a/src/usr/hdat/hdatpcia.C b/src/usr/hdat/hdatpcia.C new file mode 100644 index 000000000..129d80878 --- /dev/null +++ b/src/usr/hdat/hdatpcia.C @@ -0,0 +1,626 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hdat/hdatpcia.C $ */ +/* */ +/* 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 */ + +#include <sys/mm.h> +#include <sys/mmio.h> +#include "hdatpcia.H" +#include <targeting/common/util.H> +#include <util/align.H> + +using namespace TARGETING; + +namespace HDAT +{ +extern trace_desc_t *g_trac_hdat; + +/******************************************************************************* +* hdatSetPciaHdrs +* +* @brief Routine initializes HDIF headers for a PCIA array entry +* +* @pre None +* +* @post None +* +* @param[in] i_pcia +* The iv_spPcia array element to operate on +* +* @return A null error log handle if successful, Currently can't fail. +* +*******************************************************************************/ +static errlHndl_t hdatSetPciaHdrs(hdatSpPcia_t *i_pcia) +{ + errlHndl_t l_errlHndl = NULL; + + i_pcia->hdatHdr.hdatStructId = HDAT_HDIF_STRUCT_ID; + i_pcia->hdatHdr.hdatInstance = 0; + i_pcia->hdatHdr.hdatVersion = HDAT_PCIA_VERSION; + i_pcia->hdatHdr.hdatSize = sizeof(hdatSpPcia_t); + i_pcia->hdatHdr.hdatHdrSize = sizeof(hdatHDIF_t); + i_pcia->hdatHdr.hdatDataPtrOffset = sizeof(hdatHDIF_t); + i_pcia->hdatHdr.hdatDataPtrCnt = HDAT_PCIA_DA_CNT; + i_pcia->hdatHdr.hdatChildStrCnt = 0; + i_pcia->hdatHdr.hdatChildStrOffset = 0; + + memcpy(i_pcia->hdatHdr.hdatStructName, HDAT_PCIA_STRUCT_NAME, + sizeof(i_pcia->hdatHdr.hdatStructName)); + i_pcia->hdatPciaIntData[HDAT_PCIA_DA_COREDATA].hdatOffset = + offsetof(hdatSpPcia_t, hdatCoreData); + i_pcia->hdatPciaIntData[HDAT_PCIA_DA_COREDATA].hdatSize = + sizeof(hdatPciaCoreUniqueData_t); + i_pcia->hdatPciaIntData[HDAT_PCIA_DA_CPU_TIME_BASE].hdatOffset = + offsetof(hdatSpPcia_t, hdatTime); + i_pcia->hdatPciaIntData[HDAT_PCIA_DA_CPU_TIME_BASE].hdatSize = + sizeof(hdatPciaCpuTimeBase_t); + i_pcia->hdatPciaIntData[HDAT_PCIA_DA_CACHE_SIZE].hdatOffset = + offsetof(hdatSpPcia_t, hdatCache); + i_pcia->hdatPciaIntData[HDAT_PCIA_DA_CACHE_SIZE].hdatSize = + sizeof(hdatPciaCacheSize_t); + i_pcia->hdatPciaIntData[HDAT_PCIA_DA_THREADDATA].hdatOffset = + offsetof(hdatSpPcia_t, hdatThreadData); + i_pcia->hdatPciaIntData[HDAT_PCIA_DA_THREADDATA].hdatSize = + sizeof(hdatPciaThreadUniqueData_t); + i_pcia->hdatPciaIntData[HDAT_PCIA_DA_CPU_ATTRIBUTES].hdatOffset = + offsetof(hdatSpPcia_t, hdatAttr); + i_pcia->hdatPciaIntData[HDAT_PCIA_DA_CPU_ATTRIBUTES].hdatSize = + sizeof(hdatPciaCpuAttributes_t); + + return l_errlHndl; +} + +/******************************************************************************* +* PCIA Constructor +*******************************************************************************/ +HdatPcia::HdatPcia(errlHndl_t &o_errlHndl, const hdatMsAddr_t &i_msAddr) +: iv_numPciaEntries(0), iv_spPciaEntrySize(0), iv_spPcia(NULL) +{ + // Copy the main store address for the pcia data + memcpy(&iv_msAddr, &i_msAddr, sizeof(hdatMsAddr_t)); + + // We are using the CORE DATA section + iv_numPciaEntries = HDAT_NUM_P8_PCIA_ENTRIES; + iv_spPciaEntrySize = sizeof(hdatSpPcia_t); + + // Allocate space for each CORE -- will use max amount to start + uint64_t l_base_addr = ((uint64_t) i_msAddr.hi << 32) | i_msAddr.lo; + + void *l_virt_addr = mm_block_map ( + reinterpret_cast<void*>(ALIGN_PAGE_DOWN(l_base_addr)), + (ALIGN_PAGE(iv_numPciaEntries*iv_spPciaEntrySize)+PAGESIZE)); + + l_virt_addr = reinterpret_cast<void *>( + reinterpret_cast<uint64_t>(l_virt_addr) + + (l_base_addr - ALIGN_PAGE_DOWN(l_base_addr))); + + // initializing the space to zero + memset(l_virt_addr ,0x0, (iv_numPciaEntries*iv_spPciaEntrySize)); + + iv_spPcia = reinterpret_cast<hdatSpPcia_t *>(l_virt_addr); + + HDAT_DBG("Constructor iv_spPcia addr 0x%016llX virtual addr 0x%016llX", + (uint64_t) this->iv_spPcia, (uint64_t)l_virt_addr); +} + +/******************************************************************************* +* hdatLoadPcia +*******************************************************************************/ +errlHndl_t HdatPcia::hdatLoadPcia(uint32_t &o_size, uint32_t &o_count) +{ + errlHndl_t l_errl = NULL; + + do + { + // PCIA index + uint32_t index = 0; + + //Storing offset address for calculating the sizing of each PCIA + uint64_t l_offset = (uint64_t)&this->iv_spPcia[index]; + + // Get Max threads + ATTR_THREAD_COUNT_type l_coreThreadCount = 0; + Target* l_pTopLevel = NULL; + (void)TARGETING::targetService().getTopLevelTarget(l_pTopLevel); + if(NULL == l_pTopLevel) + { + /*@ + * @errortype + * @moduleid HDAT::MOD_PCIA_LOAD + * @reasoncode HDAT::RC_TOP_LVL_TGT_NOT_FOUND + * @devdesc Top level target not found + * @custdesc Firmware encountered an internal + * error while retrieving target data + */ + hdatBldErrLog(l_errl, + MOD_PCIA_LOAD, + RC_TOP_LVL_TGT_NOT_FOUND, + 0,0,0,0); + + HDAT_ERR("Error getting top level target"); + break; + } + + l_coreThreadCount = l_pTopLevel->getAttr<ATTR_THREAD_COUNT>(); + uint32_t l_procStatus; + if ( l_coreThreadCount == HDAT_MAX_EIGHT_THREADS_SUPPORTED ) + { + l_procStatus = + HDAT_PROC_NOT_INSTALLED | HDAT_PRIM_THREAD | HDAT_EIGHT_THREAD; + } + else if ( l_coreThreadCount == HDAT_MAX_FOUR_THREADS_SUPPORTED ) + { + l_procStatus = + HDAT_PROC_NOT_INSTALLED | HDAT_PRIM_THREAD | HDAT_FOUR_THREAD; + } + else + { + l_procStatus = + HDAT_PROC_NOT_INSTALLED | HDAT_PRIM_THREAD | HDAT_TWO_THREAD; + } + //for each procs in the system + TARGETING::PredicateCTM l_procFilter(CLASS_CHIP, TYPE_PROC); + TARGETING::PredicateHwas l_pred; + l_pred.present(true); + TARGETING::PredicatePostfixExpr l_presentProc; + l_presentProc.push(&l_procFilter).push(&l_pred).And(); + + TARGETING::TargetRangeFilter l_filter( + TARGETING::targetService().begin(), + TARGETING::targetService().end(), + &l_presentProc); + for (;l_filter;++l_filter) + { + TARGETING::Target* l_pProcTarget = *l_filter; + uint32_t Procstatus = 0; + + uint32_t l_procFabricId = + l_pProcTarget->getAttr<TARGETING::ATTR_FABRIC_NODE_ID>(); + + uint64_t l_procIntrBase = + l_pProcTarget->getAttr<TARGETING::ATTR_INTP_BASE_ADDR>(); + + uint32_t l_procPosition = + l_pProcTarget->getAttr<TARGETING::ATTR_FABRIC_CHIP_ID>(); + + TARGETING::PredicateCTM l_corePredicate(TARGETING::CLASS_UNIT, + TARGETING::TYPE_CORE); + + //Cores with partial good data are present and reported + //Cores that are present but not functional, also reported + TARGETING::PredicateHwas l_predPresent; + l_predPresent.present(true); + + TARGETING::PredicatePostfixExpr l_PresentCore; + l_PresentCore.push(&l_corePredicate).push(&l_predPresent).And(); + + TARGETING::TargetHandleList l_coreList; + + TARGETING::targetService().getAssociated(l_coreList, l_pProcTarget, + TARGETING::TargetService::CHILD, + TARGETING::TargetService::ALL, + &l_PresentCore); + + for (uint32_t l_idx = 0; l_idx < l_coreList.size(); ++l_idx) + { + HDAT_DBG("Core list size %d PCIA offset 0x%016llX", + l_coreList.size(),(uint64_t) &this->iv_spPcia[index]); + TARGETING::Target* l_pTarget = l_coreList[l_idx]; + uint32_t l_coreNum = + l_pTarget->getAttr<TARGETING::ATTR_CHIP_UNIT>(); + + for ( uint32_t l_threadIndex=0; + l_threadIndex < l_coreThreadCount; ++l_threadIndex) + { + l_errl = hdatSetCoreInfo(index, + l_pTarget,l_pProcTarget); + if(l_errl) + { + HDAT_ERR("Error [0x%08X] in call to set core info", + l_errl->reasonCode()); + break; + } + this->iv_spPcia[index].hdatThreadData. + pciaThreadData[l_threadIndex].pciaPhysThreadId = + l_threadIndex; + + HDAT_DBG("HdatPcia thread idx %d, thread id %d ", + l_threadIndex, this->iv_spPcia[index].hdatThreadData. + pciaThreadData[l_threadIndex].pciaPhysThreadId); + + /* Proc ID Reg is NNNCCCPPPPTTT + Where NNN is node number + CCC is Chip + PPPP is the core number + TTT is thread id + */ + uint32_t l_ThreadProcIdReg = l_procFabricId * 0x400; + l_ThreadProcIdReg += l_procPosition*0x80; + l_ThreadProcIdReg += (l_coreNum * l_coreThreadCount) + + l_threadIndex; + + hdatSetPciaHdrs(&this->iv_spPcia[index]); + this->iv_spPcia[index].hdatCoreData.pciaProcStatus + = l_procStatus; + this->iv_spPcia[index].hdatThreadData. + pciaThreadData[l_threadIndex].pciaProcIdReg = + l_ThreadProcIdReg; + + this->iv_spPcia[index].hdatThreadData. + pciaThreadData[l_threadIndex].pciaInterruptLine = + l_ThreadProcIdReg; + + Procstatus = isFunctional(l_pTarget) ? + HDAT_PROC_USABLE : + HDAT_PROC_NOT_USABLE; + + Procstatus |= HDAT_EIGHT_THREAD; + + uint32_t l_stat = this->iv_spPcia[index].hdatCoreData. + pciaProcStatus & HDAT_PROC_STAT_MASK; + this->iv_spPcia[index].hdatCoreData.pciaProcStatus = + (static_cast<hdatProcStatus> (Procstatus) + | l_stat ) & HDAT_EXIST_FLAGS_MASK_FOR_PCIA; + + //IBASE ADDRESS + NNNN + 000 + //Where NNNN = Thread Number = + // (Core Number * Number of threads) + Thread Number + uint64_t l_ibase = l_procIntrBase + + (l_coreNum * 0x1000 * l_coreThreadCount) + + l_threadIndex * 0x1000; + + this->iv_spPcia[index].hdatThreadData. + pciaThreadData[l_threadIndex].pciaIbaseAddr.hi = + ((l_ibase & 0xFFFFFFFF00000000ull) >> 32); + this->iv_spPcia[index].hdatThreadData. + pciaThreadData[l_threadIndex].pciaIbaseAddr.hi |= + HDAT_REAL_ADDRESS_MASK; + + this->iv_spPcia[index].hdatThreadData. + pciaThreadData[l_threadIndex].pciaIbaseAddr.lo = + (l_ibase & 0x00000000FFFFFFFFull); + + if(HDAT_PROC_NOT_INSTALLED == (HDAT_PROC_STAT_BITS & + this->iv_spPcia[index].hdatCoreData.pciaProcStatus)) + { + this->iv_spPcia[index].hdatPciaIntData + [HDAT_PCIA_DA_CPU_TIME_BASE].hdatOffset = 0; + this->iv_spPcia[index].hdatPciaIntData + [HDAT_PCIA_DA_CPU_TIME_BASE].hdatSize = 0; + this->iv_spPcia[index].hdatPciaIntData + [HDAT_PCIA_DA_CACHE_SIZE].hdatOffset = 0; + this->iv_spPcia[index].hdatPciaIntData + [HDAT_PCIA_DA_CACHE_SIZE].hdatSize = 0; + this->iv_spPcia[index].hdatPciaIntData + [HDAT_PCIA_DA_CPU_ATTRIBUTES].hdatOffset = 0; + this->iv_spPcia[index].hdatPciaIntData + [HDAT_PCIA_DA_CPU_ATTRIBUTES].hdatSize = 0; + } + // Need to setup header information for Thread Array Data + this->iv_spPcia[index].hdatThreadData.pciaThreadOffsetToData + = offsetof(hdatPciaThreadUniqueData_t, pciaThreadData); + this->iv_spPcia[index].hdatThreadData.pciaThreadNumEntries + = l_coreThreadCount; + this->iv_spPcia[index].hdatThreadData. + pciaThreadSizeAllocated = sizeof(hdatPciaThreadArray_t); + this->iv_spPcia[index].hdatThreadData.pciaThreadSizeActual = + sizeof(hdatPciaThreadArray_t); + + } + if(NULL != l_errl) + { + //Break if there is an error + HDAT_ERR("Error [0x%08X] in call to get chip parent failed", + l_errl->reasonCode()); + break; + } + index++; + if ((HDAT_RESERVE_FOR_CCM == (HDAT_RESERVE_FOR_CCM & + this->iv_spPcia[index].hdatCoreData.pciaProcStatus))|| + (HDAT_PROC_NOT_INSTALLED != (HDAT_PROC_STAT_BITS & + this->iv_spPcia[index].hdatCoreData.pciaProcStatus))) + { + // The PCIA is a fixed size, but wanted it padded to a 128 + // byte boundary + uint32_t l_rem=0, l_pad=0; + l_rem=0; l_pad=0; + // Pad to 128 bytes + l_rem = this->iv_spPcia[index-1].hdatHdr.hdatSize % 128; + l_pad = l_rem ? (128 - l_rem ) : 0; + uint8_t *l_addr= + reinterpret_cast<uint8_t *> (this->iv_spPcia); + // padding is allocated for size of PCIA entry. If it was + // smaller than 128 bytes, then you may need to bump it up + l_addr += l_pad; + this->iv_spPcia = + reinterpret_cast<hdatSpPcia_t *>(l_addr); + } + } + if(NULL != l_errl) + { + //Break if there is an error + break; + } + } + //End offset - starting offset divided by index + //for calculating each PCIA size. + o_size = ((uint64_t)&this->iv_spPcia[index] - l_offset)/index; + o_count = index; + }while(0); + + return l_errl; +} + +/******************************************************************************* +* hdatSetCoreInfo +*******************************************************************************/ +errlHndl_t HdatPcia::hdatSetCoreInfo(const uint32_t i_index, + const Target* i_pCoreTarget, + const Target* i_pProcTarget) +{ + errlHndl_t l_errl = NULL; + do + { + if(NULL == i_pCoreTarget) + { + HDAT_ERR("Input Target Pointer is NULL"); + /*@ + * @errortype + * @moduleid HDAT::MOD_PCIA_SET_CORE_INF + * @reasoncode HDAT::RC_INVALID_OBJECT + * @userdata1 Index of proc target + * @devdesc Input Target Pointer is NULL + * @custdesc Firmware encountered an internal + * error while retrieving target data + */ + hdatBldErrLog(l_errl, + MOD_PCIA_SET_CORE_INF, + RC_INVALID_OBJECT, + i_index,0,0,0); + break; + } + + if(i_pCoreTarget->getAttr<ATTR_TYPE>() != TYPE_CORE) + { + HDAT_ERR("Input Target type is not valid"); + /*@ + * @errortype + * @moduleid HDAT::MOD_PCIA_SET_CORE_INF + * @reasoncode HDAT::RC_INVALID_TGT_ATTR + * @userdata1 Index of proc target + * @userdata2 Target HUID + * @devdesc Invalid input target attribute + * @custdesc Firmware encountered an internal error + * while retrieving attribute data + */ + hdatBldErrLog(l_errl, + MOD_PCIA_SET_CORE_INF, + RC_INVALID_TGT_ATTR, + i_index,get_huid(i_pCoreTarget),0,0); + break; + } + TARGETING::Target *l_pSysTarget = NULL; + (void) TARGETING::targetService().getTopLevelTarget(l_pSysTarget); + + // asserting + assert(l_pSysTarget != NULL); + + uint32_t l_procOrdId = i_pProcTarget->getAttr<ATTR_ORDINAL_ID>(); + + uint32_t l_coreOrdId = i_pCoreTarget->getAttr<ATTR_ORDINAL_ID>(); + + HDAT_DBG("proc ord ID:0x%08X, core ord ID:0x%08X", + l_procOrdId,l_coreOrdId); + + uint32_t l_HWCardId = 0; + l_errl = HDAT::hdatGetHwCardId(i_pProcTarget,l_HWCardId); + if(NULL != l_errl) + { + HDAT_ERR("Error [0x%08X] in call to get card id failed", + l_errl->reasonCode()); + + l_errl->addFFDC(HDAT_COMP_ID,AT,sizeof(AT), + HDAT_VERSION1,HDAT_PCIA_FFDC_SUBSEC); + break; + } + HDAT_DBG("hw card ID:0x%08X", l_HWCardId); + + iv_spPcia[i_index].hdatCoreData.pciaHWCardID = l_HWCardId; + + TARGETING::TargetHandleList targetListNode; + targetListNode.clear(); + getParentAffinityTargets(targetListNode,i_pCoreTarget, + TARGETING::CLASS_ENC,TARGETING::TYPE_NODE); + if(targetListNode.empty()) + { + /*@ + * @errortype + * @moduleid HDAT::MOD_PCIA_SET_CORE_INF + * @reasoncode HDAT::RC_EMPTY_TARGET_LIST + * @devdesc Target List is Empty + * @custdesc Firmware encountered an internal + * error while retrieving target data + */ + hdatBldErrLog(l_errl, + MOD_PCIA_SET_CORE_INF, + RC_EMPTY_TARGET_LIST, + 0,0,0,0); + break; + } + //get the parent node id + Target* l_pNodeTarget = targetListNode[0]; + + uint32_t l_nodeOrdId = l_pNodeTarget->getAttr<ATTR_ORDINAL_ID>(); + + uint32_t l_fabNodeId = i_pProcTarget->getAttr<ATTR_FABRIC_NODE_ID>(); + + //Set the Internal Drawer Node ID + iv_spPcia[i_index].hdatCoreData.pciaDrawerNodeID = l_fabNodeId; + + //get the parent node id and set that + this->iv_spPcia[i_index].hdatCoreData.pciaDBOBID = l_nodeOrdId; + + //set the LCO target to 0 + this->iv_spPcia[i_index].hdatCoreData.pciaLCOTarget = 0; + this->iv_spPcia[i_index].hdatCoreData.pciaCCMNodeID = l_nodeOrdId; + //get the parent node id and set that + + //Ordinal Id of the fru containing this proc + uint32_t l_fruOrdId = i_pProcTarget->getAttr<TARGETING::ATTR_FRU_ID>(); + this->iv_spPcia[i_index].hdatCoreData.pciaFruId = l_fruOrdId; + + //Module id is same as FRU Ordinal ID + this->iv_spPcia[i_index].hdatCoreData.pciaModuleId = l_fruOrdId; + + //Ordinal ID of the core + this->iv_spPcia[i_index].hdatCoreData.pciaHdwProcId = l_coreOrdId; + + uint32_t l_eclevel = 0; + uint32_t l_chipId = 0; + + //Set the Chip EC level + l_errl = HDAT::hdatGetIdEc(i_pProcTarget, l_eclevel, l_chipId); + if(NULL != l_errl) + { + HDAT_ERR("Error [0x%08X] in call to get IdEc Failed", + l_errl->reasonCode()); + l_errl->addFFDC(HDAT_COMP_ID,AT,sizeof(AT), + HDAT_VERSION1,HDAT_PCIA_FFDC_SUBSEC); + break; + } + iv_spPcia[i_index].hdatCoreData.pciaChipEcLvl = l_eclevel; + + //Ordinal id of the proc(chip) + this->iv_spPcia[i_index].hdatCoreData.pciaChipId = l_procOrdId; + + //Set Clock Freq - Cycle Time in MHz + iv_spPcia[i_index].hdatTime.pciaClockSpeed = + l_pSysTarget->getAttr<TARGETING::ATTR_NOMINAL_FREQ_MHZ>(); + + //CPU Time Base Structure + uint32_t l_CycleTime = pow(2,34) / + iv_spPcia[i_index].hdatTime.pciaClockSpeed; + + //Set Cycle Time + iv_spPcia[i_index].hdatTime.pciaCycleTime = l_CycleTime; + //Set Time Base - units of microseconds * 2^32 + iv_spPcia[i_index].hdatTime.pciaTimeBase = + i_pProcTarget->getAttr<TARGETING::ATTR_TIME_BASE>(); + + //Set ICache Info + //Cache Size Structure + this->iv_spPcia[i_index].hdatCache.pciaICacheSize = + i_pProcTarget->getAttr<TARGETING::ATTR_ICACHE_SIZE>(); + this->iv_spPcia[i_index].hdatCache.pciaICacheLineSize = + i_pProcTarget->getAttr<TARGETING::ATTR_ICACHE_LINE_SIZE>(); + this->iv_spPcia[i_index].hdatCache.pciaICacheBlkSize = + i_pProcTarget->getAttr<TARGETING::ATTR_ICACHE_BLOCK_SIZE>(); + + this->iv_spPcia[i_index].hdatCache.pciaICacheAssocSets = + i_pProcTarget->getAttr<TARGETING::ATTR_ICACHE_ASSOC_SETS>(); + + //Set DCache Info + this->iv_spPcia[i_index].hdatCache.pciaDCacheBlkSize = + i_pProcTarget->getAttr<TARGETING::ATTR_DCACHE_LINE_SIZE>(); + this->iv_spPcia[i_index].hdatCache.pciaDCacheAssocSets = + i_pProcTarget->getAttr<TARGETING::ATTR_DCACHE_ASSOC_SETS>(); + + + //Set L1 Cache Info + this->iv_spPcia[i_index].hdatCache.pciaL1DCacheSize = + i_pProcTarget->getAttr<TARGETING::ATTR_DATA_CACHE_SIZE>(); + this->iv_spPcia[i_index].hdatCache.pciaL1DCacheLineSize = + i_pProcTarget->getAttr<TARGETING::ATTR_DATA_CACHE_LINE_SIZE>(); + + //Set L2 Cache Info + this->iv_spPcia[i_index].hdatCache.pciaL2DCacheSize = + i_pProcTarget->getAttr<TARGETING::ATTR_L2_CACHE_SIZE>(); + this->iv_spPcia[i_index].hdatCache.pciaL2DCacheLineSize = + i_pProcTarget->getAttr<TARGETING::ATTR_L2_CACHE_LINE_SIZE>(); + + this->iv_spPcia[i_index].hdatCache.pciaL2AssocSets = + i_pProcTarget->getAttr<TARGETING::ATTR_L2_CACHE_ASSOC_SETS>(); + + //Set L3 Cache Info + this->iv_spPcia[i_index].hdatCache.pciaL3DCacheSize = + i_pProcTarget->getAttr<TARGETING::ATTR_L3_CACHE_SIZE>(); + this->iv_spPcia[i_index].hdatCache.pciaL3DCacheLineSize = + i_pProcTarget->getAttr<TARGETING::ATTR_L3_CACHE_LINE_SIZE>(); + + //ECO not supported initialize to 0 + this->iv_spPcia[i_index].hdatCache.pciaL3Pt5DCacheSize = 0; + this->iv_spPcia[i_index].hdatCache.pciaL3Pt5DCacheLineSize = 0; + + //Set TLB info + this->iv_spPcia[i_index].hdatCache.pciaITlbEntries = + i_pProcTarget->getAttr<TARGETING::ATTR_TLB_INSTR_ENTRIES>(); + this->iv_spPcia[i_index].hdatCache.pciaITlbAssocSets = + i_pProcTarget->getAttr<TARGETING::ATTR_TLB_INSTR_ASSOC_SETS>(); + + this->iv_spPcia[i_index].hdatCache.pciaDTlbEntries = + i_pProcTarget->getAttr<TARGETING::ATTR_TLB_DATA_ENTRIES>(); + this->iv_spPcia[i_index].hdatCache.pciaDTlbAssocSets = + i_pProcTarget->getAttr<TARGETING::ATTR_TLB_DATA_ASSOC_SETS>(); + + this->iv_spPcia[i_index].hdatCache.pciaReserveSize = + i_pProcTarget->getAttr<TARGETING::ATTR_TLB_RESERVE_SIZE>(); + + //Set CPU Attributes + iv_spPcia[i_index].hdatAttr.pciaAttributes = + i_pProcTarget->getAttr<TARGETING::ATTR_CPU_ATTR>(); + } + while(0); + + return l_errl; +} + +/******************************************************************************* +* PCIA Destructor +*******************************************************************************/ +HdatPcia :: ~HdatPcia() +{ + int rc = 0; + rc = mm_block_unmap(reinterpret_cast<void*>(ALIGN_PAGE_DOWN( + reinterpret_cast<uint64_t>(iv_spPcia)))); + if( rc != 0) + { + errlHndl_t l_errl = NULL; + /*@ + * @errortype + * @moduleid HDAT::MOD_PCIA_DESTRUCTOR + * @reasoncode HDAT::RC_DEV_MAP_FAIL + * @devdesc Unmap a mapped region failed + * @custdesc Firmware encountered an internal error. + */ + hdatBldErrLog(l_errl, + MOD_PCIA_DESTRUCTOR, + RC_DEV_MAP_FAIL, + 0,0,0,0, + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + HDAT_VERSION1, + true); + } + +} + +} //namespace HDAT diff --git a/src/usr/hdat/hdatpcia.H b/src/usr/hdat/hdatpcia.H new file mode 100755 index 000000000..e1ba47522 --- /dev/null +++ b/src/usr/hdat/hdatpcia.H @@ -0,0 +1,356 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hdat/hdatpcia.H $ */ +/* */ +/* 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 */ + + +/** + * @file hdatpcia.H + * + * @brief This file contains the definition of the Processor Core Information + * Area (PCIA) data structure. + * + * A C++ class is defined that is used to update the copy of the PCIA. + * The PCIA is written to main memory. + */ + +#ifndef HDATPCIA_H +#define HDATPCIA_H + +/*----------------------------------------------------------------------------*/ +/* Includes */ +/*----------------------------------------------------------------------------*/ +#include <hdat/hdat.H> +#include <errl/errlentry.H> +#include <hdat/hdat_reasoncodes.H> +#include "hdatutil.H" +#include <math.h> + +namespace HDAT +{ + +/*----------------------------------------------------------------------------*/ +/* Constants */ +/*----------------------------------------------------------------------------*/ +#define HDAT_NUM_P8_PCIA_ENTRIES 32 * 8 + +const uint16_t HDAT_PCIA_VERSION = 0x01; +const char HDAT_PCIA_STRUCT_NAME[7] = "SPPCIA"; +const uint32_t HDAT_PROC_STAT_MASK = 0x00008000; + +// Bits in the proc/exist flags for PCIA data + #define HDAT_EXIST_FLAGS_MASK_FOR_PCIA 0xD0FF0000 + +/** @enum hdatDataPtrs + * Enumeration which defines the data sections of the PCIA + */ +enum hdatDataPtrs +{ + HDAT_PCIA_DA_COREDATA = 0, + HDAT_PCIA_DA_CPU_TIME_BASE = 1, + HDAT_PCIA_DA_CACHE_SIZE = 2, + HDAT_PCIA_DA_THREADDATA = 3, + HDAT_PCIA_DA_CPU_ATTRIBUTES = 4, + HDAT_PCIA_DA_CNT = 5, + HDAT_PCIA_DA_LAST = 8 +}; + +/*----------------------------------------------------------------------------*/ +/* Type definitions */ +/*----------------------------------------------------------------------------*/ + +/** @brief This defines the Core unique data section of the PCIA. + * Data here is related to processor cores + */ +struct hdatPciaCoreUniqueData_t +{ + uint32_t reserved_01; // 0x0000 Reserved. + uint32_t pciaFruId; // 0x0004 FRU ID + uint32_t pciaHdwProcId; // 0x0008 hardware processor ID + uint32_t pciaProcStatus; // 0x000C processor status flags + uint32_t pciaChipEcLvl; // 0x0010 chip EC level + uint32_t pciaChipId; // 0x0014 processor chip ID + uint32_t reserved_02; // 0x0018 Deprecated + uint32_t reserved_03; // 0x001C Deprecated + uint32_t reserved_04; // 0x0020 Reserved + uint32_t pciaModuleId; // 0x0024 module id for the DCM, + // MCM, QCM, etc. + hdatMsAddr_t reserved_05; // 0x0028 Reserved. + uint32_t reserved_06; // 0x0030 Reserved. + uint32_t reserved_07; // 0x0034 Deprecated + uint32_t reserved_08; // 0x0038 Reserved. + uint32_t pciaCCMNodeID; // 0x003C CCM Node ID + uint32_t pciaHWCardID; // 0x0040 HW Card ID + uint32_t pciaDrawerNodeID; // 0x0044 Internal Drawer Node ID + uint32_t pciaDBOBID; // 0x0048 Drawer/Book/Octant/Blade ID + uint32_t reserved_09; // 0x004C Reserved. + uint32_t pciaLCOTarget; // 0x0050 LCO Target. + uint32_t reserved_10; // 0x0054 Reserved. +} __attribute__ ((packed)); + + +/** @brief CPU Time Base portion of the FipS PCIA section + */ +struct hdatPciaCpuTimeBase_t +{ + uint32_t pciaCycleTime; // 0x0000 cycle time + uint32_t pciaTimeBase; // 0x0004 time base + uint32_t pciaClockSpeed; // 0x0008 actual clock speed + uint32_t pciaMemBusFreq; // 0x000C memory bus frequency +} __attribute__ ((packed)); + + +/** @brief Cache Size portion of the FipS PCIA section + */ +struct hdatPciaCacheSize_t +{ + uint32_t pciaICacheSize; // 0x0000 instruction cache size (in KB) + uint32_t pciaICacheLineSize; // 0x0004 instruction cache line size + // (in bytes) + uint32_t pciaL1DCacheSize; // 0x0008 L1 data cache size (in KB) + uint32_t pciaL1DCacheLineSize; // 0x000C L1 data cache line size + // (in bytes) + uint32_t pciaL2DCacheSize; // 0x0010 L2 data cache size (in KB) + uint32_t pciaL2DCacheLineSize; // 0x0014 L2 cache line size (in bytes) + uint32_t pciaL3DCacheSize; // 0x0018 L3 data cache size (in KB) + uint32_t pciaL3DCacheLineSize; // 0x001C L3 cache line size (in bytes) + uint32_t pciaDCacheBlkSize; // 0x0020 data cache block size + // (in bytes) + uint32_t pciaICacheBlkSize; // 0x0024 instruction cache block size + // (in bytes) + uint32_t pciaDCacheAssocSets; // 0x0028 number of associativity sets + // in data cache + uint32_t pciaICacheAssocSets; // 0x002C number of associativity sets + // in instruction cache + uint32_t pciaDTlbEntries; // 0x0030 number of data TLB entries + uint32_t pciaDTlbAssocSets; // 0x0034 number of associativity sets + // in data TLB + uint32_t pciaITlbEntries; // 0x0038 number of instruction TLB + // entries + uint32_t pciaITlbAssocSets; // 0x003C number of associativity sets + // in instruction TLB + uint32_t pciaReserveSize; // 0x0040 reservation size + uint32_t pciaL2AssocSets; // 0x0044 number of associativity sets + // in L2 + uint32_t pciaL3Pt5DCacheSize; // 0x0048 L3.5 data cache size (in KB) + uint32_t pciaL3Pt5DCacheLineSize; // 0x004C L3.5 cache line size + // (in bytes) +} __attribute__ ((packed)); + + +/** @brief This defines the thread array for each processor core area. + */ +struct hdatPciaThreadArray_t +{ + uint32_t pciaInterruptLine; // 0x0000 processor interrupt line. + uint32_t pciaPhysThreadId; // 0x0004 processor thread ID (0,1,...) + hdatMsAddr_t pciaIbaseAddr; // 0x0008 IBASE register address. + uint32_t pciaProcIdReg; // 0x0010 processor ID register +} __attribute__ ((packed)); + + +/** @brief This defines the thread specific data section for each + * processor core. + */ +struct hdatPciaThreadUniqueData_t +{ + uint32_t pciaThreadOffsetToData; // 0x0000 Should be fixed at size + // of this 16 byte header + uint32_t pciaThreadNumEntries; // 0x0004 Number of entries in the + // thread data array past header + uint32_t pciaThreadSizeAllocated; // 0x0008 Allocated size of array + // entry in bytes (will be + // 16 bytes for now) + uint32_t pciaThreadSizeActual; // 0x000C Actual size of each + // entry in bytes + hdatPciaThreadArray_t pciaThreadData[HDAT_MAX_THREADS_SUPPORTED]; + // 0x0010 Actual array thread data + +} __attribute__ ((packed)); + + +/** @brief CPU Attributes portion of the FipS PCIA section + */ +struct hdatPciaCpuAttributes_t +{ + uint32_t pciaAttributes; // 0x0000 bit map of attributes +} __attribute__ ((packed)); + + + +/** @brief This defines the PCIA. FipS updates this + * portion and DMAs the entire PCIA back to main memory. + */ +struct hdatSpPcia_t +{ + hdatHDIF_t hdatHdr; + hdatHDIFDataHdr_t hdatPciaIntData[HDAT_PCIA_DA_LAST]; + hdatPciaCoreUniqueData_t hdatCoreData; + hdatPciaCpuTimeBase_t hdatTime; + hdatPciaCacheSize_t hdatCache; + hdatPciaThreadUniqueData_t hdatThreadData; + hdatPciaCpuAttributes_t hdatAttr; +} __attribute__ ((packed)); + +/*----------------------------------------------------------------------------*/ +/* C++ class definition */ +/*----------------------------------------------------------------------------*/ + +/** Begin Class Description + * + * @brief The HdatPcia class is used to construct the PCIA object. + * + * Description: This class defines a specialized object. It is not intended + * that any component can create an object of this type. + * In particular, the object is built only in the + * CEC Server process when requested by the hdat component. + * + * The real purpose of the object is to create the PCIA array + * structure as defined by the PHYP Initialization architecture. + * + * Signal handler usage: This class is not intended to be used in a signal + * handler + * + * End Class Description + */ +class HdatPcia +{ + public: + /** + * @brief Construct an HdatPcia object + * + * This is the constructor for the HdatPcia object. + * + * @pre None + * + * @post An HdatPcia object pointer would be pointing to the host memory + * where the data would be directly written on to the memory. + * Each PCIA entry is initialized to indicate the processor is not + * installed. If the processor is installed, set the status and + * supply other information. + * + * @param[out] o_errlHndl + * If any errors occur, the HdatPcia object is NOT constructed + * and errors are returned in this parameter + + * @param[in] i_msAddr + * The main memory address that the PCIA structure will be DMA'd to. + * + * @return A null error log handle if successful, else the return code + * pointed to by o_errlHndl. + * + */ + + HdatPcia(errlHndl_t &o_errlHndl, + const hdatMsAddr_t &i_msAddr); + /** + * @brief HdatPcia object destructor + * + * This is the destructor for an HdatPcia object. + * + * @pre No preconditions exist + * + * @post The HdatPcia object has been destroyed and can no longer be used. + * + */ + ~HdatPcia(); + + /** + * @brief Load the HdatPcia object + * + * This function is used to the load the HdatPcia object with all the + * hdatSpPcia_t structure data. HdatPcia object would be having all + * the core data with partial good data which are present and all + * the present which are not functional also + * + * @param[out] o_size + * Size of PCIA object which are written onto Host memory. + * + * @param[out] o_count + * Count of PCIA objects which are written onto Host memory. + * + * @pre HdatPcia Object should be constructed with the main memory address + * + * @post The HdatPcia object with all the PCIA entry populated. + * + * @return A null error log handle if successful, else the return code + * pointed to by o_errlHndl. + */ + errlHndl_t hdatLoadPcia(uint32_t &o_size, uint32_t &o_count); + + private: + + /** Object instance Data + * + * Only one copy of this data exists in a process. + * + */ + + /* @li iv_msAddr - main memory address the final data structure written */ + hdatMsAddr_t iv_msAddr; + + /* @li iv_numPciaEntries - number of PCIA entries*/ + uint32_t iv_numPciaEntries; // Number of core entries + + /* @li iv_spPciaEntrySize - size of one entry in PCIA*/ + uint32_t iv_spPciaEntrySize; // Size of a PCIA entry + + /* @li iv_spPcia - pointer to the first PCIA Entry */ + hdatSpPcia_t *iv_spPcia; + + /** + * @brief Set the core specific info + * + * This function is an helper function used to the set the core + * specific info into the HdatPcia object with for all the + * hdatPciaCoreUniqueData_t, hdatPciaCacheSize_t, + * hdatPciaCpuAttributes_t structure data. + * + * @pre HdatPcia Object should be constructed with the main memory address + * Target pointer to the core which is present on the system + * Target pointer to the present procs in the system + * + * @post The HdatPcia object with all the core related data populated. + * + * @param[in] i_index + * Index value + * + * @param[in] i_pTarget + * Core target pointer. Must not be NULL (otherwise call will return an + * error log). Must be a valid target from the system blueprint. + * + * @param[in] i_pTarget + * Proc target pointer. Must not be NULL (otherwise call will return an + * error log). Must be a valid target from the system blueprint. + * + * @return A null error log handle if successful, else the return code + * pointed to by o_errlHndl. + */ + + errlHndl_t hdatSetCoreInfo(const uint32_t i_index, + const TARGETING::Target* i_pCoreTarget, + const TARGETING::Target* i_pProcTarget); +}; + +} //namespace HDAT +#endif // HDATPCIA_H diff --git a/src/usr/hdat/hdatpcrd.C b/src/usr/hdat/hdatpcrd.C new file mode 100644 index 000000000..8df9b615c --- /dev/null +++ b/src/usr/hdat/hdatpcrd.C @@ -0,0 +1,645 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hdat/hdatpcrd.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 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 */ + +#include <sys/mm.h> +#include <sys/mmio.h> +#include "hdatpcrd.H" +#include <targeting/common/util.H> +#include "hdatvpd.H" +#include <util/align.H> +#include <devicefw/driverif.H> +#include <vpd/mvpdenums.H> + +using namespace VPD; +using namespace MVPD; +using namespace TARGETING; + +namespace HDAT +{ +extern trace_desc_t *g_trac_hdat; + +/** + * @brief Data sample to be used for MVPD testing. + * NOTE: By reading this entire list, it also validates that the records + * and keywords that we expect to be there are actually there... + */ +vpdData procVpdData[] = +{ + { MVPD::VINI, MVPD::DR }, + { MVPD::VINI, MVPD::VZ }, + { MVPD::VINI, MVPD::CC }, + { MVPD::VINI, MVPD::CE }, + { MVPD::VINI, MVPD::FN }, + { MVPD::VINI, MVPD::PN }, + { MVPD::VINI, MVPD::SN }, + { MVPD::VINI, MVPD::PR }, + { MVPD::VINI, MVPD::HE }, + { MVPD::VINI, MVPD::CT }, + { MVPD::VINI, MVPD::HW }, + }; + +const HdatKeywordInfo l_mvpdKeywords[] = +{ + { MVPD::DR, "DR" }, + { MVPD::VZ, "VZ" }, + { MVPD::CC, "CC" }, + { MVPD::CE, "CE" }, + { MVPD::FN, "FN" }, + { MVPD::PN, "PN" }, + { MVPD::SN, "SN" }, + { MVPD::PR, "PR" }, + { MVPD::HE, "HE" }, + { MVPD::CT, "CT" }, + { MVPD::HW, "HW" }, + +}; + +/******************************************************************************* + * hdatSetPcrdHdrs + * + * @brief Routine initializes HDIF headers for a PCRD array entry + * + * @pre None + * + * @post None + * + * @param[in] i_pcrd + * The iv_spPcrd array element to operate on + * + * @return A null error log handle if successful, Currently can't fail. + * +*******************************************************************************/ +static errlHndl_t hdatSetPcrdHdrs(hdatSpPcrd_t *i_pcrd) +{ + errlHndl_t l_errlHndl = NULL; + + i_pcrd->hdatHdr.hdatStructId = HDAT_HDIF_STRUCT_ID; + i_pcrd->hdatHdr.hdatInstance = 0; + i_pcrd->hdatHdr.hdatVersion = HDAT_PCRD_VERSION; + i_pcrd->hdatHdr.hdatSize = offsetof(hdatSpPcrd_t, vpd_data); + i_pcrd->hdatHdr.hdatHdrSize = sizeof(hdatHDIF_t); + i_pcrd->hdatHdr.hdatDataPtrOffset = sizeof(hdatHDIF_t); + i_pcrd->hdatHdr.hdatDataPtrCnt = HDAT_PCRD_DA_CNT; + i_pcrd->hdatHdr.hdatChildStrCnt = 0; + i_pcrd->hdatHdr.hdatChildStrOffset = 0; + + memcpy(i_pcrd->hdatHdr.hdatStructName, HDAT_PCRD_STRUCT_NAME, + sizeof(i_pcrd->hdatHdr.hdatStructName)); + i_pcrd->hdatPcrdIntData[HDAT_PCRD_DA_CHIP_INFO].hdatOffset = + offsetof(hdatSpPcrd_t, hdatChipData); + i_pcrd->hdatPcrdIntData[HDAT_PCRD_DA_CHIP_INFO].hdatSize = + sizeof(hdatPcrdChipInfo_t); + + i_pcrd->hdatPcrdIntData[HDAT_PCRD_DA_CHIP_TIMEOFDAY].hdatOffset = + offsetof(hdatSpPcrd_t, hdatChipTodData); + i_pcrd->hdatPcrdIntData[HDAT_PCRD_DA_CHIP_TIMEOFDAY].hdatSize = + sizeof(hdatPcrdChipTod_t); + i_pcrd->hdatPcrdIntData[HDAT_PCRD_DA_FRU_ID].hdatOffset = + offsetof(hdatSpPcrd_t, hdatFruId); + + i_pcrd->hdatPcrdIntData[HDAT_PCRD_DA_FRU_ID].hdatSize = sizeof(hdatFruId_t); + i_pcrd->hdatPcrdIntData[HDAT_PCRD_DA_ASCII_KWD].hdatOffset = 0; + i_pcrd->hdatPcrdIntData[HDAT_PCRD_DA_ASCII_KWD].hdatSize = 0; + i_pcrd->hdatPcrdIntData[HDAT_PCRD_DA_CHIP_VPD].hdatOffset = 0; + i_pcrd->hdatPcrdIntData[HDAT_PCRD_DA_CHIP_VPD].hdatSize = 0; + + return l_errlHndl; +} + +/******************************************************************************* +* PCRD Constructor +*******************************************************************************/ +HdatPcrd::HdatPcrd(errlHndl_t &o_errlHndl, const hdatMsAddr_t &i_msAddr) + : iv_numPcrdEntries(0), iv_spPcrdEntrySize(0), iv_spPcrd(NULL) +{ + // Allocate the CHIP INFO section also + iv_numPcrdEntries = HDAT_NUM_P7_PCRD_ENTRIES; + iv_spPcrdEntrySize = sizeof(hdatSpPcrd_t) + HDAT_FULL_MVPD_SIZE; + + // Allocate space for each CHIP -- will use max amount to start + uint64_t l_base_addr = ((uint64_t) i_msAddr.hi << 32) | i_msAddr.lo; + void *l_virt_addr = mm_block_map ( + reinterpret_cast<void*>(ALIGN_PAGE_DOWN(l_base_addr)), + (ALIGN_PAGE(iv_numPcrdEntries*iv_spPcrdEntrySize)+PAGESIZE)); + + l_virt_addr = reinterpret_cast<void *>( + reinterpret_cast<uint64_t>(l_virt_addr) + + (l_base_addr - ALIGN_PAGE_DOWN(l_base_addr))); + + // initializing the space to zero + memset(l_virt_addr ,0x0,(iv_numPcrdEntries*iv_spPcrdEntrySize)); + + iv_spPcrd = reinterpret_cast<hdatSpPcrd_t *>(l_virt_addr); + + HDAT_DBG("Constructor iv_spPcrd addr 0x%016llX virtual addr 0x%016llX", + (uint64_t) this->iv_spPcrd, (uint64_t)l_virt_addr); +} + +/******************************************************************************* +* hdatLoadPcrd +*******************************************************************************/ +errlHndl_t HdatPcrd::hdatLoadPcrd(uint32_t &o_size, uint32_t &o_count) +{ + errlHndl_t l_errl = NULL; + do + { + // PCRD index + uint32_t index = 0; + + //Storing offset address for calculating the sizing of each PCRD + uint8_t *l_offset = reinterpret_cast<uint8_t *> (this->iv_spPcrd); + uint8_t *l_addr =l_offset; + + // Get Max threads + ATTR_THREAD_COUNT_type l_coreThreadCount = 0; + Target* l_pTopLevel = NULL; + (void)TARGETING::targetService().getTopLevelTarget(l_pTopLevel); + if(NULL == l_pTopLevel) + { + /*@ + * @errortype + * @moduleid HDAT::MOD_PCRD_LOAD + * @reasoncode HDAT::RC_TOP_LVL_TGT_NOT_FOUND + * @devdesc Top level target not found + * @custdesc Firmware encountered an internal + * error while retrieving target data + */ + hdatBldErrLog(l_errl, + MOD_PCRD_LOAD, + RC_TOP_LVL_TGT_NOT_FOUND, + 0,0,0,0); + + HDAT_ERR("Error getting top level target"); + break; + } + + // @TODO: RTC 142465. Add check to know whether in fused mode or not + l_coreThreadCount = l_pTopLevel->getAttr<ATTR_THREAD_COUNT>(); + uint32_t l_procStatus; + if ( l_coreThreadCount == HDAT_MAX_EIGHT_THREADS_SUPPORTED ) + { + l_procStatus = + HDAT_PROC_NOT_INSTALLED | HDAT_PRIM_THREAD | HDAT_EIGHT_THREAD; + } + else if ( l_coreThreadCount == HDAT_MAX_FOUR_THREADS_SUPPORTED ) + { + l_procStatus = + HDAT_PROC_NOT_INSTALLED | HDAT_PRIM_THREAD | HDAT_FOUR_THREAD; + } + else + { + l_procStatus = + HDAT_PROC_NOT_INSTALLED | HDAT_PRIM_THREAD | HDAT_TWO_THREAD; + } + + //for each procs in the system + TARGETING::PredicateCTM l_procFilter(CLASS_CHIP, TYPE_PROC); + TARGETING::PredicateHwas l_pred; + l_pred.present(true); + TARGETING::PredicatePostfixExpr l_presentProc; + l_presentProc.push(&l_procFilter).push(&l_pred).And(); + + TARGETING::TargetRangeFilter l_filter( + TARGETING::targetService().begin(), + TARGETING::targetService().end(), + &l_presentProc); + for (;l_filter;++l_filter) + { + HDAT_DBG("Pcrd Address 0x%08X \n", + reinterpret_cast<uint8_t *> (this->iv_spPcrd)); + bool l_all_cores_usable = true; + TARGETING::Target* l_pProcTarget = *l_filter; + TARGETING::PredicateCTM l_corePredicate(TARGETING::CLASS_UNIT, + TARGETING::TYPE_CORE); + + TARGETING::PredicateHwas l_predPresent; + l_predPresent.present(true); + + TARGETING::PredicatePostfixExpr l_PresentCore; + l_PresentCore.push(&l_corePredicate).push(&l_predPresent).And(); + + TARGETING::TargetHandleList l_coreList; + + TARGETING::targetService().getAssociated(l_coreList, l_pProcTarget, + TARGETING::TargetService::CHILD, + TARGETING::TargetService::ALL, + &l_PresentCore); + + if(l_coreList.size() == 0 ) + { + l_all_cores_usable = false; + } + + for (uint32_t l_idx = 0; l_idx < l_coreList.size(); ++l_idx) + { + TARGETING::Target* l_pTarget = l_coreList[l_idx]; + l_procStatus = isFunctional(l_pTarget) ? + HDAT_PROC_USABLE : + HDAT_PROC_NOT_USABLE; + + if(l_procStatus == HDAT_PROC_NOT_USABLE) + { + l_all_cores_usable = false; + } + l_procStatus |= l_coreThreadCount; + } + if(l_all_cores_usable) + { + l_procStatus = HDAT_PROC_USABLE; + } + else + { + l_procStatus = HDAT_PROC_FAILURES; + } + hdatSetPcrdHdrs(this->iv_spPcrd); + + l_errl = this->hdatSetProcessorInfo( l_pProcTarget, + l_procStatus); + if ( NULL != l_errl ) + { + HDAT_ERR("Error [0x%08X] in call to get processor info failed", + l_errl->reasonCode()); + break; + } + + this->iv_spPcrd->hdatFruId.hdatSlcaIdx = + l_pProcTarget->getAttr<ATTR_SLCA_INDEX>(); + this->iv_spPcrd->hdatFruId.hdatResourceId = + l_pProcTarget->getAttr<ATTR_SLCA_RID>(); + + if (HDAT_PROC_NOT_INSTALLED == (HDAT_PROC_STAT_BITS & + this->iv_spPcrd->hdatChipData.hdatPcrdStatusFlags)) + { + // Will leave the chip time-of-day info since that has its + // own exist bits and we never wiped out before + this->iv_spPcrd->hdatPcrdIntData + [HDAT_PCRD_DA_FRU_ID].hdatOffset = 0; + this->iv_spPcrd->hdatPcrdIntData + [HDAT_PCRD_DA_FRU_ID].hdatSize = 0; + this->iv_spPcrd->hdatPcrdIntData + [HDAT_PCRD_DA_ASCII_KWD].hdatOffset = 0; + this->iv_spPcrd->hdatPcrdIntData + [HDAT_PCRD_DA_ASCII_KWD].hdatSize = 0; + this->iv_spPcrd->hdatPcrdIntData + [HDAT_PCRD_DA_CHIP_VPD].hdatOffset = 0; + this->iv_spPcrd->hdatPcrdIntData + [HDAT_PCRD_DA_CHIP_VPD].hdatSize = 0; + } + else + { + // Need to complete the chip TOD information fetch + //TODO : RTC 147507 - Fetch TOD information + if(index ==0 ) + { + this->iv_spPcrd->hdatChipTodData. + hdatPcrdTodFlags=0x06; + } + else + { + this->iv_spPcrd->hdatChipTodData. + hdatPcrdTodFlags=0x05; + } + this->iv_spPcrd->hdatChipTodData.hdatPcrdTodControls= + 0x03F30000; + this->iv_spPcrd->hdatChipTodData. + hdatPcrdTodControlRegister=0x003F0000; + + // Get ascii keyword + char *l_keyword= NULL; + uint32_t l_asciiKeywordSize=0; + uint32_t l_num = sizeof(procVpdData) / sizeof(procVpdData[0]); + size_t theSize[l_num]; + l_errl = hdatGetAsciiKwd(l_pProcTarget,l_asciiKeywordSize,l_keyword, + PROC,procVpdData,l_num,theSize); + if(l_errl ) + { + HDAT_ERR("Error [0x%08X] in the collect the VPD data", + l_errl->reasonCode()); + break; + } + char *o_fmtKwd; + uint32_t o_fmtkwdSize; + l_errl = hdatformatAsciiKwd(procVpdData, l_num, + theSize, l_keyword, l_asciiKeywordSize, o_fmtKwd, + o_fmtkwdSize, l_mvpdKeywords); + if( o_fmtKwd != NULL ) + { + delete[] l_keyword; + l_keyword = new char [o_fmtkwdSize]; + memcpy(l_keyword,o_fmtKwd,o_fmtkwdSize); + l_asciiKeywordSize = o_fmtkwdSize; + delete[] o_fmtKwd; + } + + uint8_t *l_keywordAddr= + reinterpret_cast<uint8_t *> + (&this->iv_spPcrd->hdatKwd); + + memcpy(l_keywordAddr ,l_keyword,l_asciiKeywordSize); + + if(l_keyword != NULL) + { + delete[] l_keyword; + } + + this->iv_spPcrd->hdatPcrdIntData + [HDAT_PCRD_DA_ASCII_KWD].hdatOffset = + offsetof(hdatSpPcrd_t, hdatKwd); + this->iv_spPcrd->hdatPcrdIntData + [HDAT_PCRD_DA_ASCII_KWD].hdatSize = l_asciiKeywordSize; + this->iv_spPcrd->hdatHdr.hdatSize += l_asciiKeywordSize; + + // Populating of ASCII KWD Done. Time for Full mvpd dptr + // Set the offset of Full MVPD int dptr based on prev dptr end point + this->iv_spPcrd->hdatPcrdIntData + [HDAT_PCRD_DA_CHIP_VPD].hdatOffset = + offsetof(hdatSpPcrd_t, hdatKwd) + l_asciiKeywordSize; + + // Get full Mvpd. + char *l_FullMvpd = NULL; + size_t l_FullMvpdSize = HDAT_FULL_MVPD_SIZE - 1; + + l_errl = hdatGetFullEepromVpd(l_pProcTarget, + l_FullMvpdSize, + l_FullMvpd); + + if(l_errl) + { + HDAT_ERR("hdatGetFullEepromVpd returns Error [0x%08X]", + l_errl->reasonCode()); + break; + } + + //Virt address to fill full mvpd based on prev dptr end point + uint8_t *l_FullMvpdAddr = (reinterpret_cast<uint8_t *> + (&this->iv_spPcrd->hdatKwd)) + l_asciiKeywordSize; + + if(l_FullMvpd != NULL) + { + memcpy(l_FullMvpdAddr ,(uint8_t *)l_FullMvpd,l_FullMvpdSize); + delete[] l_FullMvpd; + l_FullMvpd = NULL; + } + + // Set the Full mvpd dptr and full pcrd struct sizes + this->iv_spPcrd->hdatPcrdIntData + [HDAT_PCRD_DA_CHIP_VPD].hdatSize = l_FullMvpdSize; + this->iv_spPcrd->hdatHdr.hdatSize += l_FullMvpdSize; + + } + if( NULL != l_errl) + { + break; + } + index++; + + // The PCRD structure is a fixed size and has boundary of 128 bytes + // so padding by 128 boundary. + uint32_t l_rem=0, l_pad=0; + l_rem=0; l_pad=0; + l_rem = this->iv_spPcrd->hdatHdr.hdatSize % 128; + l_pad = l_rem ? (128 - l_rem ) : 0; + + l_addr += this->iv_spPcrd->hdatHdr.hdatSize; + + // padding is allocated for size of PCRD entry. If it was + // smaller than 128 bytes, then you may need to bump it up + l_addr += l_pad; + this->iv_spPcrd = reinterpret_cast<hdatSpPcrd_t *>(l_addr); + } + o_size = (reinterpret_cast<uint8_t *> (this->iv_spPcrd) + - l_offset ) / index ; + o_count = index; + }while(0); + + return l_errl; +} + +/******************************************************************************* +* hdatSetProcessorInfo +*******************************************************************************/ +errlHndl_t HdatPcrd::hdatSetProcessorInfo( + const TARGETING::Target* i_pProcTarget, uint32_t i_procstatus) +{ + errlHndl_t l_errl = NULL; + + do + { + if(NULL == i_pProcTarget) + { + HDAT_ERR("Input Target Pointer is NULL"); + /*@ + * @errortype + * @moduleid HDAT::MOD_PCRD_SET_PROC_INF + * @reasoncode HDAT::RC_INVALID_OBJECT + * @userdata1 Index of proc target + * @userdata2 Target HUID + * @devdesc Input Target Pointer is NULL + * @custdesc Firmware encountered an internal + * error while retrieving target data + */ + hdatBldErrLog(l_errl, + MOD_PCRD_SET_PROC_INF, + RC_INVALID_OBJECT, + 0,0,0,0); + break; + } + iv_spPcrd->hdatChipData.hdatPcrdProcChipId = + i_pProcTarget->getAttr<TARGETING::ATTR_ORDINAL_ID>(); + + iv_spPcrd->hdatChipData.hdatPcrdStatusFlags = + isFunctional(i_pProcTarget)? i_procstatus : HDAT_PROC_NOT_USABLE; + + //Set NxFunctional State + iv_spPcrd->hdatChipData.hdatPcrdNxFunctional = 0; + TARGETING::PredicateCTM l_predNx(TARGETING::CLASS_UNIT, + TARGETING::TYPE_NX); + TARGETING::TargetHandleList l_predNxlist; + TARGETING::targetService().getAssociated(l_predNxlist, i_pProcTarget, + TARGETING::TargetService::CHILD, + TARGETING::TargetService::ALL, &l_predNx); + if(l_predNxlist.size() > 0) + { + TARGETING::Target *l_predNxTarget = l_predNxlist[0]; + iv_spPcrd->hdatChipData.hdatPcrdNxFunctional = + isFunctional(l_predNxTarget); + } + + //set PORE functional state + iv_spPcrd->hdatChipData.hdatPcrdPoreFunctional = 0; + TARGETING::PredicateCTM l_predPore(TARGETING::CLASS_UNIT, + TARGETING::TYPE_PORE); + TARGETING::TargetHandleList l_predPorelist; + TARGETING::targetService().getAssociated(l_predPorelist, i_pProcTarget, + TARGETING::TargetService::CHILD, + TARGETING::TargetService::ALL, &l_predPore); + + if (l_predPorelist.size() > 0) + { + TARGETING::Target *l_predPoreTarget = l_predPorelist[0]; + iv_spPcrd->hdatChipData.hdatPcrdPoreFunctional = + isFunctional(l_predPoreTarget); + + } + + uint32_t l_procFabricId = + i_pProcTarget->getAttr<TARGETING::ATTR_FABRIC_NODE_ID>(); + + // Set fabric nodeid (NNN) and chip (CC) into xscom id: NN_N0CC + uint32_t l_XscomChipId = + i_pProcTarget->getAttr<TARGETING::ATTR_FABRIC_CHIP_ID>(); + l_XscomChipId |= l_procFabricId << 3; + + + iv_spPcrd->hdatChipData.hdatPcrdXscomChipId = l_XscomChipId; + + + TARGETING::TargetHandleList targetListNode; + targetListNode.clear(); + getParentAffinityTargets(targetListNode,i_pProcTarget, + TARGETING::CLASS_ENC,TARGETING::TYPE_NODE); + if(targetListNode.empty()) + { + /*@ + * @errortype + * @moduleid HDAT::MOD_PCRD_SET_PROC_INF: + * @reasoncode HDAT::RC_EMPTY_TARGET_LIST + * @devdesc Input Target Pointer is NULL + * @custdesc Firmware encountered an internal + * error while retrieving target data + */ + hdatBldErrLog(l_errl, + MOD_PCRD_SET_PROC_INF, + RC_EMPTY_TARGET_LIST, + 0,0,0,0); + break; + } + //get the parent node id + TARGETING::Target* l_pNodeTarget = targetListNode[0]; + + iv_spPcrd->hdatChipData.hdatPcrdDbobId = + l_pNodeTarget->getAttr<TARGETING::ATTR_ORDINAL_ID>(); + + iv_spPcrd->hdatChipData.hdatPcrdOccFuncState = 0; + TARGETING::PredicateCTM l_occPredicate(TARGETING::CLASS_UNIT, + TARGETING::TYPE_OCC); + TARGETING::TargetHandleList l_occList; + TARGETING::targetService().getAssociated(l_occList, i_pProcTarget, + TARGETING::TargetService::CHILD, + TARGETING::TargetService::ALL, &l_occPredicate); + if(l_occList.size() > 0) + { + TARGETING::Target *l_pOccTarget = l_occList[0]; + iv_spPcrd->hdatChipData.hdatPcrdOccFuncState = + isFunctional(l_pOccTarget); + } + + iv_spPcrd->hdatChipData.hdatPcrdProcessorFruId = + i_pProcTarget->getAttr<TARGETING::ATTR_FRU_ID>(); + + uint32_t l_eclevel = 0; + uint32_t l_chipId = 0; + + //Set the Chip EC level + l_errl = HDAT::hdatGetIdEc(i_pProcTarget, l_eclevel, l_chipId); + if(NULL != l_errl) + { + HDAT_ERR("Error [0x%08X] in call to get IdEc Failed", + l_errl->reasonCode()); + break; + } + iv_spPcrd->hdatChipData.hdatPcrdChipECLevel = l_eclevel; + iv_spPcrd->hdatChipData.hdatPcrdHwModuleId = + i_pProcTarget->getAttr<TARGETING::ATTR_FRU_ID>(); + // Set Hardware Card ID + uint32_t l_HWCardId = 0; + l_errl = hdatGetHwCardId(i_pProcTarget,l_HWCardId); + if(NULL != l_errl) + { + HDAT_ERR("Error [0x%08X] in call to get card id failed", + l_errl->reasonCode()); + break; + } + HDAT_DBG("hw card ID:0x%llx", l_HWCardId); + + iv_spPcrd->hdatChipData.hdatPcrdHwCardID = l_HWCardId; + iv_spPcrd->hdatChipData.hdatPcrdFabricId = l_procFabricId; + iv_spPcrd->hdatChipData.hdatPcrdCcmNodeID = + l_pNodeTarget->getAttr<TARGETING::ATTR_ORDINAL_ID>(); + + //set CAPP functional state + iv_spPcrd->hdatChipData.hdatPcrdCappFunctional = 0; + TARGETING::PredicateCTM l_predCapp(TARGETING::CLASS_UNIT, + TARGETING::TYPE_CAPP); + TARGETING::TargetHandleList l_predCapplist; + TARGETING::targetService().getAssociated(l_predCapplist, i_pProcTarget, + TARGETING::TargetService::CHILD, + TARGETING::TargetService::ALL, &l_predCapp); + + if (l_predCapplist.size() > 0) + { + TARGETING::Target *l_predCappTarget = l_predCapplist[0]; + iv_spPcrd->hdatChipData.hdatPcrdCappFunctional = + isFunctional(l_predCappTarget)?1:0; + } + + //set supported stop level + iv_spPcrd->hdatChipData.hdatPcrdStopLevelSupport = + i_pProcTarget->getAttr<TARGETING::ATTR_SUPPORTED_STOP_STATES>(); + } + while(0); + return l_errl; +} + +/******************************************************************************* +* PCRD Destructor +*******************************************************************************/ +HdatPcrd :: ~HdatPcrd() +{ + int rc = 0; + rc = mm_block_unmap(reinterpret_cast<void*>(ALIGN_PAGE_DOWN( + reinterpret_cast<uint64_t>(iv_spPcrd)))); + if( rc != 0) + { + errlHndl_t l_errl = NULL; + /*@ + * @errortype + * @moduleid HDAT::MOD_PCRD_DESTRUCTOR + * @reasoncode HDAT::RC_DEV_MAP_FAIL + * @devdesc Unmap a mapped region failed + * @custdesc Firmware encountered an internal error. + */ + hdatBldErrLog(l_errl, + MOD_PCRD_DESTRUCTOR, + RC_DEV_MAP_FAIL, + 0,0,0,0, + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + HDAT_VERSION1, + true); + } +} + + +} // namespace HDATPcrd diff --git a/src/usr/hdat/hdatpcrd.H b/src/usr/hdat/hdatpcrd.H new file mode 100644 index 000000000..b3ac168d3 --- /dev/null +++ b/src/usr/hdat/hdatpcrd.H @@ -0,0 +1,267 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hdat/hdatpcrd.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 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 hdatpcrd.H + * + * @brief This file contains the definition of the Processor Chip Related + * Data structure. + * + * A C++ class is defined that is used to update the copy of the PCRD. + * The PCRD is written to main memory. + */ + +#ifndef HDATPCRD_H +#define HDATPCRD_H + +/*----------------------------------------------------------------------------*/ +/* Includes */ +/*----------------------------------------------------------------------------*/ +#include <hdat/hdat.H> +#include <errl/errlentry.H> +#include <hdat/hdat_reasoncodes.H> +#include "hdatutil.H" + +namespace HDAT +{ + +/*----------------------------------------------------------------------------*/ +/* Constants */ +/*----------------------------------------------------------------------------*/ + +#define HDAT_NUM_P7_PCRD_ENTRIES 32 +#define HDAT_FULL_MVPD_SIZE 0x10000 +const uint16_t HDAT_PCRD_VERSION = 0x0D; +const char HDAT_PCRD_STRUCT_NAME[7] = "SPPCRD"; + +/** @enum hdatDataPtrs + * Enumeration which defines the data sections of the PCRD + */ +enum hdatPcrdDataPtrs +{ + // Values used for PCRD + HDAT_PCRD_DA_CHIP_INFO = 0, + HDAT_PCRD_DA_CHIP_TIMEOFDAY = 1, + HDAT_PCRD_DA_FRU_ID = 2, + HDAT_PCRD_DA_ASCII_KWD = 3, + HDAT_PCRD_DA_CHIP_VPD = 4, + HDAT_PCRD_DA_CNT = 5, + HDAT_PCRD_DA_LAST = 8, +}; + +/*----------------------------------------------------------------------------*/ +/* Type definitions */ +/*----------------------------------------------------------------------------*/ + +/* + * @brief This defines the Chip Info structure in the PCRD. + */ +struct hdatPcrdChipInfo_t +{ + uint32_t hdatPcrdProcChipId; // 0x0000 Processor Chip ID + uint32_t hdatPcrdStatusFlags; // 0x0004 verify/exist flags + uint32_t hdatPcrdNxFunctional; // 0x0008 NX functional + uint32_t hdatPcrdPoreFunctional; // 0x000C Pore functional + uint32_t hdatPcrdXscomChipId; // 0x0010 XSCOM chip ID + uint32_t reserved_01; // 0x0014 ECO Cores + uint32_t hdatPcrdDbobId; // 0x0018 Drawer/Book/Octant/Blade ID + // (DBOB) + uint32_t hdatPcrdOccFuncState; // 0x001C OCC Functional State + uint32_t hdatPcrdProcessorFruId; // 0x0020 Processor FRU ID + uint32_t hdatPcrdChipECLevel; // 0x0024 Chip EC Level + uint32_t hdatPcrdHwModuleId; // 0x0028 Hardware module ID + uint32_t hdatPcrdHwCardID; // 0x002C HW Card ID + uint32_t hdatPcrdFabricId; // 0x0030 Internal Drawer Node ID + // (Fabric Id) + uint32_t hdatPcrdCcmNodeID; // 0x0034 CCM Node ID + uint32_t hdatPcrdCappFunctional; // 0x0038 Capp functional state + uint32_t hdatPcrdStopLevelSupport; // 0x003C Supported Stop Level +} __attribute__ ((packed)); + +/* @brief Defines 'chip time-of-day structure in the PCRD */ +struct hdatPcrdChipTod_t +{ + uint32_t hdatPcrdTodFlags; // 0x0000 Flags + uint32_t hdatPcrdTodControls; // 0x0004 Time-of-day controls + uint32_t hdatPcrdTodControlRegister; // 0x0008 Chip Time-of-day + // control register +} __attribute__ ((packed)); + +/** @brief Defines the PCRD. + * FipS updates this portion and DMAs the entire PCRD back to main memory. + */ +struct hdatSpPcrd_t +{ + hdatHDIF_t hdatHdr; + hdatHDIFDataHdr_t hdatPcrdIntData[HDAT_PCRD_DA_LAST]; + hdatPcrdChipInfo_t hdatChipData; + hdatPcrdChipTod_t hdatChipTodData; + hdatFruId_t hdatFruId; + char *hdatKwd; + uint8_t *vpd_data; + //add in padding here. uint32_t whatever it is. +} __attribute__ ((packed)); + + +/*----------------------------------------------------------------------------*/ +/* C++ class definition */ +/*----------------------------------------------------------------------------*/ + +/** Begin Class Description + * + * @brief The HdatPcrd class is used to construct the PCRD object. + * + * Description: This class defines a specialized object. It is not intended + * that any component can create an object of this type. + * In particular, the object is built only in the + * CEC Server process when requested by the hdat component. + * + * The real purpose of the object is to create the PCRD array + * structure as defined by the PHYP Initialization architecture. + * + * Signal handler usage: This class is not intended to be used in a signal + * handler + * + * End Class Description + */ +class HdatPcrd +{ + public: + /** + * @brief Construct an HdatPcrd object + * + * This is the constructor for the HdatPcrd object. + * + * @pre None + * + * @post An HdatPcrd object pointer would be pointing to the host memory + * where the data would be directly written on to the memory. + * Each PCRD entry is initialized to indicate the processor is not + * installed. If the processor is installed, set the status and + * supply other information. + * + * @param[out] o_errlHndl + * If any errors occur, the HdatPcrd object is NOT constructed + * and errors are returned in this parameter + + * @param[in] i_msAddr + * The main memory address that the PCRD structure will be DMA'd to. + * + * @return A null error log handle if successful, else the return code + * pointed to by o_errlHndl. + * + */ + + HdatPcrd(errlHndl_t &o_errlHndl, + const hdatMsAddr_t &i_msAddr); + + /** + * @brief HdatPcrd object destructor + * + * This is the destructor for an HdatPcrd object. + * + * @pre No preconditions exist + * + * @post The HdatPcrd object has been destroyed and can no longer be used. + * + */ + + ~HdatPcrd(); + + /** + * @brief Load the HdatPcrd object + * + * This function is used to the load the HdatPcrd object with all the + * hdatSpPcrd_t structure data. HdatPcrd object would be having all + * the processor data which are present and all the present which + * are not functional also + * + * @param[out] o_size + * Size of PCRD object which are written onto Host memory. + * + * @param[out] o_count + * Count of PCRD objects which are written onto Host memory. + * + * @pre HdatPcrd Object should be constructed with the main memory address + * + * @post The HdatPcrd object with all the PCRD entry populated. + * + * @return A null error log handle if successful, else the return code + * pointed to by o_errlHndl. + */ + errlHndl_t hdatLoadPcrd(uint32_t &o_size, uint32_t &o_count); + + private: + + /** Object instance Data + * + * Only one copy of this data exists in a process. + * + */ + + /* @li iv_msAddr - main memory address the final data structure written */ + hdatMsAddr_t iv_msAddr; + + /* @li iv_numPcrdEntries - number of PCRD entries*/ + uint32_t iv_numPcrdEntries; // Number of PCRD entries + + /* @li iv_spPcrdEntrySize - size of one entry in PCRD*/ + uint32_t iv_spPcrdEntrySize; // Size of a PCRD entry + + /* @li iv_spPcrd - pointer to the first PCRD Entry */ + hdatSpPcrd_t *iv_spPcrd; + + /** + * @brief Set the Processor Chip Related Info + * + * This function is an helper function used to set the processor chip + * specific info into the HdatPcrd object with for all the + * hdatHDIF_t, hdatHDIFDataHdr_t, hdatPcrdChipInfo_t, + * hdatPcrdChipTod_t and module VPD related data into structure data. + * + * @pre HdatPcrd Object should be constructed with the main memory address + * Target pointer to the present procs in the system + * + * @post The HdatPcrd object with all the processor chipd related data + * populated. + * + * @param[in] i_pTarget + * Proc target pointer. Must not be NULL (otherwise call will return an + * error log). Must be a valid target from the system blueprint. + * + * @param[in] i_procstatus + * Processor status place holder + * + * @return A null error log handle if successful, else the return code + * pointed to by o_errlHndl. + */ + + errlHndl_t hdatSetProcessorInfo(const TARGETING::Target* i_pProcTarget, + uint32_t i_procstatus); +}; + + +} //namespace HDAT +#endif // HDATPCRD_H diff --git a/src/usr/hdat/hdatram.C b/src/usr/hdat/hdatram.C new file mode 100755 index 000000000..a0d671f8e --- /dev/null +++ b/src/usr/hdat/hdatram.C @@ -0,0 +1,194 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hdat/hdatram.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 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 hdatram.C + * + * @brief This file contains the implementation of the HdatRam class. + * + */ + +/*----------------------------------------------------------------------------*/ +/* Includes */ +/*----------------------------------------------------------------------------*/ +#include "hdatram.H" // HdatRam class definition +#include "hdatutil.H" // utility functions +#include "hdatmsvpd.H" + +#include <stdio.h> + + +namespace HDAT +{ +/*----------------------------------------------------------------------------*/ +/* Global variables */ +/*----------------------------------------------------------------------------*/ +uint32_t HdatRam::cv_actualCnt; + +vpdData cvpdData[] = +{ +// { CVPD::VINI, CVPD::RT }, + { CVPD::VINI, CVPD::DR }, + { CVPD::VINI, CVPD::FN }, + { CVPD::VINI, CVPD::PN }, + { CVPD::VINI, CVPD::SN }, + { CVPD::VINI, CVPD::CC }, +// { CVPD::VINI, CVPD::PR }, + //{ CVPD::VINI, CVPD::SZ }, + { CVPD::VINI, CVPD::HE }, + { CVPD::VINI, CVPD::CT }, + { CVPD::VINI, CVPD::HW }, + // { CVPD::VINI, CVPD::B3 }, + // { CVPD::VINI, CVPD::B4 }, + // { CVPD::VINI, CVPD::B7 }, + { CVPD::VINI, CVPD::PF }, +}; +/*----------------------------------------------------------------------------*/ +/* Constants */ +/*----------------------------------------------------------------------------*/ + + + +/** @brief See the prologue in hdatram.H + */ +HdatRam::HdatRam(errlHndl_t &o_errlHndl, + TARGETING::Target * i_target, + uint32_t i_resourceId, + uint32_t i_slcaIndex) + +: HdatHdif(o_errlHndl, HDAT_RAM_STRUCT_NAME, HDAT_RAM_LAST, cv_actualCnt++, + HDAT_NO_CHILD, HDAT_RAM_VERSION), + iv_kwdSize(0), iv_kwd(NULL) +{ + HDAT_ENTER(); + + + iv_fru.hdatResourceId = i_resourceId; + + if ( i_slcaIndex != 0) + { + iv_fru.hdatSlcaIdx = i_slcaIndex; + } + else + { + iv_fru.hdatSlcaIdx = i_target->getAttr<TARGETING::ATTR_SLCA_INDEX>(); + } + + hdatGetAsciiKwdForSpd(i_target,iv_kwdSize,iv_kwd); + + // Update the base class internal data pointers + // When the data is written to the file by commit(), it must be done in the + // same order as these addData() calls + this->addData(HDAT_RAM_FRU_ID, sizeof(hdatFruId_t)); + this->addData(HDAT_RAM_KWD, iv_kwdSize); + this->addData(HDAT_RAM_ID, sizeof(hdatRamAreaId_t)); + this->addData(HDAT_RAM_SIZE, sizeof(hdatRamAreaSize_t)); + this->align(); + + HDAT_EXIT(); + return; +} + + +/** @brief See the prologue in hdatram.H + */ +HdatRam::~HdatRam() +{ + HDAT_ENTER(); + + delete [] iv_kwd; + + HDAT_EXIT(); + return; +} + + +/** @brief See the prologue in hdatram.H + */ +uint32_t HdatRam::getRamSize() +{ + uint32_t l_size = 0; + // Start committing the base class data + l_size += this->getSize(); + + // Write the various pieces of data from this derived class + l_size += sizeof(hdatFruId_t); + if (iv_kwdSize > 0) + { + l_size += iv_kwdSize; + } + l_size += sizeof(hdatRamAreaId_t); + l_size += sizeof(hdatRamAreaSize_t); + + l_size+= this->endCommitSize(); + + return l_size; +} + +/** @brief See the prologue in hdatram.H + */ +void HdatRam::commit(UtilMem &i_data) +{ + + // Start committing the base class data + this->startCommit(i_data); + + i_data.write(&iv_fru, sizeof(hdatFruId_t)); + if (iv_kwdSize > 0) + { + i_data.write(iv_kwd,iv_kwdSize); + } + i_data.write(&iv_ramArea, sizeof(hdatRamAreaId_t)); + i_data.write(&iv_ramSize, sizeof(hdatRamAreaSize_t)); + + this->endCommit(i_data); + +} + + +/** @brief See the prologue in hdatram.H + */ +void HdatRam::prt() +{ + HDAT_INF(" **** HdatRam start ****"); + HDAT_INF(" cv_actualCnt = %u", cv_actualCnt); + HDAT_INF(" iv_kwdSize = %u", iv_kwdSize); + this->print(); + //hdatPrintFruId(&iv_fru); + hdatPrintKwd(iv_kwd, iv_kwdSize); + + HDAT_INF(" **hdatRamAreaId_t**"); + HDAT_INF(" hdatRamAreaId = %u", iv_ramArea.hdatRamAreaId); + HDAT_INF(" hdatRamStatus = 0X %04X", iv_ramArea.hdatRamStatus); + + HDAT_INF(" **hdatRamAreaSize_t**"); + HDAT_INF(" hdatReserved1 = %u", iv_ramSize.hdatReserved1); + HDAT_INF(" hdatRamTotalSize = %u", iv_ramSize.hdatRamTotalSize); + + HDAT_INF(" **** HdatRam end ****"); + + return; +} +} diff --git a/src/usr/hdat/hdatram.H b/src/usr/hdat/hdatram.H new file mode 100755 index 000000000..4c8e2ec20 --- /dev/null +++ b/src/usr/hdat/hdatram.H @@ -0,0 +1,257 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hdat/hdatram.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 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 HDATRAM_H +#define HDATRAM_H + +/** + * @file hdatram.H + * + * @brief This file contains the class definition for the RAM object which + * describes memory DIMMS. This structure is part of the larger + * mainstore VPD structure which describes the various chips which + * make up the memory subsystem. + * + */ + + +/*----------------------------------------------------------------------------*/ +/* Includes */ +/*----------------------------------------------------------------------------*/ +#include <stdint.h> // standard types +#include <hdat/hdat.H> // HDAT header type definitions +#include "hdathdif.H" // HdatHdif base class definition +#include <errl/errlentry.H> // ErrlEntry class + +namespace HDAT +{ + +/*----------------------------------------------------------------------------*/ +/* Typedefs */ +/*----------------------------------------------------------------------------*/ + +/** @brief Structure definition for the RAM ID and status + */ +struct hdatRamAreaId_t +{ + uint16_t hdatRamAreaId; // 0x0000 Identifier for this RAM area + uint16_t hdatRamStatus; // 0x0002 Status of the RAM DIMM +} __attribute__ ((packed)); + + +/** @brief Structure definition for the RAM size + */ +struct hdatRamAreaSize_t +{ + uint32_t hdatReserved1; // 0x0000 Reserved to make hdatRamTotalSize 8 + // bytes in future + uint32_t hdatRamTotalSize; // 0x0004 Total size of configured main store + // in this RAM area in megabytes +} __attribute__ ((packed)); + + +/*---------------------------------------------------------------------------*/ +/* Constants */ +/*---------------------------------------------------------------------------*/ +const char HDAT_RAM_STRUCT_NAME[] = "RAM "; + +const uint16_t HDAT_RAM_VERSION = 0x0020; + + +/** @brief eye catcher for the HDIF header for the RAM data area + */ + +/** @enum hdatDataPtrs + * Constants for the internal data pointers that are added to the base class + */ +enum hdatRamDataPtrs +{ + HDAT_RAM_FRU_ID = 0, + HDAT_RAM_KWD = 1, + HDAT_RAM_ID = 2, + HDAT_RAM_SIZE = 3, + HDAT_RAM_RESERVED1 = 4, + HDAT_RAM_RESERVED2 = 5, + HDAT_RAM_LAST = 6 +}; +/*----------------------------------------------------------------------------*/ +/* C++ class definition */ +/*----------------------------------------------------------------------------*/ + +/** Begin Class Description + * + * @brief The HdatRam class is used to construct objects for memory DIMMs. + * + * Description: This class defines a specialized object. It is not intended + * that anyone can create an object of this type. In particular, + * the object is built only as a internal object within the + * HdatMsArea object. + * + * The real purpose of the object is to create the various RAM + * structures as defined by the PHYP Initialization architecture + * This data structure is eventually DMA'd to main memory. The + * class is not defined to be a general purpose interface for + * building this object by anyone other than the hdatstep process. + * + * Thread safety: An HdatRam object is not thread safe. That is, a single + * object cannot be shared and used concurrently by + * multiple threads at the same time. An object can be used by + * multiple threads if the threads serialize access. And of + * course, each thread can use its own object with no concerns + * about what other threads are doing. + * + * Signal handler usage: This class is not intended to be used in a signal + * handler and nothing has been done to try and make it safe to use + * in a signal handler. + * + * End Class Description + */ +class HdatRam : public HdatHdif +{ +public: + + + /** + * @brief Construct an HdatRam object. + * + * This is the constructor for the HdatRam object. + * + * If you are constructing this object on the heap by using new, then + * you must check the pointer returned from new to see if it is null. + * If it is null, new failed to allocate storage and the constructor + * was not called. If it is not null, then you must check o_errlHndl + * to see if the constructor ran successfully. If o_errlHndl indicates + * an error was reported by the constructor, new has already allocated + * heap storage and the object must be deleted in order to free the + * heap storage. + * + * @pre None + * + * @post An HdatRam object has been constructed. + * Heap storage has been allocated. + * + * @param[out] o_errlHndl - If any errors occur, the HdatRam object + * is NOT constructed and errors are returned in this parameter + * @param[in] i_resourceId - input parameter - The FRU's resource id + * @param[in] i_slcaIndex - input parameter - ms area slca index, + * if not provided then add dimms slca index + * + * @return A null error log handle if successful, else the return code pointed + * to by o_errlHndl contains one of: + * + * @retval HDAT_OTHER_COMP_ERROR + */ + HdatRam(errlHndl_t &o_errlHndl, + TARGETING::Target* i_target, + uint32_t i_resourceId, + uint32_t i_slcaIndex=0); + + + /** + * @brief HdatRam object destructor + * + * This is the destructor for an HdatRam object. Any heap storage + * allocated for the object is dallocated. + * + * @pre No preconditions exist + * + * @post The HdatRam object has been destroyed and can no longer be used. + * + */ + virtual ~HdatRam(); + + /** + * @brief Get Ram area size + * + * This method invokes ram getSize routine for all the child pointers + * and gets the size. + * + * @pre None + * + * @post None + * + * @return - returns size value + * + */ + uint32_t getRamSize(); + + /** + * @brief Writes the MS area data in main store memory + * + * @pre None + * + * @post None + * + * @param[inout] i_data - memory used to write the data + * + * + */ + void commit(UtilMem &i_data); + + /** + * @brief Print an HdatRam object. + * + * This method is a debug mthod which prints out a RAM object. + * + * @pre None + * + * @post None + * + */ + void prt(); + + /** Object Instance Data + * @li iv_ramArea - RAM Id structure + * @li iv_ramSize - RAM size structure + */ + hdatRamAreaId_t iv_ramArea; + hdatRamAreaSize_t iv_ramSize; + +private: + + + /** Object Instance Data + * + * @li iv_kwdSize - size of the VPD ASCII keyword + * @li iv_kwd - ptr to the VPD ASCII keyword + * @li iv_fru - FRU id structure + */ + size_t iv_kwdSize; + char *iv_kwd; + hdatFruId_t iv_fru; + + /** Class (static) Data + * + * Only one copy of this data exists in a process. + * + * @li cv_actualCnt - a count of how many HdatRam objects are created + */ + static uint32_t cv_actualCnt; + +}; // end of HdatRam class + +} + +#endif // HDATRAM_H diff --git a/src/usr/hdat/hdatspiraH.C b/src/usr/hdat/hdatspiraH.C new file mode 100755 index 000000000..b0bab3ed9 --- /dev/null +++ b/src/usr/hdat/hdatspiraH.C @@ -0,0 +1,377 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hdat/hdatspiraH.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 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 hdatspiraH.H + * + * @brief This file contains the definition of the Service Processor Interface + * Root Array Secure boot (SPIRA-H) data structure. This data structure + * is prebuilt as part of one of the LIDS loaded into memory. + * + * Usage note: The SPIRA-H structure is built as part of the host LIDs. + * These are big endian structures. If this structure is used on a little + * endian machine, the user is responsible for performing big endian to + * little endian conversions. + */ + +/*-----------------------------------------------------------------------------*/ +/* Includes */ +/*-----------------------------------------------------------------------------*/ +#include <stdlib.h> +#include <sys/mm.h> +#include <sys/mmio.h> +#include "hdatspiraH.H" +#include "hdatutil.H" +#include "hdatvpd.H" +#include <util/align.H> +#include <targeting/common/util.H> +/*-----------------------------------------------------------------------------*/ +/* Global variables */ +/*-----------------------------------------------------------------------------*/ +extern trace_desc_t *g_trac_hdat; +/*-----------------------------------------------------------------------------*/ +/* Constants */ +/*-----------------------------------------------------------------------------*/ +const uint16_t HDAT_SPIRAH_VERSION = 0x50; + +using namespace TARGETING; + +namespace HDAT +{ + +/** + * @brief Construct an HdatSpiraH object. + * + * This function maps the Service Processor Interface Root Array (SPIRA-H) + * structure from the mainstore address where the containing lid loaded. + * + * @pre The SPIRA-H containing Lid must have loaded in mainstore. + * + * @post The SPIRA-H data mapped to a HB process' memory + * + * @param o_errlHndl - output parameter - error log handle + * + * @return A null error log handle if successful, else the return code pointed + * to by errlHndl_t + * + */ +HdatSpiraH::HdatSpiraH(errlHndl_t &o_errlHndl, hdatMsAddr_t &i_msAddr) +{ + + HDAT_ENTER(); + + HDAT_DBG("HdatSpiraH i_msAddr addr hi 0x%08X lo 0x%08X", + i_msAddr.hi, i_msAddr.lo); + memcpy(&iv_msAddr , &i_msAddr , sizeof(hdatMsAddr_t)); + + // Get Target Service, and the system target. + TargetService& l_targetService = targetService(); + TARGETING::Target* l_sysTarget = NULL; + (void) l_targetService.getTopLevelTarget(l_sysTarget); + + // asserting + assert(l_sysTarget != NULL); + + uint64_t l_hrmor = l_sysTarget->getAttr<ATTR_PAYLOAD_BASE>(); + l_hrmor = l_sysTarget->getAttr<ATTR_PAYLOAD_BASE>() * MEGABYTE; + iv_msAddr +=l_hrmor; + + // Allocate space for spiraH in process memory + + iv_spirah = reinterpret_cast<hdatSpiraH_t *>(calloc(sizeof(hdatSpiraH_t), + 1)); + + if(NULL == o_errlHndl) + { // Set SPIRA-H to defaults + setSpiraHHdrs(); + } + + // Now get the spiraH from mainstore address. + o_errlHndl = getSpiraH(); + + HDAT_EXIT(); + return; +} + +/** + * @brief This function gets the spirah from the stored mainstore adress. + * The mainstore address is where spirah is loaded as part of lid. + * + * @pre The primary LID which contains the NACA and the primary/secondary LID + * which contains the SPIRA-H must have been loaded + * + * @post The SPIRA-H is copied into process space. + * + */ +errlHndl_t HdatSpiraH::getSpiraH() +{ + errlHndl_t l_errlHndl = NULL; + HDAT_ENTER(); + + if(iv_msAddr != 0) + { + uint64_t l_base_addr_down = ALIGN_PAGE_DOWN((uint64_t)iv_msAddr); + iv_virt_addr = (uint8_t *)mm_block_map( + reinterpret_cast<void*>(l_base_addr_down), + (ALIGN_PAGE(sizeof(hdatSpiraH_t)) + PAGESIZE)); + iv_virt_addr = iv_virt_addr + + ((uint64_t)iv_msAddr - ALIGN_PAGE_DOWN((uint64_t)iv_msAddr)); + + memcpy((void *)iv_spirah,(void *)iv_virt_addr,sizeof(hdatSpiraH_t)); + } + else + { + /*@ + * @errortype + * @moduleid HDAT::MOD_HDAT_GET_SPIRAH + * @reasoncode HDAT::RC_NULL_PTR_PASSED + * @devdesc Null passed for spirah ms addr + * @custdesc Firmware encountered an internal error. + */ + + hdatBldErrLog(l_errlHndl, + MOD_HDAT_GET_SPIRAH, + RC_NULL_PTR_PASSED, + 0,0,0,0, + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + HDAT_VERSION1, + true); + } + HDAT_EXIT(); + return l_errlHndl; +} + + +/** + * @brief HdatSpiraH object destructor + * + * This is the destructor for an HdatSpiraH object. Any heap storage + * allocated for the object is dallocated. + * + * @pre No preconditions exist + * + * @post The HdatSpiraH object has been destroyed and can no longer be used. + * + */ +HdatSpiraH::~HdatSpiraH() +{ + errlHndl_t l_errlHndl = NULL; + uint32_t rc=0; + HDAT_ENTER(); + + free(iv_spirah); + if(iv_virt_addr != NULL) + { + rc = mm_block_unmap(reinterpret_cast<void*>( + ALIGN_PAGE_DOWN((uint64_t)iv_virt_addr))); + if( rc != 0) + { + /*@ + * @errortype + * @moduleid HDAT::MOD_HDAT_SPIRAH_DTOR + * @reasoncode HDAT::RC_DEV_MAP_FAIL + * @userdata1 Spirah address hi + * @userdata2 Spirah address lo + * @devdesc Unmap a mapped region failed + * @custdesc Firmware encountered an internal error. + */ + hdatBldErrLog(l_errlHndl, + HDAT::MOD_HDAT_SPIRAH_DTOR, + RC_DEV_MAP_FAIL, + static_cast<uint32_t>(iv_msAddr>> 32), + static_cast<uint32_t>(iv_msAddr), + 0,0, + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + HDAT_VERSION1, + true); + } + } + + HDAT_EXIT(); +} + + +/** + * @brief This function computes the address of a 5-tuple entry within the + * SPIRA-H structure and returns it. + * + * Usage note: The SPIRA-H structure is built as part of the host LIDs. + * These are big endian structures. This function performs any + * big endian to little endian conversions needed. + * + * @pre None + * + * @post A copy of the desired 5-tuple returned, with any endian conversion done. + * + * @param i_dataArea - input parameter - an enumeration for the 5-tuple entry + * being requested. + * @param o_entry - output parameter - a copy of the 5-tuple entry being + * requested, with any endian conversion already performed. + * + * @return NONE + */ +void HdatSpiraH::getSpiraHEntry(hdatSpiraHDataAreas i_dataArea, + hdat5Tuple_t &o_entry) +{ + HDAT_ENTER(); + hdatHDIF_t *l_hdif; + hdatHDIFDataHdr_t *l_dataHdr; + hdat5Tuple_t *l_entry; + hdatHDIFDataArray_t *l_arrayHdr; + + // Compute the address of the entry in the SPIRA-H the caller wants. This + // entry is a 5-tuple for a particular data structure. + l_hdif = reinterpret_cast<hdatHDIF_t *>(iv_spirah); + + l_dataHdr = reinterpret_cast<hdatHDIFDataHdr_t *>(reinterpret_cast<char *> + (l_hdif) + l_hdif->hdatDataPtrOffset); + + l_arrayHdr = reinterpret_cast<hdatHDIFDataArray_t *>( + reinterpret_cast<char *>(l_hdif) + l_dataHdr->hdatOffset); + + l_entry = reinterpret_cast<hdat5Tuple_t *>(reinterpret_cast<char *> + (l_arrayHdr) + l_arrayHdr->hdatOffset + + (l_arrayHdr->hdatAllocSize) * i_dataArea); + + o_entry.hdatAbsAddr.hi = l_entry->hdatAbsAddr.hi; + o_entry.hdatAbsAddr.lo = l_entry->hdatAbsAddr.lo; + o_entry.hdatAllocCnt = l_entry->hdatAllocCnt; + o_entry.hdatActualCnt = l_entry->hdatActualCnt; + o_entry.hdatAllocSize = l_entry->hdatAllocSize; + o_entry.hdatActualSize = l_entry->hdatActualSize; + o_entry.hdatTceOffset = l_entry->hdatTceOffset; + HDAT_EXIT(); + return; +} + +/** + * @brief This function updates a SPIRA-H entry. Any required endian conversion + * is performed on the 5-tuple entry before the update. + * + * @pre None + * + * @post The SPIRA-H has been updated + * + * @param i_dataArea - input parameter - An enumeration for the 5-tuple entry + * being updated. + * @param i_entry - input parameter - the 5-tuple entry being updated. + */ +void HdatSpiraH::chgSpiraHEntry(hdatSpiraHDataAreas i_dataArea, + const hdat5Tuple_t &i_entry) +{ + HDAT_ENTER(); + hdatHDIF_t *l_hdif; + hdatHDIFDataHdr_t *l_dataHdr; + hdatHDIFDataArray_t *l_arrayHdr; + hdat5Tuple_t *l_entry; + + // Compute the address of the entry in the SPIRA-H the caller wants. This + // entry is a 5-tuple for a particular data structure. + l_hdif = reinterpret_cast<hdatHDIF_t *>(iv_spirah); + + l_dataHdr = reinterpret_cast<hdatHDIFDataHdr_t *>(reinterpret_cast<char *> + (l_hdif) + l_hdif->hdatDataPtrOffset); + + l_arrayHdr = reinterpret_cast<hdatHDIFDataArray_t *>( + reinterpret_cast<char *>(l_hdif) + l_dataHdr->hdatOffset); + + l_entry = reinterpret_cast<hdat5Tuple_t *>(reinterpret_cast<char *> + (l_arrayHdr) + l_arrayHdr->hdatOffset + + l_arrayHdr->hdatAllocSize * i_dataArea); + + // Update the data in the SPIRA-H entry. + l_entry->hdatAbsAddr.hi = i_entry.hdatAbsAddr.hi; + l_entry->hdatAbsAddr.lo = i_entry.hdatAbsAddr.lo; + l_entry->hdatAllocCnt = i_entry.hdatAllocCnt; + l_entry->hdatActualCnt = i_entry.hdatActualCnt; + l_entry->hdatAllocSize = i_entry.hdatAllocSize; + l_entry->hdatActualSize = i_entry.hdatActualSize; + l_entry->hdatTceOffset = i_entry.hdatTceOffset; + + HDAT_EXIT(); + return; +} + +/** + * @brief This routine initializes the SPIRA-H HDIF header and clears the N-Tuple array + * + * @pre None + * + * @post None + * + * @param None + * + * @return None + * + * @retval no errors currently defined + */ +void HdatSpiraH::setSpiraHHdrs() +{ + HDAT_ENTER(); + iv_spirah->hdatHDIF.hdatStructId = HDAT_HDIF_STRUCT_ID; + iv_spirah->hdatHDIF.hdatInstance = 0; + iv_spirah->hdatHDIF.hdatVersion = HDAT_SPIRAH_VERSION; + iv_spirah->hdatArrayInfo.hdatArrayCnt = HDAT_SPIRAH_DA_LAST; + iv_spirah->hdatHDIF.hdatSize = sizeof(hdatSpiraH_t); + + iv_spirah->hdatHDIF.hdatHdrSize = sizeof(hdatHDIF_t); + iv_spirah->hdatHDIF.hdatDataPtrOffset = sizeof(hdatHDIF_t); + iv_spirah->hdatHDIF.hdatDataPtrCnt = 1; + iv_spirah->hdatHDIF.hdatChildStrCnt = 0; + iv_spirah->hdatHDIF.hdatChildStrOffset = 0; + + memcpy(iv_spirah->hdatHDIF.hdatStructName, HDAT_SPIRAH_EYE_CATCHER, sizeof(iv_spirah->hdatHDIF.hdatStructName)); + + iv_spirah->hdatDataHdr.hdatOffset = offsetof(hdatSpiraH_t, hdatArrayInfo); + iv_spirah->hdatDataHdr.hdatSize = sizeof(hdatHDIFDataArray_t) + sizeof(iv_spirah->hdatDataArea); + iv_spirah->hdatArrayInfo.hdatOffset = sizeof(hdatHDIFDataArray_t); + iv_spirah->hdatArrayInfo.hdatAllocSize = sizeof(hdat5Tuple_t); + iv_spirah->hdatArrayInfo.hdatActSize = offsetof(hdat5Tuple_t, hdatReserved1); + + memset(iv_spirah->hdatDataArea, 0, sizeof((iv_spirah->hdatDataArea))); + HDAT_EXIT(); + return; +} + + +void HdatSpiraH::chgSpiraHEntry(hdatSpiraHDataAreas i_dataArea, + uint32_t i_actCount,uint32_t i_actSize) +{ + HDAT_ENTER(); + hdatSpiraH_t * l_temp; + + l_temp = reinterpret_cast<hdatSpiraH_t *>(iv_virt_addr); + HDAT_DBG("updating the spiraH hostdata area with count=0x%x and size=0x%x", + i_actCount,i_actSize); + l_temp->hdatDataArea[i_dataArea].hdatActualCnt = i_actCount; + l_temp->hdatDataArea[i_dataArea].hdatActualSize = i_actSize; + + HDAT_DBG("actual count=0x%x, actual size=0x%x", + l_temp->hdatDataArea[i_dataArea].hdatActualCnt, + l_temp->hdatDataArea[i_dataArea].hdatActualSize); + + HDAT_EXIT(); +} + +} //HDAT diff --git a/src/usr/hdat/hdatspiraH.H b/src/usr/hdat/hdatspiraH.H new file mode 100755 index 000000000..c0d336794 --- /dev/null +++ b/src/usr/hdat/hdatspiraH.H @@ -0,0 +1,247 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hdat/hdatspiraH.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 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 HDATSPIRAH_H +#define HDATSPIRAH_H + +/** + * @file hdatspiraH.H + * + * @brief This file contains the definition of the Service Processor Interface + * Root Array Secure boot (SPIRA-H) data structure. This data structure + * is prebuilt as part of one of the LIDS loaded into memory. + * + * Usage note: The SPIRA-H structure is built as part of the host LIDs. + * These are big endian structures. If this structure is used on a little + * endian machine, the user is responsible for performing big endian to + * little endian conversions. + */ + +/*-----------------------------------------------------------------------------*/ +/* Includes */ +/*-----------------------------------------------------------------------------*/ +#include <stdint.h> // integer data type definitions +#include <hdat/hdat.H> +#include "hdathdif.H" +/*-----------------------------------------------------------------------------*/ +/* Constants */ +/*-----------------------------------------------------------------------------*/ +const char HDAT_SPIRAH_EYE_CATCHER[] = "SPIRAH"; + +namespace HDAT +{ + +/*-----------------------------------------------------------------------------*/ +/* Type definitions */ +/*-----------------------------------------------------------------------------*/ + + +/** @enum hdatSpiraHDataAreas + * This enumeration defines the various data areas in spiraH + * This list must be kept in the same order as the 5-tuple entries in + * the SPIRA-H. + * + * If the order is changed, entries are added, or entries are deleted, + * update. + */ +enum hdatSpiraHDataAreas +{ + HDAT_SPIRAH_DA_FIRST = 0, + HDAT_SEC_HOST_DATA_AREA = 0, + HDAT_SEC_PROC_INIT = 1, // phyp-supplied processor init data + HDAT_SEC_CPU_CTRL = 2, // CPU controls + HDAT_SEC_MS_DUMP_SRC_TBL = 3, // mainstore dump source table (can change at run time) + HDAT_SEC_MS_DUMP_DST_TBL = 4, // mainstore dump destination table (can change at run time) + HDAT_SEC_MS_DUMP_RSLT_TBL = 5, // mainstore dump results table + + HDAT_SPIRAH_DA_LAST = 6 +}; + +/*-----------------------------------------------------------------------------*/ +/* Type definitions */ +/*-----------------------------------------------------------------------------*/ + +/** @brief The SPIRA-H is composed of an HDIF header and an array. Each array + * entry is an n-tuple. That is, it is a structure with a particular + * number of fields + */ +struct hdatSpiraH_t +{ + hdatHDIF_t hdatHDIF; // 0x0000 Common HDIF header + hdatHDIFDataHdr_t hdatDataHdr; // 0x0020 Data "pointers" + uint8_t hdatReserved1[8]; // 0x0028 Padding/future growth + hdatHDIFDataArray_t hdatArrayInfo; // 0x0030 Info on 5-tuple array + hdat5Tuple_t hdatDataArea[HDAT_SPIRAH_DA_LAST]; //0x0040 5-tuple array +} __attribute__ ((packed)); + +/*-----------------------------------------------------------------------------*/ +/* C++ class definition */ +/*-----------------------------------------------------------------------------*/ + +/** Begin Class Description + * + * @brief The HdatSpiraH class is used to construct the SPIRA-H object. + * + * Description: The SPIRA-H object contains mainstore addresses and other information + * about various hypervisor data structures. + * Constructing thr SPIRA-H objects maps the spiraH into a + * process' address space. + * + * Thread safety: An HdatSpiraH object is not thread safe. That is, a single + * object cannot be shared and used concurrently by multiple + * threads at the same time. + * + * Signal handler usage: This class is not intended to be used in a signal handler + * and nothing has been done to try and make it safe to use + * in a signal handler. + * + * End Class Description + */ +class HdatSpiraH +{ +public: + + /* @brief Construct an HdatSpiraH object. + * + * This function maps the Service Processor Interface Root Array (SPIRA-H) + * structure from hypervisor lid space to a process' address space. + * + * @pre The SPIRA-H containing Lid must have loaded on memory + * + * @post The SPIRA-H is mapped to a process' memory + * + * @param o_errlHndl - output parameter - error log handle + * + * @return A null error log handle if successful, else the return code pointed + * to by errlHndl_t contains one of: + */ + HdatSpiraH(errlHndl_t &o_errlHndl, hdatMsAddr_t &i_msAddr); + + /** + * @brief HdatSpiraH object destructor + * + * This is the destructor for an HdatSpiraH object. Any heap storage + * allocated for the object is dallocated. + * + * @pre No preconditions exist + * + * @post The HdatSpiraH object has been destroyed and can no longer be used. + * + */ + virtual ~HdatSpiraH(); + + /** + * @brief This function computes the address of a 5-tuple entry within the + * SPIRA-H structure and returns it. + * + * Usage note: The SPIRA-H structure is built as part of the host LIDs. + * These are big endian structures. + * + * @pre None + * + * @post A copy of the desired 5-tuple returned, with any endian conversion done. + * + * @param i_dataArea - input parameter - an enumeration for the 5-tuple entry + * being requested. + * @param o_entry - output parameter - a copy of the 5-tuple entry being + * requested, with any endian conversion already performed. + * + * @return NONE + */ + void getSpiraHEntry(hdatSpiraHDataAreas i_dataArea, + hdat5Tuple_t &o_entry); + + /** + * @brief This function updates a SPIRA-H entry. Any required endian conversion + * is performed on the 5-tuple entry before the update. + * + * @pre None + * + * @post The SPIRA-H has been updated + * + * @param i_dataArea - input parameter - An enumeration for the 5-tuple entry + * being updated. + * @param i_entry - input parameter - the 5-tuple entry being updated. + */ + void chgSpiraHEntry(hdatSpiraHDataAreas i_dataArea, + const hdat5Tuple_t &i_entry); + + /** + * @brief This function updates a data area entry for spiraH in main memory + * + * @pre spiraH is present at main memory + * + * @param i_dataArea - input parameter -An enumeration for the 5-tuple entry + * being updated + * + * @param i_actCount,i_actSize - actual count and size of the data area + */ + + void chgSpiraHEntry(hdatSpiraHDataAreas i_dataArea, + uint32_t i_actCount,uint32_t i_actSize); +private: + + /** + * @brief This function copies the Service Processor Interface Root Array (SPIRA-H) + * structure from phyp lid space. + * + * @pre The primary LID which contains the NACA and the primary/secondary LID + * which contains the SPIRA-H must have been Loaded to memory. + * + * @post The SPIRA-H is copied from main memory into iv_spirah + * + */ + + errlHndl_t getSpiraH(); + + /** + * @brief This routine initializes the SPIRA-H HDIF header and clears the N-Tuple array + * + * @pre None + * + * @post None + * + * @param None + * + * @return None + * + * @retval no errors currently defined + */ + void setSpiraHHdrs(); + + + /** Object Instance Data + * + * @li iv_spirah - pointer to the SPIRA-H structure + * @li iv_msAddr - Mainstore address of spiraH + * @li iv_virt_addr - virtual address mapped to phyisical ms addr of spirah + */ + hdatSpiraH_t *iv_spirah; + uint64_t iv_msAddr; + uint8_t *iv_virt_addr; + +}; // end of HdatSpiraH class + +} //HDAT +#endif // HDATSPIRAH_H diff --git a/src/usr/hdat/hdatspiraS.C b/src/usr/hdat/hdatspiraS.C new file mode 100755 index 000000000..b6fc0b049 --- /dev/null +++ b/src/usr/hdat/hdatspiraS.C @@ -0,0 +1,694 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hdat/hdatspiraS.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 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 hdatspiraS.C + * + * @brief + * This file contains the definition of the Service Processor Interface + * Root Array Secure boot (SPIRA-S) data structure. This data structure + * is built by FSP and placed at the beginning of the host data areas + * space located using the SPIRA-H. Data areas pointed to by this portion + * of the SPIRA will be located after it in the host data areas space. + * + */ + + +/*---------------------------------------------------------------------------*/ +/* Includes */ +/*---------------------------------------------------------------------------*/ +#include <stdlib.h> +#include "hdatspiraS.H" +#include "hdatutil.H" +#include <hdat/hdat_reasoncodes.H> +#include <sys/mm.h> +#include <sys/mmio.h> +#include "hdatpcia.H" +#include "hdatpcrd.H" +#include "hdathostslcadata.H" +#include "hdatiplparms.H" +#include "hdatspsubsys.H" +#include "hdatmsvpd.H" +#include "hdathostservices.H" +#include "hdatbldda.H" +#include "hdatiohub.H" +#include "hdathbrt.H" +#include <util/align.H> +#include <targeting/common/commontargeting.H> + + + +namespace HDAT +{ +/*---------------------------------------------------------------------------*/ +/* Global variables */ +/*---------------------------------------------------------------------------*/ +extern trace_desc_t *g_trac_hdat; +extern errlHndl_t hdatLoadIoData(const hdatMsAddr_t &i_msAddr, + uint32_t &o_size, + uint32_t &o_count); + + +/*****************************************************************************/ +// HdatSpiraS constructor +/*****************************************************************************/ + + +HdatSpiraS::HdatSpiraS(const hdatMsAddr_t &i_msAddr) +: iv_spirasSize(0), iv_spiras(NULL) +{ + HDAT_ENTER(); + + + iv_spirasSize = sizeof(hdatSpiraS_t); + + + uint64_t l_base_addr = ((uint64_t) i_msAddr.hi << 32) | i_msAddr.lo; + + HDAT_DBG("l_base_addr at SPIRA-S=0x%016llX",l_base_addr); + + + //calculate the hrmor and add to base address + TARGETING::Target * sys = NULL; + TARGETING::targetService().getTopLevelTarget( sys ); + + assert(sys != NULL); + + uint64_t l_hrmor = + sys->getAttr<TARGETING::ATTR_PAYLOAD_BASE>()*MEGABYTE; + + HDAT_DBG("HRMOR=0x%08x",l_hrmor); + + l_base_addr = l_hrmor + l_base_addr; + + HDAT_DBG("base address after adding HRMOR=0x%08x",l_base_addr); + + uint64_t l_base_addr_down = ALIGN_PAGE_DOWN(l_base_addr); + HDAT_DBG("l_base_addr_down=0x%016llX",l_base_addr_down); + + HDAT_DBG("reqd space=0x%x, will do a block map of size 0x%x", + iv_spirasSize, ALIGN_PAGE(iv_spirasSize)); + + + void *l_virt_addr = mm_block_map( reinterpret_cast<void*>(l_base_addr_down), + ALIGN_PAGE(iv_spirasSize) + PAGESIZE); + + HDAT_DBG("l_virt_addr=0x%016llX after block map",l_virt_addr); + + uint64_t l_vaddr = reinterpret_cast<uint64_t>(l_virt_addr); + + HDAT_DBG("will add offset %x to starting virtual address", + (l_base_addr-l_base_addr_down)); + + l_vaddr += l_base_addr-l_base_addr_down; + + HDAT_DBG("l_vaddr after adding=0x%016llX",l_vaddr); + + l_virt_addr = reinterpret_cast<void *>(l_vaddr); + HDAT_DBG("l_virt_addr=0x%016llX",l_virt_addr); + + + + iv_spiras = reinterpret_cast<hdatSpiraS_t *>(l_virt_addr); + + HDAT_DBG("constructor iv_spiras addr 0x%016llX virtual addr 0x%016llX,space" + " allocated=0x%x",(uint64_t) this->iv_spiras, + (uint64_t)l_virt_addr,iv_spirasSize); + + HDAT_DBG("creating SPIRA-S header"); + setSpiraSHdrs(); + + HDAT_DBG("done setting the SPIRA-S header"); + + + iv_spiras->hdatHDIF.hdatSize = sizeof(hdatSpira_t); + + HDAT_EXIT(); + + return; +} + +/*****************************************************************************/ +// setSpiraSHdrs +/*****************************************************************************/ +void HdatSpiraS::setSpiraSHdrs() +{ + HDAT_ENTER() + + + iv_spiras->hdatHDIF.hdatStructId = HDAT_HDIF_STRUCT_ID; + iv_spiras->hdatHDIF.hdatInstance = 0; + iv_spiras->hdatHDIF.hdatVersion = HDAT_SPIRAS_VERSION; + iv_spiras->hdatArrayInfo.hdatArrayCnt = HDAT_SPIRAS_DA_LAST; + iv_spiras->hdatHDIF.hdatSize = sizeof(hdatSpiraS_t); + + iv_spiras->hdatHDIF.hdatHdrSize = sizeof(hdatHDIF_t); + iv_spiras->hdatHDIF.hdatDataPtrOffset = sizeof(hdatHDIF_t); + iv_spiras->hdatHDIF.hdatDataPtrCnt = 1; + iv_spiras->hdatHDIF.hdatChildStrCnt = 0; + iv_spiras->hdatHDIF.hdatChildStrOffset = 0; + + memcpy(iv_spiras->hdatHDIF.hdatStructName, HDAT_SPIRAS_EYE_CATCHER, + sizeof(iv_spiras->hdatHDIF.hdatStructName)); + + iv_spiras->hdatDataHdr.hdatOffset = + offsetof(hdatSpiraS_t, hdatArrayInfo); + + iv_spiras->hdatDataHdr.hdatSize = + (sizeof(hdatHDIFDataArray_t) + + sizeof(iv_spiras->hdatDataArea)); + + iv_spiras->hdatArrayInfo.hdatOffset = + sizeof(hdatHDIFDataArray_t); + + iv_spiras->hdatArrayInfo.hdatAllocSize = + sizeof(hdat5Tuple_t); + + iv_spiras->hdatArrayInfo.hdatActSize = + offsetof(hdat5Tuple_t, hdatReserved1); + + + HDAT_EXIT(); + return; +} + + +/******************************************************************************/ +// ~HdatSpiraS +/******************************************************************************/ + +HdatSpiraS::~HdatSpiraS() +{ + HDAT_ENTER(); + + int rc = 0; + rc = mm_block_unmap(iv_spiras); + + if ( rc != 0 ) + { + HDAT_ERR("unmap of spiras failed"); + errlHndl_t l_errl = NULL; + hdatMsAddr_t l_tmpaddr = {0}; + + if ( iv_spiras ) + { + memcpy(&l_tmpaddr,(void*)iv_spiras,sizeof(hdatMsAddr_t)); + } + + /*@ + * @errortype + * @moduleid HDAT::MOD_SPIRAS_DESTRUCTOR + * @reasoncode HDAT::RC_DEV_MAP_FAIL + * @devdesc Unmap a mapped region failed + * @custdesc Firmware encountered an internal error + */ + hdatBldErrLog(l_errl, + MOD_SPIRAS_DESTRUCTOR, + RC_DEV_MAP_FAIL, + l_tmpaddr.hi,l_tmpaddr.lo,0,0, + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + HDAT_VERSION1, + true); + + } + + HDAT_EXIT(); + return; +} + + +/***********************************************************************/ +// getStructAddr +/***********************************************************************/ + +const hdatSpiraS_t *HdatSpiraS::getStructAddr() +{ + return iv_spiras; +} + + +/***********************************************************************/ +// loadDataArea +/***********************************************************************/ + +errlHndl_t HdatSpiraS::loadDataArea( const hdat5Tuple_t& i_spirasHostEntry, + uint32_t& o_actCount, uint32_t& o_actSize) +{ + HDAT_ENTER(); + errlHndl_t l_err = NULL; + hdatMsAddr_t l_msAddr,l_addrToPass,i_slcaMsAddr = SLCA_BUILD_ADDR; + hdat5Tuple_t l_spirasEntry; + uint32_t l_hostUsed = 0; + uint32_t l_size,l_count,l_hdatslcaSize,l_hdatSlcaCnt; + uint64_t l_binAddr; + o_actCount = 1; + o_actSize = 0; + + do { + + //calculate HRMOR + TARGETING::Target * sys = NULL; + TARGETING::targetService().getTopLevelTarget( sys ); + + assert(sys != NULL); + + uint64_t l_hrmor = + sys->getAttr<TARGETING::ATTR_PAYLOAD_BASE>()*MEGABYTE; + + HDAT_DBG("HRMOR=0x%08x",l_hrmor); + + + HDAT_DBG("building SLCA"); + l_binAddr = ((uint64_t)i_slcaMsAddr.hi << 32) + | + i_slcaMsAddr.lo; + + l_binAddr += l_hrmor; + memcpy(&i_slcaMsAddr, &l_binAddr, sizeof(l_binAddr)); + + HDAT_DBG("building SLCA at i_slcaMsAddr.hi=%x,i_slcaMsAddr.lo=%x", + i_slcaMsAddr.hi,i_slcaMsAddr.lo); + + l_err = hdatBuildSLCA(i_slcaMsAddr,l_hdatSlcaCnt,l_hdatslcaSize); + + if ( l_err ) + { + HDAT_ERR("failed to build SLCA"); + break; + } + + HDAT_DBG("built SLCA, size=0x%x",l_hdatslcaSize); + + l_hostUsed = i_spirasHostEntry.hdatActualSize + (sizeof(hdatSpiraS_t)); + + HDAT_DBG("size of hdatSpiraS_t: 0x%08X, hdatActualSize: 0x%08X", + (sizeof(hdatSpiraS_t)),i_spirasHostEntry.hdatActualSize); + + + for ( hdatSpiraSDataAreas l_entryToPrint=HDAT_SPIRAS_DA_FIRST; + (l_entryToPrint < HDAT_SPIRAS_DA_LAST); + l_entryToPrint=(hdatSpiraSDataAreas)((uint32_t)l_entryToPrint +1) ) + { + HDAT_DBG("for loop index=%d",l_entryToPrint); + l_count = 0; + l_size = 0; + + l_binAddr = 0x0; + l_binAddr = ((uint64_t)i_spirasHostEntry.hdatAbsAddr.hi << 32) + | + i_spirasHostEntry.hdatAbsAddr.lo; + + + l_binAddr += (uint64_t)l_hostUsed; + + memcpy(&l_msAddr, &l_binAddr, sizeof(l_binAddr)); + + HDAT_DBG("next spiras tuple will be l_msAddr.hi=0x%8x," + "l_msAddr.lo=0x%8x",l_msAddr.hi,l_msAddr.lo); + + + l_binAddr += l_hrmor; + + memcpy(&l_addrToPass, &l_binAddr, sizeof(l_binAddr)); + + HDAT_DBG("address to pass to next data area after adding hrmor" + " l_addrToPass.hi" + "=0x%8x,l_addrToPass.lo=0x%8x",l_addrToPass.hi,l_addrToPass.lo); + + switch ( l_entryToPrint ) + { + case HDAT_SPIRAS_SP_SUBSYS: + { + HDAT_DBG("calling SP SUBSYS from spiras"); + l_err = HdatLoadSpSubSys(l_addrToPass, + l_size,l_count); + HDAT_DBG("returned from SP SUBSYS, count=%d" + "size=0x%x",l_count,l_size); + } + break; + case HDAT_SPIRAS_IPL_PARMS: + { + HDAT_DBG("calling IPL PARMS from spiras"); + HdatIplParms l_iplParms(l_err,l_addrToPass); + + if ( NULL == l_err) + { + l_err = l_iplParms.hdatLoadIplParams(l_size,l_count); + + if ( NULL == l_err ) + { + HDAT_DBG("returned from IPL PARMS, size=0x%x,count=%d", + l_size,l_count); + } + else + { + HDAT_DBG("could not load IPL PARMS"); + } + } + else + { + HDAT_DBG("could not create IPL PARMS object"); + } + } + break; + case HDAT_SPIRAS_ENCLOSURE_VPD: + { + HDAT_DBG("calling ENCLOSURE VPD from spiras"); + l_err = hdatBldSpecificVpd(HDAT_ENCLOSURE_VPD,l_addrToPass, + l_count,l_size); + if ( l_err ) + { + HDAT_ERR("could not build ENCLOSURE VPD"); + } + else + { + HDAT_DBG("returned from ENCLOSURE VPD count=%d, size=0x%x", + l_count,l_size); + } + } + break; + case HDAT_SPIRAS_SLCA: + { + HDAT_DBG("calling SLCA from spiras "); + l_count = l_hdatSlcaCnt; + l_size = l_hdatslcaSize; + hdatMoveSLCA(i_slcaMsAddr, + l_addrToPass,l_hdatslcaSize); + HDAT_DBG("moved SLCA count=%d, size=0x%x",l_count,l_size); + } + break; + case HDAT_SPIRAS_BACKPLANE_VPD: + { + HDAT_DBG("calling BACKPLANE VPD from spiras"); + l_err = hdatBldSpecificVpd( HDAT_BACKPLANE_VPD, l_addrToPass, + l_count,l_size); + if ( l_err ) + { + HDAT_ERR("could not build BACKPLANE VPD"); + } + else + { + HDAT_DBG("returned from BACKPLANE VPD count=%d, size=0x%x", + l_count,l_size); + } + } + break; + case HDAT_SPIRAS_SYS_VPD: + { + HDAT_DBG("calling SYS VPD from spiras"); + l_err = hdatBldSpecificVpd( HDAT_SYS_VPD,l_addrToPass,l_count, + l_size); + if ( l_err ) + { + HDAT_ERR("could not build SYS VPD"); + } + else + { + HDAT_DBG("returned from SYS VPD count=%d, size=0x%x", + l_count,l_size); + } + } + break; + case HDAT_SPIRAS_CLOCK_VPD: + { + HDAT_DBG("calling CLOCK VPD from spiras"); + l_err = hdatBldSpecificVpd( HDAT_CLOCK_VPD,l_addrToPass,l_count, + l_size); + if ( l_err ) + { + HDAT_ERR("could not build CLOCK VPD"); + } + else + { + HDAT_DBG("returned from CLOCK VPD count=%d, size=0x%x", + l_count,l_size); + } + } + break; + case HDAT_SPIRAS_ANCHOR_VPD: + { + HDAT_DBG("calling ANCHOR VPD from spiras"); + l_err = hdatBldSpecificVpd(HDAT_ANCHOR_VPD,l_addrToPass,l_count, + l_size); + if ( l_err ) + { + HDAT_ERR("could not build ANCHOR VPD"); + } + else + { + HDAT_DBG("returned from ANCHOR VPD count=%d, size=0x%x", + l_count,l_size); + } + } + break; + case HDAT_SPIRAS_OP_PNL_VPD: + { + HDAT_DBG("calling OP PANL VPD from spiras"); + l_err = hdatBldSpecificVpd(HDAT_OP_PNL_VPD,l_addrToPass,l_count, + l_size); + if( l_err ) + { + HDAT_ERR("could not build OP PANL VPD"); + } + else + { + HDAT_DBG("returned from OP PANL VPD count=%d, size=0x%x", + l_count,l_size); + } + } + break; + case HDAT_SPIRAS_MISC_CEC_VPD: + { + HDAT_DBG("calling MISC CEC VPD from spiras"); + l_err = hdatBldSpecificVpd( HDAT_MISC_CEC_VPD,l_addrToPass, + l_count,l_size); + if ( l_err ) + { + HDAT_ERR("could not build MISC CEC VPD"); + } + else + { + HDAT_DBG("returned from MISC CEC VPD count=%d, size=0x%x", + l_count,l_size); + } + } + break; + case HDAT_SPIRAS_MSVPD: + { + HDAT_DBG("calling MS VPD from spiras"); + HdatMsVpd l_msvpd(l_err,l_addrToPass); + if ( l_err == NULL ) + { + l_err = l_msvpd.hdatLoadMsData(l_size,l_count); + HDAT_DBG("MS VPD count=%d, size=0x%x",l_count,l_size); + } + else + { + HDAT_DBG("could not create MS VPD object"); + } + } + break; + case HDAT_SPIRAS_IO_HUB: + { + HDAT_DBG("calling IO HUB from spiras"); + l_err = hdatLoadIoData(l_addrToPass,l_size,l_count); + HDAT_DBG("returned size=0x%x,count=%d from iohub", + l_size,l_count); + } + break; + case HDAT_SPIRAS_PCIA: + { + HDAT_DBG("calling PCIA from spiras"); + HdatPcia pcia(l_err,l_addrToPass); + if ( NULL == l_err ) + { + l_err = pcia.hdatLoadPcia(l_size,l_count); + HDAT_DBG("returned from PCIA count=%d,size=0x%x", + l_count,l_size); + } + else + { + HDAT_DBG("could not create PCIA object"); + } + } + break; + case HDAT_SPIRAS_PCRD: + { + HDAT_DBG("calling PCRD from spiras"); + HdatPcrd l_pcrd(l_err,l_addrToPass); + + if ( NULL == l_err ) + { + l_pcrd.hdatLoadPcrd(l_size,l_count); + HDAT_DBG("PCRD count=%d,size=%x",l_count,l_size); + } + else + { + HDAT_ERR("could not create PCRD object"); + } + } + break; + case HDAT_SPIRAS_HOSTSR: + { + HDAT_DBG("HOSTSR from spiras"); + HdatHostsr l_hdatHostSr(l_err,l_addrToPass,l_size,l_count); + HDAT_DBG("HOSTSR count=%d,size=%x",l_count,l_size); + } + break; + + case HDAT_SPIRAS_HBRT: + { + HDAT_DBG("HBRT from spiras"); + l_err = loadHbrt(l_addrToPass,l_size,l_count); + + if ( l_err ) + { + HDAT_ERR("loading HBRT failed"); + } + else + { + HDAT_DBG("HBRT count=%d,size=0x%x",l_count,l_size); + } + } + break; + default: + { + HDAT_ERR("not a valid data area"); + } + break; + + } + if (l_err) + { + HDAT_ERR("error in creating data area %d",l_entryToPrint); + /*@ + * @errortype + * @moduleid HDAT::MOD_SPIRAS_CREATE_DATA_AREA + * @reasoncode HDAT::RC_DATA_AREA_FAIL + * @devdesc could not create the data area from spiras + * @custdesc Firmware encountered an internal error + */ + hdatBldErrLog (l_err, + MOD_SPIRAS_CREATE_DATA_AREA, + RC_DATA_AREA_FAIL, + l_entryToPrint,0,0,0); + + break; + } + if ( l_count && l_size ) + { + memset(&l_spirasEntry, 0, sizeof(hdat5Tuple_t)); + l_spirasEntry.hdatAbsAddr.hi = l_msAddr.hi; + l_spirasEntry.hdatAbsAddr.lo = l_msAddr.lo; + + l_spirasEntry.hdatAllocCnt = l_count; + l_spirasEntry.hdatActualCnt = l_count; + + uint32_t l_rem = l_size % 128; + uint32_t l_pad = l_rem ? (128 - l_rem) : 0; + + l_spirasEntry.hdatAllocSize = l_size + l_pad; + l_spirasEntry.hdatActualSize = l_size; + + l_hostUsed += l_count * l_spirasEntry.hdatAllocSize; + + //copy the tuple to spira-s memory + + memcpy(&iv_spiras->hdatDataArea[l_entryToPrint],&l_spirasEntry, + sizeof(hdat5Tuple_t)); + + HDAT_DBG("iv_spiras->hdatDataArea[%d].hdatActualCnt=%d," + "hdatActualSize=%x",l_entryToPrint, + iv_spiras->hdatDataArea[l_entryToPrint].hdatActualCnt, + iv_spiras->hdatDataArea[l_entryToPrint].hdatActualSize); + + } + }//end for + + }while(0); + + o_actSize = l_hostUsed; + + HDAT_EXIT(); + return l_err; + +}//end loadDataArea + + +/****************************************************************/ +//getSpirasObject +/****************************************************************/ + +void HdatSpiraS::getSpirasObject(uint8_t* &io_spiras,uint32_t& o_size, + const hdatMsAddr_t& i_msAddr) +{ + HDAT_ENTER(); + + io_spiras = NULL; + + //user is responsible to free up the memory + io_spiras = new uint8_t[iv_spirasSize]; + + o_size = iv_spirasSize; + + memcpy(io_spiras, iv_spiras, iv_spirasSize); + + HDAT_EXIT(); +} + + + +/****************************************************************/ +// getSpiraSEntry +/****************************************************************/ + +void HdatSpiraS::getSpiraSEntry(hdatSpiraSDataAreas i_dataArea, + hdat5Tuple_t &o_entry) +{ + HDAT_ENTER(); + + o_entry.hdatAbsAddr.hi = iv_spiras->hdatDataArea[i_dataArea].hdatAbsAddr.hi; + o_entry.hdatAbsAddr.lo = iv_spiras->hdatDataArea[i_dataArea].hdatAbsAddr.lo; + o_entry.hdatAllocCnt = iv_spiras->hdatDataArea[i_dataArea].hdatAllocCnt; + o_entry.hdatActualCnt = iv_spiras->hdatDataArea[i_dataArea].hdatActualCnt; + o_entry.hdatAllocSize = iv_spiras->hdatDataArea[i_dataArea].hdatAllocSize; + o_entry.hdatActualSize = iv_spiras->hdatDataArea[i_dataArea].hdatActualSize; + o_entry.hdatTceOffset = iv_spiras->hdatDataArea[i_dataArea].hdatTceOffset; + + HDAT_DBG("returning tuple o_entry.hdatAbsAddr.hi : 0x%08X," + " o_entry.hdatAbsAddr.lo : 0x%08X", + o_entry.hdatAbsAddr.hi,o_entry.hdatAbsAddr.lo); + + HDAT_DBG("o_entry.hdatAllocCnt : 0x%08X, o_entry.hdatActualCnt: 0x%08X ", + o_entry.hdatAllocCnt,o_entry.hdatActualCnt); + + HDAT_DBG("o_entry.hdatAllocSize : 0x%08X, o_entry.hdatActualSize: 0x%08X", + o_entry.hdatAllocSize,o_entry.hdatActualSize); + + HDAT_EXIT(); +} + + + +}//end namespace diff --git a/src/usr/hdat/hdatspiraS.H b/src/usr/hdat/hdatspiraS.H new file mode 100755 index 000000000..97d6a5972 --- /dev/null +++ b/src/usr/hdat/hdatspiraS.H @@ -0,0 +1,293 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hdat/hdatspiraS.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 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 HDATSPIRAS_H +#define HDATSPIRAS_H + +/** + * @file hdatspiraS.H + * + * @brief This file contains the definition of the Service Processor Interface + * Root Array Secure boot (SPIRA-S) data structure. This data structure + * is built by FSP and placed at the beginning of the host data areas + * space located using the SPIRA-H. Data areas pointed to by this portion + * of the SPIRA will be located after it in the host data areas space. + * + */ + + + +/*---------------------------------------------------------------------------*/ +/* Includes */ +/*---------------------------------------------------------------------------*/ +#include <stdint.h> +#include <errl/errlentry.H> +#include <hdat/hdat.H> + + +namespace HDAT +{ + +/*---------------------------------------------------------------------------*/ +/* Constants */ +/*---------------------------------------------------------------------------*/ +const char HDAT_SPIRAS_EYE_CATCHER[] = "SPIRAS"; + +const uint16_t HDAT_SPIRAS_VERSION = 0x40; + +const hdatMsAddr_t SLCA_BUILD_ADDR = {0x00000000, 0x80000000}; + +/*---------------------------------------------------------------------------*/ +/* Type definitions */ +/*---------------------------------------------------------------------------*/ +enum hdatSpiraSDataAreas +{ + HDAT_SPIRAS_DA_FIRST = 0, + HDAT_SPIRAS_SP_SUBSYS = 0, // service processor subsystem + HDAT_SPIRAS_IPL_PARMS = 1, // IPL parameters + HDAT_SPIRAS_ENCLOSURE_VPD = 2, // enclosure vital product data + HDAT_SPIRAS_SLCA = 3, // slot location code array + HDAT_SPIRAS_BACKPLANE_VPD = 4, // backplane vital product data + HDAT_SPIRAS_SYS_VPD = 5, // system vital product data + HDAT_SPIRAS_CLOCK_VPD = 6, // clock vital product data + HDAT_SPIRAS_ANCHOR_VPD = 7, // anchor card vital product data + HDAT_SPIRAS_OP_PNL_VPD = 8, // operator panel vital product data + HDAT_SPIRAS_MISC_CEC_VPD = 9, // miscellaneous FRU vital product data + HDAT_SPIRAS_MSVPD = 10, // memory description tree + HDAT_SPIRAS_IO_HUB = 11, // I/O hub FRU array + HDAT_SPIRAS_PCIA = 12, // PCIA (Core information area) + HDAT_SPIRAS_PCRD = 13, // PCRD (Chip related data area) + HDAT_SPIRAS_HOSTSR = 14, // HOSTSR (Host service data) + HDAT_SPIRAS_HBRT = 15, //HBRT (runtime data) + + HDAT_SPIRAS_DA_LAST = 16 +}; + + +/** @brief The SPIRA-S is composed of an HDIF header and an array. Each array + * entry is an n-tuple. That is, it is a structure with a particular + * number of fields + */ +struct hdatSpiraS_t +{ + hdatHDIF_t hdatHDIF; // 0x0000 Common HDIF header + hdatHDIFDataHdr_t hdatDataHdr; // 0x0020 Data "pointers" + uint8_t hdatReserved1[8]; // 0x0028 Padding/future growth + hdatHDIFDataArray_t hdatArrayInfo; // 0x0030 Info on 5-tuple array + hdat5Tuple_t hdatDataArea[HDAT_SPIRAS_DA_LAST]; //0x0040 5-tuple array + // At this point, the host OS may have reserved extra space for future growth + // but FipS does not need to be concerned with the reserved space nor DMA it + // back from main memory. +} __attribute__ ((packed)); + + +/*---------------------------------------------------------------------------*/ +/* C++ class definition */ +/*---------------------------------------------------------------------------*/ + +/** Begin Class Description + * + * @brief The HdatSpiraS class is used to construct the SPIRA-S object + * + * Description: + * The SPIRA-S object contains mainstore addresses and other information + * about various hypervisor data structures. The SPIRA-S is initially + * DMA'd from mainstore to FipS control store and written to a + * file. Constructing thr SPIRA-S objects maps the file into a + * process' address space. + * + * Thread safety: + * An HdatSpiraS object is not thread safe. That is, a single + * object cannot be shared and used concurrently by multiple + * threads at the same time. + * + * Signal handler usage: + * This class is not intended to be used in a signal handler + * and nothing has been done to try and make it safe to use + * in a signal handler. + * + * End Class Description + */ +class HdatSpiraS +{ +public: + + + /** + * @brief Construct an HdatSpiraS object. + * + * This function reads in the Service Processor Interface Root Array + * (SPIRA-S) structure from main memory, + * + * THIS CONSTRUCTOR CAN BE USED ONLY BY THE HDAT COMPONENT. + * + * @pre The primary LID which contains the NACA and the primary/secondary LID + * which contains the SPIRA-S must have been read to main memory. + * + * @post The SPIRA-S is read from main memory and is initiailized to default + * values + * + * + * @param i_msAddr - input parameter - The main memory address where the + * SPIRA-S is located + * + * @return A null error log handle if successful, else the return code + * pointed to by errlHndl_t contains one of: + * + * @retval HDAT_ALLOC_ERROR + * @retval HDAT_FILE_ERROR + */ + HdatSpiraS(const hdatMsAddr_t& i_msAddr); + + + /** + * @brief HdatSpiraS object destructor + * + * This is the destructor for an HdatSpiraS object. Any heap storage + * allocated for the object is dallocated. + * + * @pre No preconditions exist + * + * @post The HdatSpiraS object has been destroyed and can no longer be used. + * + */ + ~HdatSpiraS(); + + + + + /** + * @brief This function returns the address to the raw SPIRA-S structure. It + * is intended to be used only to put the structure into an error log. + * + * THIS FUNCTION SHOULD BE USED ONLY BY THE HDAT COMPONENT. + * + * @pre None + * + * @post None + * + * @return An address to the spiraH + */ + const hdatSpiraS_t *getStructAddr(); + + + /** + * @brief This routine initializes the SPIRA-S HDIF header and + * clears the N-Tuple array + * + * @pre None + * + * @post None + * + * @param None + * + * @return None + * + * @retval no errors currently defined + */ + void setSpiraSHdrs(); + + + /** + * @brief This function constructs the (SPIRA-S) + * structure in main memory + * + * @pre The primary LID which contains the NACA and the primary/secondary LID + * which contains the SPIRA-S must have been read to main memory. + * + * THIS FUNCTION CAN BE USED ONLY BY THE HDAT COMPONENT. + * + * @post The SPIRA-S is written to main memory, and initialized to default + * values if required + * + * @param i_spirasHostEntry the spiras starting address entry fetched + * from spira-h + * + * @return A null error log handle if successful, else the return code pointed + * to by errlHndl_t contains one of: + * + * @retval HDAT_ALLOC_ERROR + * @retval HDAT_FILE_ERROR + */ + errlHndl_t loadDataArea( const hdat5Tuple_t& i_spirasHostEntry, + uint32_t& o_actCount, uint32_t& o_actSize); + + + /** + * @brief this function returns a copy of the spiras object into + * a buffer provided by the user + * + * @pre None + * + * @post the buffer area is allocated and spiras is copied to that area. + * the user is responsible to free up the memory area used + * + * @param io_spiras - input-output parameter- area where spiras is copied + * + * @param i_msAddr - starting address of spiras retrieved from spirah + * + * @return None + */ + + void getSpirasObject(uint8_t * &io_spiras,uint32_t& o_size, + const hdatMsAddr_t& i_msAddr); + + + + /** + * @brief This function computes the address of a 5-tuple entry within the + * SPIRA-S structure and returns it + * + * Usage note: The SPIRA-S structure is already built as part of the Host + * LIDS + * @pre None + * @post A copy of the desired 5-tuple returned + * + * @param i_dataArea - input parameter - an enumeration for the 5-tuple entry + * being requested + * @param o_entry - output parameter - a copy of the 5-tuple entry being + * requested + * + * @return NONE + */ + + void getSpiraSEntry(hdatSpiraSDataAreas i_dataArea, + hdat5Tuple_t &o_entry); + + +private: + + + /** Object Instance Data + * + * @li iv_spirasSize - size if the SPIRA-S structure + * @li iv_spiras - pointer to the SPIRA-S structure + */ + uint32_t iv_spirasSize; + hdatSpiraS_t *iv_spiras; + +}; // end of HdatSpiraS class + +} //end namespace +#endif // HDATSPIRAS_H diff --git a/src/usr/hdat/hdatspsubsys.C b/src/usr/hdat/hdatspsubsys.C new file mode 100755 index 000000000..540d43e25 --- /dev/null +++ b/src/usr/hdat/hdatspsubsys.C @@ -0,0 +1,521 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hdat/hdatspsubsys.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 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 hdatspsubsys.C + * + * @brief This file contains the implementation of the HdatSpSubsys class. + * + */ + + +/*---------------------------------------------------------------------------*/ +/* Includes */ +/*---------------------------------------------------------------------------*/ +#include <stdlib.h> +#include <sys/mm.h> +#include <sys/mmio.h> +#include <pnor/pnorif.H> +#include <util/align.H> +#include "hdatspsubsys.H" +#include "hdathdif.H" +#include "hdatutil.H" +#include "hdatvpd.H" +#include <targeting/common/util.H> + +using namespace TARGETING; + +namespace HDAT +{ + +/*----------------------------------------------------------------------------*/ +/* Global variables */ +/*----------------------------------------------------------------------------*/ +uint32_t HdatSpSubsys::cv_actualCnt; + + +vpdData mvpdDataTable[] = +{ + { MVPD::VINI, MVPD::DR }, + { MVPD::VINI, MVPD::VZ }, + { MVPD::VINI, MVPD::CC }, + { MVPD::VINI, MVPD::CE }, + { MVPD::VINI, MVPD::FN }, + { MVPD::VINI, MVPD::PN }, + { MVPD::VINI, MVPD::SN }, + { MVPD::VINI, MVPD::PR }, + { MVPD::VINI, MVPD::HE }, + { MVPD::VINI, MVPD::CT }, + { MVPD::VINI, MVPD::HW }, +}; + +const HdatKeywordInfo l_mvpdKeywords[] = +{ + { MVPD::DR, "DR" }, + { MVPD::VZ, "VZ" }, + { MVPD::CC, "CC" }, + { MVPD::CE, "CE" }, + { MVPD::FN, "FN" }, + { MVPD::PN, "PN" }, + { MVPD::SN, "SN" }, + { MVPD::PR, "PR" }, + { MVPD::HE, "HE" }, + { MVPD::CT, "CT" }, + { MVPD::HW, "HW" }, + +}; + +extern trace_desc_t *g_trac_hdat; + +/** + * @brief This routine fill up the SP I/O path information. + * + * @pre The o_pathArray must be set to zero. + * + * @post None + * + * @param l_pSpTarget - input parameter - Target handle of the SP + * @param o_arrayHdr - output parameter - The I/O path array header structure + * @param o_pathArray - output parameter - The structure to update with the SP + * I/O path information + * @return A null error log handle if successful, else the return code pointed + * to by errlHndl_t contains one of: + * + * @retval + */ +static errlHndl_t hdatGetPathInfo( + uint32_t &io_numOfIoPaths, + hdatHDIFDataArray_t &o_arrayHdr, + hdatSpIoPath_t o_pathArray[]) +{ + + HDAT_ENTER(); + + errlHndl_t l_errlHndl = NULL; + + // Set the number of Io Paths. + // For now, we have only 1, may change in future + io_numOfIoPaths = HDAT_NUM_IO_PATHS_FOR_BMC; + + // Set fields in the array header + o_arrayHdr.hdatOffset = sizeof(hdatHDIFDataArray_t); + o_arrayHdr.hdatAllocSize = sizeof(hdatSpIoPath_t); + o_arrayHdr.hdatActSize = sizeof(hdatSpIoPath_t); + o_arrayHdr.hdatArrayCnt = 0; + + for( ; o_arrayHdr.hdatArrayCnt < io_numOfIoPaths ; ) + { + o_pathArray[o_arrayHdr.hdatArrayCnt]. + hdatPathType = HDAT_LPC_PATH_TYPE; + o_pathArray[o_arrayHdr.hdatArrayCnt]. + hdatLinkStatus = HDAT_CURRENT_LINK; + o_pathArray[o_arrayHdr.hdatArrayCnt].hdatML2ChipVer = 0x10; + o_pathArray[o_arrayHdr.hdatArrayCnt]. + hdatSlcaCnt = LPC_PATH_FRU_CNT_FOR_BMC; + + // Get the master proc handle. + + TARGETING::Target* l_pMasterProcChipTargetHandle = NULL; + (void)TARGETING::targetService().masterProcChipTargetHandle( + l_pMasterProcChipTargetHandle); + + if (l_pMasterProcChipTargetHandle == NULL) + { + /*@ + * @errortype + * @moduleid HDAT::MOD_GET_PATH_INFO + * @reasoncode HDAT::RC_MASTER_PROC_TARGET_NULL + * @devdesc Master proc target returned is Null + * @custdesc Firmware encountered an internal + * error while retrieving target handle + */ + hdatBldErrLog(l_errlHndl, + MOD_GET_PATH_INFO, + RC_MASTER_PROC_TARGET_NULL, + 0,0,0,0); + + HDAT_ERR("Master proc target handle is Null"); + } + else + { + + o_pathArray[o_arrayHdr.hdatArrayCnt].hdatProcChipId = + l_pMasterProcChipTargetHandle->getAttr<ATTR_ORDINAL_ID>(); + + uint64_t l_gxcBaseAddr = 0; + memcpy(&o_pathArray[o_arrayHdr.hdatArrayCnt].hdatGxcBaseAddr, + &l_gxcBaseAddr, + sizeof(o_pathArray[o_arrayHdr.hdatArrayCnt].hdatGxcBaseAddr)); + } + + // LPC link doesn't have any FRU's in the path + // except the end points Service Processor and master proc + // The Fru's slca index should be populated for this entry by + // starting from SP + + /* TARGETING::Target* l_lpcPathTargetsArray[] = + { i_pSpTarget , l_pMasterProcChipTargetHandle }; + uint32_t l_fruIdx = 0; + for ( ; l_fruIdx < LPC_PATH_FRU_CNT_FOR_BMC ; l_fruIdx++) + { + o_pathArray[o_arrayHdr.hdatArrayCnt].hdatSlcaIdx[l_fruIdx] = + l_lpcPathTargetsArray[l_fruIdx]->getAttr<ATTR_SLCA_INDEX>(); + }*/ + o_arrayHdr.hdatArrayCnt++; + } + + HDAT_EXIT(); + return l_errlHndl; +} + +/** + * @brief This routine Loads SP Sub sys information. + * + * @param io_msAddr- input parameter - Mainstore address for SP subsys to write + * @param o_spSubSysTotalSize - output parameter Total size of sp sub sys + * @param o_spSubsysCnt - output parameter - Count of SP Sub sys structures + * + * @return A null error log handle if successful, else the return code pointed + * to by errlHndl_t contains one of: + * + * @retval + */ + +errlHndl_t HdatLoadSpSubSys(hdatMsAddr_t &io_msAddr, + uint32_t &o_spSubSysTotalSize, + uint32_t &o_spSubsysCnt) +{ + errlHndl_t l_errlHndl = NULL; + hdatMsAddr_t l_msAddr = io_msAddr; + + HDAT_ENTER(); + + + HdatSpSubsys l_hdatSpSubsys(l_errlHndl, l_msAddr); + + // Iterate through the SP targets and fill the SP sub sys + // structure for each SP + /* do{ + TARGETING::PredicateCTM l_spFilter(CLASS_CHIP, TYPE_SP, MODEL_BMC); + TARGETING::PredicateHwas l_pred; + l_pred.present(true); + TARGETING::PredicatePostfixExpr l_presentSp; + l_presentSp.push(&l_spFilter).push(&l_pred).And(); + + TARGETING::TargetRangeFilter l_filter( + TARGETING::targetService().begin(), + TARGETING::targetService().end(), + &l_presentSp); + for( ; l_filter ; ++l_filter ) + { + TARGETING::Target* l_pSpTarget = *l_filter; + + HdatSpSubsys l_hdatSpSubsys(l_errlHndl, l_msAddr); */ + + if( l_errlHndl ) + { + // Break the loop and return the error + HDAT_ERR("Got an error while filling sp sub sys" + " for sp: 0x%x", o_spSubsysCnt); + // break; + } + else + { + // Update the count and msaddr before continuing + // the loop for next SP. + memcpy(&io_msAddr , &l_msAddr , sizeof(hdatMsAddr_t)); + o_spSubsysCnt++; + o_spSubSysTotalSize += l_hdatSpSubsys.getSpSubSysStructSize();; + } + + //} + //}while(0); + + HDAT_EXIT(); + return l_errlHndl; +} + + +/** @brief See the prologue in hdatspsubsys.H + */ +HdatSpSubsys::HdatSpSubsys(errlHndl_t &o_errlHndl, + hdatMsAddr_t &io_msAddr + ): + HdatHdif(o_errlHndl, HDAT_STRUCT_NAME, + HDAT_SPSUBSYS_LAST, cv_actualCnt++, HDAT_NO_CHILD, + HDAT_SP_SUBSYS_VERSION), iv_kwdSize(0), + iv_kwd(NULL),iv_ioPathArray(NULL), + iv_spSubsys(NULL),iv_size(0), + iv_numOfIoPaths(0) +{ + + HDAT_ENTER(); + + // Copy the input phy address to this object member variable + iv_msAddr = ((uint64_t) io_msAddr.hi << 32) | io_msAddr.lo; + + do{ + // Fill the internal data pointers + o_errlHndl = this->hdatFillDataPtrs(); + if(o_errlHndl) + { + HDAT_ERR("Error while filling internal data ptrs for SP subsys"); + break; + } + + // Size of the SP sub sys structure + iv_size = sizeof(hdatHDIF_t) + + ( sizeof(hdatHDIFDataHdr_t) * + HDAT_SPSUBSYS_NUM_DATA_PTRS)+ + sizeof(hdatFruId_t) + + iv_kwdSize + + sizeof(hdatSpImpl_t) + + sizeof(hdatSpMem_t) + + sizeof(hdatHDIFDataArray_t) + + (sizeof(hdatSpIoPath_t) * iv_numOfIoPaths); + + uint64_t l_base_addr_down = ALIGN_PAGE_DOWN(iv_msAddr); + uint8_t *l_virt_addr = + (uint8_t *) mm_block_map ( + reinterpret_cast<void*>(l_base_addr_down), + (ALIGN_PAGE(iv_size) + PAGESIZE)); + iv_spSubsys = l_virt_addr + (iv_msAddr - ALIGN_PAGE_DOWN(iv_msAddr)); + + // initializing the space to zero + memset(iv_spSubsys ,0x0, iv_size ); + + iv_spSubsys = this->setHdif(iv_spSubsys); + + memcpy(iv_spSubsys, &iv_fru, sizeof(hdatFruId_t)); + iv_spSubsys += sizeof(hdatFruId_t); + + memcpy(iv_spSubsys, iv_kwd, iv_kwdSize); + iv_spSubsys += iv_kwdSize; + + memcpy(iv_spSubsys, &iv_impl, sizeof(hdatSpImpl_t)); + iv_spSubsys += sizeof(hdatSpImpl_t); + + memcpy(iv_spSubsys, &iv_mem, sizeof(hdatSpMem_t)); + iv_spSubsys += sizeof(hdatSpMem_t); + + memcpy(iv_spSubsys , &iv_ioPathArrayHdr, sizeof(hdatHDIFDataArray_t)); + iv_spSubsys += sizeof(hdatHDIFDataArray_t); + + memcpy(iv_spSubsys, iv_ioPathArray, + sizeof(hdatSpIoPath_t) * iv_numOfIoPaths); + iv_spSubsys += sizeof(hdatSpIoPath_t) * iv_numOfIoPaths; + + // update the base address for next SP sub sys + uint64_t l_msAddrEnd = iv_msAddr + iv_size; + + memcpy(&io_msAddr, &l_msAddrEnd, sizeof(hdatMsAddr_t)); + + } while(0); + + HDAT_EXIT(); + return; +} + +errlHndl_t HdatSpSubsys::hdatFillDataPtrs() +{ + errlHndl_t l_errlHndl = NULL; + + HDAT_ENTER(); + + do{ + // Initialize all the values to zero + memset(&iv_impl , 0x0 , sizeof(hdatSpImpl_t)); + memset(&iv_fru, 0x0 , sizeof(hdatFruId_t)); + memset(&iv_mem, 0x0 , sizeof(hdatSpMem_t)); + + // Fill the SP impl data + iv_impl.hdatHdwVer = 0x0003; + iv_impl.hdatSftVer = 0x0002; + iv_impl.hdatChipVer = 0x10; + iv_impl.hdatStatus = HDAT_SP_INSTALLED; + iv_impl.hdatStatus |= HDAT_SP_PRIMARY; + iv_impl.hdatStatus |= HDAT_SP_FUNCTIONAL; + + // Fill the FRU data + iv_fru.hdatSlcaIdx = 0; + iv_fru.hdatResourceId = 0; + + // Fill the SP memory info + PNOR::SectionInfo_t l_info; + l_errlHndl = PNOR::getSectionInfo(PNOR::NVRAM, l_info); + if(l_errlHndl) + { + HDAT_ERR("PNOR::getSectionInfo returns error. Fill the size as 0"); + iv_mem.hdatHostRamSize = 0; + } + else + { + iv_mem.hdatHostRamSize = l_info.size; + } + + // Fill the SP I/O path information + + iv_ioPathArray = reinterpret_cast<hdatSpIoPath_t *>(calloc( + HDAT_MAX_NUM_IO_PATHS,sizeof(hdatSpIoPath_t))); + // No need to check iv_ioPathArray because calloc won't return if out of memory. + + l_errlHndl = hdatGetPathInfo( + iv_numOfIoPaths, + iv_ioPathArrayHdr, + iv_ioPathArray); + HDAT_DBG(" Num of Io Paths returned : %d", iv_numOfIoPaths); + if(l_errlHndl) + { + HDAT_ERR("hdatGetPathInfo returns Error"); + break; + } + + // Fill the kwd + + // As of now there is no VPD present on BMC. + // Hence we are filling PROC data to get things moving. + // TODO : RTC : 151618 Will relook at this once we get mail from Tom. + + + TARGETING::Target* l_pMasterProcChipTargetHandle = NULL; + (void)TARGETING::targetService().masterProcChipTargetHandle( + l_pMasterProcChipTargetHandle); + + if (l_pMasterProcChipTargetHandle == NULL) + { + /*@ + * @errortype + * @moduleid HDAT::MOD_HDAT_SP_SUBSYS_CTOR + * @reasoncode HDAT::RC_MASTER_PROC_TARGET_NULL + * @devdesc Master proc target returned is Null + * @custdesc Firmware encountered an internal + * error while retrieving target data + */ + hdatBldErrLog(l_errlHndl, + MOD_GET_PATH_INFO, + RC_MASTER_PROC_TARGET_NULL, + 0,0,0,0); + + HDAT_ERR("Master proc target handle is Null"); + break; + } + else + { + uint32_t l_num = sizeof(mvpdDataTable) / sizeof(vpdData); + size_t theSize[l_num]; + HDAT_DBG(" spsubsys number of vpd : %X", l_num); + l_errlHndl = hdatGetAsciiKwd(l_pMasterProcChipTargetHandle, + iv_kwdSize, + iv_kwd, + HDAT::PROC, + mvpdDataTable, + l_num,theSize); + HDAT_DBG(" initial size vpd : %X", iv_kwdSize); + if(l_errlHndl) + { + HDAT_ERR("hdatGetAsciiKwd returns Error"); + break; + } + char *o_fmtKwd; + uint32_t o_fmtkwdSize; + l_errlHndl = hdatformatAsciiKwd(mvpdDataTable, l_num, theSize, + iv_kwd, iv_kwdSize, o_fmtKwd, + o_fmtkwdSize, l_mvpdKeywords); + if( o_fmtKwd != NULL ) + { + delete[] iv_kwd; + iv_kwd = new char [o_fmtkwdSize + 8]; + memcpy(iv_kwd,o_fmtKwd,o_fmtkwdSize); + iv_kwdSize = o_fmtkwdSize + 8; + delete[] o_fmtKwd; + } + } + + // Done with getting all the data. Now its time to Add. + if( l_errlHndl == NULL ) + { + this->addData(HDAT_SPSUBSYS_FRU_ID, sizeof(hdatFruId_t)); + this->addData(HDAT_SPSUBSYS_KWD, iv_kwdSize); + this->addData(HDAT_SPSUBSYS_IMPL, sizeof(hdatSpImpl_t)); + this->addData(HDAT_SPSUBSYS_DEPRECATED, 0); // Still need to account for the deprecated pointer pair + + this->addData(HDAT_SPSUBSYS_MEMORY, sizeof(hdatSpMem_t)); + this->addData(HDAT_SPSUBSYS_IO_PATH, sizeof(hdatHDIFDataArray_t) + + sizeof(hdatSpIoPath_t) * iv_ioPathArrayHdr.hdatArrayCnt); + + this->align(); + } + + }while(0); + HDAT_EXIT(); + return l_errlHndl; +} + +/** @brief get the sp sub sys structure total size +*/ +uint32_t HdatSpSubsys::getSpSubSysStructSize() +{ + return iv_size; +} + + +/** @brief See the prologue in hdathdatspsubsys.H + */ +HdatSpSubsys::~HdatSpSubsys() +{ + errlHndl_t o_errlHndl=NULL; + + HDAT_ENTER(); + + // Free the memory allocated for filling this entry. + int rc=0; + free(iv_ioPathArray); + delete[] iv_kwd; + rc = mm_block_unmap(reinterpret_cast<void*>( + ALIGN_PAGE_DOWN((uint64_t)iv_spSubsys))); + if( rc != 0) + { + /*@ + * @errortype + * @moduleid HDAT::MOD_HDAT_SP_SUBSYS_DTOR + * @reasoncode HDAT::RC_DEV_MAP_FAIL + * @devdesc Unmap a mapped region failed + * @custdesc Firmware encountered an internal error. + */ + hdatBldErrLog(o_errlHndl, + HDAT::MOD_HDAT_SP_SUBSYS_DTOR, + RC_DEV_MAP_FAIL, + 0,0,0,0, + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + HDAT_VERSION1, + true); + } + + HDAT_EXIT(); + return; +} + + +} // end namespace diff --git a/src/usr/hdat/hdatspsubsys.H b/src/usr/hdat/hdatspsubsys.H new file mode 100755 index 000000000..927bc13f0 --- /dev/null +++ b/src/usr/hdat/hdatspsubsys.H @@ -0,0 +1,291 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hdat/hdatspsubsys.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 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 hdatspsubsys.H + * + * @brief This file contains the class definition for the service processor + * subsystem object. + * + */ + +#ifndef HDATSPSUBSYS_H +#define HDATSPSUBSYS_H + +/*--------------------------------------------------------------------------*/ +/* Includes */ +/*--------------------------------------------------------------------------*/ +#include <stdint.h> // standard types +#include <hdat/hdat.H> // HDAT header type definitions +#include "hdathdif.H" // HdatHdif base class definition +#include <hdat/hdat_reasoncodes.H> + +namespace HDAT +{ + +/*--------------------------------------------------------------------------*/ +/* Type definitions */ +/*--------------------------------------------------------------------------*/ + +/** @enum hdatSpStatus + * Status of a service procesor card + */ +enum hdatSpStatus +{ + HDAT_SP_INSTALLED = 0x8000, // service processor is installed + HDAT_SP_FUNCTIONAL = 0x4000, // service processor is functional + HDAT_SP_PRIMARY = 0x2000 // this is the primary service processor +}; + +// The number of data pointers in hdatDataPtrs (defined in hdatspsubsys.C) +#define HDAT_SPSUBSYS_NUM_DATA_PTRS 8 + +/** @brief eye catcher for the HDIF header for the SP subsystem data area + */ +const char HDAT_STRUCT_NAME[] = "SPINFO"; + +/** @brief Structure version number + */ +const uint16_t HDAT_SP_SUBSYS_VERSION = 0x0021; + +/** @brief Structure definition for service processor hardware and software. + Reserved bytes are added to make the structure a multiple of 4 bytes. + Adjust the reserved size as necessary if new members are added to this + structure. + */ +struct hdatSpImpl_t +{ + uint16_t hdatHdwVer; // 0x0000 Hardware version + uint16_t hdatSftVer; // 0x0002 Software version + uint16_t hdatStatus; // 0x0004 SP functionality/status + uint8_t hdatChipVer; // 0x0006 SP chip DD level + uint8_t hdatReserved1; // 0x0007 padding for alignment +} __attribute__ ((packed)); + + +/** @brief Structure definition for the I/O path to the service processor + */ +struct hdatSpIoPath_t +{ + uint16_t hdatPathType; // 0x0000 I/O path type + uint16_t hdatLinkStatus; // 0x0002 PSI Link status + uint8_t hdatML2ChipVer; // 0x0004 Chip DD level of ML2 controller + uint8_t hdatResvd[1]; // 0x0005 Reserved + uint16_t hdatSlcaCnt; // 0x0006 Count of entries in hdatSlxaIdx + uint16_t hdatSlcaIdx[8]; // 0x0008 Array of SLCA indexes + uint32_t hdatProcChipId; // 0x0018 Processor chip id + uint8_t hdatResvd1[4]; // 0x001C Padding for alignment + hdatMsAddr_t hdatGxcBaseAddr; // 0x0020 PSI GX Base address + +} __attribute__ ((packed)); + +#define HDAT_NON_FUNCTIONAL 0 // PSI link is not functional +#define HDAT_CURRENT_LINK 1 // This FSP's current functional link +#define HDAT_CANDIDATE_LINK 2 // Candidate link if current link fails + +/** @brief Structure definition for the service processor memory + */ +struct hdatSpMem_t +{ + uint32_t deprecated1[5]; // Deprecated in latest spec 9.13c + uint32_t hdatHostRamSize; // 0x0014 Size of host private NVRAM + uint32_t deprecated2[2]; // Deprecated in latest spec 9.13c +} __attribute__ ((packed)); + +/** @enum hdatSpSubSysDataPtrs + * Constants for the internal data pointers that are added to the base + * class + */ +enum hdatSpSubSysDataPtrs +{ + HDAT_SPSUBSYS_FRU_ID = 0, + HDAT_SPSUBSYS_KWD = 1, + HDAT_SPSUBSYS_IMPL = 2, + HDAT_SPSUBSYS_DEPRECATED = 3, + HDAT_SPSUBSYS_MEMORY = 4, + HDAT_SPSUBSYS_IO_PATH = 5, + HDAT_SPSUBSYS_RESERVED1 = 6, + HDAT_SPSUBSYS_RESERVED2 = 7, + HDAT_SPSUBSYS_LAST = 8 +}; + +const uint32_t HDAT_MAX_NUM_IO_PATHS = 32; +const uint16_t HDAT_LPC_PATH_TYPE = 3; +const uint32_t HDAT_NUM_IO_PATHS_FOR_BMC = 1; +const uint32_t LPC_PATH_FRU_CNT_FOR_BMC = 2; + + +/*-----------------------------------------------------------------------------*/ +/* C++ class definition */ +/*-----------------------------------------------------------------------------*/ + +/** Begin Class Description + * + * @brief The HdatSpSubsys class is used to construct objects that describe + * the service processor hardware and software. + * + * Description: This class defines a specialized object. It is not intended + * that anyone can create an object of this type. In particular, + * the object is built only in the hdatstep process when the step + * that builds hypervisor data structures is run. + * + * The real purpose of the object is to create the service processor + * subsystem structure as defined by the PHYP Initialization architecture + * This data structure is eventually DMA'd to main memory. The + * class is not defined to be a general purpose interface for + * building this object by anyone other than the hdatstep process. + * + * Thread safety: An HdatSpSubsys object is not thread safe. That is, a single + * object cannot be shared and used concurrently by + * multiple threads at the same time. An object can be used by + * multiple threads if the threads serialize access. And of + * course, each thread can use its own object with no concerns + * about what other threads are doing. + * + * Signal handler usage: This class is not intended to be used in a signal handler + * and nothing has been done to try and make it safe to use + * in a signal handler. + * + * End Class Description + */ +class HdatSpSubsys : public HdatHdif +{ + public: + + /** + * @brief Construct an HdatSpSubsys object. + * + * This is the constructor for the HdatSpSubsys object. + * + * If you are constructing this object on the heap by using new, then + * you must check the pointer returned from new to see if it is null. + * If it is null, new failed to allocate storage and the constructor + * was not called. If it is not null, then you must check o_errlHndl + * to see if the constructor ran successfully. If o_errlHndl indicates + * an error was reported by the constructor, new has already allocated + * heap storage and the object must be deleted in order to free the + * heap storage. + * + * @pre None + * + * @post An HdatSpSubsys object has been constructed. Heap storage has been allocated. + * + * @param o_errlHndl - output parameter - If any errors occur, the HdatSpSubsys object + * is NOT constructed and errors are returned in this parameter + * @param i_resourceId - input parameter - The resource id of the service processor FRU + * @param i_msAddr - input parameter - The main memory address that the service + * processor subsystem structure will be DMA'd to. + * + * @return A null error log handle if successful, else the return code pointed + * to by o_errlHndl contains one of: + * + * @retval HDAT_REGISTRY_ERROR + * @retval HDAT_OTHER_COMP_ERROR + */ + HdatSpSubsys(errlHndl_t &o_errlHndl, + hdatMsAddr_t &io_msAddr); + + + /** + * @brief HdatSpSubsys object destructor + * + * This is the destructor for an HdatSpSubsys object. Any heap storage + * allocated for the object is dallocated. + * + * @pre No preconditions exist + * + * @post The HdatSpSubsys object has been destroyed and can no longer be used. + * + */ + virtual ~HdatSpSubsys(); + /** + * @brief member function to get the size of sp sub sys structure + * + * Getter for iv_size + */ + uint32_t getSpSubSysStructSize(); + + /** + * @brief function to fill internal data pointers. + * + * @return A null error handle if successfull + */ + errlHndl_t hdatFillDataPtrs(); + + + private: + /** Object Instance Data + * + * @li iv_msAddr - Mainstore phyisical address + * @li iv_kwdSize - size of the ASCII keyword + * @li iv_kwd - ptr to storage which holds the ASCII keyword + * @li iv_fru - FRU Id information + * @li iv_impl - hardware/software implementation + * @li iv_mem - FSP memory information + * @li iv_ioPathArrayHdr - I/O path array header + * @li iv_ioPathArray - I/O path(s) to the FSP card + * @li iv_spSubsys - virtual address for SP sub sys data + * @li iv_size - size of the sp sub sys total structure + */ + uint64_t iv_msAddr; + uint32_t iv_kwdSize; + char *iv_kwd; + hdatFruId_t iv_fru; + hdatSpImpl_t iv_impl; + hdatSpMem_t iv_mem; + hdatHDIFDataArray_t iv_ioPathArrayHdr; + hdatSpIoPath_t *iv_ioPathArray; + uint8_t *iv_spSubsys; + uint32_t iv_size; + uint32_t iv_numOfIoPaths; + + + /** Class (static) Data + * + * Only one copy of this data exists in a process. + * + * @li cv_actualCnt - a count of how many HdatSpSubsys objects are created + */ + static uint32_t cv_actualCnt; + +}; // end of HdatSpSubsys class + +/** + * @brief This routine Loads SP Sub sys information. + * + * @param io_msAddr - input parameter - Mainstore address for SP subsys to write + * @param o_spSubsysCnt - output parameter - Count of SP Sub sys structures + * + * @return A null error log handle if successful, else the return code pointed + * to by errlHndl_t contains one of: + * + * @retval + */ + +errlHndl_t HdatLoadSpSubSys(hdatMsAddr_t &i_msAddr, + uint32_t &o_spSubSysTotalSize , uint32_t &o_spSubsysCnt); + +} +#endif // HDATSPSUBSYS_H diff --git a/src/usr/hdat/hdatutil.C b/src/usr/hdat/hdatutil.C new file mode 100644 index 000000000..4d95fbc8f --- /dev/null +++ b/src/usr/hdat/hdatutil.C @@ -0,0 +1,1351 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hdat/hdatutil.C $ */ +/* */ +/* 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 */ + +#include "hdatutil.H" +#include <i2c/eepromif.H> +#include <stdio.h> + +#define UINT16_IN_LITTLE_ENDIAN(x) (((x) >> 8) | ((x) << 8)) + +using namespace TARGETING; +namespace HDAT +{ +trace_desc_t *g_trac_hdat = NULL; +TRAC_INIT(&g_trac_hdat,HDAT_COMP_NAME,4096); + + +/******************************************************************************* +* hdatBldErrLog +*******************************************************************************/ +void hdatBldErrLog(errlHndl_t & io_err, + const uint8_t i_modid, + const uint16_t i_rc, + const uint32_t i_data1, + const uint32_t i_data2, + const uint32_t i_data3, + const uint32_t i_data4, + const ERRORLOG::errlSeverity_t i_sev, + const uint16_t i_version, + const bool i_commit, + const bool i_callout ) +{ + HDAT_DBG("mod:0x%02X, rc:0x%02X, data:%08X %08X %08X %08X, sev:0x%02X", + i_modid, i_rc, i_data1, i_data2, i_data3, i_data4, + i_sev); + + if (NULL == io_err) + { + io_err = new ERRORLOG::ErrlEntry(i_sev, + i_modid, + i_rc, + TWO_UINT32_TO_UINT64(i_data1,i_data2), + TWO_UINT32_TO_UINT64(i_data3,i_data4)); + } + else + { + uint32_t additionalSrc[] = + { + uint32_t(HDAT_COMP_ID | i_rc), uint32_t(i_modid), + uint32_t(i_sev), + i_data1, i_data2, i_data3, i_data4 + }; + io_err->addFFDC(HDAT_COMP_ID, + additionalSrc, + sizeof(additionalSrc), + i_version, + SUBSEC_ADDITIONAL_SRC); + + } + + if ( i_callout ) + { + io_err->addProcedureCallout(HWAS::EPUB_PRC_HB_CODE, + HWAS::SRCI_PRIORITY_HIGH); + } + io_err->collectTrace(HDAT_COMP_NAME); + io_err->collectTrace("HDAT_DBG"); + io_err->collectTrace("HDAT_ERR"); + + if ( i_commit ) + { + ERRORLOG::errlCommit(io_err,HDAT_COMP_ID); + } +} + +/******************************************************************************* +* isFunctional +*******************************************************************************/ +bool isFunctional( const Target* i_Target) +{ + bool o_funcState = false; + errlHndl_t l_errl = NULL; + do + { + if(NULL == i_Target) + { + HDAT_ERR("Input Target Pointer is NULL"); + /*@ + * @errortype + * @moduleid HDAT::MOD_UTIL_IS_FUNCTIONAL + * @reasoncode HDAT::RC_INVALID_OBJECT + * @devdesc Input Target Pointer is NULL + * @custdesc Firmware encountered an internal error + */ + hdatBldErrLog(l_errl, + MOD_UTIL_IS_FUNCTIONAL, + RC_INVALID_OBJECT, + 0,0,0,0, + ERRORLOG::ERRL_SEV_INFORMATIONAL, + HDAT_VERSION1, + true); + break; + } + else + { + o_funcState = i_Target->getAttr<ATTR_HWAS_STATE>().functional; + } + }while(0); + return o_funcState; +} + +/******************************************************************************* +* hdatGetIdEc +*******************************************************************************/ +errlHndl_t hdatGetIdEc(const Target *i_pTarget, + uint32_t &o_ecLevel, + uint32_t &o_chipId) +{ + errlHndl_t l_err = NULL; + + do + { + const TARGETING::Target *l_pCTarget = NULL; + if(i_pTarget->getAttr<TARGETING::ATTR_CLASS>() != TARGETING::CLASS_CHIP) + { + l_pCTarget = getParentChip(i_pTarget); + o_ecLevel = l_pCTarget->getAttr<TARGETING::ATTR_EC>(); + o_chipId = l_pCTarget->getAttr<TARGETING::ATTR_CHIP_ID>(); + } + else + { + o_ecLevel = i_pTarget->getAttr<TARGETING::ATTR_EC>(); + o_chipId = i_pTarget->getAttr<TARGETING::ATTR_CHIP_ID>(); + } + } + while(0); + + return l_err; +} + +/******************************************************************************* +* hdatGetHwCardId +*******************************************************************************/ +errlHndl_t hdatGetHwCardId(const Target *i_pTarget, uint32_t &o_cardId) +{ + errlHndl_t l_errl = NULL; + do + { + if(NULL == i_pTarget) + { + HDAT_ERR("Input Target pointer is NULL."); + /*@ + * @errortype + * @moduleid HDAT::MOD_UTIL_CARD_ID + * @reasoncode HDAT::RC_INVALID_OBJECT + * @devdesc Input Target Pointer is NULL + * @custdesc Firmware encountered an internal + * error while retrieving target data + */ + hdatBldErrLog(l_errl, + MOD_UTIL_CARD_ID, + RC_INVALID_OBJECT, + 0,0,0,0); + break; + } + if((i_pTarget->getAttr<ATTR_CLASS>() != CLASS_CARD)&& + (i_pTarget->getAttr<ATTR_CLASS>() != CLASS_LOGICAL_CARD)&& + (i_pTarget->getAttr<ATTR_CLASS>() != CLASS_CHIP)) + { + HDAT_ERR("Input Target is class not supported."); + /*@ + * @errortype + * @moduleid HDAT::MOD_UTIL_CARD_ID + * @reasoncode HDAT::RC_TARGET_UNSUPPORTED + * @devdesc Target is not currently supported + * @custdesc Firmware encountered an internal error + * while retrieving attribute data + */ + hdatBldErrLog(l_errl, + MOD_UTIL_CARD_ID, + RC_TARGET_UNSUPPORTED, + 0,0,0,0); + break; + } + TARGETING::TargetHandleList targetList; + targetList.clear(); + getParentAffinityTargets(targetList,i_pTarget, + TARGETING::CLASS_ENC,TARGETING::TYPE_NODE); + if(targetList.empty()) + { + /*@ + * @errortype + * @moduleid HDAT::MOD_UTIL_CARD_ID + * @reasoncode HDAT::RC_EMPTY_TARGET_LIST + * @devdesc Target list is empty + * @custdesc Firmware encountered an internal + * error while retrieving target data + */ + hdatBldErrLog(l_errl, + MOD_UTIL_CARD_ID, + RC_EMPTY_TARGET_LIST, + 0,0,0,0); + break; + } + //get the parent node id + TARGETING::Target* l_pNodeTarget = targetList[0]; + o_cardId = l_pNodeTarget->getAttr<ATTR_ORDINAL_ID>(); + } + while(0); + + return l_errl; +} + +/** + * @brief This routine populates the MTM and Serial number attributes + of system Target + * + * @pre None + * + * @post None + * + * @param None + * + * @return None + */ +void hdatPopulateMTMAndSerialNumber() +{ + errlHndl_t l_errl = NULL; + TARGETING::ATTR_RAW_MTM_type l_rawMTM = {0}; + TARGETING::ATTR_SERIAL_NUMBER_type l_serialNumber = {0}; + TARGETING::Target *l_pSysTarget = NULL; + size_t l_vpdSize = 0; + + (void) TARGETING::targetService().getTopLevelTarget(l_pSysTarget); + if(l_pSysTarget == NULL) + { + HDAT_ERR("Error in getting Top Level Target"); + assert(l_pSysTarget != NULL); + } + + TARGETING::PredicateCTM l_nodePredicate(TARGETING::CLASS_ENC, + TARGETING::TYPE_NODE); + TARGETING::PredicateHwas l_predHwas; + l_predHwas.present(true); + + TARGETING::PredicatePostfixExpr l_presentNode; + l_presentNode.push(&l_nodePredicate).push(&l_predHwas).And(); + + //Get all Nodes + TARGETING::TargetRangeFilter l_nodeFilter( + TARGETING::targetService().begin(), + TARGETING::targetService().end(), + &l_presentNode); + + TARGETING::Target *l_nodeTarget = (*l_nodeFilter); + + l_errl = deviceRead(l_nodeTarget, NULL, l_vpdSize, + DEVICE_PVPD_ADDRESS( PVPD::OSYS, PVPD::MM )); + + if(l_errl == NULL) + { + uint8_t l_vpddata[l_vpdSize]; + + l_errl = deviceRead(l_nodeTarget, l_vpddata, l_vpdSize, + DEVICE_PVPD_ADDRESS( PVPD::OSYS, PVPD::MM )); + + if(l_errl == NULL) + { + const uint8_t l_mtmSize= 0x08; + //phyp would requre just 8 character of MTM + strncpy(l_rawMTM,reinterpret_cast<const char*>(l_vpddata), + l_mtmSize); + for(uint8_t i=0; i<sizeof(l_rawMTM); i++) + { + if(l_rawMTM[i] == '-') + { + l_rawMTM[i]='.'; + break; + } + } + + if(!l_pSysTarget->trySetAttr<TARGETING::ATTR_RAW_MTM> + (l_rawMTM)) + { + HDAT_ERR("Error in setting MTM"); + } + } + } + if(l_errl) + { + ERRORLOG::errlCommit(l_errl,HDAT_COMP_ID); + } + + l_errl = deviceRead(l_nodeTarget, NULL, l_vpdSize, + DEVICE_PVPD_ADDRESS( PVPD::OSYS, PVPD::SS )); + + if(l_errl == NULL) + { + uint8_t l_vpddata[l_vpdSize]; + + l_errl = deviceRead(l_nodeTarget, l_vpddata, l_vpdSize, + DEVICE_PVPD_ADDRESS( PVPD::OSYS, PVPD::SS )); + + if(l_errl == NULL) + { + const uint8_t l_serialSize = 0x07; + //phyp would requre just 7 character of serial number + strncpy(reinterpret_cast<char *>(l_serialNumber), + reinterpret_cast<const char*>(l_vpddata),l_serialSize); + + if(!l_pSysTarget->trySetAttr + <TARGETING::ATTR_SERIAL_NUMBER>(l_serialNumber)) + { + HDAT_ERR("Error in setting Serial Number"); + } + } + } + + if(l_errl) + { + ERRORLOG::errlCommit(l_errl,HDAT_COMP_ID); + } + +} + +/** + * @brief This routine gets prefix of location code + * + * @pre None + * + * @post None + * + * @param o_locCode - output parameter - Location Code Prefix + * + * @return None + */ +void hdatGetLocationCodePrefix(char *o_locCode) +{ + TARGETING::ATTR_RAW_MTM_type l_rawMTM = {0}; + TARGETING::ATTR_SERIAL_NUMBER_type l_serialNumber = {0}; + TARGETING::Target *l_pSysTarget = NULL; + + (void) TARGETING::targetService().getTopLevelTarget(l_pSysTarget); + if(l_pSysTarget == NULL) + { + HDAT_ERR("Error in getting Top Level Target"); + assert(l_pSysTarget != NULL); + } + + strcpy(o_locCode, "U"); + + //if(l_pSysTarget == TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL) + // { + // assert(false); + // } + + if(l_pSysTarget->tryGetAttr<TARGETING::ATTR_RAW_MTM>(l_rawMTM)) + { + if(l_pSysTarget->tryGetAttr<TARGETING::ATTR_SERIAL_NUMBER> + (l_serialNumber)) + { + strcat(o_locCode,"OPWR"); + strcat(o_locCode,"."); + strcat(o_locCode,"BAR"); + strcat(o_locCode,"."); + strcat(o_locCode,(const char*)l_serialNumber); + } + else + { + HDAT_ERR("Error accessing ATTR_SERIAL_NUMBER attribute"); + } + } + else + { + HDAT_ERR("Error accessing ATTR_RAW_MTM attribute"); + } +} + +/** + * @brief This routine constructs the location Code for the incoming target + * + * @pre None + * + * @post None + * + * @param i_pFruTarget - input parameter - System target + * i_locCodePrefix - input parameter - Location Code prefix + * o_locCode - output parameter - Constructed location code + * + * @return None + */ +void hdatGetLocationCode(TARGETING::Target *i_pFruTarget, + char *i_locCodePrefix, + char *o_locCode) +{ + TARGETING::ATTR_PHYS_PATH_type l_physPath; + char *l_pPhysPath; + char l_locCode[64] = {0}; + +//@TODO:RTC 149347: Add methods to generate location codes + + if(i_pFruTarget->tryGetAttr<TARGETING::ATTR_PHYS_PATH>(l_physPath)) + { + char *l_cutString; + char *l_suffix; + + l_pPhysPath = i_pFruTarget->getAttr + <TARGETING::ATTR_PHYS_PATH>().toString(); + + l_cutString = strchr(l_pPhysPath, '/'); + l_suffix = l_cutString; + + while (l_cutString != NULL) + { + l_suffix = l_cutString; + l_cutString = strchr(l_cutString+1, '/'); + } + +#if USE_PHYS_PATH_FOR_LOC_CODE + + strncpy(l_hdatslcaentry.location_code, + reinterpret_cast<const char *> + (i_Target->getAttr<TARGETING::ATTR_PHYS_PATH>().toString()), + l_hdatslcaentry.max_location_code_len); +#else + + sprintf(l_locCode, "%s-%s",i_locCodePrefix,(l_suffix+1)); + + uint8_t l_index = 0; + while(l_index < strlen(l_locCode)) + { + if(l_locCode[l_index] != ' ') + { + *o_locCode++ = l_locCode[l_index]; + } + l_index++; + } + // *o_locCode = 0; +#endif + } + else + { + HDAT_ERR("Error accessing ATTR_PHYS_PATH attribute"); + } +} + +/******************************************************************************/ +//hdatGetAsciiKwd +/******************************************************************************/ + +errlHndl_t hdatGetAsciiKwd( TARGETING::Target * i_target,uint32_t &o_kwdSize, + char* &o_kwd,vpdType i_vpdtype,struct vpdData i_fetchVpd[], + uint32_t i_num, size_t theSize[]) +{ + HDAT_ENTER(); + errlHndl_t l_err = NULL; + + switch (i_vpdtype) + { + case PROC: + l_err = hdatGetAsciiKwdForMvpd(i_target,o_kwdSize,o_kwd, + i_fetchVpd,i_num,theSize); + HDAT_DBG("got back kwd size=%x",o_kwdSize); + break; + case BP: + l_err = hdatGetAsciiKwdForPvpd(i_target,o_kwdSize,o_kwd, + i_fetchVpd,i_num,theSize); + HDAT_DBG("got back kwd size=%x",o_kwdSize); + break; + default: + HDAT_DBG("no appropriate vpd function to call"); + break; + } + HDAT_EXIT(); + return l_err; +}//end hdatGetAsciiKwd + +/******************************************************************************/ +//hdatGetAsciiKwdForPvpd +/******************************************************************************/ +errlHndl_t hdatGetAsciiKwdForPvpd(TARGETING::Target * i_target, + uint32_t &o_kwdSize,char* &o_kwd, + struct vpdData i_fetchVpd[], size_t i_num, size_t theSize[]) +{ + + errlHndl_t l_err = NULL; + uint64_t cmds = 0x0; + uint64_t fails = 0x0; + VPD::vpdRecord theRecord = 0x0; + VPD::vpdKeyword theKeyword = 0x0; + + + o_kwd = NULL; + o_kwdSize = 0; + //size_t theSize[i_num]; + memset (theSize,0, sizeof(theSize)); + + do + { + assert(i_target != NULL); + + uint8_t *theData = NULL; + + const uint32_t numCmds = i_num; + + for( uint32_t curCmd = 0; curCmd < numCmds; curCmd++ ) + { + cmds++; + theRecord = i_fetchVpd[curCmd].record; + theKeyword = i_fetchVpd[curCmd].keyword; + + if( theKeyword == PVPD::LX) + { + theSize[curCmd] = 0; + continue; + } + l_err = deviceRead( i_target, + NULL, + theSize[curCmd], + DEVICE_PVPD_ADDRESS( theRecord, + theKeyword ) ); + if( l_err ) + { + fails++; + HDAT_DBG("hdatGetAsciiKwdForPvpd::failure reading keyword size " + "rec: 0x%04x, kwd: 0x%04x", + theRecord,theKeyword ); + /*@ + * @errortype + * @moduleid HDAT::MOD_UTIL_PVPD_READ_FUNC + * @reasoncode HDAT::RC_PVPD_FAIL + * @userdata1 pvpd record + * @userdata2 pvpd keyword + * @devdesc PVPD read fail + * @custdesc Firmware encountered an internal error + */ + hdatBldErrLog(l_err, + MOD_UTIL_PVPD_READ_FUNC, + RC_PVPD_FAIL, + theRecord,theKeyword,0,0, + ERRORLOG::ERRL_SEV_INFORMATIONAL, + HDAT_VERSION1, + true); + + continue; + } + HDAT_DBG("fetching BP kwd size PVPD, size initialised=%x " + " keyword =%04x",theSize[curCmd],theKeyword); + o_kwdSize += theSize[curCmd]; + } + + HDAT_DBG("hdatGetAsciiKwdForPvpd:: allocating total key word size %d", + o_kwdSize); + o_kwd = new char[o_kwdSize]; + + uint32_t loc = 0; + for( uint32_t curCmd = 0; curCmd < numCmds; curCmd++ ) + { + theRecord = i_fetchVpd[curCmd].record; + theKeyword = i_fetchVpd[curCmd].keyword; + + //this conidtion is , if in the top loop there is a fail then + //theSize[curCmd] will be 0. + if( theSize[curCmd] == 0) + { + continue; + } + theData = new uint8_t [theSize[curCmd]]; + + HDAT_DBG("hdatGetAsciiKwdForPvpd: reading %dth keyword of size %d", + curCmd,theSize[curCmd]); + + l_err = deviceRead( i_target, + theData, + theSize[curCmd], + DEVICE_PVPD_ADDRESS( theRecord, + theKeyword ) ); + HDAT_DBG("hdatGetAsciiKwdForPvpd: read BP data %s",theData); + + if ( l_err ) + { + fails++; + HDAT_DBG("hdatGetAsciiKwdForPvpd: Failure on Record: " + "0x%04x, keyword: 0x%04x, of size: 0x%04x - test %d", + theRecord,theKeyword,theSize,curCmd); + /*@ + * @errortype + * @moduleid HDAT::MOD_UTIL_PVPD_READ_FUNC + * @reasoncode HDAT::RC_PVPD_READ_FAIL + * @userdata1 pvpd record + * @userdata2 pvpd keyword + * @devdesc PVPD read fail + * @custdesc Firmware encountered an internal error + */ + hdatBldErrLog(l_err, + MOD_UTIL_PVPD_READ_FUNC, + RC_PVPD_READ_FAIL, + theRecord,theKeyword,0,0, + ERRORLOG::ERRL_SEV_INFORMATIONAL, + HDAT_VERSION1, + true); + + if ( NULL != theData ) + { + delete[] theData; + theData = NULL; + } + continue; + } + if ( NULL != theData ) + { + memcpy(reinterpret_cast<void *>(o_kwd + loc),theData, + theSize[curCmd]); + + loc += theSize[curCmd]; + delete[] theData; + theData = NULL; + HDAT_DBG("hdatGetAsciiKwdForPvpd: copied to main array %d kwd", + curCmd); + } + } + }while(0); + + HDAT_DBG("hdatGetAsciiKwdForPvpd: returning keyword size %d and data %s", + o_kwdSize,o_kwd); + return l_err; + +} + +/******************************************************************************/ +// hdatGetAsciiKwdForMvpd +/******************************************************************************/ + +errlHndl_t hdatGetAsciiKwdForMvpd(TARGETING::Target * i_target, + uint32_t &o_kwdSize,char* &o_kwd, + struct vpdData i_fetchVpd[], uint32_t i_num,size_t theSize[]) +{ + HDAT_ENTER(); + errlHndl_t err = NULL; + uint64_t cmds = 0x0; + uint64_t fails = 0x0; + uint64_t theRecord = 0x0; + uint64_t theKeyword = 0x0; + + o_kwd = NULL; + o_kwdSize = 0; + + + do + { + if(i_target == NULL) + { + HDAT_ERR("no functional Targets found"); + break; + } + + //size_t theSize[100] = {0};//assuming max kwd num 100 + uint8_t *theData = NULL; + + + for( uint32_t curCmd = 0; curCmd < i_num; curCmd++ ) + { + cmds++; + theRecord = (uint64_t)i_fetchVpd[curCmd].record; + theKeyword = (uint64_t)i_fetchVpd[curCmd].keyword; + + HDAT_DBG("fetching proc kwd size MVPD, size initialised=%x", + theSize[curCmd]); + err = deviceRead( i_target, + NULL, + theSize[curCmd], + DEVICE_MVPD_ADDRESS( theRecord, + theKeyword ) ); + HDAT_DBG("fetched proc kwd size MVPD, size=%x",theSize[curCmd]); + + if( err ) + { + fails++; + HDAT_DBG("failure reading keyword size " + "rec: 0x%04x, kwd: 0x%04x", + theRecord,theKeyword ); + /*@ + * @errortype + * @moduleid HDAT::MOD_UTIL_VPD + * @reasoncode HDAT::RC_DEV_READ_FAIL + * @devdesc Device read failed + * @custdesc Firmware encountered an internal error + */ + hdatBldErrLog(err, + MOD_UTIL_VPD, + RC_DEV_READ_FAIL, + theRecord,theKeyword,0,0, + ERRORLOG::ERRL_SEV_INFORMATIONAL, + HDAT_VERSION1, + true); + continue; + } + o_kwdSize += theSize[curCmd]; + } + + HDAT_DBG("allocating total key word size %d", + o_kwdSize); + //o_kwd = static_cast<char *>(malloc( o_kwdSize)); + o_kwd = new char[o_kwdSize]; + + uint32_t loc = 0; + for( uint32_t curCmd = 0; curCmd < i_num; curCmd++ ) + { + theRecord = (uint64_t)i_fetchVpd[curCmd].record; + theKeyword = (uint64_t)i_fetchVpd[curCmd].keyword; + + //theData = static_cast<uint8_t*>(malloc( theSize[curCmd] )); + theData = new uint8_t [theSize[curCmd]]; + + HDAT_DBG("reading %dth keyword of size %d", + curCmd,theSize[curCmd]); + + err = deviceRead( i_target, + theData, + theSize[curCmd], + DEVICE_MVPD_ADDRESS( theRecord, + theKeyword ) ); + HDAT_DBG("read PROC data %s",theData); + + if ( err ) + { + fails++; + HDAT_DBG("hdatGetAsciiKwdForMvpd: Failure on Record: " + "0x%04x, keyword: 0x%04x, of size: 0x%04x - test %d", + theRecord,theKeyword,theSize,curCmd); + + delete err; + + if ( NULL != theData ) + { + // free( theData ); + delete[] theData; + theData = NULL; + } + continue; + } + if ( NULL != theData ) + { + //copy to output array and free theData + memcpy(reinterpret_cast<void *>(o_kwd + loc),theData, + theSize[curCmd]); + + loc += theSize[curCmd]; + //free( theData ); + delete[] theData; + theData = NULL; + HDAT_DBG("copied to main array %d kwd", + curCmd); + } + } + + }while(0); + + HDAT_DBG("returning keyword size %d and data %s", + o_kwdSize,o_kwd); + + HDAT_EXIT(); + return err; +}//end hdatGetAsciiKwdForMvpd + + +/******************************************************************************/ +// hdatGetAsciiKwdForCvpd +/******************************************************************************/ +errlHndl_t hdatGetAsciiKwdForCvpd(TARGETING::Target * i_target, + uint32_t &o_kwdSize,char* &o_kwd, + struct vpdData i_fetchVpd[], size_t i_num,size_t theSize[]) +{ + + errlHndl_t l_err = NULL; + uint64_t cmds = 0x0; + uint64_t fails = 0x0; + VPD::vpdRecord theRecord = 0x0; + VPD::vpdKeyword theKeyword = 0x0; + + + o_kwd = NULL; + o_kwdSize = 0; + //size_t theSize[i_num]; + + do + { + assert(i_target != NULL); + + uint8_t *theData = NULL; + + const uint32_t numCmds = i_num; + + for( uint32_t curCmd = 0; curCmd < numCmds; curCmd++ ) + { + cmds++; + theRecord = i_fetchVpd[curCmd].record; + theKeyword = i_fetchVpd[curCmd].keyword; + + HDAT_DBG("fetching DIMM kwd size CVPD, size initialised=%x", + theSize[curCmd]); + l_err = deviceRead( i_target, + NULL, + theSize[curCmd], + DEVICE_CVPD_ADDRESS( theRecord, + theKeyword ) ); + + if( l_err ) + { + fails++; + HDAT_DBG("hdatGetAsciiKwdForCvpd::failure reading keyword size " + "rec: 0x%04x, kwd: 0x%04x", + theRecord,theKeyword ); + /*@ + * @errortype + * @moduleid HDAT::MOD_UTIL_CVPD_READ_FUNC + * @reasoncode HDAT::RC_CVPD_FAIL + * @userdata1 cvpd record + * @userdata2 cvpd keyword + * @devdesc CVPD read fail + * @custdesc Firmware encountered an internal error + */ + hdatBldErrLog(l_err, + MOD_UTIL_CVPD_READ_FUNC, + RC_CVPD_FAIL, + theRecord,theKeyword,0,0, + ERRORLOG::ERRL_SEV_INFORMATIONAL, + HDAT_VERSION1, + true); + + + continue; + } + o_kwdSize += theSize[curCmd]; + } + + HDAT_DBG("hdatGetAsciiKwdForCvpd:: allocating total key word size %d", + o_kwdSize); + o_kwd = new char[o_kwdSize]; + + uint32_t loc = 0; + for( uint32_t curCmd = 0; curCmd < numCmds; curCmd++ ) + { + theRecord = i_fetchVpd[curCmd].record; + theKeyword = i_fetchVpd[curCmd].keyword; + + //this conidtion is , if in the top loop there is a fail then + //theSize[curCmd] will be 0. + if( theSize[curCmd] == 0) + { + continue; + } + theData = new uint8_t [theSize[curCmd]]; + + HDAT_DBG("hdatGetAsciiKwdForCvpd: reading %dth keyword of size %d", + curCmd,theSize[curCmd]); + + l_err = deviceRead( i_target, + theData, + theSize[curCmd], + DEVICE_CVPD_ADDRESS( theRecord, + theKeyword ) ); + HDAT_DBG("hdatGetAsciiKwdForCvpd: read PROC data %s",theData); + + if ( l_err ) + { + fails++; + HDAT_DBG("hdatGetAsciiKwdForCvpd: Failure on Record: " + "0x%04x, keyword: 0x%04x, of size: 0x%04x - test %d", + theRecord,theKeyword,theSize,curCmd); + /*@ + * @errortype + * @moduleid HDAT::MOD_UTIL_CVPD_READ_FUNC + * @reasoncode HDAT::RC_CVPD_READ_FAIL + * @userdata1 cvpd record + * @userdata2 cvpd keyword + * @devdesc CVPD read fail + * @custdesc Firmware encountered an internal error + */ + hdatBldErrLog(l_err, + MOD_UTIL_CVPD_READ_FUNC, + RC_CVPD_READ_FAIL, + theRecord,theKeyword,0,0, + ERRORLOG::ERRL_SEV_INFORMATIONAL, + HDAT_VERSION1, + true); + + if ( NULL != theData ) + { + delete[] theData; + theData = NULL; + } + continue; + } + if ( NULL != theData ) + { + //copy to output array and free theData + memcpy(reinterpret_cast<void *>(o_kwd + loc),theData, + theSize[curCmd]); + + loc += theSize[curCmd]; + delete[] theData; + theData = NULL; + HDAT_DBG("hdatGetAsciiKwdForCvpd: copied to main array %d kwd", + curCmd); + } + } + }while(0); + + HDAT_DBG("hdatGetAsciiKwdForCvpd: returning keyword size %d and data %s", + o_kwdSize,o_kwd); + return l_err; + +} + +/******************************************************************************* +* hdatGetMaxCecNodes +*******************************************************************************/ + +uint32_t hdatGetMaxCecNodes() +{ + TARGETING::TargetHandleList l_nodeTargetList; + do + { + TARGETING::Target* sys = NULL; + TARGETING::targetService().getTopLevelTarget(sys); + + PredicateCTM predNode(CLASS_ENC, TYPE_NODE); + PredicateHwas predFunctional; + predFunctional.functional(true); + PredicatePostfixExpr nodeCheckExpr; + nodeCheckExpr.push(&predNode).push(&predFunctional).And(); + targetService().getAssociated(l_nodeTargetList, sys, + TargetService::CHILD, TargetService::IMMEDIATE, + &nodeCheckExpr); + + }while(0); + + return l_nodeTargetList.size(); +} + +/******************************************************************************* +* hdatPrintHdrs +*******************************************************************************/ +void hdatPrintHdrs(const hdatHDIF_t *i_hdif, + const hdatHDIFDataHdr_t *i_data, + const hdatHDIFDataArray_t *i_dataArray, + const hdatHDIFChildHdr_t *i_child) +{ + hdatHDIFDataHdr_t *l_data; + hdatHDIFChildHdr_t *l_child; + uint32_t l_idx; + char l_string[sizeof(i_hdif->hdatStructName)+1]; + + if (NULL != i_hdif) + { + // Null terminate the eye catcher string. + memcpy(l_string, &i_hdif->hdatStructName, + sizeof(i_hdif->hdatStructName)); + l_string[sizeof(i_hdif->hdatStructName)] = 0x00; + + HDAT_INF(" **hdatHDIF_t**"); + HDAT_INF(" hdatStructId = 0X %04X ", i_hdif->hdatStructId); + HDAT_INF(" hdatStructName = %s", l_string); + HDAT_INF(" hdatInstance = %hu", i_hdif->hdatInstance); + HDAT_INF(" hdatVersion = %hu", i_hdif->hdatVersion); + HDAT_INF(" hdatSize = %u", i_hdif->hdatSize); + HDAT_INF(" hdatHdrSize = %u", i_hdif->hdatHdrSize); + HDAT_INF(" hdatDataPtrOffset = %u", i_hdif->hdatDataPtrOffset); + HDAT_INF(" hdatDataPtrCnt = %hu", i_hdif->hdatDataPtrCnt); + HDAT_INF(" hdatChildStrCnt = %hu", i_hdif->hdatChildStrCnt); + HDAT_INF(" hdatChildStrOffset = %u", i_hdif->hdatChildStrOffset); + } + + if (NULL != i_data && NULL != i_hdif) + { + l_data = const_cast<hdatHDIFDataHdr_t *>(i_data); + HDAT_INF(" **hdatHDIFDataHdr_t**"); + for (l_idx=0; l_idx<i_hdif->hdatDataPtrCnt; l_idx++) + { + HDAT_INF(" hdatOffset = %u", l_data->hdatOffset); + HDAT_INF(" hdatSize = %u", l_data->hdatSize); + l_data++; + } + } + + if (NULL != i_child && NULL != i_hdif) + { + l_child = const_cast<hdatHDIFChildHdr_t *>(i_child); + HDAT_INF(" **hdatHDIFChildHdr_t**"); + for (l_idx=0; l_idx<i_hdif->hdatChildStrCnt; l_idx++) + { + HDAT_INF(" hdatOffset = %u", l_child->hdatOffset); + HDAT_INF(" hdatSize = %u", l_child->hdatSize); + HDAT_INF(" hdatCnt = %u", l_child->hdatCnt); + l_child++; + } + HDAT_INF(""); + } + + if (NULL != i_dataArray) + { + HDAT_INF(" **hdatHDIFDataArray_t**"); + HDAT_INF(" hdatOffset = %u", i_dataArray->hdatOffset); + HDAT_INF(" hdatArrayCnt = %u", i_dataArray->hdatArrayCnt); + HDAT_INF(" hdatAllocSize = %u", i_dataArray->hdatAllocSize); + HDAT_INF(" hdatActSize = %u", i_dataArray->hdatActSize); + } + + return; +} + +/******************************************************************************* +* hdatPrintKwd +*******************************************************************************/ +void hdatPrintKwd(const char *i_kwd, + int32_t i_kwdLen) +{ + const uint32_t HDAT_HEX_SIZE = 16; //16 hex characters per line + uint32_t l_cnt, l_lines, l_rem ; + char * l_kwd = const_cast<char *>(i_kwd); + + + l_lines = i_kwdLen / HDAT_HEX_SIZE; + l_rem = i_kwdLen % HDAT_HEX_SIZE; + + HDAT_INF(" **ASCII keyword VPD**"); + if (NULL == i_kwd) + { + HDAT_INF(" No keyword VPD"); + } + else + { + for (l_cnt = 0; l_cnt < l_lines; l_cnt++) + { + HDAT_INF( "0X %08X %08X %08X %08X", + (*(reinterpret_cast<uint32_t *>(l_kwd ))) , + (*(reinterpret_cast<uint32_t *>(l_kwd + 4))), + (*(reinterpret_cast<uint32_t *>(l_kwd + 8))) , + (*(reinterpret_cast<uint32_t *>(l_kwd + 12))) ); + + i_kwd += 16; + } // end for loop + + + if ( l_rem > 0 ) + { + // More to print, but can't go past end of storage and + // not easy to use TRACF statements for this + if ( l_rem < 5 ) + { + HDAT_INF( "0X %08X ", (*(reinterpret_cast<uint32_t *>(l_kwd))) ); + } + else if ( l_rem < 9 ) + { + HDAT_INF( "0X %08X %08X ", + (*(reinterpret_cast<uint32_t *>(l_kwd ))) , + (*(reinterpret_cast<uint32_t *>(l_kwd + 4))) ); + } + else if ( l_rem < 13 ) + { + HDAT_INF( "0X %08X %08X %08X ", + (*(reinterpret_cast<uint32_t *>(l_kwd ))) , + (*(reinterpret_cast<uint32_t *>(l_kwd + 4))), + (*(reinterpret_cast<uint32_t *>(l_kwd + 8))) ); + } + else + { // remainder is up to 15 bytes + HDAT_INF( "0X %08X %08X %08X %08X", + (*(reinterpret_cast<uint32_t *>(l_kwd ))) , + (*(reinterpret_cast<uint32_t *>(l_kwd + 4))), + (*(reinterpret_cast<uint32_t *>(l_kwd + 8))) , + (*(reinterpret_cast<uint32_t *>(l_kwd + 12))) ); + } + + } // end if remainder non-zero + + } // else we have keyword VPD + + return; +} + +/******************************************************************************/ +// hdatGetAsciiKwdForSpd +/******************************************************************************/ +errlHndl_t hdatGetAsciiKwdForSpd(TARGETING::Target * i_target, + size_t &o_kwdSize,char* &o_kwd) +{ + + errlHndl_t l_err = NULL; + uint64_t keyword = SPD::ENTIRE_SPD; + + do + { + assert(i_target != NULL); + + l_err = deviceRead( i_target, + NULL, + o_kwdSize, + DEVICE_SPD_ADDRESS(keyword) ); + if (l_err) + { + break; + } + + o_kwd = new char[o_kwdSize]; + + l_err = deviceRead( i_target, + o_kwd, + o_kwdSize, + DEVICE_SPD_ADDRESS(keyword) ); + + }while(0); + if ( l_err ) + { + HDAT_DBG("hdatGetAsciiKwdForSpd : Failure on " + " keyword: 0x%04x, of size: 0x%04x ", + keyword,o_kwdSize); + /*@ + * @errortype + * @moduleid HDAT::MOD_UTIL_SPD_READ_FUNC + * @reasoncode HDAT::RC_SPD_READ_FAIL + * @userdata1 spd keyword + * @devdesc SPD read fail + * @custdesc Firmware encountered an internal error + */ + hdatBldErrLog(l_err, + MOD_UTIL_SPD_READ_FUNC, + RC_SPD_READ_FAIL, + keyword,0,0,0, + ERRORLOG::ERRL_SEV_INFORMATIONAL, + HDAT_VERSION1, + true); + + if ( NULL != o_kwd) + { + delete[] o_kwd; + o_kwd = NULL; + } + } + + HDAT_DBG("hdatGetAsciiKwdForSpd: returning keyword size %d and data %s", + o_kwdSize,o_kwd); + return l_err; + +} + +void hdatGetTarget (const hdatSpiraDataAreas i_dataArea, + TARGETING::TargetHandleList &o_targList) +{ + TARGETING::TYPE l_type; + TARGETING::CLASS l_class; + + switch (i_dataArea) + { + case HDAT_BACKPLANE_VPD: + l_type = TARGETING::TYPE_NODE; + l_class = TARGETING::CLASS_ENC; + break; + + case HDAT_CLOCK_VPD: + l_type = TARGETING::TYPE_NA; + l_class = TARGETING::CLASS_NA; + break; + + case HDAT_SYS_VPD: + l_type = TARGETING::TYPE_SYS; + l_class = TARGETING::CLASS_SYS; + break; + + case HDAT_ENCLOSURE_VPD: + l_type = TARGETING::TYPE_NA; + l_class = TARGETING::CLASS_NA; + break; + + case HDAT_ANCHOR_VPD: + l_type = TARGETING::TYPE_NA; + l_class = TARGETING::CLASS_NA; + break; + + case HDAT_MISC_CEC_VPD: + l_type = TARGETING::TYPE_NA; + l_class = TARGETING::CLASS_NA; + break; + default: + l_type = TARGETING::TYPE_NA; + l_class = TARGETING::CLASS_NA; + break; + } + + if ( (l_type != TARGETING::TYPE_NA) && + (l_class != TARGETING::CLASS_NA)) + { + TARGETING::Target* l_sys = NULL; + TARGETING::targetService().getTopLevelTarget(l_sys); + assert(l_sys != NULL); + + if( (l_type == TARGETING::TYPE_SYS ) && + (l_class == TARGETING::CLASS_SYS)) + { + o_targList.push_back(l_sys); + } + else + { + PredicateCTM predNode(l_class, l_type); + PredicateHwas predFunctional; + predFunctional.functional(true); + PredicatePostfixExpr nodeCheckExpr; + nodeCheckExpr.push(&predNode).push(&predFunctional).And(); + + targetService().getAssociated(o_targList, l_sys, + TargetService::CHILD, TargetService::IMMEDIATE, + &nodeCheckExpr); + } + + } + +} + +errlHndl_t hdatformatAsciiKwd(const struct vpdData i_fetchVpd[], + const size_t &i_num, const size_t theSize[], char* &i_kwd, + const uint32_t &i_kwdSize, char* &o_fmtKwd, uint32_t &o_fmtkwdSize, + const HdatKeywordInfo i_Keywords[]) +{ + HDAT_ENTER(); + + // i_kwdSize - data size + // (i_num* sizeof(uint8_t)) - individual datat size + // (2 * sizeof(uint8_t)) - 0x78, 0x84 + // sizeof(uint16_t) = total data size in size + // (i_num* 2) - keyword size + o_fmtkwdSize = i_kwdSize + (i_num* sizeof(uint8_t)) + + (2 * sizeof(uint8_t)) + sizeof(uint16_t) + (i_num* 2); + + o_fmtKwd = new char[o_fmtkwdSize]; + //Tag for start of the section + uint8_t l_initial = 0x84; + uint16_t l_kwdSize = o_fmtkwdSize - sizeof(uint16_t) - (2*sizeof(uint8_t)); + + //Need to convert the size into little endian as per format + l_kwdSize= UINT16_IN_LITTLE_ENDIAN(l_kwdSize); + memcpy(reinterpret_cast<void *>(o_fmtKwd ),&l_initial,sizeof(l_initial)); + memcpy(reinterpret_cast<void *>(o_fmtKwd + 1),&l_kwdSize,sizeof(l_kwdSize)); + + uint32_t l_loc = sizeof(uint16_t) + sizeof(uint8_t); + char *ptr = i_kwd; + + for( uint32_t curCmd = 0; curCmd < i_num; curCmd++ ) + { + if( theSize[curCmd] != 0) + { + memcpy(reinterpret_cast<void *>(o_fmtKwd + l_loc), + &i_Keywords[curCmd].keywordName, 2); + l_loc += 2; + + uint8_t l_var = theSize[curCmd]; + memcpy(reinterpret_cast<void *>(o_fmtKwd + l_loc),&l_var, + sizeof(uint8_t)); + + l_loc += sizeof(uint8_t); + + memcpy(reinterpret_cast<void *>(o_fmtKwd + l_loc),ptr, + theSize[curCmd]); + + l_loc += theSize[curCmd]; + + ptr += theSize[curCmd]; + } + } + //End start tag of the section + uint8_t l_end= 0x78; + memcpy(reinterpret_cast<void *>(o_fmtKwd +l_loc),&l_end,sizeof(uint8_t)); + l_loc +=sizeof(uint8_t); + + HDAT_EXIT(); + return NULL; +} + + +errlHndl_t hdatGetFullEepromVpd(TARGETING::Target * i_target, + size_t &io_dataSize, + char* &o_data) +{ + errlHndl_t err = NULL; + + HDAT_ENTER(); + if(i_target != NULL) + { + o_data = new char[io_dataSize]; + + //Collecting Full module VPD data + err = deviceOp( DeviceFW::READ, + i_target, + o_data, + io_dataSize, + DEVICE_EEPROM_ADDRESS(EEPROM::VPD_PRIMARY, 0)); + if(err) + { + HDAT_ERR("Reading Full vpd from Eeprom failed"); + /*@ + * @errortype + * @moduleid HDAT::MOD_UTIL_FULL_MVPD_READ_FUNC + * @reasoncode HDAT::RC_DEV_READ_VPD_FAIL + * @devdesc Device read failed + * @custdesc Firmware encountered an internal error + */ + hdatBldErrLog(err, + MOD_UTIL_FULL_MVPD_READ_FUNC, + RC_DEV_READ_VPD_FAIL, + 0,0,0,0, + ERRORLOG::ERRL_SEV_INFORMATIONAL, + HDAT_VERSION1, + true); + if(o_data != NULL) // No point in keeping this data with err + { + delete[] o_data; + o_data = NULL; + } + } + } + else + { + HDAT_ERR("Input Target is Null"); + } + HDAT_EXIT(); + return(err); +} + + +} //namespace HDAT diff --git a/src/usr/hdat/hdatutil.H b/src/usr/hdat/hdatutil.H new file mode 100755 index 000000000..6ded4f426 --- /dev/null +++ b/src/usr/hdat/hdatutil.H @@ -0,0 +1,396 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hdat/hdatutil.H $ */ +/* */ +/* 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 */ + + +/** + * @file hdatutil.H + * + * @brief This file contains various utility functions used internally by the + * hypervisor data area component. + */ + +#ifndef HDATUTIL_H +#define HDATUTIL_H + +/*----------------------------------------------------------------------------*/ +/* Includes */ +/*----------------------------------------------------------------------------*/ +#include <errl/errlentry.H> +#include <errl/errlmanager.H> +#include <hdat/hdat_reasoncodes.H> +#include <trace/interface.H> +#include <targeting/common/targetservice.H> +#include <targeting/common/utilFilter.H> +#include <hdat/hdat.H> +#include "hdatvpd.H" +#include "hdatbldda.H" +#include<vpd/mvpdenums.H> +#include<vpd/pvpdenums.H> +#include<vpd/cvpdenums.H> +#include<vpd/spdenums.H> +#include <devicefw/driverif.H> +#include <targeting/common/predicates/predicatectm.H> + +/*----------------------------------------------------------------------------*/ +/* Constants */ +/*----------------------------------------------------------------------------*/ +const uint16_t HDAT_VERSION1 = 1; +const uint16_t HDAT_VERSION2 = 2; +const uint16_t HDAT_VERSION3 = 3; +#define DBG_MRK "D>" + +//initialize the trac buffers +#define HDAT_ENTER() \ + TRACFCOMP(g_trac_hdat,ENTER_MRK"[%s]",__FUNCTION__); + +#define HDAT_EXIT() \ + TRACFCOMP(g_trac_hdat,EXIT_MRK"[%s]",__FUNCTION__); + +#define STRINGIFY(x) #x +#define TOSTRING(x) STRINGIFY(x) + +#define AT " [ " __FILE__ " ]:[ " TOSTRING(__LINE__) " ]: " + +#define HDAT_ERR( _fmt_, _args_...) \ + TRACFCOMP( g_trac_hdat,ERR_MRK AT _fmt_, ##_args_ ); + +#define HDAT_DBG( _fmt_, _args_...) \ + TRACFCOMP( g_trac_hdat,DBG_MRK _fmt_, ##_args_ ); + +#define HDAT_INF( _fmt_, _args_...) \ + TRACFCOMP( g_trac_hdat,DBG_MRK _fmt_, ##_args_ ); + +namespace HDAT +{ + +extern trace_desc_t* g_trac_hdat; + + +/** + * @brief Create/Build an Error log and add HADT component trace + * if the log exists then FFDC will be added to the existing log and + * trace will be collected + * + * @param[in,out] io_err Error handle to use or NULL to create new handle + * @param[in] i_modid Module ID + * @param[in] i_rc Return Code + * @param[in] i_data1 User data word 1 + * @param[in] i_data2 User data word 2 + * @param[in] i_data3 User data word 3 + * @param[in] i_data4 User data word 4 + * @param[in] i_sev Error severity + * @param[in] i_version Data Version identifier for errorlog user details + * @param[in] i_commit true if the log should be committed inside + * the function + * @param[in] i_callout Default is true to add software callout info + */ +void hdatBldErrLog(errlHndl_t & io_err, + const uint8_t i_modid, + const uint16_t i_rc, + const uint32_t i_data1 = 0, + const uint32_t i_data2 = 0, + const uint32_t i_data3 = 0, + const uint32_t i_data4 = 0, + const ERRORLOG::errlSeverity_t i_sev = + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + const uint16_t i_version = + HDAT_VERSION1, + const bool i_commit = false, + bool i_callout = true); + +/** + * @brief Check whether the supplied Target is functional + * + * @param[in] i_pTarget - Target pointer + * + * @return bool - Functional state of Target. + * functional(TRUE) or not(FALSE). If an invalid target is + * supplied then the interface will commit and will return false. + * + */ +bool isFunctional( const TARGETING::Target* i_Target); + +/** + * @brief Get the EC Id and Chip Level for the target + * + * @param[in] i_pTarget + * Input target pointer. Must not be NULL (otherwise call will return an + * error log). Must be a valid target from the system blueprint. + * + * @param[out] o_ecLevel - value of EC level for the target + * @param[out] o_chipId - value of Chip id for the target + * + * @return errlHndl_t Error log handle indicating the status of the operation + * @retval NULL for Success, non NULL for Failure + * + */ +errlHndl_t hdatGetIdEc(const TARGETING::Target *i_pTarget, uint32_t &o_ecLevel, + uint32_t &o_chipId); + +/** + * @brief Get the Hardware Card ID + * + * @param[in] i_pTarget + * Input target pointer. Must not be NULL (otherwise call will return an + * error log). Must be a valid target from the system blueprint. + * + * @param[out] o_cardId - Hardware Card ID + * + * @return errlHndl_t Error log handle indicating the status of the operation + * @retval NULL for Success, non NULL for Failure + * + */ +errlHndl_t hdatGetHwCardId(const TARGETING::Target *i_pTarget, + uint32_t &o_cardId); + +/** + * @brief This routine populates the MTM and Serial number attributes + of system Target + * + * @pre None + * + * @post None + * + * @param None + * + * @return None + */ +void hdatPopulateMTMAndSerialNumber(); + +/** + * @brief This routine gets suffix of location code + * + * @pre None + * + * @post None + * + * @param i_pFruTarget - input parameter - System target + * o_LocCodeSuffix - output parameter - Location Code suffix + * + * @return None + */ +void hdatGetLocationCode(TARGETING::Target *i_pFruTarget, + char *i_locCodePrefix, + char *o_locCode); + +/** + * @brief This routine gets prefix of location code + * + * @pre None + * + * @post None + * + * @param i_pnodeTarget - input parameter - Node target + * o_locCode - output parameter - Location Code Prefix + * + * @return None + */ +void hdatGetLocationCodePrefix(char *o_locCode); + +/** + * @brief Get the ascii keyword for a TARGET + * + * @param[in] i_Target input target pointer + * + * @param[out]o_kwdSize: keyword size + * @param[out]o_kwd: key word array + * + * @param[in] i_vpdtype: enum vpdType to select the appropriate device address + * @param[in] i_fetchVpd: relevant structure to be read to fetch the VPD + * @param[in] i_num: number of elements in the structure + * + * @return errlHndl_t NULL on success + */ +errlHndl_t hdatGetAsciiKwd( + TARGETING::Target * i_target, + uint32_t &o_kwdSize, + char* &o_kwd, + vpdType i_vpdtype, + struct vpdData i_fetchVpd[], + uint32_t i_num,size_t theSize[]); + +/** + * @brief Get the ascii keyword for proc + * + * @param[in] i_target input target pointer + * @param[out]o_kwdSize: keyword size + * @param[out]o_kwd: key word array + * @param[in] i_fetchVpd: relevant structure to be read to fetch the VPD + * @param[in] i_num: number of elements in the structure + * + * @return errlHndl_t NULL on success + * + */ +errlHndl_t hdatGetAsciiKwdForMvpd( + TARGETING::Target * i_target, + uint32_t &o_kwdSize, + char* &o_kwd, + struct vpdData i_fetchVpd[], + uint32_t i_num,size_t theSize[]); + +/** + * @brief Get the ascii keyword for backplane + * + * @param[out]o_kwdSize: keyword size + * @param[out]o_kwd: key word array + * @param[in] i_fetchVpd: relevant structure to be read to fetch the VPD + * @param[in] i_num: number of elements in the structure + * + * @return errlHndl_t NULL on success + * + */ +errlHndl_t hdatGetAsciiKwdForPvpd( + TARGETING::Target * i_target, + uint32_t &o_kwdSize, + char* &o_kwd, + struct vpdData i_fetchVpd[], + size_t i_num,size_t theSize[]); +/** + * @brief Get the ascii keyword for membuf + * + * @param[in] i_pTarget input target pointer + * + * @param[out]o_kwdSize: keyword size + * @param[out]o_kwd: key word array + * @param[in] i_fetchVpd: Vpd record-keyword table + * @return errlHndl_t NULL on success + * + */ +errlHndl_t hdatGetAsciiKwdForCvpd( + TARGETING::Target * i_target, + uint32_t &o_kwdSize, + char* &o_kwd, + struct vpdData i_fetchVpd[], + size_t i_num,size_t theSize[]); +/** + * @brief Get the ascii keyword for dimm + * + * @param[in] i_pTarget input target pointer + * + * @param[out]o_kwdSize: keyword size + * @param[out]o_kwd: key word array + * @return errlHndl_t NULL on success + * + */ +errlHndl_t hdatGetAsciiKwdForSpd( + TARGETING::Target * i_target, + size_t&o_kwdSize, + char* &o_kwd); +/** + * @brief Get the Max Cec nde count + * + * + * @return - Number of nodes present + * + */ +uint32_t hdatGetMaxCecNodes(); + + +/** + * @brief This routine is a debug routine that prints out the headers associated + * with an HDIF data structure. + * + * @pre None + * + * @post Output is directed to standard out + * + * @param[in] i_hdif - Pointer to data of type hdatHDIF_t + * @param[in] i_data - Pointer to data of type hdatHDIFDataHdr_t + * @param[in] i_dataArray - Pointer to data of type hdatHDIFDataArray_t + * @param[in] i_child - Pointer to data of type hdatHDIFChildHdr_t + * + */ + +void hdatPrintHdrs(const hdatHDIF_t *i_hdif, + const hdatHDIFDataHdr_t *i_data, + const hdatHDIFDataArray_t *i_dataArray, + const hdatHDIFChildHdr_t *i_child); + +/** + * @brief This routine is a debug routine that prints out the ASCII keyword VPD + * + * @pre None + * + * @post Output is directed to standard out + * + * @param[in] i_kwd - Pointer to the ASCII keyword VPD + * @param[in] i_kwdLen - Length of the ASCII keyword VPD + * + */ + +void hdatPrintKwd(const char *i_kwd, + int32_t i_kwdLen); + +/** + * @brief This routine return the target list for the given data area. + * + * @pre None + * + * @post Output is directed to standard out + * + * @param[in] i_dataArea - area that indicates different VPD type + * @param[out] o_targList - target list + * + */ +void hdatGetTarget (const hdatSpiraDataAreas i_dataArea, + TARGETING::TargetHandleList &o_targList); +/** + * @brief Format the ascii keyword based on the HDAT specifiction format + * + * @param[in] i_fetchVpd: relevant structure to be read to fetch the VPD + * @param[in] i_num: number of elements in the structure + * @param[in] theSize: Size of the each keyword data value + * @param[in] i_kwd: keyword data array + * @param[in] i_kwdSize: keyword data size + * @param[out] o_kwd: format keyword data array + * @param[out] o_kwdSize: format keyword data size + * @param[in] i_Keywords : keyword string array + * + * @return errlHndl_t NULL on success + * + */ + +errlHndl_t hdatformatAsciiKwd(const struct vpdData i_fetchVpd[], + const size_t &i_num, const size_t theSize[], char* &i_kwd, + const uint32_t &i_kwdSize, char* &o_fmtKwd, uint32_t &o_fmtkwdSize, + const HdatKeywordInfo i_Keywords[]) ; + + +/** + * @brief Get the Full vpd of the target from eeprom + * + * @param[in] i_pTarget input target pointer + * @param[in/out]io_dataSize: VPD data size + * @param[out] o_data: VPD data + * @return errlHndl_t NULL on success + * + */ +errlHndl_t hdatGetFullEepromVpd ( TARGETING::Target * i_target, + size_t &io_dataSize, + char* &o_data); + +};// end namespace + +#endif // HDATUTILITY_H diff --git a/src/usr/hdat/hdatvpd.C b/src/usr/hdat/hdatvpd.C new file mode 100755 index 000000000..cc453f111 --- /dev/null +++ b/src/usr/hdat/hdatvpd.C @@ -0,0 +1,239 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hdat/hdatvpd.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 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 hdatvpd.C + * + * @brief This file contains the implementation of the HdatVpd class. + * + */ + + +/*----------------------------------------------------------------------------*/ +/* Includes */ +/*----------------------------------------------------------------------------*/ +#include <stdlib.h> +#include "hdatvpd.H" +#include "hdatutil.H" +#include <hdat/hdat_reasoncodes.H> +#include <targeting/common/targetservice.H> +#include <targeting/common/utilFilter.H> +#include <targeting/common/predicates/predicatectm.H> +#include <targeting/common/util.H> + +using namespace TARGETING; + +namespace HDAT +{ + +/*----------------------------------------------------------------------------*/ +/* Global variables */ +/*----------------------------------------------------------------------------*/ +extern trace_desc_t * g_hdatTraceDesc; + + +/*----------------------------------------------------------------------------*/ +/* Constants */ +/*----------------------------------------------------------------------------*/ +const uint16_t HDAT_VPD_VERSION = 0x0020; + + +/** @brief See the prologue in hdatvpd.H + */ +HdatVpd::HdatVpd(errlHndl_t &o_errlHndl, + uint32_t i_resourceId, + TARGETING::Target * i_target, + const char *i_eyeCatcher, + uint32_t i_index, + vpdType i_vpdType, + struct vpdData i_fetchVpd[], + uint32_t i_num, + const HdatKeywordInfo i_pvpdKeywords[]) +: HdatHdif(o_errlHndl, i_eyeCatcher, HDAT_VPD_LAST,i_index,HDAT_NO_CHILD, + HDAT_VPD_VERSION), +iv_kwdSize(0), iv_kwd(NULL) +{ + HDAT_ENTER(); + o_errlHndl = NULL; + uint32_t l_slcaIdx = 0; + TARGETING::Target * l_target=i_target; + i_target->tryGetAttr<TARGETING::ATTR_SLCA_INDEX>(l_slcaIdx); + + //overriding target for BP vpd + if ( FRU_SV == (i_resourceId >> 8 ) ) + { + TARGETING::TargetHandleList l_targList; + PredicateCTM predNode(TARGETING::CLASS_ENC, TARGETING::TYPE_NODE); + PredicateHwas predFunctional; + predFunctional.functional(true); + PredicatePostfixExpr nodeCheckExpr; + nodeCheckExpr.push(&predNode).push(&predFunctional).And(); + + targetService().getAssociated(l_targList, i_target, + TargetService::CHILD, TargetService::IMMEDIATE, + &nodeCheckExpr); + l_target = l_targList[0]; + } + + //@TODO:RTC 149382(Method to get VPD collected status for Targets) + GARD_FunctionalState l_functional = GARD_Functional; + GARD_UsedState l_used = GARD_Used; + + if (GARD_Functional == l_functional || + GARD_PartialFunctional == l_functional) + { + iv_status.hdatFlags = HDAT_VPD_FRU_FUNCTIONAL; + } + if (GARD_Used == l_used) + { + iv_status.hdatFlags |= HDAT_VPD_REDUNDANT_FRU_USED; + } + + iv_fru.hdatResourceId = i_resourceId; + size_t theSize[i_num]; + //get the SLCA index and the keyword for the RID + o_errlHndl = hdatGetAsciiKwd(l_target,iv_kwdSize,iv_kwd,i_vpdType, + i_fetchVpd,i_num,theSize); + + HDAT_DBG("hdatGetAsciiKwd returned kwd size =%d",iv_kwdSize); + + if(strcmp(i_eyeCatcher,"IO KID")==0) + { + using namespace TARGETING; + // Get Target Service, and the system target. + TARGETING::TargetService& l_targetService = targetService(); + TARGETING::Target* l_sysTarget = NULL; + (void) l_targetService.getTopLevelTarget(l_sysTarget); + + assert(l_sysTarget != NULL); + + //fetching lx data + uint64_t l_LXvalue = l_sysTarget->getAttr<ATTR_ASCII_VPD_LX_KEYWORD>(); + char *temp_kwd = new char [iv_kwdSize]; + uint32_t temp_kwdSize = iv_kwdSize; + memcpy(temp_kwd, iv_kwd,iv_kwdSize); + delete[] iv_kwd; + iv_kwdSize +=sizeof(uint64_t); + iv_kwd = new char [iv_kwdSize]; + memcpy(iv_kwd,temp_kwd,temp_kwdSize); + memcpy((void *)(iv_kwd+temp_kwdSize),&l_LXvalue,sizeof(uint64_t)); + theSize[i_num-1] = sizeof(uint64_t); + delete[] temp_kwd; + } + char *o_fmtKwd; + uint32_t o_fmtkwdSize; + o_errlHndl = hdatformatAsciiKwd(i_fetchVpd, i_num, theSize, iv_kwd, + iv_kwdSize, o_fmtKwd, o_fmtkwdSize, i_pvpdKeywords); + if( o_fmtKwd != NULL ) + { + delete[] iv_kwd; + iv_kwd = new char [o_fmtkwdSize]; + memcpy(iv_kwd,o_fmtKwd,o_fmtkwdSize); + iv_kwdSize = o_fmtkwdSize; + delete[] o_fmtKwd; + } + + if (NULL == o_errlHndl) + { + iv_fru.hdatSlcaIdx = l_slcaIdx; + this->addData(HDAT_VPD_FRU_ID, sizeof(hdatFruId_t)); + this->addData(HDAT_VPD_OP_STATUS, sizeof(hdatFruOpStatus_t)); + //Padding the size + this->addData(HDAT_VPD_KWD, iv_kwdSize+1); + this->align(); + } + HDAT_EXIT(); +} + + +/** @brief See the prologue in hdatvpd.H + */ +HdatVpd::~HdatVpd() +{ + HDAT_ENTER(); + if(iv_kwd!= NULL ) + { + delete[] iv_kwd; + } + HDAT_EXIT(); +} + + +uint8_t * HdatVpd::setVpd(uint8_t * io_virt_addr) +{ + uint32_t l_size = 0; + HDAT_DBG("virtual address=0x%016llX", + (uint64_t)io_virt_addr); + + + io_virt_addr = this->setHdif(io_virt_addr); + + + //write hdatFruId_t iv_fru + hdatFruId_t *l_hdatFruId = reinterpret_cast<hdatFruId_t *>(io_virt_addr); + + HDAT_DBG("writing FRU ID from address=0x%016llX", + (uint64_t)l_hdatFruId); + + l_hdatFruId->hdatSlcaIdx = this->iv_fru.hdatSlcaIdx; + l_hdatFruId->hdatResourceId = this->iv_fru.hdatResourceId; + + l_hdatFruId++; + + + //write hdatFruOpStatus_t iv_status + hdatFruOpStatus_t *l_hdatFruOpStatus = + reinterpret_cast<hdatFruOpStatus_t *>(l_hdatFruId); + + l_hdatFruOpStatus->hdatFlags = this->iv_status.hdatFlags; + + l_hdatFruOpStatus++; + + //write kwd + io_virt_addr = reinterpret_cast<uint8_t *>(l_hdatFruOpStatus); + + if ( (NULL != this->iv_kwd) && (this->iv_kwdSize > 0)) + { + HDAT_DBG("writing kwd from address 0x%016llX", + (uint64_t)io_virt_addr); + HDAT_DBG("kwd to be added %s," + "size=0x%x sizeof(this->iv_kwd)=0x%x", + this->iv_kwd,this->iv_kwdSize,sizeof(this->iv_kwd)); + + memcpy(io_virt_addr,(this->iv_kwd),this->iv_kwdSize); + + io_virt_addr += this->iv_kwdSize; + + } + + //write pad + + io_virt_addr = this->setpadding( io_virt_addr,l_size ); + + HDAT_EXIT(); + return io_virt_addr; + +}//end setVpd + +} //namespace HDAT diff --git a/src/usr/hdat/hdatvpd.H b/src/usr/hdat/hdatvpd.H new file mode 100755 index 000000000..5c12dda13 --- /dev/null +++ b/src/usr/hdat/hdatvpd.H @@ -0,0 +1,248 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hdat/hdatvpd.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 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 HDATVPD_H +#define HDATVPD_H + +/** + * @file hdatvpd.H + * + * @brief This file contains the class definition for the VPD object + * with data obtained from the SVPD component. Besides typical VPD objects + * such as the Clock Card VPD object, this alos supports VPD objects which + * are part of a bigger object (such as the daughter card VPD object which + * is part of the HdatIoHubFru object). + * + */ + + +/*----------------------------------------------------------------------------*/ +/* Includes */ +/*----------------------------------------------------------------------------*/ +#include <stdint.h> +#include <hdat/hdat.H> +#include "hdathdif.H" +#include <errl/errlentry.H> +#include <vpd/vpd_if.H> +//#include "hdatutil.H" + +namespace HDAT +{ + +typedef struct +{ + VPD::vpdKeyword keyword; + char keywordName[2+1]; +} HdatKeywordInfo; + + + +struct vpdData +{ + VPD::vpdRecord record; + VPD::vpdKeyword keyword; +}; + +enum vpdType +{ + PROC = 0x0, + DIMM, + BP, + CLOCK, + ENCLOSURE, + ANCHOR, + BP_EXT, +};//add as required. this needs to be passed to hdatGetAsciiKwd +//to choose the appropriate device address + + +/*----------------------------------------------------------------------------*/ +/* Type definitions */ +/*----------------------------------------------------------------------------*/ + +enum hdatVpdFruStatus +{ + HDAT_VPD_FRU_FUNCTIONAL = 0x01, + HDAT_VPD_REDUNDANT_FRU_USED = 0x02 +}; + +/** @enum hdatDataPtrs + * Constants for the internal data pointers that are added to the base + * class + */ +enum hdatVpdDataPtrs +{ + HDAT_VPD_FRU_ID = 0, + HDAT_VPD_KWD = 1, + HDAT_VPD_OP_STATUS = 2, + HDAT_VPD_RESERVED2 = 3, + HDAT_VPD_LAST = 4 +}; + +typedef enum { + GARD_Functional, + GARD_PartialFunctional, + GARD_NotFunctional +}GARD_FunctionalState; + +typedef enum { + GARD_Used, + GARD_NotUsed +}GARD_UsedState; + +struct hdatFruOpStatus_t +{ + uint8_t hdatFlags; + uint8_t hdatReserved1[3]; +} __attribute__ ((packed)); + + +/*----------------------------------------------------------------------------*/ +/* C++ class definition */ +/*----------------------------------------------------------------------------*/ + +/** Begin Class Description + * + * @brief The HdatVpd class is used to construct objects that have the general + * format of VPD keyword data such as the CEC backplane VPD or L3 VPD, + * etc + * + * Description: This class defines a specialized object. It is not intended + * that anyone can create an object of this type. In particular, + * the object is built only in the hdatstep process when the step + * that builds hypervisor data structures is run. + * + * The real purpose of the object is to create the various VPD + * structures as defined by the PHYP Initialization architecture + * This data structure is eventually DMA'd to main memory. The + * class is not defined to be a general purpose interface for + * building this object by anyone other than the hdatstep process. + * + * Thread safety: An HdatVpd object is not thread safe. That is, a single + * object cannot be shared and used concurrently by + * multiple threads at the same time. An object can be used by + * multiple threads if the threads serialize access. And of + * course, each thread can use its own object with no concerns + * about what other threads are doing. + * + * Signal handler usage: + * This class is not intended to be used in a signal handler + * and nothing has been done to try and make it safe to use + * in a signal handler. + * + * End Class Description + */ +class HdatVpd : public HdatHdif +{ +public: + + /** + * @brief Construct an HdatVpd object. + * + * This is the constructor for the HdatVpd object + * + * If you are constructing this object on the heap by using new, then + * you must check the pointer returned from new to see if it is null. + * If it is null, new failed to allocate storage and the constructor + * was not called. If it is not null, then you must check o_errlHndl + * to see if the constructor ran successfully. If o_errlHndl indicates + * an error was reported by the constructor, new has already allocated + * heap storage and the object must be deleted in order to free the + * heap storage. + * + * @pre None + * @param o_errlHndl output error handle + * @param i_resourceId input resource id + * @param i_target input Target + * @param i_eyeCatcher input the eyecatcher string + * @param i_index input object instance + * @param i_vpdType input the vpd type to be added + * @param i_fetchVpd input the record-kwd structure like mVpd or pVpd etc + * @param i_num input the number of elements in the i_fetchVpd structure + * @param i_Keywords string array + * + * @post An HdatVpd object has been constructed. Heap storage has been + * allocated. + * + */ + HdatVpd(errlHndl_t &o_errlHndl, + uint32_t i_resourceId, + TARGETING::Target * i_target, + const char *i_eyeCatcher, + uint32_t i_index, + vpdType i_vpdType, + struct vpdData i_fetchVpd[], + uint32_t i_num, const HdatKeywordInfo i_pvpdKeywords[]); + + + + /** + * @brief HdatVpd object destructor + * + * This is the destructor for an HdatVpd object. Any heap storage + * allocated for the object is dallocated. + * + * @pre No preconditions exist + * + * @post The HdatVpd object has been destroyed and can no longer be used. + * + */ + ~HdatVpd(); + + /* + * @brief write the vpd object to memory + * + * @pre the object must be constructed and the address to write at must + * be provided + * + * @param io_virt_addr - input parameter - inputs the address + * to start to write to mainstore + * @returns outputs thenext address + + * @post data is written to memory and the next address is returned + * + */ + uint8_t * setVpd(uint8_t * io_virt_addr); + + +private: + + /** Object Instance Data + * + * @li iv_kwdSize - size of the ASCII keyword + * @li iv_kwd - ptr to storage which holds the ASCII keyword + * @li iv_fru - FRU Id information + * @li iv_status - FRU operational status + */ + uint32_t iv_kwdSize; + char *iv_kwd; + hdatFruId_t iv_fru; + hdatFruOpStatus_t iv_status; + + + +}; // end of HdatVpd class + +} //namespace HDAT +#endif // HDATVPD_H diff --git a/src/usr/hdat/makefile b/src/usr/hdat/makefile new file mode 100644 index 000000000..456664f49 --- /dev/null +++ b/src/usr/hdat/makefile @@ -0,0 +1,51 @@ +# IBM_PROLOG_BEGIN_TAG +# This is an automatically generated prolog. +# +# $Source: src/usr/hdat/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 = hdat + +EXTRAINCDIR += + +OBJS += hdatutil.o +OBJS += hdatpcia.o +OBJS += hdatiplparms.o +OBJS += hdathostslcadata.o +OBJS += hdathdif.o +OBJS += hdatvpd.o +OBJS += hdatnaca.o +OBJS += hdatiohub.o +OBJS += hdatmsvpd.o +OBJS += hdatmsarea.o +OBJS += hdatram.o +OBJS += hdatspsubsys.o +OBJS += hdatpcrd.o +OBJS += hdatbldda.o +OBJS += hdatnodedata.o +OBJS += hdathostservices.o +OBJS += hdathbrt.o +OBJS += hdatspiraS.o +OBJS += hdatspiraH.o + +include ${ROOTPATH}/config.mk |