diff options
author | Roland Veloz <rveloz@us.ibm.com> | 2019-03-06 13:44:46 -0600 |
---|---|---|
committer | Daniel M. Crowell <dcrowell@us.ibm.com> | 2019-04-10 13:48:37 -0500 |
commit | 8d531bced31e0dd68706db205b586c1e9e34b336 (patch) | |
tree | 82940514b94b13af46ce77b96e711ee0cf87fdea /src/usr/fapi2/test | |
parent | f79af6ea7e3817c443fee39525973c7a67e55aa7 (diff) | |
download | blackbird-hostboot-8d531bced31e0dd68706db205b586c1e9e34b336.tar.gz blackbird-hostboot-8d531bced31e0dd68706db205b586c1e9e34b336.zip |
Added unit test for HWP call ddimm_get_efd
- Wrote a unit test for the HWP call ddimm_get_efd
- Does negative and positive testing of the HWP call
Change-Id: I9bbcbc2620a5fd5498244674d8e13ca3628fb371
RTC: 205964
Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/72940
Reviewed-by: Matt Derksen <mderkse1@us.ibm.com>
Reviewed-by: Christian R. Geddes <crgeddes@us.ibm.com>
Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com>
Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Diffstat (limited to 'src/usr/fapi2/test')
-rw-r--r-- | src/usr/fapi2/test/fapi2DdimmGetEfdTest.C | 1272 | ||||
-rw-r--r-- | src/usr/fapi2/test/fapi2DdimmGetEfdTest.H | 401 | ||||
-rw-r--r-- | src/usr/fapi2/test/fapi2Test.mk | 1 |
3 files changed, 1674 insertions, 0 deletions
diff --git a/src/usr/fapi2/test/fapi2DdimmGetEfdTest.C b/src/usr/fapi2/test/fapi2DdimmGetEfdTest.C new file mode 100644 index 000000000..13f0ed87b --- /dev/null +++ b/src/usr/fapi2/test/fapi2DdimmGetEfdTest.C @@ -0,0 +1,1272 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/fapi2/test/fapi2DdimmGetEfdTest.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2019 */ +/* [+] 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 <cxxtest/TestSuite.H> +#include <fapi2DdimmGetEfdTest.H> + +//****************************************************************************** +// Useful Constants +// +// Set up some constants to facilitate the testing +// +//****************************************************************************** + +// Set a default size for the SPD buffer +const size_t DEFAULT_SPD_BUFFER_SIZE_DEFAULT = (5 * KILOBYTE); + +// SPD DDIMM consts +const size_t SPD_DDIMM_TYPE_OFFSET = 2; +const uint8_t DEFAULT_SPD_DDIMM_TYPE = 0x0C; +const size_t DEFAULT_SPD_DDIMM_SIZE = 512; + +// EFD data block consts +const size_t DEFAULT_EFD_BLOCK_SIZE_MULTIPLIER = 4; // 4 thirty two bytes +const size_t DEFAULT_EFD_BLOCK_SIZE = + (DEFAULT_EFD_BLOCK_SIZE_MULTIPLIER * 32);// 4 * 32 bytes = 128 +const size_t EFD_MEMORY_SPACE_OFFSET = 277; +const size_t DEFAULT_EFD_MEMORY_SPACE_LOCATION = 1024; +const size_t EFD_MEMORY_SPACE_SIZE_OFFSET = 285; +const size_t DEFAULT_EFD_MEMORY_SPACE_SIZE = 0x02; +const size_t EFD_COUNT_OFFSET = 286; +const uint16_t DEFAULT_EFD_COUNT = 32; + +// DMB consts +const size_t SPD_DMB_MFG_ID_OFFSET = 198; +const uint16_t DEFAULT_SPD_DMB_MFG_ID = 0x2980; +const size_t SPD_DMB_REVISION_OFFSET = 200; +const uint8_t DEFAULT_SPD_DMB_REVISION = 0x00; + +/// EFD consts +const size_t EFD_META_DATA_OFFSET = 288; +// EFD's extended function type consts +const size_t EXTENDED_FUNCTION_TYPE_MASK = 0x0F; +const size_t EXTENDED_FUNCTION_TYPE_INVERSE_MASK = 0xF0; +const uint8_t DEFAULT_EXTENDED_FUNCTION_TYPE = 0x03; +// EFD's is implemented consts +const size_t IS_IMPLEMENTED_MASK = 0x80; +const size_t IS_IMPLEMENTED_INVERSE_MASK = 0x7F; + +// Frequency valid values and what they map to in the code +// 12800(0x0001), 14930(0x0002), 17060(0x0004), 19200(0x0008), +// 21330(0x0010), 23460(0x0020), 25600(0x0040) +const uint16_t DEFAULT_FREQUENCY = 25600; + +// Master Rank valid values and what they map to in the code +// MR0(0x01), MR1(0x02), MR3(0x04), MR4(0x08), +const uint8_t DEFAULT_MASTER_RANK = 0; // MR0 + + +//****************************************************************************** +// Public API +//****************************************************************************** + +//****************************************************************************** +// fapi2DdimmGetEfdTest ctor +//****************************************************************************** +fapi2DdimmGetEfdTest::fapi2DdimmGetEfdTest() + : iv_efdBufferPtr(nullptr), + iv_spdBufferPtr(nullptr), + iv_spdBufferSize(DEFAULT_SPD_BUFFER_SIZE_DEFAULT), + iv_efdMetaDataPtr(nullptr), + iv_efdBlockDataPtr(nullptr), + iv_efdBlockSizeMultiplier(DEFAULT_EFD_BLOCK_SIZE_MULTIPLIER), + iv_efdBlockSize(DEFAULT_EFD_BLOCK_SIZE), + iv_efdMemorySpaceLocation(DEFAULT_EFD_MEMORY_SPACE_LOCATION), + iv_efdMemorySpaceSize(DEFAULT_EFD_MEMORY_SPACE_SIZE), + iv_efdCount(DEFAULT_EFD_COUNT), + iv_spdDmbMfgId(DEFAULT_SPD_DMB_MFG_ID), + iv_spdDmbRevision(DEFAULT_SPD_DMB_REVISION), + iv_extendedFunctionType(DEFAULT_EXTENDED_FUNCTION_TYPE), + iv_frequency(DEFAULT_FREQUENCY), + iv_rank(DEFAULT_MASTER_RANK), + iv_ocmbChipTarget(nullptr), + iv_rc(fapi2::FAPI2_RC_SUCCESS), + iv_vpdInfo(fapi2::EFD), + iv_numTests(0), + iv_numFails(0), + iv_attrModel(TARGETING::MODEL_NA) +{ + FAPI_INF(">> fapi2DdimmGetEfdTest"); + + if(TARGETING::MODEL_AXONE != TARGETING::targetService().getProcessorModel()) + { + FAPI_INF("<< fapi2DdimmGetEfdTest: This is not AXONE. " + "Skipping AXONE tests."); + return; + } + + // Find a valid target of type OCMB_CHIP + TARGETING::TargetHandleList l_ocmbTargetList; + TARGETING::getAllChips(l_ocmbTargetList, TARGETING::TYPE_OCMB_CHIP, true); + if (!l_ocmbTargetList.size()) + { + TS_FAIL("<< fapi2DdimmGetEfdTest: No valid TYPE_OCMB_CHIP target found. " + "Can not execute tests."); + return; + } + else + { + iv_ocmbChipTarget = l_ocmbTargetList[0]; + } + + // Initialize the SPD buffer to a known good state + initializeSpdBuffer(); + // Initialize the VPDInfo to a known good state and match SPD buffer + initializeVpdInfo(iv_vpdInfo); + // Create EFD buffer to match VPDInfo iv_size + createEfdBuffer(iv_efdBufferPtr, iv_vpdInfo.iv_size); +}; + +//****************************************************************************** +// testDdimmGetEfdHwpCall +//****************************************************************************** +void fapi2DdimmGetEfdTest::testDdimmGetEfdHwpCall() +{ + // If initialization process was unable to find an OCMB chip target, then + // exit without running any tests. + if (TARGETING::MODEL_AXONE != iv_attrModel || !iv_ocmbChipTarget) + { + return; + } + + if (!sanityCheckTest()) + { + TS_FAIL("<< fapi2DdimmGetEfdTest: Test configuration failed. " + "Test is broken - needs fixing/updating."); + } + else + { + // Call the actual tests + sizeMisMatchTest(); + dmbDataTest(); + vpdInfoInputTest(); + findMatchTest(); + } + + FAPI_INF("<< fapi2DdimmGetEfdTest: Test Complete. %d/%d fails.", + iv_numFails, iv_numTests); +} + +//****************************************************************************** +// Private Test Cases +//****************************************************************************** + +//****************************************************************************** +// sanityCheckTest +//****************************************************************************** +bool fapi2DdimmGetEfdTest::sanityCheckTest() +{ + FAPI_INF(">> sanityCheckTest"); + + bool l_sanityCheckTestPassed(true); + + // Create a TARGET_TYPE_OCMB_CHIP FAPI2 target + const fapi2::Target<fapi2::TARGET_TYPE_OCMB_CHIP> + l_fapi2Target(iv_ocmbChipTarget); + + + ++iv_numTests; + // Should get a match immediately, if not, test setup is broken + iv_rc = ddimm_get_efd(l_fapi2Target, iv_vpdInfo, iv_efdBufferPtr, + iv_spdBufferPtr, iv_spdBufferSize); + if (iv_rc != fapi2::FAPI2_RC_SUCCESS) + { + l_sanityCheckTestPassed = false; + ++iv_numFails; + TS_FAIL("sanityCheckTest: Test configuration failed: " + "Should have found a match for frequency(%d) and master " + "rank(%d). Test is broken, please fix.", + iv_vpdInfo.iv_omi_freq_mhz, iv_vpdInfo.iv_rank); + } + + FAPI_INF("<< sanityCheckTest"); + + return l_sanityCheckTestPassed; +} + +//****************************************************************************** +// sizeMisMatchTest +//****************************************************************************** +void fapi2DdimmGetEfdTest::sizeMisMatchTest() +{ + FAPI_INF(">> sizeMisMatchTest"); + + // Create a TARGET_TYPE_OCMB_CHIP FAPI2 target + const fapi2::Target<fapi2::TARGET_TYPE_OCMB_CHIP> + l_fapi2Target(iv_ocmbChipTarget); + + // Some handy variables + size_t l_bufferSize(0); + // This type is an invalid type, it is used for negative tetsting + uint8_t l_ddrType(0xAA); + + + ++iv_numTests; + /// Test when buffer size is 0 + // Set the buffer size to 0 + l_bufferSize = 0; + iv_rc = ddimm_get_efd(l_fapi2Target, iv_vpdInfo, iv_efdBufferPtr, + iv_spdBufferPtr, l_bufferSize); + if (iv_rc == fapi2::FAPI2_RC_SUCCESS) + { + ++iv_numFails; + TS_FAIL("sizeMisMatchTest: test failed. Buffer size is %d", + l_bufferSize); + } + + + ++iv_numTests; + /// Test when buffer size is < the needed DDR size, + /// but DDR type is the correct type + // Set the buffer size to 1 less than size of the DDR type's size + l_bufferSize = DEFAULT_SPD_DDIMM_SIZE - 1; + iv_rc = ddimm_get_efd(l_fapi2Target, iv_vpdInfo, iv_efdBufferPtr, + iv_spdBufferPtr, l_bufferSize); + if (iv_rc == fapi2::FAPI2_RC_SUCCESS) + { + ++iv_numFails; + TS_FAIL("sizeMisMatchTest: test failed. Buffer (%d) size is " + "less than the DDR size (%d)", + l_bufferSize, DEFAULT_SPD_DDIMM_SIZE); + } + + + ++iv_numTests; + /// Test when buffer size is large enough, but DDR type is incorrect + // Set the DDR type to an incorrect type + l_ddrType = 0xAA; + setSpdDdimmType(l_ddrType); + iv_rc = ddimm_get_efd(l_fapi2Target, iv_vpdInfo, iv_efdBufferPtr, + iv_spdBufferPtr, iv_spdBufferSize); + if (iv_rc == fapi2::FAPI2_RC_SUCCESS) + { + ++iv_numFails; + TS_FAIL("sizeMisMatchTest: test failed. " + "Should have failed with DDR type set at 0xAA"); + } + // Restore the DDR type + setSpdDdimmType(DEFAULT_SPD_DDIMM_TYPE); + + + ++iv_numTests; + /// Test when buffer is a nullptr + iv_rc = ddimm_get_efd(l_fapi2Target, iv_vpdInfo, nullptr, + iv_spdBufferPtr, iv_spdBufferSize); + if (iv_rc != fapi2::FAPI2_RC_SUCCESS) + { + ++iv_numFails; + TS_FAIL("sizeMisMatchTest: test failed: " + "Passing a nullptr EFD buffer is a valid value."); + } + else if (iv_vpdInfo.iv_size != DEFAULT_EFD_BLOCK_SIZE) + { + ++iv_numFails; + TS_FAIL("sizeMisMatchTest: test failed: " + "Returned EFD buffer size is not what is expected. " + "May just need to update test to reflect code."); + } + + + ++iv_numTests; + /// Test when EFD memory space location resides within the DDR4 memory space + // Set the memory space location to reside within the DDR4 memory space + setEfdMemorySpaceLocation(DEFAULT_SPD_DDIMM_SIZE - 1); + iv_rc = ddimm_get_efd(l_fapi2Target, iv_vpdInfo, iv_efdBufferPtr, + iv_spdBufferPtr, iv_spdBufferSize); + if (iv_rc == fapi2::FAPI2_RC_SUCCESS) + { + ++iv_numFails; + TS_FAIL("sizeMisMatchTest: test failed: " + "EFD memory space cannot reside in the DDR4 memory space."); + } + // Restore the memory space location + setEfdMemorySpaceLocation(iv_efdMemorySpaceLocation); + + + ++iv_numTests; + /// Test when mapping for EFD memory size is incorrect + // Set the memory space size mapping value to an incorrect value + setEfdMemorySpaceSize(0x07); + iv_rc = ddimm_get_efd(l_fapi2Target, iv_vpdInfo, iv_efdBufferPtr, + iv_spdBufferPtr, iv_spdBufferSize); + if (iv_rc == fapi2::FAPI2_RC_SUCCESS) + { + ++iv_numFails; + TS_FAIL("sizeMisMatchTest: test failed: " + "There is no EFD memory space maping for 0x07."); + } + // Restore the memory space size mapping value + setEfdMemorySpaceSize(iv_efdMemorySpaceSize); + + + ++iv_numTests; + /// Test when mapping for EFD memory size + EFD memory space offset + /// is out of bounds. + // In this scenario, increase the EFD memory space size beyond + // the VPD memory bounds. + setEfdMemorySpaceSize(iv_efdMemorySpaceSize + 1); + iv_rc = ddimm_get_efd(l_fapi2Target, iv_vpdInfo, iv_efdBufferPtr, + iv_spdBufferPtr, iv_spdBufferSize); + if (iv_rc == fapi2::FAPI2_RC_SUCCESS) + { + ++iv_numFails; + TS_FAIL("sizeMisMatchTest: test failed: " + "EFD memory size + EFD memory space offset is out of bounds."); + } + // Restore the EFD memory space size + setEfdMemorySpaceSize(iv_efdMemorySpaceSize); + + + ++iv_numTests; + /// Test when mapping for EFD memory size + EFD memory space location + /// is out of bounds + // In this scenario, increase the EFD memory space location such that the + // EFD memory size +EFD memory space offset is beyond the VPD memory bounds. + setEfdMemorySpaceLocation(iv_efdMemorySpaceLocation + 1); + iv_rc = ddimm_get_efd(l_fapi2Target, iv_vpdInfo, iv_efdBufferPtr, + iv_spdBufferPtr, iv_spdBufferSize); + if (iv_rc == fapi2::FAPI2_RC_SUCCESS) + { + ++iv_numFails; + TS_FAIL("sizeMisMatchTest: test failed: " + "EFD memory size + EFD memory space offset is out of bounds."); + } + // Restore the memory space location + setEfdMemorySpaceLocation(iv_efdMemorySpaceLocation); + + + ++iv_numTests; + /// Test when the number of EFDs is 0. + // Set EFD count to 0 + setEfdCount(0); + iv_rc = ddimm_get_efd(l_fapi2Target, iv_vpdInfo, iv_efdBufferPtr, + iv_spdBufferPtr, iv_spdBufferSize); + if (iv_rc == fapi2::FAPI2_RC_SUCCESS) + { + ++iv_numFails; + TS_FAIL("sizeMisMatchTest: test failed: " + "Number of EFDs is 0, need at least one."); + } + // Restore the EFD count + setEfdCount(iv_efdCount); + + + ++iv_numTests; + /// Test when the size of the EFD data block size is greater than the + /// EFD buffer size + // Increase the EFD data block size + setAllEfdMetaDatasEfdDataBlockSize(5); + iv_rc = ddimm_get_efd(l_fapi2Target, iv_vpdInfo, iv_efdBufferPtr, + iv_spdBufferPtr, iv_spdBufferSize); + if (iv_rc == fapi2::FAPI2_RC_SUCCESS) + { + ++iv_numFails; + TS_FAIL("sizeMisMatchTest: test failed: " + "EFD data block size is greater than EFD buffer size."); + } + // Restore the EFD data block size + setAllEfdMetaDatasEfdDataBlockSize(iv_efdBlockSizeMultiplier); + + + ++iv_numTests; + // Test when the size of the EFD buffer size is less than the + // EFD data block size + // Shrink EFD buffer size + iv_vpdInfo.iv_size = DEFAULT_EFD_BLOCK_SIZE - 1; + iv_rc = ddimm_get_efd(l_fapi2Target, iv_vpdInfo, iv_efdBufferPtr, + iv_spdBufferPtr, iv_spdBufferSize); + if (iv_rc == fapi2::FAPI2_RC_SUCCESS) + { + ++iv_numFails; + TS_FAIL("sizeMisMatchTest: test failed: " + "EFD buffer size is greater than EFD data block size."); + } + // Restore the EFD buffer size + iv_vpdInfo.iv_size = DEFAULT_EFD_BLOCK_SIZE; + + FAPI_INF("<< sizeMisMatchTest"); +} + +//****************************************************************************** +// dmbDataTest +//****************************************************************************** +void fapi2DdimmGetEfdTest::dmbDataTest() +{ + FAPI_INF(">> dmbDataTest"); + + // Create a TARGET_TYPE_OCMB_CHIP FAPI2 target + const fapi2::Target<fapi2::TARGET_TYPE_OCMB_CHIP> + l_fapi2Target(iv_ocmbChipTarget); + + + ++iv_numTests; + /// Test when DMB manufacturer ID is incorrect + // Set the DMB manufacturer ID to an incorrect value + // and FFDC enabled is false + setSpdDmbMfgId(0x5540); + iv_vpdInfo.iv_is_config_ffdc_enabled = false; + iv_rc = ddimm_get_efd(l_fapi2Target, iv_vpdInfo, iv_efdBufferPtr, + iv_spdBufferPtr, iv_spdBufferSize); + if (iv_rc == fapi2::FAPI2_RC_SUCCESS) + { + ++iv_numFails; + TS_FAIL("dmbDataTest: test failed: " + "EFD memory size + EFD memory space offset is out of bounds."); + } + // Restore the DMB manufacturer ID + setSpdDmbMfgId(iv_spdDmbMfgId); + + + ++iv_numTests; + /// Test when DMB revision is incorrect + // Set the DMB revision to an incorrect value + // and FFDC enabled is false + setSpdDmbRevision(0x20); + iv_vpdInfo.iv_is_config_ffdc_enabled = false; + iv_rc = ddimm_get_efd(l_fapi2Target, iv_vpdInfo, iv_efdBufferPtr, + iv_spdBufferPtr, iv_spdBufferSize); + if (iv_rc == fapi2::FAPI2_RC_SUCCESS) + { + ++iv_numFails; + TS_FAIL("dmbDataTest: test failed: " + "EFD memory size + EFD memory space offset is out of bounds."); + } + // Restore DMB manufacturer ID + setSpdDmbRevision(iv_spdDmbRevision); + + /// Test when DMB manufacturer ID is incorrect + // Set the DMB manufacturer ID to an incorrect value + // and FFDC enabled is true + setSpdDmbMfgId(0x5540); + iv_vpdInfo.iv_is_config_ffdc_enabled = true; + iv_rc = ddimm_get_efd(l_fapi2Target, iv_vpdInfo, iv_efdBufferPtr, + iv_spdBufferPtr, iv_spdBufferSize); + if (iv_rc == fapi2::FAPI2_RC_SUCCESS) + { + ++iv_numFails; + TS_FAIL("dmbDataTest: test failed: " + "EFD memory size + EFD memory space offset is out of bounds."); + } + // Restore the DMB manufacturer ID + setSpdDmbMfgId(iv_spdDmbMfgId); + + + ++iv_numTests; + /// Test when DMB revision is incorrect + // Set the DMB revision to an incorrect value + // and FFDC enabled is true + setSpdDmbRevision(0x20); + iv_vpdInfo.iv_is_config_ffdc_enabled = true; + iv_rc = ddimm_get_efd(l_fapi2Target, iv_vpdInfo, iv_efdBufferPtr, + iv_spdBufferPtr, iv_spdBufferSize); + if (iv_rc == fapi2::FAPI2_RC_SUCCESS) + { + ++iv_numFails; + TS_FAIL("dmbDataTest: test failed: " + "EFD memory size + EFD memory space offset is out of bounds."); + } + // Restore DMB manufacturer ID + setSpdDmbRevision(iv_spdDmbRevision); + + + FAPI_INF("<< dmbDataTest"); +} + +//****************************************************************************** +// vpdInfoInputTest +//****************************************************************************** +void fapi2DdimmGetEfdTest::vpdInfoInputTest() +{ + FAPI_INF(">> vpdInfoInputTest"); + + // Create a TARGET_TYPE_OCMB_CHIP FAPI2 target + const fapi2::Target<fapi2::TARGET_TYPE_OCMB_CHIP> + l_fapi2Target(iv_ocmbChipTarget); + + + ++iv_numTests; + /// Test when caller passes in an incorrect frequency value and + /// set FFDC enabled flag to true + // Set the frequency to an incorrect value and enable FFDC flag + iv_vpdInfo.iv_omi_freq_mhz = iv_frequency - 1; + iv_vpdInfo.iv_is_config_ffdc_enabled = true; + iv_rc = ddimm_get_efd(l_fapi2Target, iv_vpdInfo, iv_efdBufferPtr, + iv_spdBufferPtr, iv_spdBufferSize); + if (iv_rc == fapi2::FAPI2_RC_SUCCESS) + { + ++iv_numFails; + TS_FAIL("vpdInfoInputTest: test failed: " + "VPD info frequency value (%d) is not valid.", + iv_vpdInfo.iv_omi_freq_mhz); + } + // Restore frequency + iv_vpdInfo.iv_omi_freq_mhz = iv_frequency; + + + ++iv_numTests; + /// Test when caller passes in an incorrect master rank and + /// set FFDC enabled flag to true + // Set the master rank to an incorrect value and enable FFDC flag + iv_vpdInfo.iv_rank = 4; + iv_vpdInfo.iv_is_config_ffdc_enabled = true; + iv_rc = ddimm_get_efd(l_fapi2Target, iv_vpdInfo, iv_efdBufferPtr, + iv_spdBufferPtr, iv_spdBufferSize); + if (iv_rc == fapi2::FAPI2_RC_SUCCESS) + { + ++iv_numFails; + TS_FAIL("vpdInfoInputTest: test failed: " + "VPD info master rank (%d) is not valid.", + iv_vpdInfo.iv_rank); + } + // Restore master rank + iv_vpdInfo.iv_rank = iv_rank; + + + ++iv_numTests; + /// Test when caller passes in an incorrect frequency value and + /// set FFDC enabled flag to false + // Set the frequency to an incorrect value and disable FFDC flag + iv_vpdInfo.iv_omi_freq_mhz = iv_frequency - 1; + iv_vpdInfo.iv_is_config_ffdc_enabled = false; + iv_rc = ddimm_get_efd(l_fapi2Target, iv_vpdInfo, iv_efdBufferPtr, + iv_spdBufferPtr, iv_spdBufferSize); + if (iv_rc == fapi2::FAPI2_RC_SUCCESS) + { + ++iv_numFails; + TS_FAIL("vpdInfoInputTest: test failed: " + "VPD info frequency value (%d) is not valid.", + iv_vpdInfo.iv_omi_freq_mhz); + } + // Restore frequency and FFDC flag + iv_vpdInfo.iv_omi_freq_mhz = iv_frequency; + iv_vpdInfo.iv_is_config_ffdc_enabled = true; + + + ++iv_numTests; + /// Test when caller passes in an incorrect master rank and + /// set FFDC enabled flag to false + // Set the master rank to an incorrect value and enable FFDC flag + iv_vpdInfo.iv_rank = 4; + iv_vpdInfo.iv_is_config_ffdc_enabled = false; + iv_rc = ddimm_get_efd(l_fapi2Target, iv_vpdInfo, iv_efdBufferPtr, + iv_spdBufferPtr, iv_spdBufferSize); + if (iv_rc == fapi2::FAPI2_RC_SUCCESS) + { + ++iv_numFails; + TS_FAIL("vpdInfoInputTest: test failed: " + "VPD info master rank (%d) is not valid.", + iv_vpdInfo.iv_rank); + } + // Restore master rank and FFDC flag + iv_vpdInfo.iv_rank = iv_rank; + iv_vpdInfo.iv_is_config_ffdc_enabled = true; + + FAPI_INF("<< vpdInfoInputTest"); +} + +//****************************************************************************** +// findMatchTest +//****************************************************************************** +void fapi2DdimmGetEfdTest::findMatchTest() +{ + FAPI_INF(">> findMatchTest"); + + // Create a TARGET_TYPE_OCMB_CHIP FAPI2 target + const fapi2::Target<fapi2::TARGET_TYPE_OCMB_CHIP> + l_fapi2Target(iv_ocmbChipTarget); + + + ++iv_numTests; + // Match EFD data block[0] + configureEfdDataBlockN(0, iv_frequency, iv_rank, 0xAA, 0xDD); + iv_rc = ddimm_get_efd(l_fapi2Target, iv_vpdInfo, iv_efdBufferPtr, + iv_spdBufferPtr, iv_spdBufferSize); + if (iv_rc != fapi2::FAPI2_RC_SUCCESS) + { + ++iv_numFails; + TS_FAIL("findMatchTest: test failed: " + "VPD info frequency value (%d) / master rank (%d) " + "are valid. Should have been found in the EFD data block.", + iv_vpdInfo.iv_omi_freq_mhz, iv_vpdInfo.iv_rank); + } + else if ( !(verifyEfdBuffer(iv_frequency, iv_rank, 0xAA, 0xDD) ) ) + { + ++iv_numFails; + TS_FAIL("findMatchTest: test failed: " + "Found matches for frequency value (%d) / master rank " + "(%d) but the EFD buffer returned frequency value " + "(%d) / master rank (%d) which don't match.", + iv_frequency, iv_rank, + iv_vpdInfo.iv_omi_freq_mhz, iv_vpdInfo.iv_rank); + } + + + ++iv_numTests; + /// Match EFD data block[31] + // 31 - The EFD data block to set up for this test + // 14930 - a valid frequency (see doc 1U2UDDIMM_SPD.docx) to be found + // 2 - a valid master rank (see doc 1U2UDDIMM_SPD.docx) to be found + // 0x11 and 0x22 - Tag data for the EFD data block. This will tag the + // EFD data block, at the start and end, so that it can be confirmed + // the actual EFD data block is returned. Without this tag, the + // ddimm_get_efd call can spoof data coming back. This is to keep the + // code honest. + configureEfdDataBlockN(31, 14930, 2, 0x11, 0x22); + iv_vpdInfo.iv_omi_freq_mhz = 14930; + iv_vpdInfo.iv_rank = 2; + iv_rc = ddimm_get_efd(l_fapi2Target, iv_vpdInfo, iv_efdBufferPtr, + iv_spdBufferPtr, iv_spdBufferSize); + if (iv_rc != fapi2::FAPI2_RC_SUCCESS) + { + ++iv_numFails; + TS_FAIL("findMatchTest: test failed: " + "VPD info frequency value (%d) / master rank (%d) " + "are valid. Should have been found in the EFD data block.", + iv_vpdInfo.iv_omi_freq_mhz, iv_vpdInfo.iv_rank); + } + else if ( !(verifyEfdBuffer(14930, 2, 0x11, 0x22) ) ) + { + ++iv_numFails; + TS_FAIL("findMatchTest: test failed: " + "Found matches for frequency value (14930) / master rank " + "(2) but the EFD buffer returned frequency value " + "(%d) / master rank (%d) which don't match.", + iv_vpdInfo.iv_omi_freq_mhz, iv_vpdInfo.iv_rank); + } + + + ++iv_numTests; + /// Set EFD data block[31] to not implemented, no match + // 31 -The EFD data block to set to not implemented. Although + // the data is match, this should not be returned because it is + // not implemented. + setEfdMetaDataNisImplemented(31, false); + // 31 - The EFD data block to set up for this test + // 14930 - a valid frequency (see doc 1U2UDDIMM_SPD.docx) to be found + // 2 - a valid master rank (see doc 1U2UDDIMM_SPD.docx) to be found + // 0x11 and 0x22 - Tag data for the EFD data block. This will tag the + // EFD data block, at the start and end, so that it can be confirmed + // the actual EFD data block is returned. Without this tag, the + // ddimm_get_efd call can spoof data coming back. This is to keep the + // code honest. BUT, in this case nothing should be returned because + // the block is not implemented. + configureEfdDataBlockN(31, 14930, 2, 0x11, 0x22); + iv_vpdInfo.iv_omi_freq_mhz = 14930; + iv_vpdInfo.iv_rank = 2; + iv_rc = ddimm_get_efd(l_fapi2Target, iv_vpdInfo, iv_efdBufferPtr, + iv_spdBufferPtr, iv_spdBufferSize); + if (iv_rc == fapi2::FAPI2_RC_SUCCESS) + { + ++iv_numFails; + TS_FAIL("findMatchTest: test failed: " + "VPD info frequency value (%d) / master rank (%d) should " + "not have been found in the EFD data block, because the " + "implemented flag is false.", + iv_vpdInfo.iv_omi_freq_mhz, iv_vpdInfo.iv_rank); + } + + + ++iv_numTests; + /// Set EFD data block[31] to not implemented, turn FFDC off, no match + // 31 -The EFD data block to set to not implemented. Although + // the data is match, this should not be returned because it is + // not implemented. + setEfdMetaDataNisImplemented(31, false); + // 31 - The EFD data block to set up for this test + // 14930 - a valid frequency (see doc 1U2UDDIMM_SPD.docx) to be found + // 2 - a valid master rank (see doc 1U2UDDIMM_SPD.docx) to be found + // 0x11 and 0x22 - Tag data for the EFD data block. This will tag the + // EFD data block, at the start and end, so that it can be confirmed + // the actual EFD data block is returned. Without this tag, the + // ddimm_get_efd call can spoof data coming back. This is to keep the + // code honest. BUT, in this case nothing should be returned because + // the block is not implemented. + configureEfdDataBlockN(31, 14930, 2, 0x11, 0x22); + iv_vpdInfo.iv_omi_freq_mhz = 14930; + iv_vpdInfo.iv_rank = 2; + // Exercise the FFDC enabled flag to not do FFDC + iv_vpdInfo.iv_is_config_ffdc_enabled = false; + iv_rc = ddimm_get_efd(l_fapi2Target, iv_vpdInfo, iv_efdBufferPtr, + iv_spdBufferPtr, iv_spdBufferSize); + if (iv_rc == fapi2::FAPI2_RC_SUCCESS) + { + ++iv_numFails; + TS_FAIL("findMatchTest: test failed: " + "VPD info frequency value (%d) / master rank (%d) should " + "not have been found in the EFD data block, because the " + "implemented flag is false.", + iv_vpdInfo.iv_omi_freq_mhz, iv_vpdInfo.iv_rank); + } + + + ++iv_numTests; + /// Match on EFD data block[15] + // 31 -The EFD data block to set to implemented. So the EFD data block + // is returned when matched. + setEfdMetaDataNisImplemented(15, true); + // 15 - The EFD data block to set up for this test + // 21330 - a valid frequency (see doc 1U2UDDIMM_SPD.docx) to be found + // 2 - a valid master rank (see doc 1U2UDDIMM_SPD.docx) to be found + // 0x44 and 0x55 - Tag data for the EFD data block. This will tag the + // EFD data block, at the start and end, so that it can be confirmed + // the actual EFD data block is returned. Without this tag, the + // ddimm_get_efd call can spoof data coming back. This is to keep the + // code honest. + configureEfdDataBlockN(15, 21330, 2, 0x44, 0x55); + // 12800, 17060, 25600 - these valid frequencies (see doc + // 1U2UDDIMM_SPD.docx) will be ORed to all EFD data blocks. This will + // test if the data block is found when the frequency is obfuscated with + // other frequencies. + appendToAllEfdDataBlocksFreq(12800); + appendToAllEfdDataBlocksFreq(17060); + appendToAllEfdDataBlocksFreq(25600); + iv_vpdInfo.iv_omi_freq_mhz = 21330; + iv_vpdInfo.iv_rank = 2; + // Exercise the FFDC enabled flag to not do FFDC + iv_vpdInfo.iv_is_config_ffdc_enabled = false; + iv_rc = ddimm_get_efd(l_fapi2Target, iv_vpdInfo, iv_efdBufferPtr, + iv_spdBufferPtr, iv_spdBufferSize); + if (iv_rc != fapi2::FAPI2_RC_SUCCESS) + { + ++iv_numFails; + TS_FAIL("findMatchTest: test failed: " + "VPD info frequency value (%d) / master rank (%d) " + "are valid. Should have been found in the EFD data block.", + iv_vpdInfo.iv_omi_freq_mhz, iv_vpdInfo.iv_rank); + } + else if ( !(verifyEfdBuffer(21330, 2, 0x44, 0x55) ) ) + { + ++iv_numFails; + TS_FAIL("findMatchTest: test failed: " + "Found matches for frequency value (21330) / master rank " + "(2) but the EFD buffer returned frequency value " + "(%d) / master rank (%d) which don't match.", + iv_vpdInfo.iv_omi_freq_mhz, iv_vpdInfo.iv_rank); + } + + + ++iv_numTests; + /// Match on EFD data block[23] + // 23 -The EFD data block to set to implemented. So the EFD data block + // is returned when matched. + setEfdMetaDataNisImplemented(23, true); + // 1 - set all EFD data blocks to this valid master rank (see doc + // 1U2UDDIMM_SPD.docx) will + setAllEfdDataBlocksRank(1); + // 12800 - set all EFD data blocks to this valid frequency (see doc + // 1U2UDDIMM_SPD.docx) will + setAllEfdDataBlocksFreq(12800); + // 23 - The EFD data block to set up for this test + // 19200 - a valid frequency (see doc 1U2UDDIMM_SPD.docx) to be found + // 3 - a valid master rank (see doc 1U2UDDIMM_SPD.docx) to be found + // 0x13 and 0x67 - Tag data for the EFD data block. This will tag the + // EFD data block, at the start and end, so that it can be confirmed + // the actual EFD data block is returned. Without this tag, the + // ddimm_get_efd call can spoof data coming back. This is to keep the + // code honest. + configureEfdDataBlockN(23, 19200, 3, 0x13, 0x67); + // 12800, 14930, 17060, 21330, 23460, 25600 - these valid frequencies (see + // doc 1U2UDDIMM_SPD.docx) will be ORed to all EFD data blocks. This will + // test if the data block is found when the frequency is obfuscated with + // other frequencies. + appendToAllEfdDataBlocksFreq(12800); + appendToAllEfdDataBlocksFreq(14930); + appendToAllEfdDataBlocksFreq(17060); + appendToAllEfdDataBlocksFreq(21330); + appendToAllEfdDataBlocksFreq(23460); + appendToAllEfdDataBlocksFreq(25600); + iv_vpdInfo.iv_omi_freq_mhz = 19200; + iv_vpdInfo.iv_rank = 3; + // Exercise the FFDC enabled flag to not do FFDC + iv_vpdInfo.iv_is_config_ffdc_enabled = false; + iv_rc = ddimm_get_efd(l_fapi2Target, iv_vpdInfo, iv_efdBufferPtr, + iv_spdBufferPtr, iv_spdBufferSize); + if (iv_rc != fapi2::FAPI2_RC_SUCCESS) + { + ++iv_numFails; + TS_FAIL("findMatchTest: test failed: " + "VPD info frequency value (%d) / master rank (%d) " + "are valid. Should have been found in the EFD data block.", + iv_vpdInfo.iv_omi_freq_mhz, iv_vpdInfo.iv_rank); + } + else if ( !(verifyEfdBuffer(19200, 3, 0x13, 0x67) ) ) + { + ++iv_numFails; + TS_FAIL("findMatchTest: test failed: " + "Found matches for frequency value (19200) / master rank " + "(3) but the EFD buffer returned frequency value " + "(%d) / master rank (%d) which don't match.", + iv_vpdInfo.iv_omi_freq_mhz, iv_vpdInfo.iv_rank); + } + + FAPI_INF("<< findMatchTest"); +} + +//****************************************************************************** +// Private Utilities To Facilitate Testing +//****************************************************************************** + +//****************************************************************************** +// initializeSpdBuffer +//****************************************************************************** +void fapi2DdimmGetEfdTest::initializeSpdBuffer() +{ + // Create SPD buffer and scrub the memory + createSpdBuffer(iv_spdBufferPtr, iv_spdBufferSize); + + // I am not going to check if buffer is large enough to do the + // following. I am not writing tests for test cases!!! + + // Configure the SPD buffer to defaults + setSpdDdimmType(DEFAULT_SPD_DDIMM_TYPE); + setEfdMemorySpaceLocation(iv_efdMemorySpaceLocation); + setEfdMemorySpaceSize(iv_efdMemorySpaceSize); + setEfdCount(iv_efdCount); + setSpdDmbMfgId(iv_spdDmbMfgId); + setSpdDmbRevision(iv_spdDmbRevision); + + // Configure the EFD meta data to defaults + setAllEfdMetaDatasEfdDataBlockSize(iv_efdBlockSizeMultiplier); + setAllEfdMetaDatasExtendedFunctionType(iv_extendedFunctionType); + setAllEfdMetaDatasIsImplemented(true); + + // Configure the EFD data blocks to defaults + setAllEfdDataBlocksFreq(iv_frequency); + setAllEfdDataBlocksRank(iv_rank); +} + +//****************************************************************************** +// createSpdBuffer +//****************************************************************************** +void fapi2DdimmGetEfdTest::createSpdBuffer(uint8_t* &o_spdBufferPtr, + const size_t i_spdBufferSize) +{ + delete o_spdBufferPtr; // it is OK to delete a nullptr + + o_spdBufferPtr = new uint8_t[i_spdBufferSize]; + // Set data to all 1's, so testing can be more vigorous + memset(o_spdBufferPtr, 0xFF, i_spdBufferSize); + + // Set the pointer to beginning of the EFD meta data + iv_efdMetaDataPtr = o_spdBufferPtr + EFD_META_DATA_OFFSET; +} + +//****************************************************************************** +// setSpdDdimmType +//****************************************************************************** +void fapi2DdimmGetEfdTest::setSpdDdimmType(const uint8_t i_spdDdimmType) +{ + memcpy(&(iv_spdBufferPtr[SPD_DDIMM_TYPE_OFFSET]), + reinterpret_cast<const uint8_t*>(&i_spdDdimmType), + sizeof(i_spdDdimmType) ); +} + +//****************************************************************************** +// setEfdMemorySpaceLocation +//****************************************************************************** +void fapi2DdimmGetEfdTest::setEfdMemorySpaceLocation( + const uint64_t i_efdMemorySpaceLocation) +{ + uint64_t l_efdMemorySpaceLocation = le64toh(i_efdMemorySpaceLocation); + memcpy(&(iv_spdBufferPtr[EFD_MEMORY_SPACE_OFFSET]), + reinterpret_cast<const uint8_t*>(&l_efdMemorySpaceLocation), + sizeof(l_efdMemorySpaceLocation) ); + + // Update / Set EFD Memory Block pointer to point the beginning of the + // memory space + l_efdMemorySpaceLocation = *(reinterpret_cast<const uint64_t*> + (&iv_spdBufferPtr[EFD_MEMORY_SPACE_OFFSET])); + l_efdMemorySpaceLocation = le64toh(l_efdMemorySpaceLocation); + iv_efdBlockDataPtr = iv_spdBufferPtr + l_efdMemorySpaceLocation; +} + +//****************************************************************************** +// setEfdMemorySpaceSize +//****************************************************************************** +void fapi2DdimmGetEfdTest::setEfdMemorySpaceSize( + const uint8_t i_efdMemorySpaceSize) +{ + memcpy(&(iv_spdBufferPtr[EFD_MEMORY_SPACE_SIZE_OFFSET]), + &i_efdMemorySpaceSize, + sizeof(i_efdMemorySpaceSize) ); +} + +//****************************************************************************** +// setEfdCount +//****************************************************************************** +void fapi2DdimmGetEfdTest::setEfdCount(const uint16_t i_efdCount) +{ + uint16_t l_efdCount = le16toh(i_efdCount); + memcpy(&(iv_spdBufferPtr[EFD_COUNT_OFFSET]), + reinterpret_cast<const uint8_t*>(&l_efdCount), + sizeof(l_efdCount) ); +} + +//****************************************************************************** +// setSpdDmbMfgId +//****************************************************************************** +void fapi2DdimmGetEfdTest::setSpdDmbMfgId(const uint16_t i_spdDmbMfgId) +{ + uint16_t l_spdDmbMfgId = le16toh(i_spdDmbMfgId); + memcpy( &(iv_spdBufferPtr[SPD_DMB_MFG_ID_OFFSET]), + reinterpret_cast<const uint8_t*>(&l_spdDmbMfgId), + sizeof(l_spdDmbMfgId) ); +} + +//****************************************************************************** +// setSpdDmbRevision +//****************************************************************************** +void fapi2DdimmGetEfdTest::setSpdDmbRevision(const uint8_t i_spdDmbRevision) +{ + memcpy( &(iv_spdBufferPtr[SPD_DMB_REVISION_OFFSET]), + &i_spdDmbRevision, + sizeof(i_spdDmbRevision) ); +} + +//****************************************************************************** +// setEfdMetaDataNEfdDataBlockEnd +//****************************************************************************** +void fapi2DdimmGetEfdTest::setEfdMetaDataNEfdDataBlockEnd( + const size_t i_efdMetaDataN, + const uint8_t i_efdDataBlockEnd) +{ + memcpy( &(iv_efdMetaDataPtr[(i_efdMetaDataN * 4) + 2]), + &i_efdDataBlockEnd, + sizeof(i_efdDataBlockEnd) ); +} + +//****************************************************************************** +// setAllEfdMetaDatasEfdDataBlockSize +//****************************************************************************** +void fapi2DdimmGetEfdTest::setAllEfdMetaDatasEfdDataBlockSize( + const uint8_t i_efdDataBlockSize) +{ + for (int ii = 0; ii < iv_efdCount; ++ii) + { + setEfdMetaDataNEfdDataBlockEnd(ii, (ii + 1) * i_efdDataBlockSize); + } +} + +//****************************************************************************** +// setEfdMetaDataExtendedFunctionType +//****************************************************************************** +void fapi2DdimmGetEfdTest::setEfdMetaDataExtendedFunctionType( + const size_t i_efdMetaDataN, + const uint8_t i_extendedFunctionType) + +{ + // Extended Function Type is located 1 byte from the beginning of the meta + // data. It is in bits 4 - 7 of byte 1 (0 based) + + // First extracts bits 4 to 7 from input + uint8_t l_eft = EXTENDED_FUNCTION_TYPE_MASK & i_extendedFunctionType; + + // Retrieve the Extended Function Type + // (iv_efdMetaDataPtr[(i_efdMetaDataN * 4) + 1]) and zero out bits 4 - 7, + // then OR this with the given Extended Function Type (l_eft). + l_eft = (l_eft | + ( (iv_efdMetaDataPtr[(i_efdMetaDataN * 4) + 1]) & + EXTENDED_FUNCTION_TYPE_INVERSE_MASK) ); + + memcpy(&(iv_efdMetaDataPtr[(i_efdMetaDataN * 4) + 1]), + &l_eft, + sizeof(l_eft) ); +} + +//****************************************************************************** +// setAllEfdMetaDatasExtendedFunctionType +//****************************************************************************** +void fapi2DdimmGetEfdTest::setAllEfdMetaDatasExtendedFunctionType( + const uint8_t i_extendedFunctionType) +{ + for (int ii = 0; ii < iv_efdCount; ++ii) + { + setEfdMetaDataExtendedFunctionType(ii, i_extendedFunctionType); + } +} + +//****************************************************************************** +// setEfdMetaDataNisImplemented +//****************************************************************************** +void fapi2DdimmGetEfdTest::setEfdMetaDataNisImplemented( + const size_t i_efdMetaDataN, + const bool i_isImplemented) +{ + // Initially set to false + uint8_t l_isImplemented = 0x00; + if (i_isImplemented) + { + // Change to true + l_isImplemented = 0x80; + } + + // Implemented state is located 3 bytes from the beginning of the meta + // data. It is in bit 7 of byte 3 (0 based) + // Then map that to the byte that is there + l_isImplemented = l_isImplemented | + (iv_efdMetaDataPtr[(i_efdMetaDataN * 4) + 3] & + IS_IMPLEMENTED_INVERSE_MASK) ; + + memcpy( &(iv_efdMetaDataPtr[(i_efdMetaDataN * 4) + 3]), + &l_isImplemented, + sizeof(l_isImplemented) ); +} + +//****************************************************************************** +// setAllEfdMetaDatasIsImplemented +//****************************************************************************** +void fapi2DdimmGetEfdTest::setAllEfdMetaDatasIsImplemented( + const bool i_isImplemented) +{ + for (size_t ii = 0; ii < iv_efdCount; ++ii) + { + setEfdMetaDataNisImplemented(ii, i_isImplemented); + } +} + +//****************************************************************************** +// convertFrequency +// +// Byte 0 of an EFD data block (data from document 1U2UDDIMM_SPD.docx) +// INPUT: 25600 | 23460 | 21330 | 19200 | 17060 | 14930 | 12800 +// OUTPUT: Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 +//****************************************************************************** +uint16_t fapi2DdimmGetEfdTest::convertFrequency(const uint16_t i_frequency) +{ + uint16_t l_frequency(0); + switch (i_frequency) + { + // data from document 1U2UDDIMM_SPD.docx + case 12800: l_frequency = 0x0001; break; + case 14930: l_frequency = 0x0002; break; + case 17060: l_frequency = 0x0004; break; + case 19200: l_frequency = 0x0008; break; + case 21330: l_frequency = 0x0010; break; + case 23460: l_frequency = 0x0020; break; + case 25600: l_frequency = 0x0040; break; + default: TS_FAIL("Uknown Frequency (0x%.4X). Test needs updating " + "to accommodate this value", i_frequency ); break; + } + + return le16toh(l_frequency); +} + +//****************************************************************************** +// setEfdDataBlockNFreq +//****************************************************************************** +void fapi2DdimmGetEfdTest::setEfdDataBlockNFreq(const size_t i_efdDataBlockN, + const uint16_t i_frequency) +{ + uint16_t l_frequency = convertFrequency(i_frequency); + memcpy(&(iv_efdBlockDataPtr[i_efdDataBlockN * iv_efdBlockSize]), + reinterpret_cast<const uint8_t*>(&l_frequency), + sizeof(l_frequency) ); +} + +//****************************************************************************** +// setAllEfdDataBlocksFreq +//****************************************************************************** +void fapi2DdimmGetEfdTest::setAllEfdDataBlocksFreq(const uint16_t i_frequency) +{ + for (size_t ii = 0; ii < iv_efdCount; ++ii) + { + setEfdDataBlockNFreq(ii, i_frequency); + } +} + +//****************************************************************************** +// appendToEfdDataBlockNFreq +//****************************************************************************** +void fapi2DdimmGetEfdTest::appendToEfdDataBlockNFreq( + const size_t i_efdDataBlockN, + const uint16_t i_frequency) +{ + uint16_t l_frequency = convertFrequency(i_frequency); + uint16_t l_currentFreq = *(reinterpret_cast<const uint16_t*>( + &(iv_efdBlockDataPtr[i_efdDataBlockN * iv_efdBlockSize]) ) ); + l_frequency = l_frequency | l_currentFreq; + memcpy(&(iv_efdBlockDataPtr[i_efdDataBlockN * iv_efdBlockSize]), + reinterpret_cast<const uint8_t*>(&l_frequency), + sizeof(l_frequency) ); +} + + +//****************************************************************************** +// appendToAllEfdDataBlocksFreq +//****************************************************************************** +void fapi2DdimmGetEfdTest::appendToAllEfdDataBlocksFreq( + const uint16_t i_frequency) +{ + for (size_t ii = 0; ii < iv_efdCount; ++ii) + { + appendToEfdDataBlockNFreq(ii, i_frequency); + } +} + +//****************************************************************************** +// convertRank +// +// Master Rank (MR) (data from document 1U2UDDIMM_SPD.docx) +// Byte 2 of an EFD data block +// INPUT: MR 3 | MR 2 | MR 1 | MR 0 +// OUTPUT: Bit 3 | Bit 2 | Bit 1 | Bit 0 +//****************************************************************************** +uint8_t fapi2DdimmGetEfdTest::convertRank(const uint8_t i_rank) +{ + uint8_t l_rank(0); + switch (i_rank) + { + // data from document 1U2UDDIMM_SPD.docx + case 0: l_rank = 0x01; break; + case 1: l_rank = 0x02; break; + case 2: l_rank = 0x04; break; + case 3: l_rank = 0x08; break; + default: TS_FAIL("Uknown Rank (0x%.2X). Test needs updating " + "to accommodate this value", i_rank ); break; + } + + return l_rank; +} + + +//****************************************************************************** +// setEfdDataBlockNRank +//****************************************************************************** +void fapi2DdimmGetEfdTest::setEfdDataBlockNRank(const size_t i_efdDataBlockN, + const uint8_t i_rank) +{ + uint8_t l_rank = convertRank(i_rank); + memcpy( &(iv_efdBlockDataPtr[(i_efdDataBlockN * iv_efdBlockSize) + 2]), + &l_rank, + sizeof(l_rank) ); +} + + +//****************************************************************************** +// setAllEfdDataBlocksRank +//****************************************************************************** +void fapi2DdimmGetEfdTest::setAllEfdDataBlocksRank(const uint8_t i_rank) +{ + for (size_t ii = 0; ii < iv_efdCount; ++ii) + { + setEfdDataBlockNRank(ii, i_rank); + } +} + + +//****************************************************************************** +// createEfdBuffer +//****************************************************************************** +void fapi2DdimmGetEfdTest::createEfdBuffer(uint8_t* &o_efdBufferPtr, + const size_t i_efdBufferSize) +{ + delete o_efdBufferPtr; // it is OK to delete a nullptr + + o_efdBufferPtr = new uint8_t[i_efdBufferSize]; + // Set data to all 1's, so testing can be more vigorous + memset(o_efdBufferPtr, 0xFF, i_efdBufferSize); +} + + +//****************************************************************************** +// initializeVpdInfo +//****************************************************************************** +void fapi2DdimmGetEfdTest::initializeVpdInfo( + fapi2::VPDInfo<fapi2::TARGET_TYPE_OCMB_CHIP>& o_vpdInfo) +{ + // Set the size to a default value + o_vpdInfo.iv_size = iv_efdBlockSize; + + // Set frequency to default value + o_vpdInfo.iv_omi_freq_mhz = iv_frequency; + + // Set rank to default value + o_vpdInfo.iv_rank = iv_rank; + + // Enable the FFDC enable flag + o_vpdInfo.iv_is_config_ffdc_enabled = true; +} + + +//****************************************************************************** +// configureEfdDataBlockN +//****************************************************************************** +void fapi2DdimmGetEfdTest::configureEfdDataBlockN( + const size_t i_efdDataBlockN, + const uint16_t i_frequency, + const uint8_t i_rank, + const uint8_t i_beginTag, + const uint8_t i_endTag) +{ + setEfdDataBlockNFreq(i_efdDataBlockN, i_frequency); + setEfdDataBlockNRank(i_efdDataBlockN, i_rank); + tagEfdDataBlockN(i_efdDataBlockN, i_beginTag, i_endTag); +} + + +//****************************************************************************** +// verifyEfdBuffer +//****************************************************************************** +bool fapi2DdimmGetEfdTest::verifyEfdBuffer(const uint16_t i_frequency, + const uint8_t i_rank, + const uint8_t i_beginTag, + const uint8_t i_endTag) + +{ + uint8_t l_rank = convertRank(i_rank); + uint16_t l_frequency = convertFrequency(i_frequency); + + const uint16_t l_efdfreq = + *(reinterpret_cast<const uint16_t*>(iv_efdBufferPtr)); + + return ( (l_rank == iv_efdBufferPtr[2]) && + (l_frequency | l_efdfreq) && + (iv_efdBufferPtr[4] == i_beginTag) && + (iv_efdBufferPtr[iv_efdBlockSize - 1] == i_endTag) ); +} + + +//****************************************************************************** +// tagEfdDataBlockN +//****************************************************************************** +void fapi2DdimmGetEfdTest::tagEfdDataBlockN(const size_t i_efdDataBlockN, + const uint8_t i_beginTag, + const uint8_t i_endTag) +{ + // Tag data 4 bytes beyond the beginning of the EFD data block. The + // first bytes of the EFD data block contain the frequency and master + // rank. Need that data for comparison. Do not want to over write that + // data so tag after the frequency and master rank data. + memcpy(&(iv_efdBlockDataPtr[(i_efdDataBlockN * iv_efdBlockSize) + 4]), + &i_beginTag, + sizeof(i_beginTag) ); + + // Tag the ending byte. + memcpy(&(iv_efdBlockDataPtr[(i_efdDataBlockN * iv_efdBlockSize) + + (iv_efdBlockSize - 1)]), + &i_endTag, + sizeof(i_endTag) ); +} diff --git a/src/usr/fapi2/test/fapi2DdimmGetEfdTest.H b/src/usr/fapi2/test/fapi2DdimmGetEfdTest.H new file mode 100644 index 000000000..43a359381 --- /dev/null +++ b/src/usr/fapi2/test/fapi2DdimmGetEfdTest.H @@ -0,0 +1,401 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/fapi2/test/fapi2DdimmGetEfdTest.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2019 */ +/* [+] 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 __FAPI2_DDIMM_GET_EFD_TEST_H +#define __FAPI2_DDIMM_GET_EFD_TEST_H + +#include <cxxtest/TestSuite.H> +#include <ddimm_get_efd.H> + +//****************************************************************************** +// class fapi2DdimmGetEfdTest +// +// @brief This tests the HWP call ddimm_get_efd/ddr4_get_efd +// +//****************************************************************************** +class fapi2DdimmGetEfdTest : public CxxTest::TestSuite +{ +public: + +//****************************************************************************** +// Public API +//****************************************************************************** + +//****************************************************************************** +// fapi2DdimmGetEfdTest ctor +//****************************************************************************** +fapi2DdimmGetEfdTest(); + +//****************************************************************************** +// testDdimmGetEfdHwpCall +// +// @brief A wrapper around the actual test procedures. +// +//****************************************************************************** +void testDdimmGetEfdHwpCall(); + +private: + +//****************************************************************************** +// Private Test Cases +//****************************************************************************** + +//****************************************************************************** +// sanityCheckTest +// +// @brief The setup creates a perfect scenario to get a match from the get go. +// If this fails, then setup is broken/corrupt, design has changed, etc. +// Either way, no point in continuing until fixed. +// +// @return true if a match was found (which signifies that the test suite has +// been initialized correctly), false if no match found (which +// signifies that the test suite has NOT been initialized correctly) +// +//****************************************************************************** +bool sanityCheckTest(); + +//****************************************************************************** +// sizeMisMatchTest +// +// @brief Do negative testing on the sizes of the different elements - SPD +// buffer, EFD memory space size, etc. +// +//****************************************************************************** +void sizeMisMatchTest(); + +//****************************************************************************** +// dmbDataTest +// +// @brief Do negative testing on the DMB manufacturer ID and the DMB revision. +// Test for incorrect values. +// +//****************************************************************************** +void dmbDataTest(); + +//****************************************************************************** +// vpdInfoInputTest +// +// @brief Do negative testing on the frequency and master rank data passed in +// via the VPDInfo struct. Test for incorrect values. +// +//****************************************************************************** +void vpdInfoInputTest(); + +//****************************************************************************** +// findMatchTest +// +// @brief Do positive testing on finding/not finding a match for given +// frequency and rank. +// +//****************************************************************************** +void findMatchTest(); + + + +//****************************************************************************** +// +// Private utilities to facilitate the testing. These utilities help +// to manipulate buffers for easy testing. +// +//****************************************************************************** + +/* + * @brief Initialize the SPD buffer to a good state - one that has no issues + * finding an EFD to match the criteria in the VPDInfo struct. + */ +void initializeSpdBuffer(); + +/* + * @brief Create the buffer for the SPD with given parameters. + * + * @param[out] o_spdBufferPtr, pointer to a newly created SPD buffer + * @param[in] i_spdBufferSize, size to make the SPD buffer + */ +void createSpdBuffer( uint8_t* &o_spdBufferPtr, + const size_t i_spdBufferSize); + +/* + * @brief Set the DDIMM type of SPD buffer at the proper location + * within the SPD buffer. + * + * @param[in] i_spdDdimmType, DDIMM type to set within the SPD buffe + */ +void setSpdDdimmType(const uint8_t i_spdDdimmType); + +/* + * @brief Set the EFD memory space location at the proper location + * within the SPD buffer. + * + * @param[in] i_efdMemorySpaceLocation, the EFD memory space location + */ +void setEfdMemorySpaceLocation(const uint64_t i_efdMemorySpaceLocation); + +/* + * @brief Set the EFD memory space size at the proper location + * within the SPD buffer. + * + * @param[in] i_efdMemorySpaceSize, the EFD memory space size + */ +void setEfdMemorySpaceSize(const uint8_t i_efdMemorySpaceSize); + +/* + * @brief Set the number of EFDs, for this buffer, at the proper location + * within the SPD buffer. + * + * @param[in] i_efdCount, the number of EFDs + */ +void setEfdCount(const uint16_t i_efdCount); + +/* + * @brief Set the DMB manufacturer ID at the proper location + * within the SPD buffer. + * + * @param[in] i_spdDmbMfgId, the DMB manufacturer ID + */ +void setSpdDmbMfgId(const uint16_t i_spdDmbMfgId); + +/* + * @brief Set the DMB revision at the proper location within the SPD buffer. + * + * @param[in] i_spdDmbMfgId, the DMB revision + */ +void setSpdDmbRevision(const uint8_t i_spdDmbRevision); + +/* + * @brief Set individual EFD data block ending offset within the EFD meta data + * + * @param[in] i_efdMetaDataN, the individual EFD meta data to modify, 0 based + * @param[in] i_efdDataBlockEnd, the corresponding EFD data block end + * for the given EFD meta data + */ +void setEfdMetaDataNEfdDataBlockEnd(const size_t i_efdMetaDataN, + const uint8_t i_efdDataBlockEnd); +/* + * @brief Set all the EFD data block sizes within the EFD meta datas + * + * @param[in] i_efdDataBlockSize, size of the EFD data block + */ +void setAllEfdMetaDatasEfdDataBlockSize(const uint8_t i_efdDataBlockSize); + +/* + * @brief Set an individual EFD meta data's extended function type + * + * @param[in] i_efdMetaDataN, the individual EFD meta data to modify, 0 based + * @param[in] i_extendedFunctionType, the extended function type value + */ +void setEfdMetaDataExtendedFunctionType(const size_t i_efdMetaDataN, + const uint8_t i_extendedFunctionType); + + /* + * @brief Set all the EFD meta data's extended function type + * + * @param[in] i_extendedFunctionType, the extended function type value + */ +void setAllEfdMetaDatasExtendedFunctionType( + const uint8_t i_extendedFunctionType); +/* + * @brief Set an individual EFD meta data's implemented state + * + * @param[in] i_efdMetaDataN, the individual EFD meta data to modify, 0 based + * @param[in] i_isImplemented, state of the EFD meta data to be set to + */ +void setEfdMetaDataNisImplemented(const size_t i_efdMetaDataN, + const bool i_isImplemented); + +/* + * @brief Set all the EFD meta data's implemented state + * + * @param[in] i_isImplemented, state of the EFD meta data to be set to + */ +void setAllEfdMetaDatasIsImplemented(const bool i_isImplemented); + + /* + * @brief Set an individual EFD data block's frequency + * + * @param[in] i_frequency, the frequency, in numeric form + */ +uint16_t convertFrequency(const uint16_t i_frequency); + + /* + * @brief Set an individual EFD data block's frequency + * + * @param[in] i_efdDataBlockN, the individual EFD data block to modify, 0 based + * @param[in] i_frequency, the frequency, in numeric form, to set the + * individual EFD data block to + */ +void setEfdDataBlockNFreq(const size_t i_efdDataBlockN, + const uint16_t i_frequency); + + /* + * @brief Set all the EFD data block's frequency + * + * @param[in] i_frequency, the frequency, in numeric form, to set all EFD + * data blocks to + */ +void setAllEfdDataBlocksFreq(const uint16_t i_frequency); + + /* + * @brief Append a frequency to an individual EFD data block + * + * @param[in] i_efdDataBlockN, the individual EFD data block to modify, 0 based + * @param[in] i_frequency, the frequency, in numeric form, to append + */ +void appendToEfdDataBlockNFreq(const size_t i_efdDataBlockN, + const uint16_t i_frequency); + + /* + * @brief Append a frequency to all EFD data blocks + * + * @param[in] i_frequency, the frequency, in numeric form, to append + */ +void appendToAllEfdDataBlocksFreq(const uint16_t i_frequency); + +/* + * @brief Map master rank to bit mask. + * + * @param[in] i_rank, the master rank, in numeric form + */ +uint8_t convertRank(const uint8_t i_rank); + +/* + * @brief Set an individual EFD data block's master rank + * + * @param[in] i_efdDataBlockN, the individual EFD data block to modify, 0 based + * @param[in] i_rank, the master rank, in numeric form, to set the individual + * EFD data block to + */ +void setEfdDataBlockNRank(const size_t i_efdDataBlockN, + const uint8_t i_rank); + + /* + * @brief Set all the EFD data block's master rank + * + * @param[in] i_rank, the master rank, in numeric form, to set all EFD + * data blocks to + * + */ +void setAllEfdDataBlocksRank(const uint8_t i_rank); + +/* + * @brief Create the buffer for the EFD with given parameters. + * + * @param[out] o_efdBufferPtr, pointer to a newly created EFD buffer + * @param[in] i_efdBufferSize, size to make the EFD buffer + */ +void createEfdBuffer( uint8_t* &o_efdBufferPtr, + const size_t i_efdBufferSize); + +/* + * @brief Initialize a VPDInfo struct to a known state + * + * @param[out] o_vpdInfo, VPDInfo struct to initialize + */ +void initializeVpdInfo(fapi2::VPDInfo<fapi2::TARGET_TYPE_OCMB_CHIP>& o_vpdInfo); + +/* + * @brief Configure an EFD data block to given data + * + * @param[in] i_efdDataBlockN, the individual EFD data block to modify, 0 based + * @param[in] i_frequency, the frequency, in numeric form, + * to set EFD data block to + * @param[in] i_rank, the master rank, in numeric form, + * to set EFD data block to + * @param[in] i_beginTag, tag to use at the beginning of the EFD data block + * @param[in] i_endTag, tag to use at the end of the EFD data block + */ +void configureEfdDataBlockN(const size_t i_efdDataBlockN, + const uint16_t i_frequency, + const uint8_t i_rank, + const uint8_t i_beginTag, + const uint8_t i_endTag); + +/* + * @brief Verify the EFD buffer has the expected value. It is not enough to + * say we found a match. Must confirm we retrieved the correct EFD + * data block. + * + * @param[in] i_frequency, the frequency, in numeric form, + * to match in EFD data block + * @param[in] i_rank, the master rank, in numeric form, + * to match in EFD data block + * @param[in] i_beginTag, tag to match at the beginning of the EFD data block + * @param[in] i_endTag, tag to match at the end of the EFD data block + * + * @return true if the EFD buffer matches data given, else false if no match + */ +bool verifyEfdBuffer(const uint16_t i_frequency, + const uint8_t i_rank, + const uint8_t i_beginTag, + const uint8_t i_endTag); + +/* + * @brief Tag an EFD data block to help identify it when found + * Tagging the EFD data block at specific memory places within the EFD + * data block, ensures that when a match is found, indeed that block + * is returned - the called function cannot spoof the data. The tags + * ensure that the called function is returning the correct EFD data + * block in it's entirety. + * + * @param[in] i_efdDataBlockN, the individual EFD data block to modify, 0 based + * @param[in] i_beginTag, tag to use at the beginning of the EFD data block + * @param[in] i_endTag, tag to use at the end of the EFD data block + */ +void tagEfdDataBlockN(const size_t i_efdDataBlockN, + const uint8_t i_beginTag, + const uint8_t i_endTag); + +//****************************************************************************** +// +// Private data members +// +//****************************************************************************** + + uint8_t* iv_efdBufferPtr; + uint8_t* iv_spdBufferPtr; + size_t iv_spdBufferSize; + uint8_t* iv_efdMetaDataPtr; + uint8_t* iv_efdBlockDataPtr; + uint8_t iv_efdBlockSizeMultiplier; + size_t iv_efdBlockSize; + size_t iv_efdMemorySpaceLocation; + size_t iv_efdMemorySpaceSize; + uint16_t iv_efdCount; + uint16_t iv_spdDmbMfgId; + uint8_t iv_spdDmbRevision; + uint8_t iv_extendedFunctionType; + uint16_t iv_frequency; + uint8_t iv_rank; + + TARGETING::Target * iv_ocmbChipTarget; + fapi2::ReturnCode iv_rc; + fapi2::VPDInfo<fapi2::TARGET_TYPE_OCMB_CHIP> iv_vpdInfo; + + size_t iv_numTests; + size_t iv_numFails; + TARGETING::MODEL iv_attrModel; +}; // end class fapi2DdimmGetEfdTest + +#endif + diff --git a/src/usr/fapi2/test/fapi2Test.mk b/src/usr/fapi2/test/fapi2Test.mk index dbe7268c2..54d8b37da 100644 --- a/src/usr/fapi2/test/fapi2Test.mk +++ b/src/usr/fapi2/test/fapi2Test.mk @@ -49,6 +49,7 @@ OBJS += p9_sample_procedure.o OBJS += p9_hwtests.o OBJS += rcSupport.o OBJS += fapi2TestUtils.o +OBJS += fapi2DdimmGetEfdTest.o OBJS += getVpdTest.o OBJS += p9_pm_get_poundv_bucket.o |