summaryrefslogtreecommitdiffstats
path: root/src/usr/isteps/nvdimm/nvdimmdd.C
diff options
context:
space:
mode:
Diffstat (limited to 'src/usr/isteps/nvdimm/nvdimmdd.C')
-rwxr-xr-xsrc/usr/isteps/nvdimm/nvdimmdd.C532
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
OpenPOWER on IntegriCloud