summaryrefslogtreecommitdiffstats
path: root/src/usr/i2c/eepromdd.C
diff options
context:
space:
mode:
authoraalugore <aalugore@us.ibm.com>2016-01-22 13:36:14 -0600
committerStephen Cprek <smcprek@us.ibm.com>2016-04-21 13:51:43 -0500
commit4f4f097d65e919bcc8bd5706f50ea0f413b8bfef (patch)
tree90030301032f3a87e952e5c161763bab0ad812be /src/usr/i2c/eepromdd.C
parent18e7af4cee8e4a9b88dee257edffb528b969ecd3 (diff)
downloadtalos-hostboot-4f4f097d65e919bcc8bd5706f50ea0f413b8bfef.tar.gz
talos-hostboot-4f4f097d65e919bcc8bd5706f50ea0f413b8bfef.zip
DDR4 - Allow SPD writes
-DDR4 has 512-byte EEPROM with 2 256-byte pages. This commit contains the necessary page switching logic to support this. Change-Id: Iaa8e3e344def98b71d6a9e9387c5e0d9137a0397 RTC:137707 ForwardPort: yes Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/797 Tested-by: Jenkins Server Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com> Tested-by: Jenkins OP Build CI Reviewed-by: William G. Hoffa <wghoffa@us.ibm.com> Tested-by: Jenkins OP HW Tested-by: FSP CI Jenkins Reviewed-by: Matthew A. Ploetz <maploetz@us.ibm.com> Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/871
Diffstat (limited to 'src/usr/i2c/eepromdd.C')
-rwxr-xr-xsrc/usr/i2c/eepromdd.C895
1 files changed, 650 insertions, 245 deletions
diff --git a/src/usr/i2c/eepromdd.C b/src/usr/i2c/eepromdd.C
index 55b136cc1..dc3eaa9cc 100755
--- a/src/usr/i2c/eepromdd.C
+++ b/src/usr/i2c/eepromdd.C
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2015 */
+/* Contributors Listed Below - COPYRIGHT 2011,2016 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -114,7 +114,7 @@ errlHndl_t eepromPerformOp( DeviceFW::OperationType i_opType,
va_list i_args )
{
errlHndl_t err = NULL;
- TARGETING::Target * theTarget = NULL;
+ TARGETING::Target * i2cMasterTarget = NULL;
eeprom_addr_t i2cInfo;
i2cInfo.chip = va_arg( i_args, uint64_t );
@@ -124,7 +124,7 @@ errlHndl_t eepromPerformOp( DeviceFW::OperationType i_opType,
ENTER_MRK"eepromPerformOp()" );
TRACUCOMP (g_trac_eeprom, ENTER_MRK"eepromPerformOp(): "
- "i_opType=%d, chip=%d, offset=%d, len=%d",
+ "i_opType=%d, chip=%d, offset=%x, len=%d",
(uint64_t) i_opType, i2cInfo.chip, i2cInfo.offset, io_buflen);
#ifdef __HOSTBOOT_RUNTIME
@@ -149,7 +149,7 @@ errlHndl_t eepromPerformOp( DeviceFW::OperationType i_opType,
// the I2C Master
err = eepromGetI2CMasterTarget( i_target,
i2cInfo,
- theTarget );
+ i2cMasterTarget );
if( err )
{
@@ -196,10 +196,10 @@ errlHndl_t eepromPerformOp( DeviceFW::OperationType i_opType,
#ifdef __HOSTBOOT_RUNTIME
// Disable Sensor Cache if the I2C master target is MEMBUF
- if( theTarget->getAttr<TARGETING::ATTR_TYPE>() ==
+ if( i2cMasterTarget->getAttr<TARGETING::ATTR_TYPE>() ==
TARGETING::TYPE_MEMBUF )
{
- err = I2C::i2cDisableSensorCache(theTarget,scacDisabled);
+ err = I2C::i2cDisableSensorCache(i2cMasterTarget,scacDisabled);
if ( err )
{
break;
@@ -210,7 +210,7 @@ errlHndl_t eepromPerformOp( DeviceFW::OperationType i_opType,
// Do the read or write
if( i_opType == DeviceFW::READ )
{
- err = eepromRead( theTarget,
+ err = eepromRead( i2cMasterTarget,
io_buffer,
io_buflen,
i2cInfo );
@@ -223,7 +223,7 @@ errlHndl_t eepromPerformOp( DeviceFW::OperationType i_opType,
}
else if( i_opType == DeviceFW::WRITE )
{
- err = eepromWrite( theTarget,
+ err = eepromWrite( i2cMasterTarget,
io_buffer,
io_buflen,
i2cInfo );
@@ -265,18 +265,18 @@ errlHndl_t eepromPerformOp( DeviceFW::OperationType i_opType,
// Re-enable sensor cache if it was disabled before the eeprom op and
// the I2C master target is MEMBUF
if( scacDisabled &&
- (theTarget->getAttr<TARGETING::ATTR_TYPE>() == TARGETING::TYPE_MEMBUF) )
+ (i2cMasterTarget->getAttr<TARGETING::ATTR_TYPE>() == TARGETING::TYPE_MEMBUF) )
{
errlHndl_t tmp_err = NULL;
- tmp_err = I2C::i2cEnableSensorCache(theTarget);
+ tmp_err = I2C::i2cEnableSensorCache(i2cMasterTarget);
if( err && tmp_err)
{
delete tmp_err;
TRACFCOMP(g_trac_eeprom,
ERR_MRK" Enable Sensor Cache failed for HUID=0x%.8X",
- TARGETING::get_huid(theTarget));
+ TARGETING::get_huid(i2cMasterTarget));
}
else if(tmp_err)
{
@@ -308,12 +308,11 @@ errlHndl_t eepromPerformOp( DeviceFW::OperationType i_opType,
//-------------------------------------------------------------------
bool eepromPresence ( TARGETING::Target * i_target )
{
-
- TRACDCOMP(g_trac_eeprom, ENTER_MRK"eepromPresence()");
+ TRACUCOMP(g_trac_eeprom, ENTER_MRK"eepromPresence()");
errlHndl_t err = NULL;
bool l_present = false;
- TARGETING::Target * theTarget = NULL;
+ TARGETING::Target * i2cMasterTarget = NULL;
eeprom_addr_t i2cInfo;
@@ -337,7 +336,7 @@ bool eepromPresence ( TARGETING::Target * i_target )
// the I2C Master
err = eepromGetI2CMasterTarget( i_target,
i2cInfo,
- theTarget );
+ i2cMasterTarget );
if( err )
{
@@ -347,7 +346,7 @@ bool eepromPresence ( TARGETING::Target * i_target )
}
//Check for the target at the I2C level
- l_present = I2C::i2cPresence(theTarget,
+ l_present = I2C::i2cPresence(i2cMasterTarget,
i2cInfo.port,
i2cInfo.engine,
i2cInfo.devAddr );
@@ -367,6 +366,126 @@ bool eepromPresence ( TARGETING::Target * i_target )
#endif
+
+// ------------------------------------------------------------------
+// eepromPageOp
+// ------------------------------------------------------------------
+errlHndl_t eepromPageOp( TARGETING::Target * i_target,
+ bool i_switchPage,
+ bool i_lockMutex,
+ bool & io_pageLocked,
+ uint8_t i_desiredPage,
+ eeprom_addr_t i_i2cInfo )
+{
+ TRACUCOMP(g_trac_eeprom,
+ ENTER_MRK"eepromPageOp()");
+
+ errlHndl_t l_err = NULL;
+ size_t l_placeHolderZero = 0;
+
+ do
+ {
+ // DDR4 requires EEPROM page to be selected before read/write operation.
+ // The following operation locks the EEPROM_PAGE attribute behind a
+ // mutex and switches all DIMMs on the I2C bus to the appropriate
+ // page.
+ if( i_i2cInfo.addrSize == ONE_BYTE_ADDR_PAGESELECT )
+ {
+
+ bool l_lockPage;
+ if( i_switchPage )
+ {
+ // we want to switch to the desired page
+ l_lockPage = true;
+ l_err = deviceOp( DeviceFW::WRITE,
+ i_target,
+ NULL,
+ l_placeHolderZero,
+ DEVICE_I2C_CONTROL_PAGE_OP(
+ i_i2cInfo.port,
+ i_i2cInfo.engine,
+ l_lockPage,
+ i_desiredPage,
+ i_lockMutex ));
+
+ if( l_err )
+ {
+ TRACFCOMP(g_trac_eeprom,
+ "eepromPageOp::Failed locking EEPROM page");
+ break;
+ }
+ // if we make it this far, we successfully locked the page mutex
+ io_pageLocked = true;
+ }
+ else
+ {
+ // we only want to unlock the page
+ l_lockPage = false;
+ l_err = deviceOp( DeviceFW::WRITE,
+ i_target,
+ NULL,
+ l_placeHolderZero,
+ DEVICE_I2C_CONTROL_PAGE_OP(
+ i_i2cInfo.port,
+ i_i2cInfo.engine,
+ l_lockPage,
+ l_placeHolderZero,
+ i_lockMutex ));
+
+ if( l_err )
+ {
+ TRACFCOMP( g_trac_eeprom,
+ "eepromPageOp()::failed unlocking EEPROM page");
+ break;
+ }
+ // if we make it this far, we successfully unlocked the page
+ io_pageLocked = false;
+ }
+ }
+ }while(0);
+ TRACUCOMP(g_trac_eeprom,
+ EXIT_MRK"eepromPageOp()");
+ return l_err;
+}
+
+
+// ------------------------------------------------------------------
+// crossesEepromPageBoundary
+// ------------------------------------------------------------------
+bool crossesEepromPageBoundary( uint64_t i_originalOffset,
+ size_t i_originalLen,
+ size_t & io_newLen,
+ size_t & o_pageTwoBuflen,
+ eeprom_addr_t i_i2cInfo )
+{
+ bool l_boundaryCrossed = false;
+ size_t l_higherBound = i_originalOffset + i_originalLen;
+
+ if( ( i_i2cInfo.addrSize == ONE_BYTE_ADDR_PAGESELECT ) &&
+ ( ( i_originalOffset < EEPROM_PAGE_SIZE ) &&
+ ( l_higherBound > EEPROM_PAGE_SIZE) ) )
+ {
+ // The read/write request crosses the boundary
+ l_boundaryCrossed = true;
+
+ // Calculate the new length of the page 0 buffer and the
+ // length of the page 1 buffer
+ o_pageTwoBuflen = l_higherBound - EEPROM_PAGE_SIZE;
+ io_newLen = i_originalLen - o_pageTwoBuflen;
+ }
+ else
+ {
+ // The read/write request does not cross the boundary.
+ // Update new length to be used by subsequent operations
+ io_newLen = i_originalLen;
+ o_pageTwoBuflen = 0;
+ }
+
+ return l_boundaryCrossed;
+}
+
+
+
// ------------------------------------------------------------------
// eepromRead
// ------------------------------------------------------------------
@@ -376,33 +495,194 @@ errlHndl_t eepromRead ( TARGETING::Target * i_target,
eeprom_addr_t i_i2cInfo )
{
errlHndl_t err = NULL;
- errlHndl_t err_NACK = NULL;
uint8_t byteAddr[MAX_BYTE_ADDR];
size_t byteAddrSize = 0;
- bool unlock = false;
+ bool l_pageLocked = false;
+ uint8_t l_desiredPage = 0;
+ bool l_boundaryCrossed = false;
+ size_t l_readBuflen = 0;
+ size_t l_pageTwoBuflen = 0;
- TRACDCOMP( g_trac_eeprom,
+ TRACUCOMP( g_trac_eeprom,
ENTER_MRK"eepromRead()" );
do
{
- TRACSCOMP( g_trac_eepromr,
+ TRACUCOMP( g_trac_eepromr,
"EEPROM READ START : Chip: %02d : Offset %.2X : Len %d",
i_i2cInfo.chip, i_i2cInfo.offset, i_buflen );
- err = eepromPrepareAddress( &byteAddr,
+
+ // Check to see if the Read operation straddles the EEPROM page
+ //boundary
+ l_boundaryCrossed = crossesEepromPageBoundary( i_i2cInfo.offset,
+ i_buflen,
+ l_readBuflen,
+ l_pageTwoBuflen,
+ i_i2cInfo );
+
+ // Set addressing parameters
+ err = eepromPrepareAddress( i_target,
+ &byteAddr,
byteAddrSize,
- i_i2cInfo );
+ l_desiredPage,
+ i_i2cInfo);
if( err )
{
+ TRACFCOMP(g_trac_eeprom,
+ ERR_MRK"eepromRead()::eepromPrepareAddress()");
+ break;
+ }
+
+
+ // Attempt to lock page mutex
+ bool l_switchPage = true;
+ bool l_lockMutex = true;
+ err = eepromPageOp( i_target,
+ l_switchPage,
+ l_lockMutex,
+ l_pageLocked,
+ l_desiredPage,
+ i_i2cInfo );
+
+ if( err )
+ {
+ TRACFCOMP(g_trac_eeprom,
+ "eepromRead()::eepromPageOp()::failed locking page");
break;
}
// Lock to sequence operations
mutex_lock( &g_eepromMutex );
- unlock = true;
+ // First Read. If Second read is necessary, this call will read
+ // everything from the original offset up to the 256th byte
+ err = eepromReadData( i_target,
+ o_buffer,
+ l_readBuflen,
+ &byteAddr,
+ byteAddrSize,
+ i_i2cInfo );
+ if( err )
+ {
+ TRACFCOMP(g_trac_eeprom,
+ "Failed reading data: original read");
+ break;
+ }
+
+
+ // Perform the second Read if necessary. Read starts at
+ // begining of EEPROM page 1 (offset=0x100) and reads the
+ // rest of the required data.
+ if( l_boundaryCrossed )
+ {
+ //Prepare the address to read at the start of EEPROM page one
+ i_i2cInfo.offset = EEPROM_PAGE_SIZE; // 0x100
+ err = eepromPrepareAddress( i_target,
+ &byteAddr,
+ byteAddrSize,
+ l_desiredPage,
+ i_i2cInfo );
+ if( err )
+ {
+ TRACFCOMP(g_trac_eeprom,
+ "Error preparing address: second eeprom read");
+ break;
+ }
+
+ // Switch to the second EEPROM page
+ l_switchPage = true;
+ l_lockMutex = false;
+ err = eepromPageOp( i_target,
+ l_switchPage,
+ l_lockMutex,
+ l_pageLocked,
+ l_desiredPage,
+ i_i2cInfo );
+
+ if( err )
+ {
+ TRACFCOMP( g_trac_eeprom,
+ "Failed switching to EEPROM page 1 for second read op");
+ break;
+ }
+
+ // Perform the second read operation
+ err = eepromReadData(
+ i_target,
+ &(reinterpret_cast<uint8_t*>(o_buffer)[l_readBuflen]),
+ l_pageTwoBuflen,
+ &byteAddr,
+ byteAddrSize,
+ i_i2cInfo );
+
+ if( err )
+ {
+ TRACFCOMP( g_trac_eeprom,
+ "Failed reading data: second read");
+ break;
+ }
+ }
+
+
+
+
+ TRACUCOMP( g_trac_eepromr,
+ "EEPROM READ END : Chip: %02d : Offset %.2X : Len %d : %016llx",
+ i_i2cInfo.chip, l_originalOffset, i_buflen,
+ *((uint64_t*)o_buffer) );
+
+ } while( 0 );
+
+ // Unlock eeprom mutex no matter what
+ mutex_unlock( & g_eepromMutex );
+
+ // Whether we failed in the main routine or not, unlock page iff the page is locked
+ if( l_pageLocked )
+ {
+ errlHndl_t l_pageOpErrl = NULL;
+ bool l_switchPage = false;
+ bool l_lockMutex = false;
+ l_pageOpErrl = eepromPageOp( i_target,
+ l_switchPage,
+ l_lockMutex,
+ l_pageLocked,
+ l_desiredPage,
+ i_i2cInfo );
+ if( l_pageOpErrl )
+ {
+ TRACFCOMP(g_trac_eeprom,
+ "eepromRead()::Failed unlocking page");
+ errlCommit(l_pageOpErrl, I2C_COMP_ID);
+ }
+
+ }
+
+ TRACUCOMP( g_trac_eeprom,
+ EXIT_MRK"eepromRead()" );
+
+ return err;
+} // end eepromRead
+
+
+// ------------------------------------------------------------------
+// eepromReadData
+// ------------------------------------------------------------------
+errlHndl_t eepromReadData( TARGETING::Target * i_target,
+ void * o_buffer,
+ size_t i_buflen,
+ void * i_byteAddress,
+ size_t i_byteAddressSize,
+ eeprom_addr_t i_i2cInfo )
+{
+ errlHndl_t l_err = NULL;
+ errlHndl_t err_NACK = NULL;
+
+ TRACUCOMP(g_trac_eeprom,
+ ENTER_MRK"eepromReadData()");
+ do
+ {
/***********************************************************/
/* Attempt read multiple times ONLY on NACK fails */
/***********************************************************/
@@ -412,10 +692,10 @@ errlHndl_t eepromRead ( TARGETING::Target * i_target,
{
// Only write the byte address if we have data to write
- if( 0 != byteAddrSize )
+ if( 0 != i_byteAddressSize )
{
// Use the I2C OFFSET Interface for the READ
- err = deviceOp( DeviceFW::READ,
+ l_err = deviceOp( DeviceFW::READ,
i_target,
o_buffer,
i_buflen,
@@ -423,18 +703,18 @@ errlHndl_t eepromRead ( TARGETING::Target * i_target,
i_i2cInfo.port,
i_i2cInfo.engine,
i_i2cInfo.devAddr,
- byteAddrSize,
- reinterpret_cast<uint8_t*>(&byteAddr)));
+ i_byteAddressSize,
+ reinterpret_cast<uint8_t*>(i_byteAddress)));
- if( err )
+ if( l_err )
{
TRACFCOMP(g_trac_eeprom,
- ERR_MRK"eepromRead(): I2C Read-Offset failed on "
+ ERR_MRK"eepromReadData(): I2C Read-Offset failed on "
"%d/%d/0x%X aS=%d",
i_i2cInfo.port, i_i2cInfo.engine,
- i_i2cInfo.devAddr, byteAddrSize);
- TRACFBIN(g_trac_eeprom, "byteAddr[]",
- &byteAddr, byteAddrSize);
+ i_i2cInfo.devAddr, i_byteAddressSize);
+ TRACFBIN(g_trac_eeprom, "i_byteAddress[]",
+ i_byteAddress, i_byteAddressSize);
// Don't break here -- error handled below
}
@@ -442,7 +722,7 @@ errlHndl_t eepromRead ( TARGETING::Target * i_target,
else
{
// Do the actual read via I2C
- err = deviceOp( DeviceFW::READ,
+ l_err = deviceOp( DeviceFW::READ,
i_target,
o_buffer,
i_buflen,
@@ -450,10 +730,10 @@ errlHndl_t eepromRead ( TARGETING::Target * i_target,
i_i2cInfo.engine,
i_i2cInfo.devAddr ) );
- if( err )
+ if( l_err )
{
TRACFCOMP(g_trac_eeprom,
- ERR_MRK"eepromRead(): I2C Read failed on "
+ ERR_MRK"eepromReadData(): I2C Read failed on "
"%d/%d/0x%0X", i_i2cInfo.port, i_i2cInfo.engine,
i_i2cInfo.devAddr);
@@ -461,21 +741,21 @@ errlHndl_t eepromRead ( TARGETING::Target * i_target,
}
}
- if ( err == NULL )
+ if ( l_err == NULL )
{
// Operation completed successfully
// break from retry loop
break;
}
- else if ( err->reasonCode() != I2C::I2C_NACK_ONLY_FOUND )
+ else if ( l_err->reasonCode() != I2C::I2C_NACK_ONLY_FOUND )
{
// Only retry on NACK failures: break from retry loop
- TRACFCOMP( g_trac_eeprom, ERR_MRK"eepromRead(): Non-Nack "
+ TRACFCOMP( g_trac_eeprom, ERR_MRK"eepromReadData(): Non-Nack "
"Error: rc=0x%X, tgt=0x%X, No Retry (retry=%d)",
- err->reasonCode(),
+ l_err->reasonCode(),
TARGETING::get_huid(i_target), retry);
- err->collectTrace(EEPROM_COMP_NAME);
+ l_err->collectTrace(EEPROM_COMP_NAME);
// break from retry loop
break;
@@ -489,9 +769,9 @@ errlHndl_t eepromRead ( TARGETING::Target * i_target,
if ( err_NACK == NULL )
{
// Save original NACK error
- err_NACK = err;
+ err_NACK = l_err;
- TRACFCOMP( g_trac_eeprom, ERR_MRK"eepromRead(): "
+ TRACFCOMP( g_trac_eeprom, ERR_MRK"eepromReadData(): "
"NACK Error rc=0x%X, eid=0x%X, tgt=0x%X, "
"retry/MAX=%d/%d. Save error and retry",
err_NACK->reasonCode(),
@@ -504,11 +784,11 @@ errlHndl_t eepromRead ( TARGETING::Target * i_target,
else
{
// Add data to original NACK error
- TRACFCOMP( g_trac_eeprom, ERR_MRK"eepromRead(): "
+ TRACFCOMP( g_trac_eeprom, ERR_MRK"eepromReadData(): "
"Another NACK Error rc=0x%X, eid=0x%X "
"plid=0x%X, tgt=0x%X, retry/MAX=%d/%d. "
"Delete error and retry",
- err->reasonCode(), err->eid(), err->plid(),
+ l_err->reasonCode(), l_err->eid(), l_err->plid(),
TARGETING::get_huid(i_target),
retry, EEPROM_MAX_NACK_RETRIES);
@@ -517,8 +797,8 @@ errlHndl_t eepromRead ( TARGETING::Target * i_target,
.addToLog(err_NACK);
// Delete this new NACK error
- delete err;
- err = NULL;
+ delete l_err;
+ l_err = NULL;
}
// continue to retry
@@ -526,14 +806,14 @@ errlHndl_t eepromRead ( TARGETING::Target * i_target,
}
else // no more retries: trace and break
{
- TRACFCOMP( g_trac_eeprom, ERR_MRK"eepromRead(): "
+ TRACFCOMP( g_trac_eeprom, ERR_MRK"eepromReadData(): "
"Error rc=0x%X, eid=%d, tgt=0x%X. No More "
"Retries (retry/MAX=%d/%d). Returning Error",
- err->reasonCode(), err->eid(),
+ l_err->reasonCode(), l_err->eid(),
TARGETING::get_huid(i_target),
retry, EEPROM_MAX_NACK_RETRIES);
- err->collectTrace(EEPROM_COMP_NAME);
+ l_err->collectTrace(EEPROM_COMP_NAME);
// break from retry loop
break;
@@ -545,12 +825,12 @@ errlHndl_t eepromRead ( TARGETING::Target * i_target,
// Handle saved NACK error, if any
if (err_NACK)
{
- if (err)
+ if (l_err)
{
// commit original NACK error with new err PLID
- err_NACK->plid(err->plid());
- TRACFCOMP(g_trac_eeprom, "eepromRead(): Committing saved NACK "
- "err eid=0x%X with plid of returned err: 0x%X",
+ err_NACK->plid(l_err->plid());
+ TRACFCOMP(g_trac_eeprom, "eepromReadData(): Committing saved NACK "
+ "l_err eid=0x%X with plid of returned err: 0x%X",
err_NACK->eid(), err_NACK->plid());
ERRORLOG::ErrlUserDetailsTarget(i_target)
@@ -561,7 +841,7 @@ errlHndl_t eepromRead ( TARGETING::Target * i_target,
else
{
// Since we eventually succeeded, delete original NACK error
- TRACFCOMP(g_trac_eeprom, "eepromRead(): Op successful, "
+ TRACFCOMP(g_trac_eeprom, "eepromReadData(): Op successful, "
"deleting saved NACK err eid=0x%X, plid=0x%X",
err_NACK->eid(), err_NACK->plid());
@@ -570,28 +850,13 @@ errlHndl_t eepromRead ( TARGETING::Target * i_target,
}
}
+ }while( 0 );
- mutex_unlock( &g_eepromMutex );
- unlock = false;
-
- TRACSCOMP( g_trac_eepromr,
- "EEPROM READ END : Chip: %02d : Offset %.2X : Len %d : %016llx",
- i_i2cInfo.chip, i_i2cInfo.offset, i_buflen,
- *((uint64_t*)o_buffer) );
-
- } while( 0 );
+ TRACUCOMP(g_trac_eeprom,
+ EXIT_MRK"eepromReadData");
+ return l_err;
+}
- // Catch it if we break out early.
- if( unlock )
- {
- mutex_unlock( & g_eepromMutex );
- }
-
- TRACDCOMP( g_trac_eeprom,
- EXIT_MRK"eepromRead()" );
-
- return err;
-} // end eepromRead
// ------------------------------------------------------------------
@@ -603,31 +868,62 @@ errlHndl_t eepromWrite ( TARGETING::Target * i_target,
eeprom_addr_t i_i2cInfo )
{
errlHndl_t err = NULL;
- errlHndl_t err_NACK = NULL;
+ uint8_t l_desiredPage = 0;
+ uint8_t l_originalPage = 0;
uint8_t byteAddr[MAX_BYTE_ADDR];
size_t byteAddrSize = 0;
uint8_t * newBuffer = NULL;
bool needFree = false;
bool unlock = false;
+ bool l_pageLocked = false;
uint32_t data_left = 0;
uint32_t diff_wps = 0;
+ size_t l_writeBuflen = 0;
+ size_t l_bytesIntoSecondPage = 0;
TRACDCOMP( g_trac_eeprom,
ENTER_MRK"eepromWrite()" );
do
{
- TRACSCOMP( g_trac_eepromr,
+ TRACUCOMP( g_trac_eeprom,
"EEPROM WRITE START : Chip: %02d : Offset %.2X : Len %d : %016llx",
i_i2cInfo.chip, i_i2cInfo.offset, io_buflen,
*((uint64_t*)io_buffer) );
- err = eepromPrepareAddress( &byteAddr,
+
+ // Prepare address parameters
+ err = eepromPrepareAddress( i_target,
+ &byteAddr,
byteAddrSize,
- i_i2cInfo );
+ l_desiredPage,
+ i_i2cInfo);
if( err )
{
+ TRACFCOMP(g_trac_eeprom,
+ ERR_MRK"eepromWrite()::eepromPrepareAddress()");
+ break;
+ }
+
+ // Save original Page
+ l_originalPage = l_desiredPage;
+ // Attempt to lock page mutex
+ bool l_switchPage = true; // true: Lock and switch page
+ // false: Just unlock page
+ bool l_lockMutex = true; // true: Lock mutex
+ // false: Skip locking mutex step
+ err = eepromPageOp( i_target,
+ l_switchPage,
+ l_lockMutex,
+ l_pageLocked,
+ l_desiredPage,
+ i_i2cInfo );
+
+ if( err )
+ {
+ TRACFCOMP(g_trac_eeprom,
+ "eepromWrite()::Failed locking EEPROM page");
break;
}
@@ -677,10 +973,7 @@ errlHndl_t eepromWrite ( TARGETING::Target * i_target,
size_t loop_data_length = 0;
size_t total_bytes_written = 0;
-
- for ( uint64_t i = 0 ;
- total_bytes_written < io_buflen ;
- i++ )
+ while( total_bytes_written < io_buflen )
{
// Determine how much data can be written in this loop
// Can't go over a writePageSize boundary
@@ -701,187 +994,91 @@ errlHndl_t eepromWrite ( TARGETING::Target * i_target,
loop_data_length );
+
+ // Check if loop_data_length crosses the EEPROM page boundary
+ crossesEepromPageBoundary( i_i2cInfo.offset,
+ loop_data_length,
+ l_writeBuflen,
+ l_bytesIntoSecondPage,
+ i_i2cInfo );
+
// Setup offset/address parms
- err = eepromPrepareAddress( &byteAddr,
- byteAddrSize,
- i_i2cInfo );
+ err = eepromPrepareAddress( i_target,
+ &byteAddr,
+ byteAddrSize,
+ l_desiredPage,
+ i_i2cInfo );
+
if( err )
{
+ TRACFCOMP(g_trac_eeprom,
+ ERR_MRK"eepromWrite::eepromPrepareAddress()::loop version");
break;
}
- TRACUCOMP(g_trac_eeprom,"eepromWrite() Loop: %d/%d/0x%X "
- "loop=%d, l_d_l=%d, offset=0x%X, bAS=%d, diffs=%d/%d",
- i_i2cInfo.port, i_i2cInfo.engine, i_i2cInfo.devAddr,
- i, loop_data_length, i_i2cInfo.offset, byteAddrSize,
- data_left, diff_wps);
-
- /***********************************************************/
- /* Attempt write multiple times ONLY on NACK fails */
- /***********************************************************/
- for (uint8_t retry = 0;
- retry <= EEPROM_MAX_NACK_RETRIES;
- retry++)
- {
- // Do the actual data write
- err = deviceOp( DeviceFW::WRITE,
- i_target,
- newBuffer,
- loop_data_length,
- DEVICE_I2C_ADDRESS_OFFSET(
- i_i2cInfo.port,
- i_i2cInfo.engine,
- i_i2cInfo.devAddr,
- byteAddrSize,
- reinterpret_cast<uint8_t*>(
- &byteAddr)));
- if ( err == NULL )
- {
- // Operation completed successfully
- // break from retry loop
- break;
- }
- else if ( err->reasonCode() != I2C::I2C_NACK_ONLY_FOUND )
+ // if desired page has changed mid-request, switch to correct page
+ if( l_desiredPage != l_originalPage )
+ {
+ l_switchPage = true;
+ l_lockMutex = false;
+ err = eepromPageOp( i_target,
+ l_switchPage,
+ l_lockMutex,
+ l_pageLocked,
+ l_desiredPage,
+ i_i2cInfo );
+ if( err )
{
- // Only retry on NACK failures: break from retry loop
- TRACFCOMP(g_trac_eeprom, ERR_MRK"eepromWrite(): I2C "
- "Write Non-NACK fail %d/%d/0x%X loop=%d, "
- "ldl=%d, offset=0x%X, aS=%d, retry=%d",
- i_i2cInfo.port, i_i2cInfo.engine,
- i_i2cInfo.devAddr, i, loop_data_length,
- i_i2cInfo.offset, i_i2cInfo.addrSize, retry);
-
- err->collectTrace(EEPROM_COMP_NAME);
-
- // break from retry loop
+ TRACFCOMP( g_trac_eeprom,
+ "Failed switching to new EEPROM page!");
break;
}
- else // Handle NACK error
- {
- TRACFCOMP(g_trac_eeprom, ERR_MRK"eepromWrite(): I2C "
- "Write NACK fail %d/%d/0x%X loop=%d, "
- "ldl=%d, offset=0x%X, aS=%d",
- i_i2cInfo.port, i_i2cInfo.engine,
- i_i2cInfo.devAddr, i, loop_data_length,
- i_i2cInfo.offset, i_i2cInfo.addrSize);
-
- // If op will be attempted again: save error and continue
- if ( retry < EEPROM_MAX_NACK_RETRIES )
- {
- // Only save original NACK error
- if ( err_NACK == NULL )
- {
- // Save original NACK error
- err_NACK = err;
-
- TRACFCOMP( g_trac_eeprom, ERR_MRK"eepromWrite(): "
- "Error rc=0x%X, eid=0x%X plid=0x%X, "
- "tgt=0x%X, retry/MAX=%d/%d. Save error "
- "and retry",
- err_NACK->reasonCode(),
- err_NACK->eid(),
- err_NACK->plid(),
- TARGETING::get_huid(i_target),
- retry, EEPROM_MAX_NACK_RETRIES);
-
- err_NACK->collectTrace(EEPROM_COMP_NAME);
- }
- else
- {
- // Add data to original NACK error
- TRACFCOMP( g_trac_eeprom, ERR_MRK"eepromWrite(): "
- "Another NACK Error rc=0x%X, eid=0x%X "
- "plid=0x%X, tgt=0x%X, retry/MAX=%d/%d. "
- "Delete error and retry",
- err->reasonCode(), err->eid(),
- err->plid(),
- TARGETING::get_huid(i_target),
- retry, EEPROM_MAX_NACK_RETRIES);
-
- ERRORLOG::ErrlUserDetailsString(
- "Another NACK ERROR found")
- .addToLog(err_NACK);
-
- // Delete this new NACK error
- delete err;
- err = NULL;
- }
-
- // continue to retry
- continue;
- }
- else // no more retries: trace and break
- {
- TRACFCOMP( g_trac_eeprom, ERR_MRK"eepromWrite(): "
- "Error rc=0x%X, tgt=0x%X. No More Retries "
- "(retry/MAX=%d/%d). Returning Error",
- err->reasonCode(),
- TARGETING::get_huid(i_target),
- retry, EEPROM_MAX_NACK_RETRIES);
-
- err->collectTrace(EEPROM_COMP_NAME);
-
- // break from retry loop
- break;
- }
- }
+ l_originalPage = l_desiredPage;
+ }
- } // end of retry loop
- /***********************************************************/
- // Handle saved NACK errors, if any
- if (err_NACK)
- {
- if (err)
- {
- // commit original NACK error with new err PLID
- err_NACK->plid(err->plid());
- TRACFCOMP(g_trac_eeprom, "eepromWrite(): Committing saved "
- "NACK err eid=0x%X with plid of returned err: "
- "0x%X",
- err_NACK->eid(), err_NACK->plid());
- ERRORLOG::ErrlUserDetailsTarget(i_target)
- .addToLog(err_NACK);
+ TRACUCOMP(g_trac_eeprom,"eepromWrite() Loop: %d/%d/0x%X "
+ "loop=%d, writeBuflen=%d, offset=0x%X, bAS=%d, diffs=%d/%d",
+ i_i2cInfo.port, i_i2cInfo.engine, i_i2cInfo.devAddr,
+ i, l_writeBuflen, i_i2cInfo.offset, byteAddrSize,
+ data_left, diff_wps);
- errlCommit(err_NACK, EEPROM_COMP_ID);
- }
- else
- {
- // Since we eventually succeeded, delete original NACK error
- TRACFCOMP(g_trac_eeprom, "eepromWrite(): Op successful, "
- "deleting saved NACK err eid=0x%X, plid=0x%X",
- err_NACK->eid(), err_NACK->plid());
- delete err_NACK;
- err_NACK = NULL;
- }
- }
+ // Perform the requested write operation
+ err = eepromWriteData( i_target,
+ newBuffer,
+ l_writeBuflen,
+ &byteAddr,
+ byteAddrSize,
+ i_i2cInfo );
if ( err )
{
// Can't assume that anything was written if
// there was an error, so no update to total_bytes_written
// for this loop
+ TRACFCOMP(g_trac_eeprom,
+ "Failed writing data: original eeprom write");
break;
}
// Wait for EEPROM to write data to its internal memory
// i_i2cInfo.writeCycleTime value in milliseconds
- nanosleep(0, i_i2cInfo.writeCycleTime * NS_PER_MSEC);
+ nanosleep( 0, i_i2cInfo.writeCycleTime * NS_PER_MSEC );
// Update how much data was written
- total_bytes_written += loop_data_length;
+ total_bytes_written += l_writeBuflen;
// Update offset
- i_i2cInfo.offset += loop_data_length;
+ i_i2cInfo.offset += l_writeBuflen;
TRACUCOMP(g_trac_eeprom,"eepromWrite() Loop %d End: "
- "l_d_l=%d, offset=0x%X, t_b_w=%d, io_buflen=%d",
- i, loop_data_length, i_i2cInfo.offset,
+ "writeBuflen=%d, offset=0x%X, t_b_w=%d, io_buflen=%d",
+ i, l_writeBuflen, i_i2cInfo.offset,
total_bytes_written, io_buflen);
} // end of write for-loop
@@ -890,14 +1087,10 @@ errlHndl_t eepromWrite ( TARGETING::Target * i_target,
mutex_unlock( &g_eepromMutex );
unlock = false;
+
// Set how much data was actually written
io_buflen = total_bytes_written;
- if( err )
- {
- // Leave do-while loop
- break;
- }
TRACSCOMP( g_trac_eepromr,
"EEPROM WRITE END : Chip: %02d : Offset %.2X : Len %d",
@@ -916,6 +1109,30 @@ errlHndl_t eepromWrite ( TARGETING::Target * i_target,
mutex_unlock( & g_eepromMutex );
}
+
+ // Whether we failed in the main routine or not, unlock the page iff it is already
+ // locked
+ if( l_pageLocked )
+ {
+ errlHndl_t l_pageOpErrl = NULL;
+
+ bool l_switchPage = false;
+ bool l_lockMutex = false;
+ l_pageOpErrl = eepromPageOp( i_target,
+ l_switchPage,
+ l_lockMutex,
+ l_pageLocked,
+ l_desiredPage,
+ i_i2cInfo );
+ if( l_pageOpErrl )
+ {
+ TRACFCOMP(g_trac_eeprom,
+ "eepromWrite()::Failed unlocking page");
+ errlCommit(l_pageOpErrl, I2C_COMP_ID);
+ }
+
+ }
+
TRACDCOMP( g_trac_eeprom,
EXIT_MRK"eepromWrite()" );
@@ -924,15 +1141,185 @@ errlHndl_t eepromWrite ( TARGETING::Target * i_target,
} // end eepromWrite
+
+// ------------------------------------------------------------------
+// eepromWriteData
+// ------------------------------------------------------------------
+errlHndl_t eepromWriteData( TARGETING::Target * i_target,
+ void * i_dataToWrite,
+ size_t i_dataLen,
+ void * i_byteAddress,
+ size_t i_byteAddressSize,
+ eeprom_addr_t i_i2cInfo )
+{
+ TRACDCOMP( g_trac_eeprom,
+ ENTER_MRK"eepromWriteData()");
+ errlHndl_t err = NULL;
+ errlHndl_t err_NACK = NULL;
+ do
+ {
+ /***********************************************************/
+ /* Attempt write multiple times ONLY on NACK fails */
+ /***********************************************************/
+ for (uint8_t retry = 0;
+ retry <= EEPROM_MAX_NACK_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)));
+
+
+ if ( err == NULL )
+ {
+ // Operation completed successfully
+ // break from retry loop
+ break;
+ }
+ else if ( err->reasonCode() != I2C::I2C_NACK_ONLY_FOUND )
+ {
+ // Only retry on NACK failures: break from retry loop
+ TRACFCOMP(g_trac_eeprom, ERR_MRK"eepromWriteData(): I2C "
+ "Write Non-NACK 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.offset, i_i2cInfo.addrSize, retry);
+
+ err->collectTrace(EEPROM_COMP_NAME);
+
+ // break from retry loop
+ break;
+ }
+ else // Handle NACK error
+ {
+ TRACFCOMP(g_trac_eeprom, ERR_MRK"eepromWriteData(): I2C "
+ "Write NACK 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);
+
+ // If op will be attempted again: save error and continue
+ if ( retry < EEPROM_MAX_NACK_RETRIES )
+ {
+ // Only save original NACK error
+ if ( err_NACK == NULL )
+ {
+ // Save original NACK error
+ err_NACK = err;
+
+ TRACFCOMP( g_trac_eeprom, ERR_MRK"eepromWriteData(): "
+ "Error rc=0x%X, eid=0x%X plid=0x%X, "
+ "tgt=0x%X, retry/MAX=%d/%d. Save error "
+ "and retry",
+ err_NACK->reasonCode(),
+ err_NACK->eid(),
+ err_NACK->plid(),
+ TARGETING::get_huid(i_target),
+ retry, EEPROM_MAX_NACK_RETRIES);
+
+ err_NACK->collectTrace(EEPROM_COMP_NAME);
+ }
+ else
+ {
+ // Add data to original NACK error
+ TRACFCOMP( g_trac_eeprom, ERR_MRK"eepromWriteData(): "
+ "Another NACK Error rc=0x%X, eid=0x%X "
+ "plid=0x%X, tgt=0x%X, retry/MAX=%d/%d. "
+ "Delete error and retry",
+ err->reasonCode(), err->eid(),
+ err->plid(),
+ TARGETING::get_huid(i_target),
+ retry, EEPROM_MAX_NACK_RETRIES);
+
+ ERRORLOG::ErrlUserDetailsString(
+ "Another NACK ERROR found")
+ .addToLog(err_NACK);
+
+ // Delete this new NACK error
+ delete err;
+ err = NULL;
+ }
+
+ // continue to retry
+ continue;
+ }
+ else // no more retries: trace and break
+ {
+ TRACFCOMP( g_trac_eeprom, ERR_MRK"eepromWriteData(): "
+ "Error rc=0x%X, tgt=0x%X. No More Retries "
+ "(retry/MAX=%d/%d). Returning Error",
+ err->reasonCode(),
+ TARGETING::get_huid(i_target),
+ retry, EEPROM_MAX_NACK_RETRIES);
+
+ err->collectTrace(EEPROM_COMP_NAME);
+
+ // break from retry loop
+ break;
+ }
+ }
+
+ } // end of retry loop
+ /***********************************************************/
+
+ // Handle saved NACK errors, if any
+ if (err_NACK)
+ {
+ if (err)
+ {
+ // commit original NACK error with new err PLID
+ err_NACK->plid(err->plid());
+ TRACFCOMP(g_trac_eeprom, "eepromWriteData(): Committing saved "
+ "NACK err eid=0x%X with plid of returned err: "
+ "0x%X",
+ err_NACK->eid(), err_NACK->plid());
+
+ ERRORLOG::ErrlUserDetailsTarget(i_target)
+ .addToLog(err_NACK);
+
+ errlCommit(err_NACK, EEPROM_COMP_ID);
+ }
+ else
+ {
+ // Since we eventually succeeded, delete original NACK error
+ TRACFCOMP(g_trac_eeprom, "eepromWriteData(): Op successful, "
+ "deleting saved NACK err eid=0x%X, plid=0x%X",
+ err_NACK->eid(), err_NACK->plid());
+
+ delete err_NACK;
+ err_NACK = NULL;
+ }
+ }
+ }while( 0 );
+ TRACDCOMP( g_trac_eeprom,
+ EXIT_MRK"eepromWriteData()");
+ return err;
+}
+
+
+
// ------------------------------------------------------------------
// eepromPrepareAddress
// ------------------------------------------------------------------
-errlHndl_t eepromPrepareAddress ( void * io_buffer,
+errlHndl_t eepromPrepareAddress ( TARGETING::Target * i_target,
+ void * io_buffer,
size_t & o_bufSize,
+ uint8_t & o_desiredPage,
eeprom_addr_t i_i2cInfo )
{
errlHndl_t err = NULL;
-
o_bufSize = 0;
TRACDCOMP( g_trac_eeprom,
@@ -954,6 +1341,21 @@ errlHndl_t eepromPrepareAddress ( void * io_buffer,
*((uint8_t*)io_buffer+1) = (i_i2cInfo.offset & 0x00FFull);
break;
+ case ONE_BYTE_ADDR_PAGESELECT:
+ // If the offset is less than 256 bytes, report page zero, else page 1
+ if( i_i2cInfo.offset >= EEPROM_PAGE_SIZE )
+ {
+ o_desiredPage = 1;
+ }
+ else
+ {
+ o_desiredPage = 0;
+ }
+ o_bufSize = 1;
+ memset( io_buffer, 0x0, o_bufSize );
+ *((uint8_t*)io_buffer) = (i_i2cInfo.offset & 0xFFull);
+ break;
+
case ONE_BYTE_ADDR:
o_bufSize = 1;
memset( io_buffer, 0x0, o_bufSize );
@@ -1058,7 +1460,6 @@ errlHndl_t eepromReadAttributes ( TARGETING::Target * i_target,
break;
case SBE_BACKUP:
-
if( (!i_target->
tryGetAttr<TARGETING::ATTR_EEPROM_SBE_BACKUP_INFO>
( reinterpret_cast<
@@ -1132,22 +1533,26 @@ errlHndl_t eepromReadAttributes ( TARGETING::Target * i_target,
}
// Successful reading of Attribute, so extract the data
- o_i2cInfo.port = eepromData.port;
- o_i2cInfo.devAddr = eepromData.devAddr;
- o_i2cInfo.engine = eepromData.engine;
- o_i2cInfo.i2cMasterPath = eepromData.i2cMasterPath;
- o_i2cInfo.writePageSize = eepromData.writePageSize;
- o_i2cInfo.devSize_KB = eepromData.maxMemorySizeKB;
+ o_i2cInfo.port = eepromData.port;
+ o_i2cInfo.devAddr = eepromData.devAddr;
+ o_i2cInfo.engine = eepromData.engine;
+ o_i2cInfo.i2cMasterPath = eepromData.i2cMasterPath;
+ o_i2cInfo.writePageSize = eepromData.writePageSize;
+ o_i2cInfo.devSize_KB = eepromData.maxMemorySizeKB;
o_i2cInfo.writeCycleTime = eepromData.writeCycleTime;
// Convert attribute info to eeprom_addr_size_t enum
- if ( eepromData.byteAddrOffset == 0x2 )
+ if ( eepromData.byteAddrOffset == 0x3 )
+ {
+ o_i2cInfo.addrSize = ONE_BYTE_ADDR;
+ }
+ else if ( eepromData.byteAddrOffset == 0x2 )
{
o_i2cInfo.addrSize = TWO_BYTE_ADDR;
}
else if ( eepromData.byteAddrOffset == 0x1 )
{
- o_i2cInfo.addrSize = ONE_BYTE_ADDR;
+ o_i2cInfo.addrSize = ONE_BYTE_ADDR_PAGESELECT;
}
else if ( eepromData.byteAddrOffset == 0x0 )
{
OpenPOWER on IntegriCloud