summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMatt Derksen <mderkse1@us.ibm.com>2019-06-27 15:03:42 -0500
committerDaniel M Crowell <dcrowell@us.ibm.com>2020-01-20 10:23:06 -0600
commit829e56fb1456d699806f8e69ebddf7835c1ae633 (patch)
tree1b92407305312ea3983f817c45866e8d98755ec6 /src
parent1cb00f7e0e9c6cd2646d7e0245a5f22ecf97ab0c (diff)
downloadtalos-hostboot-829e56fb1456d699806f8e69ebddf7835c1ae633.tar.gz
talos-hostboot-829e56fb1456d699806f8e69ebddf7835c1ae633.zip
NVDIMM: Use block write for nvdimm update
In an effort to speed up the nvdimm update, full 32-byte blocks can now be sent via I2C SMBUS with no initial byte count byte. Since a block write seems more prone to random system interrupt, this code should be restricted to run on v3.A or beyond which has the timeout increased to mitigate these interrupts. Test results have shown about a 5 minute improvement per NVDIMM. Change-Id: I040a5f2cc5afb76a73129ef9f6ac965cf36775f4 CQ: SW471053 Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/79678 Reviewed-by: Corey V Swenson <cswenson@us.ibm.com> Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com> Reviewed-by: TSUNG K YEUNG <tyeung@us.ibm.com> Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com> Tested-by: Jenkins OP HW <op-hw-jenkins+hostboot@us.ibm.com> Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com> Reviewed-by: Daniel M Crowell <dcrowell@us.ibm.com>
Diffstat (limited to 'src')
-rw-r--r--src/include/usr/devicefw/driverif.H3
-rw-r--r--src/include/usr/devicefw/userif.H19
-rwxr-xr-xsrc/usr/i2c/i2c.C55
-rw-r--r--src/usr/isteps/nvdimm/nvdimm_update.C106
-rw-r--r--src/usr/isteps/nvdimm/nvdimm_update.H15
-rwxr-xr-xsrc/usr/isteps/nvdimm/nvdimmdd.C39
-rwxr-xr-xsrc/usr/isteps/nvdimm/nvdimmdd.H4
7 files changed, 204 insertions, 37 deletions
diff --git a/src/include/usr/devicefw/driverif.H b/src/include/usr/devicefw/driverif.H
index 118e08973..66c420c21 100644
--- a/src/include/usr/devicefw/driverif.H
+++ b/src/include/usr/devicefw/driverif.H
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2019 */
+/* Contributors Listed Below - COPYRIGHT 2011,2020 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -104,6 +104,7 @@ namespace DeviceFW
I2C_SMBUS_BYTE = 4, ///< I2c SMBUS Read/Write Byte
I2C_SMBUS_SEND_OR_RECV = 5, ///< I2c SMBUS Send/Receive Byte
I2C_SMBUS_WORD_NO_PEC = 6, ///< I2c SMBUS Read/Write Word without PEC byte
+ I2C_SMBUS_BLOCK_NO_BYTE_COUNT = 7, ///< I2c SMBUS Block Read/Write without first byte being a byte count
};
#ifndef PARSER
diff --git a/src/include/usr/devicefw/userif.H b/src/include/usr/devicefw/userif.H
index 772511566..ec94bef32 100644
--- a/src/include/usr/devicefw/userif.H
+++ b/src/include/usr/devicefw/userif.H
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2019 */
+/* Contributors Listed Below - COPYRIGHT 2011,2020 */
/* [+] Google Inc. */
/* [+] International Business Machines Corp. */
/* */
@@ -393,6 +393,21 @@ namespace DeviceFW
/**
* @brief Construct the device addressing parameters for the
+ * NVDIMM RAW device ops + use block size specified
+ * @details This a raw call to read/write a NVDIMM address which means it
+ * will not set the page before it does the read/write call. Hence,
+ * for this call to work properly, the page must have been set
+ * properly beforehand.
+ * @see DEVICE_NVDIMM_ADDRESS for a NVDIMM read/write call with
+ * page setting.
+ * @param[i] i_address - NVDIMM address to an internal register
+ * @param[i] i_blockSize - maximum block size for operation (0 = default size, 2 and 32 valid)
+ */
+ #define DEVICE_NVDIMM_RAW_ADDRESS_WITH_BLOCKSIZE(i_address, i_blockSize)\
+ DeviceFW::NVDIMM_RAW, static_cast<uint64_t>((i_address)), static_cast<uint64_t>((i_blockSize))
+
+ /**
+ * @brief Construct the device addressing parameters for the
* NVDIMM RAW device ops.
* @details This a raw call to read/write a NVDIMM address which means it
* will not set the page before it does the read/write call. Hence,
@@ -403,7 +418,7 @@ namespace DeviceFW
* @param[i] i_address - NVDIMM address to an internal register
*/
#define DEVICE_NVDIMM_RAW_ADDRESS(i_address)\
- DeviceFW::NVDIMM_RAW, static_cast<uint64_t>((i_address))
+ DEVICE_NVDIMM_RAW_ADDRESS_WITH_BLOCKSIZE(i_address, 0)
/**
* Construct the device addressing parameters for the FAPI I2C operation
diff --git a/src/usr/i2c/i2c.C b/src/usr/i2c/i2c.C
index 226b96acf..2439f1eff 100755
--- a/src/usr/i2c/i2c.C
+++ b/src/usr/i2c/i2c.C
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2019 */
+/* Contributors Listed Below - COPYRIGHT 2011,2020 */
/* [+] Google Inc. */
/* [+] International Business Machines Corp. */
/* */
@@ -448,10 +448,11 @@ errlHndl_t i2cPerformOp( DeviceFW::OperationType i_opType,
// Else this is not a page operation, call the normal common function
else
{
- if( (subop==DeviceFW::I2C_SMBUS_BLOCK)
- || (subop==DeviceFW::I2C_SMBUS_BYTE)
- || (subop==DeviceFW::I2C_SMBUS_WORD)
- || (subop == DeviceFW::I2C_SMBUS_WORD_NO_PEC) )
+ if( (subop == DeviceFW::I2C_SMBUS_BLOCK)
+ || (subop == DeviceFW::I2C_SMBUS_BYTE)
+ || (subop == DeviceFW::I2C_SMBUS_WORD)
+ || (subop == DeviceFW::I2C_SMBUS_WORD_NO_PEC)
+ || (subop == DeviceFW::I2C_SMBUS_BLOCK_NO_BYTE_COUNT) )
{
args.smbus.commandCode =
static_cast<decltype(args.smbus.commandCode)>(
@@ -487,6 +488,11 @@ errlHndl_t i2cPerformOp( DeviceFW::OperationType i_opType,
args.smbus.usePec = false;
args.subop = DeviceFW::I2C_SMBUS_WORD;
}
+ else if (subop == DeviceFW::I2C_SMBUS_BLOCK_NO_BYTE_COUNT)
+ {
+ args.smbus.usePec = false;
+ args.subop=subop;
+ }
else
{
args.subop=subop;
@@ -1450,7 +1456,8 @@ errlHndl_t i2cCommonOp( DeviceFW::OperationType i_opType,
/*******************************************************/
/* Perform the I2C Operation */
/*******************************************************/
-
+ TRACUCOMP( g_trac_i2c, INFO_MRK "i2cCommonOp() -- opType: %d, subOp: %d",
+ static_cast<uint64_t>(i_opType), i_args.subop);
/***********************************************/
/* I2C SMBUS Send Byte */
/***********************************************/
@@ -1618,14 +1625,16 @@ errlHndl_t i2cCommonOp( DeviceFW::OperationType i_opType,
/***********************************************/
/* I2C SMBUS Block Write */
/***********************************************/
- else if( (i_opType == DeviceFW::WRITE )
- && (i_args.subop == DeviceFW::I2C_SMBUS_BLOCK))
+ else if( (i_opType == DeviceFW::WRITE ) &&
+ ((i_args.subop == DeviceFW::I2C_SMBUS_BLOCK) ||
+ (i_args.subop == DeviceFW::I2C_SMBUS_BLOCK_NO_BYTE_COUNT)) )
{
TRACUCOMP(g_trac_i2c, INFO_MRK
- "I2C SMBUS Block Write: Command code = 0x%02X, "
- "Use PEC = %d. io_buflen = %lu",
- i_args.smbus.commandCode,
- i_args.smbus.usePec, io_buflen);
+ "I2C SMBUS Block Write: Command code = 0x%02X, SubCmd = 0x%02X "
+ "Use PEC = %d. io_buflen = %lu, io_buffer byte0: 0x%02X",
+ i_args.smbus.commandCode, i_args.subop,
+ i_args.smbus.usePec, io_buflen,
+ *reinterpret_cast<uint8_t*>(io_buffer));
// If requested length is for < 1 byte or > 255 bytes for a block
// write transaction, throw an error.
@@ -1669,12 +1678,29 @@ errlHndl_t i2cCommonOp( DeviceFW::OperationType i_opType,
io_buflen,
io_buffer,
i_args.smbus.usePec);
+ void * writeStart = &blockWrite.commandCode;
+
+ // byteCount might be altered into commandCode, so store its value
+ size_t dataByteCount = blockWrite.byteCount;
+ if (i_args.subop == DeviceFW::I2C_SMBUS_BLOCK_NO_BYTE_COUNT)
+ {
+ // Moving commandCode down a byte so it is followed
+ // immediately by dataBytes[] instead of byteCount
+ // (this removes byteCount from the block write)
+ writeStart = &blockWrite.byteCount;
+ blockWrite.byteCount = blockWrite.commandCode;
+ blockWrite.messageSize -= sizeof(blockWrite.commandCode);
+ TRACUCOMP(g_trac_i2c, INFO_MRK
+ "I2C SMBUS Block Write no-byte-count: removing byteCount,"
+ " msgSize = %d", blockWrite.messageSize);
+ }
+
do {
size_t writeSize = blockWrite.messageSize;
const auto writeSizeExp = writeSize;
err = i2cWrite(i_target,
- &blockWrite.commandCode,
+ writeStart,
writeSize,
i_args);
if(err)
@@ -1686,7 +1712,8 @@ errlHndl_t i2cCommonOp( DeviceFW::OperationType i_opType,
"Write size mismatch; expected %d but got %d",
writeSizeExp,writeSize);
- io_buflen = blockWrite.byteCount;
+
+ io_buflen = dataByteCount;
} while(0);
diff --git a/src/usr/isteps/nvdimm/nvdimm_update.C b/src/usr/isteps/nvdimm/nvdimm_update.C
index dc5f7e693..6075a660f 100644
--- a/src/usr/isteps/nvdimm/nvdimm_update.C
+++ b/src/usr/isteps/nvdimm/nvdimm_update.C
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2018,2019 */
+/* Contributors Listed Below - COPYRIGHT 2018,2020 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -271,7 +271,8 @@ NvdimmInstalledImage::NvdimmInstalledImage(TARGETING::Target * i_nvDimm) :
iv_timeout(INVALID_TIMEOUT),
iv_max_blocks_per_region(INVALID_REGION_BLOCK_SIZE),
iv_fw_update_mode_enabled(false),
- iv_region_write_retries(0)
+ iv_region_write_retries(0),
+ iv_blockSizeSupported(INVALID_BLOCK_SIZE)
{
// initialize to invalid values
}
@@ -357,6 +358,46 @@ errlHndl_t NvdimmInstalledImage::getVersion(uint16_t & o_version,
return l_err;
}
+errlHndl_t NvdimmInstalledImage::getBlockWriteSizeSupported(uint64_t & o_blockSize)
+{
+ errlHndl_t l_err = nullptr;
+
+ do {
+ if (iv_blockSizeSupported == INVALID_BLOCK_SIZE)
+ {
+ uint16_t version = INVALID_VERSION;
+ l_err = getVersion(version, 0);
+ if (l_err)
+ {
+ TRACFCOMP(g_trac_nvdimm_upd, ERR_MRK"getBlockWriteSizeSupported: "
+ "Failed to get version for 0x%.8X NVDIMM",
+ TARGETING::get_huid(iv_dimm));
+ break;
+ }
+
+ // The block write is more prone to random system interrupt
+ // which does something funny to the i2c bus.
+ // v3.A has the timeout increased to mitigate that
+ if (version >= 0x3A00)
+ {
+ // version supports 32-byte block size
+ iv_blockSizeSupported = 32;
+ }
+ else
+ {
+ // default to word size max write
+ iv_blockSizeSupported = sizeof(uint16_t);
+ }
+ TRACFCOMP( g_trac_nvdimm_upd, ERR_MRK"getBlockWriteSizeSupported: "
+ "block size %d supported for 0x%.8X NVDIMM (version 0x%04X)",
+ iv_blockSizeSupported, TARGETING::get_huid(iv_dimm),
+ version );
+ }
+ } while (0);
+ o_blockSize = iv_blockSizeSupported;
+ return l_err;
+}
+
errlHndl_t NvdimmInstalledImage::updateImage(NvdimmLidImage * i_lidImage)
{
errlHndl_t l_err = nullptr;
@@ -1081,8 +1122,9 @@ errlHndl_t NvdimmInstalledImage::waitFwOpsBlockReceived()
{
errlHndl_t l_err = nullptr;
- // retry for a total of 100ms
- uint32_t timeout_ms_val = 100;
+ // retry for a total of 500ms
+ const uint32_t MAX_WAIT_FOR_OPS_BLOCK_RECEIVED = 500;
+ uint32_t timeout_ms_val = MAX_WAIT_FOR_OPS_BLOCK_RECEIVED;
bool blockReceived = false;
fw_ops_status_t opStatus;
@@ -1098,6 +1140,7 @@ errlHndl_t NvdimmInstalledImage::waitFwOpsBlockReceived()
TARGETING::get_huid(iv_dimm), timeout_ms_val);
break;
}
+
if (!opStatus.fw_ops_block_received)
{
// wait 1 millisecond between checking status
@@ -1122,6 +1165,12 @@ errlHndl_t NvdimmInstalledImage::waitFwOpsBlockReceived()
if (!blockReceived && !l_err)
{
+ TRACFCOMP(g_trac_nvdimm_upd, ERR_MRK"waitFwOpsBlockReceived: "
+ "NVDIMM 0x%.8X FIRMWARE_OPS_STATUS (timeout: %d ms) "
+ "-- Last status: 0x%02X",
+ TARGETING::get_huid(iv_dimm), MAX_WAIT_FOR_OPS_BLOCK_RECEIVED,
+ opStatus.whole);
+
/*@
*@errortype
*@moduleid WAIT_FW_OPS_BLOCK_RECEIVED
@@ -1142,7 +1191,7 @@ errlHndl_t NvdimmInstalledImage::waitFwOpsBlockReceived()
(
TWO_UINT8_TO_UINT16( 0x00,
opStatus.whole),
- 100,
+ MAX_WAIT_FOR_OPS_BLOCK_RECEIVED,
timeout_ms_val
),
ERRORLOG::ErrlEntry::NO_SW_CALLOUT );
@@ -1580,15 +1629,29 @@ errlHndl_t NvdimmInstalledImage::byteRegionBlockTransfer(const uint8_t * i_data,
TRACFCOMP(g_trac_nvdimm_upd, ERR_MRK"byteRegionBlockTransfer: "
"Unable to open page for BLOCK %d transfer of NVDIMM "
"0x%.8X", blockNum, TARGETING::get_huid(iv_dimm));
+ break;
}
size_t l_numBytes = BYTES_PER_BLOCK;
uint8_t l_reg_addr = ADDRESS(TYPED_BLOCK_DATA_BYTE0);
+
+ // Grab whether word or 32-byte block write is supported
+ uint64_t blockSizeSupported = INVALID_BLOCK_SIZE;
+ l_err = getBlockWriteSizeSupported(blockSizeSupported);
+ if (l_err)
+ {
+ TRACFCOMP(g_trac_nvdimm_upd, ERR_MRK"byteRegionBlockTransfer: "
+ "Unable to grab maximum block write size for NVDIMM 0x%.8X",
+ TARGETING::get_huid(iv_dimm));
+ break;
+ }
+
l_err = DeviceFW::deviceOp( DeviceFW::WRITE,
iv_dimm,
pCurrentBlockData,
l_numBytes,
- DEVICE_NVDIMM_RAW_ADDRESS(l_reg_addr) );
+ DEVICE_NVDIMM_RAW_ADDRESS_WITH_BLOCKSIZE(l_reg_addr, blockSizeSupported)
+ );
if (l_err)
{
TRACFCOMP(g_trac_nvdimm_upd, ERR_MRK"byteRegionBlockTransfer: "
@@ -1596,24 +1659,49 @@ errlHndl_t NvdimmInstalledImage::byteRegionBlockTransfer(const uint8_t * i_data,
blockNum, l_reg_addr, TARGETING::get_huid(iv_dimm));
break;
}
- // increment to next block
- pCurrentBlockData += BYTES_PER_BLOCK;
// After a block has been transferred, verify that the 32-byte block
// was received by polling FIRMWARE_OPS_STATUS offset for
// FIRMWARE_BLOCK_RECEIVED.
- TRACUCOMP(g_trac_nvdimm_upd, ">> waitFwOpsBlockReceived");
l_err = waitFwOpsBlockReceived();
if (l_err)
{
TRACFCOMP(g_trac_nvdimm_upd, ERR_MRK"byteRegionBlockTransfer: "
"Block %d read of FIRMWARE_OPS_STATUS failed on NVDIMM "
" 0x%.8X", blockNum, TARGETING::get_huid(iv_dimm));
+
+ size_t tmpNumBytes = l_numBytes;
+ uint8_t tmpBuffer[tmpNumBytes];
+ errlHndl_t l_err2 = DeviceFW::deviceOp( DeviceFW::READ,
+ iv_dimm,
+ tmpBuffer,
+ tmpNumBytes,
+ DEVICE_NVDIMM_ADDRESS(l_reg_addr) );
+ if (l_err2)
+ {
+ TRACFCOMP(g_trac_nvdimm_upd, ERR_MRK"byteRegionBlockTransfer: "
+ "Block %d read from 0x%02X failed on NVDIMM 0x%.8X",
+ blockNum, l_reg_addr, TARGETING::get_huid(iv_dimm));
+ l_err2->plid(l_err->plid());
+ l_err2->collectTrace(NVDIMM_COMP_NAME);
+ l_err2->collectTrace(NVDIMM_UPD);
+ errlCommit(l_err2, NVDIMM_COMP_ID);
+ break;
+ }
+ else
+ {
+ TRACFBIN(g_trac_nvdimm_upd, "byteRegionBlockTransfer: Wrote block", pCurrentBlockData, l_numBytes);
+ TRACFBIN(g_trac_nvdimm_upd, "byteRegionBlockTransfer: Read-back block", tmpBuffer, l_numBytes);
+ }
+
break;
}
// block of data successfully sent to NV controller
TRACUCOMP(g_trac_nvdimm_upd,"byteRegionBlockTransfer: block 0x%02X successfully sent to NV controller", blockNum);
+
+ // increment to next block
+ pCurrentBlockData += BYTES_PER_BLOCK;
blockNum++;
}
diff --git a/src/usr/isteps/nvdimm/nvdimm_update.H b/src/usr/isteps/nvdimm/nvdimm_update.H
index 1e48f7ef8..3f71dff56 100644
--- a/src/usr/isteps/nvdimm/nvdimm_update.H
+++ b/src/usr/isteps/nvdimm/nvdimm_update.H
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2018,2019 */
+/* Contributors Listed Below - COPYRIGHT 2018,2020 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -42,6 +42,7 @@ const uint16_t INVALID_ID = 0xFFFF;
const uint16_t INVALID_VERSION = 0xFFFF;
const uint16_t INVALID_TIMEOUT = 0xFFFF;
const uint32_t INVALID_TYPE = 0xFFFFFFFF;
+const uint8_t INVALID_BLOCK_SIZE = 0x00;
// Type is combination of manufacturer id and product id
const uint32_t SMART_NVDIMM_16GB_TYPE = 0x01945377;
@@ -245,6 +246,15 @@ class NvdimmInstalledImage
}
/**
+ * @brief Accessor for what write size is supported for this installed nvdimm
+ * Prior to level 0x3A, only word size supported
+ * Level 0x3A and beyond support 32 byte block writes
+ * @param[out] maximum number of bytes allowed per write
+ * @return block write size supported for this current nvdimm level
+ */
+ errlHndl_t getBlockWriteSizeSupported(uint64_t & o_blockSize);
+
+ /**
* @brief Update the current NV Controller
* @param Update using this image
* @return error pointer if failure to update, else nullptr
@@ -277,6 +287,9 @@ class NvdimmInstalledImage
// retry attempts for all regions
uint8_t iv_region_write_retries;
+ // what size block can be written (2 or 32 byte)
+ uint64_t iv_blockSizeSupported;
+
// Helper functions for updating the installed lid
/**
diff --git a/src/usr/isteps/nvdimm/nvdimmdd.C b/src/usr/isteps/nvdimm/nvdimmdd.C
index 5454fcb37..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. */
/* */
/* */
@@ -189,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()" );
@@ -399,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"
@@ -800,11 +801,13 @@ errlHndl_t nvdimmWrite ( TARGETING::Target * i_target,
// Setup a max-size buffer of writePageSize
size_t newBufLen = i_i2cInfo.writePageSize;
- // Break data into word size transfers if possible
- if ( (io_buflen > sizeof(uint16_t)) &&
- ((io_buflen % sizeof(uint16_t)) == 0) )
+ // 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 = sizeof(uint16_t);
+ newBufLen = i_i2cInfo.blockSize;
}
assert(newBufLen > 0, "Unable to allocate 0 buffer size for nvdimmWrite()");
@@ -937,15 +940,16 @@ errlHndl_t nvdimmWriteData( TARGETING::Target * i_target,
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++)
+ 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
@@ -966,6 +970,23 @@ errlHndl_t nvdimmWriteData( TARGETING::Target * i_target,
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,
diff --git a/src/usr/isteps/nvdimm/nvdimmdd.H b/src/usr/isteps/nvdimm/nvdimmdd.H
index 6a3f07be0..88bc388c0 100755
--- a/src/usr/isteps/nvdimm/nvdimmdd.H
+++ b/src/usr/isteps/nvdimm/nvdimmdd.H
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2019 */
+/* Contributors Listed Below - COPYRIGHT 2019,2020 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -69,6 +69,7 @@ struct nvdimm_addr_t
uint64_t devSize_KB; // in kilobytes
uint64_t chipCount; // number of chips making up nvdimm device
uint64_t writeCycleTime; // in milliseconds
+ uint8_t blockSize; // size of write block supported for this nvdimm
uint8_t i2cMuxBusSelector;
TARGETING::EntityPath i2cMuxPath;
@@ -86,6 +87,7 @@ struct nvdimm_addr_t
devSize_KB(0),
chipCount(0),
writeCycleTime(0),
+ blockSize(0),
i2cMuxBusSelector(I2C_MUX::NOT_APPLICABLE),
i2cMuxPath()
{
OpenPOWER on IntegriCloud