diff options
Diffstat (limited to 'src/usr/isteps/nvdimm/nvdimmdd.C')
-rwxr-xr-x | src/usr/isteps/nvdimm/nvdimmdd.C | 532 |
1 files changed, 413 insertions, 119 deletions
diff --git a/src/usr/isteps/nvdimm/nvdimmdd.C b/src/usr/isteps/nvdimm/nvdimmdd.C index 730fe0271..044be454b 100755 --- a/src/usr/isteps/nvdimm/nvdimmdd.C +++ b/src/usr/isteps/nvdimm/nvdimmdd.C @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2011,2019 */ +/* Contributors Listed Below - COPYRIGHT 2011,2020 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -35,6 +35,7 @@ // Includes // ---------------------------------------------- #include <string.h> +#include <time.h> #include <sys/time.h> #include <trace/interface.H> #include <errl/errlentry.H> @@ -67,16 +68,18 @@ TRAC_INIT( & g_trac_nvdimmr, "NVDIMMR", KILOBYTE ); // Easy macro replace for unit testing -#define TRACUCOMP(args...) TRACFCOMP(args) -//#define TRACUCOMP(args...) +//#define TRACUCOMP(args...) TRACFCOMP(args) +#define TRACUCOMP(args...) // ---------------------------------------------- // Defines // ---------------------------------------------- #define MAX_BYTE_ADDR 2 #define NVDIMM_MAX_RETRIES 2 +#define MAX_READ_RETRY_SECS 30 // ---------------------------------------------- +using namespace TARGETING; namespace { @@ -95,13 +98,83 @@ static bool errorIsRetryable(uint16_t reasonCode) namespace NVDIMM { -// Register the perform Op with the routing code for DIMMs. +// Register the perform Op router with the routing code for DIMMs. DEVICE_REGISTER_ROUTE( DeviceFW::WILDCARD, DeviceFW::NVDIMM, TARGETING::TYPE_DIMM, + nvdimmPerformOpRouter ); + +// Register the perform Op with the routing code for DIMMs. +DEVICE_REGISTER_ROUTE( DeviceFW::WILDCARD, + DeviceFW::NVDIMM_RAW, + TARGETING::TYPE_DIMM, nvdimmPerformOp ); // ------------------------------------------------------------------ +// nvdimmPerformOpRouter +// ------------------------------------------------------------------ +errlHndl_t nvdimmPerformOpRouter( DeviceFW::OperationType i_opType, + TARGETING::Target * i_target, + void * io_buffer, + size_t & io_buflen, + int64_t i_accessType, + va_list i_args ) +{ + errlHndl_t l_err(nullptr); + + TRACDCOMP( g_trac_nvdimm, + ENTER_MRK"nvdimmPerformOpRouter()" ); + + // Get the NVDIMM register's address, where data will be accessed from + // Although the data is being retrieved as a 64 bit value + // it is really a 16 bit value. Data passed via an arg list + // are retrieved in 64 bit chunks. + uint16_t l_registerAddress = + static_cast<uint16_t>(va_arg(i_args, uint64_t)); + + // Get a handle to the data buffer for easy referencing + uint8_t* l_data = static_cast<uint8_t*>(io_buffer); + + TRACUCOMP(g_trac_nvdimm, INFO_MRK"nvdimmPerformOpRouter(): " + "operation type=%d, target HUID=0x%.8X, access type=%d, " + "buffer length=%d, buffer data=0x%.8X, register address=0x%.8X", + static_cast<uint64_t>(i_opType), get_huid(i_target), i_accessType, + io_buflen, *l_data, l_registerAddress); + + // Make the right read/write call based on operation type + if( i_opType == DeviceFW::READ ) + { + l_err = nvdimmReadReg( i_target, + l_registerAddress, + *l_data, + PAGE_VERIFY); + if (!l_err) + { + TRACUCOMP (g_trac_nvdimm, INFO_MRK"nvdimmPerformOpRouter(): " + "Read data(0x%X) from register(0x%X)", + *l_data, l_registerAddress); + } + } + else if( i_opType == DeviceFW::WRITE ) + { + TRACUCOMP (g_trac_nvdimm, INFO_MRK"nvdimmPerformOpRouter(): " + "Writing data(0x%X) to register(0x%X) ...", + *l_data, l_registerAddress); + + l_err = nvdimmWriteReg( i_target, + l_registerAddress, + *l_data, + PAGE_VERIFY); + } + + TRACDCOMP(g_trac_nvdimm, + EXIT_MRK"nvdimmPerformOpRouter() returning with %s", + (l_err == nullptr ? "no error, success" : "an error, failure") ); + + return l_err; +} + +// ------------------------------------------------------------------ // nvdimmPerformOp // ------------------------------------------------------------------ errlHndl_t nvdimmPerformOp( DeviceFW::OperationType i_opType, @@ -116,6 +189,7 @@ errlHndl_t nvdimmPerformOp( DeviceFW::OperationType i_opType, nvdimm_addr_t i2cInfo; i2cInfo.offset = va_arg( i_args, uint64_t ); + i2cInfo.blockSize = va_arg( i_args, uint64_t ); TRACDCOMP( g_trac_nvdimm, ENTER_MRK"nvdimmPerformOp()" ); @@ -206,7 +280,7 @@ errlHndl_t nvdimmPerformOp( DeviceFW::OperationType i_opType, l_currentOpLen = l_snglChipSize - i2cInfo.offset; } - TRACFCOMP( g_trac_nvdimm, + TRACUCOMP( g_trac_nvdimm, "nvdimmPerformOp(): i_opType=%d " "e/p/dA=%d/%d/0x%X, offset=0x%X, len=0x%X, " "snglChipKB=0x%X, chipCount=0x%X, devSizeKB=0x%X", i_opType, @@ -216,7 +290,7 @@ errlHndl_t nvdimmPerformOp( DeviceFW::OperationType i_opType, // Printing mux info separately, if combined, nothing is displayed char* l_muxPath = i2cInfo.i2cMuxPath.toString(); - TRACFCOMP(g_trac_nvdimm, "nvdimmPerformOp(): " + TRACUCOMP(g_trac_nvdimm, "nvdimmPerformOp(): " "muxSelector=0x%X, muxPath=%s", i2cInfo.i2cMuxBusSelector, l_muxPath); @@ -326,7 +400,7 @@ errlHndl_t crossesNvdimmPageBoundary( uint64_t i_offset, errlHndl_t err = nullptr; - if(i_offset >= NVDIMM_PAGE_SIZE || (i_offset+i_buflen) >= NVDIMM_PAGE_SIZE) + if(i_offset >= NVDIMM_PAGE_SIZE || (i_offset+i_buflen) > NVDIMM_PAGE_SIZE) { TRACFCOMP( g_trac_nvdimm, ERR_MRK"crossesNvdimmPageBoundary() - offset 0x%X, buflen 0x%X" @@ -425,7 +499,7 @@ errlHndl_t nvdimmRead ( TARGETING::Target * i_target, if( err ) { TRACFCOMP(g_trac_nvdimm, - "Failed reading data: original read"); + ERR_MRK"nvdimmRead(): Failed reading data: original read"); break; } @@ -462,12 +536,13 @@ errlHndl_t nvdimmReadData( TARGETING::Target * i_target, ENTER_MRK"nvdimmReadData()"); do { + timespec_t l_CurTime, l_PrevTime; + clock_gettime(CLOCK_MONOTONIC, &l_PrevTime); + int retry = 0; /************************************************************/ /* Attempt read multiple times ONLY on retryable fails */ /************************************************************/ - for (uint8_t retry = 0; - retry <= NVDIMM_MAX_RETRIES; - retry++) + do { // Only write the byte address if we have data to write if( 0 != i_byteAddressSize ) @@ -488,12 +563,10 @@ errlHndl_t nvdimmReadData( TARGETING::Target * i_target, if( l_err ) { - TRACFCOMP(g_trac_nvdimm, - ERR_MRK"nvdimmReadData(): I2C Read-Offset failed on " - "%d/%d/0x%X, aS=%d", - i_i2cInfo.port, i_i2cInfo.engine, - i_i2cInfo.devAddr, - i_byteAddressSize); + TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimmReadData(): " + "I2C Read-Offset failed on %d/%d/0x%X, aS=%d", + i_i2cInfo.port, i_i2cInfo.engine, + i_i2cInfo.devAddr, i_byteAddressSize); // Printing mux info separately, if combined, nothing is displayed char* l_muxPath = i_i2cInfo.i2cMuxPath.toString(); @@ -526,7 +599,7 @@ errlHndl_t nvdimmReadData( TARGETING::Target * i_target, if( l_err ) { - TRACFCOMP(g_trac_nvdimm, + TRACUCOMP(g_trac_nvdimm, ERR_MRK"nvdimmReadData(): I2C Read failed on " "%d/%d/0x%0X", i_i2cInfo.port, i_i2cInfo.engine, @@ -534,7 +607,7 @@ errlHndl_t nvdimmReadData( TARGETING::Target * i_target, // Printing mux info separately, if combined, nothing is displayed char* l_muxPath = i_i2cInfo.i2cMuxPath.toString(); - TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimmReadData(): " + TRACUCOMP(g_trac_nvdimm, ERR_MRK"nvdimmReadData(): " "muxSelector=0x%X, muxPath=%s", i_i2cInfo.i2cMuxBusSelector, l_muxPath); @@ -567,64 +640,35 @@ errlHndl_t nvdimmReadData( TARGETING::Target * i_target, else // Handle retryable error { // If op will be attempted again: save log and continue - if ( retry < NVDIMM_MAX_RETRIES ) + // Only save original retryable error + if ( err_retryable == nullptr ) { - // Only save original retryable error - if ( err_retryable == nullptr ) - { - // Save original retryable error - err_retryable = l_err; - - TRACFCOMP( g_trac_nvdimm, ERR_MRK"nvdimmReadData(): " - "Retryable Error rc=0x%X, eid=0x%X, tgt=0x%X, " - "retry/MAX=%d/%d. Save error and retry", - err_retryable->reasonCode(), - err_retryable->eid(), - TARGETING::get_huid(i_target), - retry, NVDIMM_MAX_RETRIES); - - err_retryable->collectTrace(NVDIMM_COMP_NAME); - } - else - { - // Add data to original retryable error - TRACFCOMP( g_trac_nvdimm, ERR_MRK"nvdimmReadData(): " - "Another Retryable Error rc=0x%X, eid=0x%X " - "plid=0x%X, tgt=0x%X, retry/MAX=%d/%d. " - "Delete error and retry", - l_err->reasonCode(), l_err->eid(), l_err->plid(), - TARGETING::get_huid(i_target), - retry, NVDIMM_MAX_RETRIES); - - ERRORLOG::ErrlUserDetailsString( - "Another Retryable ERROR found") - .addToLog(err_retryable); - - // Delete this new retryable error - delete l_err; - l_err = nullptr; - } + // Save original retryable error + err_retryable = l_err; + + TRACUCOMP( g_trac_nvdimm, ERR_MRK"nvdimmReadData(): " + "Retryable Error rc=0x%X, eid=0x%X, tgt=0x%X, " + "retry=%d. Save error and retry", + err_retryable->reasonCode(), + err_retryable->eid(), + TARGETING::get_huid(i_target), + retry); - // continue to retry - continue; + err_retryable->collectTrace(NVDIMM_COMP_NAME); } - else // no more retries: trace and break + else { - TRACFCOMP( g_trac_nvdimm, ERR_MRK"nvdimmReadData(): " - "Error rc=0x%X, eid=%d, tgt=0x%X. No More " - "Retries (retry/MAX=%d/%d). Returning Error", - l_err->reasonCode(), l_err->eid(), - TARGETING::get_huid(i_target), - retry, NVDIMM_MAX_RETRIES); - - l_err->collectTrace(NVDIMM_COMP_NAME); - - // break from retry loop - break; + // Delete this new retryable error + delete l_err; + l_err = nullptr; } - } + } // retryable error + // update current time + clock_gettime(CLOCK_MONOTONIC, &l_CurTime); + retry++; } // end of retry loop + while( (l_CurTime.tv_sec - l_PrevTime.tv_sec) < MAX_READ_RETRY_SECS ); // Handle saved retryable error, if any if (err_retryable) @@ -641,13 +685,29 @@ errlHndl_t nvdimmReadData( TARGETING::Target * i_target, .addToLog(err_retryable); errlCommit(err_retryable, NVDIMM_COMP_ID); + + // Add trace of what operation failed for returned error + TRACFCOMP(g_trac_nvdimm, + ERR_MRK"nvdimmReadData(): I2C Read failed on " + "%d/%d/0x%0X", + i_i2cInfo.port, i_i2cInfo.engine, i_i2cInfo.devAddr ); + + // Printing mux info separately, if combined, nothing is displayed + char* l_muxPath = i_i2cInfo.i2cMuxPath.toString(); + TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimmReadData(): " + "muxSelector=0x%X, muxPath=%s", + i_i2cInfo.i2cMuxBusSelector, + l_muxPath); + free(l_muxPath); + l_muxPath = nullptr; } else { // Since we eventually succeeded, delete original retryable error - TRACFCOMP(g_trac_nvdimm, "nvdimmReadData(): Op successful, " - "deleting saved retryable err eid=0x%X, plid=0x%X", - err_retryable->eid(), err_retryable->plid()); + TRACUCOMP(g_trac_nvdimm, "nvdimmReadData(): Op successful, " + "after %d retries. Deleting saved retryable err eid=" + "0x%X, plid=0x%X", + retry, err_retryable->eid(), err_retryable->plid()); delete err_retryable; err_retryable = nullptr; @@ -676,8 +736,6 @@ errlHndl_t nvdimmWrite ( TARGETING::Target * i_target, size_t byteAddrSize = 0; uint8_t * newBuffer = nullptr; bool needFree = false; - uint32_t data_left = 0; - uint32_t diff_wps = 0; TRACDCOMP( g_trac_nvdimm, ENTER_MRK"nvdimmWrite()" ); @@ -742,6 +800,17 @@ errlHndl_t nvdimmWrite ( TARGETING::Target * i_target, // Setup a max-size buffer of writePageSize size_t newBufLen = i_i2cInfo.writePageSize; + + // Break data into max supported i2c transfer size, if possible + // (speeds up i2c operation) + if ( (i_i2cInfo.blockSize != 0) && + (io_buflen >= i_i2cInfo.blockSize) && + ((io_buflen % i_i2cInfo.blockSize) == 0) ) + { + newBufLen = i_i2cInfo.blockSize; + } + assert(newBufLen > 0, "Unable to allocate 0 buffer size for nvdimmWrite()"); + newBuffer = static_cast<uint8_t*>(malloc( newBufLen )); needFree = true; @@ -756,16 +825,6 @@ errlHndl_t nvdimmWrite ( TARGETING::Target * i_target, while( total_bytes_written < io_buflen ) { - // Determine how much data can be written in this loop - // Can't go over a writePageSize boundary - - // Total data left to write - data_left = io_buflen - total_bytes_written; - - // Difference to next writePageSize boundary - diff_wps = i_i2cInfo.writePageSize - - (i_i2cInfo.offset % i_i2cInfo.writePageSize); - // Add the data the user wanted to write memcpy( newBuffer, &l_data_ptr[total_bytes_written], @@ -785,15 +844,13 @@ errlHndl_t nvdimmWrite ( TARGETING::Target * i_target, } TRACUCOMP(g_trac_nvdimm,"nvdimmWrite() Loop: %d/%d/0x%X " - "writeBuflen=%d, offset=0x%X, " - "bAS=%d, diffs=%d/%d", + "writeBuflen=%d, offset=0x%X, bAS=%d", i_i2cInfo.port, i_i2cInfo.engine, i_i2cInfo.devAddr, - newBufLen, i_i2cInfo.offset, byteAddrSize, - data_left, diff_wps); + newBufLen, i_i2cInfo.offset, byteAddrSize); // Printing mux info separately, if combined, nothing is displayed char* l_muxPath = i_i2cInfo.i2cMuxPath.toString(); - TRACFCOMP(g_trac_nvdimm, "nvdimmWrite(): " + TRACUCOMP(g_trac_nvdimm, "nvdimmWrite(): " "muxSelector=0x%X, muxPath=%s", i_i2cInfo.i2cMuxBusSelector, l_muxPath); @@ -815,6 +872,14 @@ errlHndl_t nvdimmWrite ( TARGETING::Target * i_target, // for this loop TRACFCOMP(g_trac_nvdimm, "Failed writing data: original nvdimm write"); + // total writes for the data size (divide by each write size) + size_t totalWritesNeeded = io_buflen/newBufLen; + // current write number (writes done + next one) + size_t currentWrite = total_bytes_written/newBufLen + 1; + TRACFCOMP( g_trac_nvdimm,ERR_MRK"nvdimmWrite(): " + "Tried to write out %d bytes out of %d total: " + "Failed on the %d of %d writes", newBufLen, io_buflen, + currentWrite, totalWritesNeeded ); break; } @@ -842,7 +907,7 @@ errlHndl_t nvdimmWrite ( TARGETING::Target * i_target, io_buflen = total_bytes_written; - TRACSCOMP( g_trac_nvdimmr, + TRACUCOMP( g_trac_nvdimmr, "NVDIMM WRITE END : Offset %.2X : Len %d", i_i2cInfo.offset, io_buflen ); } while( 0 ); @@ -874,30 +939,70 @@ errlHndl_t nvdimmWriteData( TARGETING::Target * i_target, ENTER_MRK"nvdimmWriteData()"); errlHndl_t err = nullptr; errlHndl_t err_retryable = nullptr; + size_t data_length; + do { - /***********************************************************/ - /* Attempt write multiple times ONLY on retryable fails */ - /***********************************************************/ - for (uint8_t retry = 0; - retry <= NVDIMM_MAX_RETRIES; - retry++) - { - // Do the actual data write - err = deviceOp( DeviceFW::WRITE, - i_target, - i_dataToWrite, - i_dataLen, - DEVICE_I2C_ADDRESS_OFFSET( - i_i2cInfo.port, - i_i2cInfo.engine, - i_i2cInfo.devAddr, - i_byteAddressSize, - reinterpret_cast<uint8_t*>( - i_byteAddress), - i_i2cInfo.i2cMuxBusSelector, - &(i_i2cInfo.i2cMuxPath) )); + /***********************************************************/ + /* Attempt write multiple times ONLY on retryable fails */ + /***********************************************************/ + for ( uint8_t retry = 0; retry <= NVDIMM_MAX_RETRIES; retry++) + { + // use a temporary variable to allow retry as the + // data_length could be altered by deviceOp() failure + data_length = i_dataLen; + // Do the actual data write + if ( i_dataLen == sizeof(uint16_t) ) + { + err = deviceOp( DeviceFW::WRITE, + i_target, + i_dataToWrite, + data_length, + DeviceFW::I2C, + I2C_SMBUS_RW_W_CMD_PARAMS( + DeviceFW::I2C_SMBUS_WORD_NO_PEC, + i_i2cInfo.engine, + i_i2cInfo.port, + i_i2cInfo.devAddr, + *(reinterpret_cast<uint8_t*>(i_byteAddress) + + (i_byteAddressSize-1)), + i_i2cInfo.i2cMuxBusSelector, + &(i_i2cInfo.i2cMuxPath)) ); + } + else if ( i_dataLen == 32 ) + { + err = deviceOp( DeviceFW::WRITE, + i_target, + i_dataToWrite, + data_length, + DeviceFW::I2C, + I2C_SMBUS_RW_W_CMD_PARAMS( + DeviceFW::I2C_SMBUS_BLOCK_NO_BYTE_COUNT, + i_i2cInfo.engine, + i_i2cInfo.port, + i_i2cInfo.devAddr, + *(reinterpret_cast<uint8_t*>(i_byteAddress) + + (i_byteAddressSize-1)), + i_i2cInfo.i2cMuxBusSelector, + &(i_i2cInfo.i2cMuxPath)) ); + } + else + { + err = deviceOp( DeviceFW::WRITE, + i_target, + i_dataToWrite, + data_length, + DEVICE_I2C_ADDRESS_OFFSET( + i_i2cInfo.port, + i_i2cInfo.engine, + i_i2cInfo.devAddr, + i_byteAddressSize, + reinterpret_cast<uint8_t*>( + i_byteAddress), + i_i2cInfo.i2cMuxBusSelector, + &(i_i2cInfo.i2cMuxPath) )); + } if ( err == nullptr ) { // Operation completed successfully @@ -911,7 +1016,7 @@ errlHndl_t nvdimmWriteData( TARGETING::Target * i_target, "Write Non-Retryable fail %d/%d/0x%X, " "ldl=%d, offset=0x%X, aS=%d, retry=%d", i_i2cInfo.port, i_i2cInfo.engine, - i_i2cInfo.devAddr, i_dataLen, + i_i2cInfo.devAddr, data_length, i_i2cInfo.offset, i_i2cInfo.addrSize, retry); // Printing mux info separately, if combined, nothing is displayed @@ -930,7 +1035,7 @@ errlHndl_t nvdimmWriteData( TARGETING::Target * i_target, } else // Handle retryable error { - TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimmWriteData(): I2C " + TRACUCOMP(g_trac_nvdimm, ERR_MRK"nvdimmWriteData(): I2C " "Write retryable fail %d/%d/0x%X, " "ldl=%d, offset=0x%X, aS=%d, writePageSize = %x", i_i2cInfo.port, i_i2cInfo.engine, @@ -940,7 +1045,7 @@ errlHndl_t nvdimmWriteData( TARGETING::Target * i_target, // Printing mux info separately, if combined, nothing is displayed char* l_muxPath = i_i2cInfo.i2cMuxPath.toString(); - TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimmWriteData(): " + TRACUCOMP(g_trac_nvdimm, ERR_MRK"nvdimmWriteData(): " "muxSelector=0x%X, muxPath=%s", i_i2cInfo.i2cMuxBusSelector, l_muxPath); @@ -956,7 +1061,7 @@ errlHndl_t nvdimmWriteData( TARGETING::Target * i_target, // Save original retryable error err_retryable = err; - TRACFCOMP( g_trac_nvdimm, ERR_MRK"nvdimmWriteData(): " + TRACUCOMP( g_trac_nvdimm, ERR_MRK"nvdimmWriteData(): " "Error rc=0x%X, eid=0x%X plid=0x%X, " "tgt=0x%X, retry/MAX=%d/%d. Save error " "and retry", @@ -971,7 +1076,7 @@ errlHndl_t nvdimmWriteData( TARGETING::Target * i_target, else { // Add data to original retryable error - TRACFCOMP( g_trac_nvdimm, ERR_MRK"nvdimmWriteData(): " + TRACUCOMP( g_trac_nvdimm, ERR_MRK"nvdimmWriteData(): " "Another Retryable Error rc=0x%X, eid=0x%X " "plid=0x%X, tgt=0x%X, retry/MAX=%d/%d. " "Delete error and retry", @@ -1016,6 +1121,24 @@ errlHndl_t nvdimmWriteData( TARGETING::Target * i_target, { if (err) { + // Trace failure write parameters + TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimmWriteData(): I2C " + "Write retryable fail %d/%d/0x%X, " + "ldl=%d, offset=0x%X, aS=%d, writePageSize = %x", + i_i2cInfo.port, i_i2cInfo.engine, + i_i2cInfo.devAddr, i_dataLen, + i_i2cInfo.offset, i_i2cInfo.addrSize, + i_i2cInfo.writePageSize); + + // Printing mux info separately, if combined, nothing is displayed + char* l_muxPath = i_i2cInfo.i2cMuxPath.toString(); + TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimmWriteData(): " + "muxSelector=0x%X, muxPath=%s", + i_i2cInfo.i2cMuxBusSelector, + l_muxPath); + free(l_muxPath); + l_muxPath = nullptr; + // commit original retryable error with new err PLID err_retryable->plid(err->plid()); TRACFCOMP(g_trac_nvdimm, "nvdimmWriteData(): Committing saved " @@ -1031,7 +1154,7 @@ errlHndl_t nvdimmWriteData( TARGETING::Target * i_target, else { // Since we eventually succeeded, delete original retryable error - TRACFCOMP(g_trac_nvdimm, "nvdimmWriteData(): Op successful, " + TRACUCOMP(g_trac_nvdimm, "nvdimmWriteData(): Op successful, " "deleting saved retryable err eid=0x%X, plid=0x%X", err_retryable->eid(), err_retryable->plid()); @@ -1221,7 +1344,7 @@ errlHndl_t nvdimmReadAttributes ( TARGETING::Target * i_target, // Printing mux info separately, if combined, nothing is displayed char* l_muxPath = o_i2cInfo.i2cMuxPath.toString(); - TRACFCOMP(g_trac_nvdimm, "nvdimmReadAttributes(): " + TRACUCOMP(g_trac_nvdimm, "nvdimmReadAttributes(): " "muxSelector=0x%X, muxPath=%s", o_i2cInfo.i2cMuxBusSelector, l_muxPath); @@ -1481,4 +1604,175 @@ void getNVDIMMs( std::list<EEPROM::EepromInfo_t>& o_info ) o_info.size()); } +/** + * @brief Helper structure to keep track of memory ranges + */ +typedef struct memGroups_t +{ + Target* proc; + uint64_t membottom; + uint64_t memtop; + size_t group; +} memGroups_t; + +/** + * @brief Comparator for memGroups_t to allow sorting, sorts big-to-small + * @param[in] Left-side of compare + * @param[in] Right-side of compare + * @return true:left-side is bigger, false:right-side is bigger + */ +bool compare_memGroups(memGroups_t& i_ls, + memGroups_t& i_rs) +{ + return (i_ls.memtop > i_rs.memtop); +} + +/** + * @brief Check if given address is owned by nvdimms and return + * a new address that isn't if it was + */ +uint64_t get_top_addr_with_no_nvdimms( uint64_t i_topAddr ) +{ + // Default to just returning the same value we got (no nvdimms) + uint64_t o_topAddr = i_topAddr; + + // On a NVDIMM system we need to make sure that we don't + // use the NV memory for the HOMER (or other reserved + // memory). Depending on the specific memory layout + // the NV memory could be placed at the top of memory + // where we would normally land. + + // NVDIMMs are only on Nimbus systems + if( TARGETING::MODEL_NIMBUS + !=TARGETING::targetService().getProcessorModel() ) + { + return o_topAddr; + } + + // Skip all of this checking if the input value is weird + if( i_topAddr == 0 ) + { + return o_topAddr; + } + + // Build up a list of possible memory ranges + std::vector<memGroups_t> l_memGroups; + + ATTR_PROC_MEM_BASES_type l_memBases = {0}; + ATTR_PROC_MEM_SIZES_type l_memSizes = {0}; + const size_t l_numGroups = sizeof(ATTR_PROC_MEM_SIZES_type) + /sizeof(l_memSizes[0]); + + TARGETING::TargetHandleList l_procList; + TARGETING::getAllChips(l_procList, TARGETING::TYPE_PROC); + assert(l_procList.size() != 0, "Empty proc list returned!"); + for (auto l_pProc : l_procList) + { + // Get the memory group ranges under this proc + assert(l_pProc->tryGetAttr<ATTR_PROC_MEM_BASES>(l_memBases), + "Unable to get ATTR_PROC_MEM_BASES attribute"); + assert(l_pProc->tryGetAttr<ATTR_PROC_MEM_SIZES>(l_memSizes), + "Unable to get ATTR_PROC_MEM_SIZES attribute"); + + for (size_t l_grp=0; l_grp < l_numGroups; l_grp++) + { + // Non-zero size means that there is memory present + if (l_memSizes[l_grp]) + { + memGroups_t l_mg; + l_mg.proc = l_pProc; + l_mg.membottom = l_memBases[l_grp]; + l_mg.memtop = l_memBases[l_grp] + l_memSizes[l_grp]; + l_mg.group = l_grp; + l_memGroups.push_back(l_mg); + } + } + } + + + // Loop through the groups from biggest to smallest + // l_top_homer_addr should hit the biggest one first, then we'll + // find the next biggest if the first match has a nvdimm in it. + std::sort( l_memGroups.begin(), l_memGroups.end(), compare_memGroups ); + for( auto l_memGroup : l_memGroups ) + { + bool l_foundNvdimm = false; + + // Get the array of mcas/group from the attribute + // The attr contains 8 8-bit entries, one entry per group + // The bits specify which mcas are included in the group + ATTR_MSS_MEM_MC_IN_GROUP_type l_memMcGroup = {0}; + assert(l_memGroup.proc->tryGetAttr<ATTR_MSS_MEM_MC_IN_GROUP> + (l_memMcGroup), + "Unable to get ATTR_MSS_MEM_MC_IN_GROUP attribute"); + + // Get list of mcas under this proc + TargetHandleList l_mcaList; + getChildAffinityTargets( l_mcaList, + l_memGroup.proc, + CLASS_UNIT, + TYPE_MCA ); + + // Loop through the mcas on this proc + for (const auto & l_mcaTarget : l_mcaList) + { + // Get the chip unit for this mca + ATTR_CHIP_UNIT_type l_mcaUnit = 0; + l_mcaUnit = l_mcaTarget->getAttr<ATTR_CHIP_UNIT>(); + + // Check if this mca is included in the memory group + const uint8_t l_mcMask = 0x80; + if (l_memMcGroup[l_memGroup.group] & (l_mcMask >> l_mcaUnit)) + { + // Get the list of dimms under this mca + TargetHandleList l_dimmList; + getChildAffinityTargets( l_dimmList, + l_mcaTarget, + CLASS_NA, + TYPE_DIMM ); + for (const auto & l_dimmTarget : l_dimmList) + { + if( isNVDIMM(l_dimmTarget) ) + { + l_foundNvdimm = true; + break; + } + } + if( l_foundNvdimm ) { break; } + } + } // for all MCAs + + // If we didn't find a nvdimm, we have a candidate for a valid + // top address + if( l_foundNvdimm ) + { + // Check if top addr is in this group's memory range + if( (o_topAddr >= l_memGroup.membottom) && + (o_topAddr <= l_memGroup.memtop) ) + { + TRACFCOMP(g_trac_nvdimm,"get_top_addr_with_no_nvdimms> Chosen address 0x%llX has nvdimms, cannot be used", + o_topAddr); + o_topAddr = 0; + } + } + else + { + // Since we are sorted by size, this must be the + // largest group without a nvdimm + if( o_topAddr != l_memGroup.memtop ) + { + o_topAddr = l_memGroup.memtop; + TRACFCOMP(g_trac_nvdimm,"get_top_addr_with_no_nvdimms> Choosing address 0x%llX as new top", + o_topAddr); + break; + } + } + } //for all memgroups + + assert( o_topAddr != 0, "get_top_addr_with_no_nvdimms> No valid memory group found without a NVDIMM" ); + + return o_topAddr; +} + + } // end namespace NVDIMM |