summaryrefslogtreecommitdiffstats
path: root/src/usr/i2c/eepromdd.C
diff options
context:
space:
mode:
Diffstat (limited to 'src/usr/i2c/eepromdd.C')
-rwxr-xr-xsrc/usr/i2c/eepromdd.C662
1 files changed, 662 insertions, 0 deletions
diff --git a/src/usr/i2c/eepromdd.C b/src/usr/i2c/eepromdd.C
new file mode 100755
index 000000000..e57647d27
--- /dev/null
+++ b/src/usr/i2c/eepromdd.C
@@ -0,0 +1,662 @@
+// IBM_PROLOG_BEGIN_TAG
+// This is an automatically generated prolog.
+//
+// $Source: src/usr/i2c/eepromdd.C $
+//
+// IBM CONFIDENTIAL
+//
+// COPYRIGHT International Business Machines Corp. 2011
+//
+// p1
+//
+// Object Code Only (OCO) source materials
+// Licensed Internal Code Source Materials
+// IBM HostBoot Licensed Internal Code
+//
+// The source code for this program is not published or other-
+// wise divested of its trade secrets, irrespective of what has
+// been deposited with the U.S. Copyright Office.
+//
+// Origin: 30
+//
+// IBM_PROLOG_END
+/**
+ * @file eepromdd.C
+ *
+ * @brief Implementation of the EEPROM device driver,
+ * which will access various EEPROMs within the
+ * system via the I2C device driver
+ *
+ */
+
+// ----------------------------------------------
+// Includes
+// ----------------------------------------------
+#include <string.h>
+#include <sys/time.h>
+
+#include <trace/interface.H>
+#include <errl/errlentry.H>
+#include <errl/errlmanager.H>
+#include <targeting/targetservice.H>
+#include <devicefw/driverif.H>
+#include <i2c/eepromddreasoncodes.H>
+
+#include "eepromdd.H"
+// ----------------------------------------------
+// Globals
+// ----------------------------------------------
+mutex_t g_eepromMutex;
+bool g_initEepromMutex = true;
+
+// ----------------------------------------------
+// Trace definitions
+// ----------------------------------------------
+trace_desc_t* g_trac_eeprom = NULL;
+TRAC_INIT( & g_trac_eeprom, "EEPROM", 4096 );
+
+trace_desc_t* g_trac_eepromr = NULL;
+TRAC_INIT( & g_trac_eepromr, "EEPROMR", 4096 );
+
+// Easy macro replace for unit testing
+//#define TRACUCOMP(args...) TRACFCOMP(args)
+#define TRACUCOMP(args...)
+// ----------------------------------------------
+// Defines
+// ----------------------------------------------
+#define MAX_BYTE_ADDR 2
+// ----------------------------------------------
+
+namespace EEPROM
+{
+
+// Register the perform Op with the routing code for Procs.
+DEVICE_REGISTER_ROUTE( DeviceFW::WILDCARD,
+ DeviceFW::EEPROM,
+ TARGETING::TYPE_PROC,
+ eepromPerformOp );
+
+// Register the perform Op with the routing code for DIMMs.
+DEVICE_REGISTER_ROUTE( DeviceFW::WILDCARD,
+ DeviceFW::EEPROM,
+ TARGETING::TYPE_DIMM,
+ eepromPerformOp );
+
+// Register the perform Op with the routing code for Memory Buffers.
+DEVICE_REGISTER_ROUTE( DeviceFW::WILDCARD,
+ DeviceFW::EEPROM,
+ TARGETING::TYPE_MEMBUF,
+ eepromPerformOp );
+
+// ------------------------------------------------------------------
+// eepromPerformOp
+// ------------------------------------------------------------------
+errlHndl_t eepromPerformOp( 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 err = NULL;
+ TARGETING::Target * theTarget = NULL;
+ eeprom_addr_t i2cInfo;
+ i2cInfo.deviceType = LAST_DEVICE_TYPE;
+
+ i2cInfo.addr = va_arg( i_args, uint64_t );
+ i2cInfo.chip = va_arg( i_args, uint64_t );
+
+ TRACDCOMP( g_trac_eeprom,
+ ENTER_MRK"eepromPerformOp()" );
+
+ do
+ {
+ if( g_initEepromMutex )
+ {
+ mutex_init( &g_eepromMutex );
+ g_initEepromMutex = false;
+ }
+
+ // Read Attributes needed to complete the operation
+ err = eepromReadAttributes( i_target,
+ i2cInfo );
+
+ if( err )
+ {
+ break;
+ }
+
+ // Check to see if we need to find a new target for
+ // the I2C Master
+ err = eepromGetI2CMasterTarget( i_target,
+ theTarget );
+
+ if( err )
+ {
+ break;
+ }
+
+ // Do the read or write
+ if( i_opType == DeviceFW::READ )
+ {
+ err = eepromRead( theTarget,
+ io_buffer,
+ io_buflen,
+ i2cInfo );
+
+ if( err )
+ {
+ break;
+ }
+ }
+ else if( i_opType == DeviceFW::WRITE )
+ {
+ err = eepromWrite( theTarget,
+ io_buffer,
+ io_buflen,
+ i2cInfo );
+
+ if( err )
+ {
+ break;
+ }
+ }
+ else
+ {
+ TRACFCOMP( g_trac_eeprom,
+ ERR_MRK"Invalid EEPROM Operation!" );
+
+ /*@
+ * @errortype
+ * @reasoncode EEPROM_INVALID_OPERATION
+ * @severity ERRL_SEV_UNRECOVERABLE
+ * @moduleid EEPROM_PERFORM_OP
+ * @userdata1 Operation Type
+ * @userdata2 Chip to Access
+ * @devdesc Invalid Operation type.
+ */
+ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ EEPROM_PERFORM_OP,
+ EEPROM_INVALID_OPERATION,
+ i_opType,
+ i2cInfo.chip );
+
+ break;
+ }
+ } while( 0 );
+
+ TRACDCOMP( g_trac_eeprom,
+ EXIT_MRK"eepromPerformOp() - %s",
+ ((NULL == err) ? "No Error" : "With Error") );
+
+ return err;
+} // end eepromPerformOp
+
+
+// ------------------------------------------------------------------
+// eepromRead
+// ------------------------------------------------------------------
+errlHndl_t eepromRead ( TARGETING::Target * i_target,
+ void * o_buffer,
+ size_t i_buflen,
+ eeprom_addr_t i_i2cInfo )
+{
+ errlHndl_t err = NULL;
+ uint8_t byteAddr[MAX_BYTE_ADDR];
+ size_t byteAddrSize = 0;
+ bool unlock = false;
+
+ TRACDCOMP( g_trac_eeprom,
+ ENTER_MRK"eepromRead()" );
+
+ do
+ {
+ TRACSCOMP( g_trac_eepromr,
+ "EEPROM READ START : Chip: %02d : Addr %.2X : Len %d",
+ i_i2cInfo.chip, i_i2cInfo.addr, i_buflen );
+
+ err = eepromPrepareAddress( &byteAddr,
+ byteAddrSize,
+ i_i2cInfo );
+
+ if( err )
+ {
+ break;
+ }
+
+ // Lock to sequence operations
+ mutex_lock( &g_eepromMutex );
+ unlock = true;
+
+ // Only write the byte address if we have data to write
+ if( 0 != byteAddrSize )
+ {
+ // Write the Byte Address of the Slave Device
+ err = deviceOp( DeviceFW::WRITE,
+ i_target,
+ &byteAddr,
+ byteAddrSize,
+ DEVICE_I2C_ADDRESS( i_i2cInfo.port,
+ i_i2cInfo.engine,
+ i_i2cInfo.devAddr ) );
+
+ if( err )
+ {
+ break;
+ }
+ }
+
+ // Do the actual read via I2C
+ err = deviceOp( DeviceFW::READ,
+ i_target,
+ o_buffer,
+ i_buflen,
+ DEVICE_I2C_ADDRESS( i_i2cInfo.port,
+ i_i2cInfo.engine,
+ i_i2cInfo.devAddr ) );
+
+ if( err )
+ {
+ break;
+ }
+
+ mutex_unlock( &g_eepromMutex );
+ unlock = false;
+
+ TRACSCOMP( g_trac_eepromr,
+ "EEPROM READ END : Chip: %02d : Addr %.2X : Len %d : %016llx",
+ i_i2cInfo.chip, i_i2cInfo.addr, i_buflen, *((uint64_t*)o_buffer) );
+ } while( 0 );
+
+ // Catch it if we break out early.
+ if( unlock )
+ {
+ mutex_unlock( & g_eepromMutex );
+ }
+
+ TRACDCOMP( g_trac_eeprom,
+ EXIT_MRK"eepromRead()" );
+
+ return err;
+} // end eepromRead
+
+
+// ------------------------------------------------------------------
+// eepromWrite
+// ------------------------------------------------------------------
+errlHndl_t eepromWrite ( TARGETING::Target * i_target,
+ void * io_buffer,
+ size_t io_buflen,
+ eeprom_addr_t i_i2cInfo )
+{
+ errlHndl_t err = NULL;
+ uint8_t byteAddr[MAX_BYTE_ADDR];
+ size_t byteAddrSize = 0;
+ uint8_t * newBuffer = NULL;
+ bool needFree = true;
+
+ TRACDCOMP( g_trac_eeprom,
+ ENTER_MRK"eepromWrite()" );
+
+ do
+ {
+ TRACSCOMP( g_trac_eepromr,
+ "EEPROM WRITE START : Chip: %02d : Addr %.2X : Len %d : %016llx",
+ i_i2cInfo.chip, i_i2cInfo.addr, io_buflen, *((uint64_t*)io_buffer) );
+
+ err = eepromPrepareAddress( &byteAddr,
+ byteAddrSize,
+ i_i2cInfo );
+
+ if( err )
+ {
+ break;
+ }
+
+ size_t newBufLen = byteAddrSize + io_buflen;
+ newBuffer = static_cast<uint8_t*>(malloc( newBufLen ));
+ needFree = true;
+
+ TRACFCOMP( g_trac_eeprom,
+ "OPIET: byteAddrSize: %d, io_buflen: %d, newBufLen: %d",
+ byteAddrSize, io_buflen, newBufLen );
+
+ // If we have an address to add to the buffer, do it now.
+ // Add the byte address to the buffer
+ memcpy( newBuffer, byteAddr, byteAddrSize );
+
+ // Now add the data the user wanted to write
+ memcpy( &newBuffer[byteAddrSize], io_buffer, io_buflen );
+
+ // Lock for operation sequencing
+ mutex_lock( &g_eepromMutex );
+
+ // Do the actual data write
+ err = deviceOp( DeviceFW::WRITE,
+ i_target,
+ newBuffer,
+ newBufLen,
+ DEVICE_I2C_ADDRESS( i_i2cInfo.port,
+ i_i2cInfo.engine,
+ i_i2cInfo.devAddr ) );
+
+ mutex_unlock( &g_eepromMutex );
+
+ if( err )
+ {
+ // Can't assume that anything was written if
+ // there was an error.
+ io_buflen = 0;
+ break;
+ }
+
+ io_buflen = newBufLen - byteAddrSize;
+
+ TRACSCOMP( g_trac_eepromr,
+ "EEPROM WRITE END : Chip: %02d : Addr %.2X : Len %d",
+ i_i2cInfo.chip, i_i2cInfo.addr, io_buflen );
+ } while( 0 );
+
+ // Free memory
+ if( needFree )
+ {
+ free( newBuffer );
+ }
+
+ TRACDCOMP( g_trac_eeprom,
+ EXIT_MRK"eepromWrite()" );
+
+ return err;
+} // end eepromWrite
+
+
+// ------------------------------------------------------------------
+// eepromPrepareAddress
+// ------------------------------------------------------------------
+errlHndl_t eepromPrepareAddress ( void * o_buffer,
+ size_t & o_bufSize,
+ eeprom_addr_t i_i2cInfo )
+{
+ errlHndl_t err = NULL;
+
+ o_bufSize = 0;
+
+ TRACDCOMP( g_trac_eeprom,
+ ENTER_MRK"eepromPrepareAddress()" );
+
+ do
+ {
+ // --------------------------------------------------------------------
+ // TODO - eventually there will be different I2C devices and the way
+ // they handle addressing. A new attribute will need to be added to
+ // EEPROM_ADDR_INFOx to indicate the device type so the addressing
+ // here can be handled properly.
+ //
+ // Until we get a different device, we'll just code for the 2 examples
+ // that I know of now.
+ // --------------------------------------------------------------------
+ switch( i_i2cInfo.deviceType )
+ {
+ case TWO_BYTE_ADDR:
+ o_bufSize = 2;
+ memset( o_buffer, 0x0, o_bufSize );
+ *((uint8_t*)o_buffer) = (i_i2cInfo.addr & 0xFF00ull) >> 8;
+ *((uint8_t*)o_buffer+1) = (i_i2cInfo.addr & 0x00FFull);
+ break;
+
+ case ONE_BYTE_ADDR:
+ o_bufSize = 1;
+ memset( o_buffer, 0x0, o_bufSize );
+ *((uint8_t*)o_buffer) = (i_i2cInfo.addr & 0xFFull);
+ break;
+
+ default:
+ TRACFCOMP( g_trac_eeprom,
+ ERR_MRK"eepromPrepareAddress() - Invalid device type: %08x",
+ i_i2cInfo.deviceType );
+
+ /*@
+ * @errortype
+ * @reasoncode EEPROM_INVALID_DEVICE_TYPE
+ * @severity ERRL_SEV_UNRECOVERABLE
+ * @moduleid EEPROM_PREPAREADDRESS
+ * @userdata1 Device Type
+ * @userdata2 <UNUSED>
+ * @devdesc The Device type was not recognized as one supported.
+ */
+ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ EEPROM_PREPAREADDRESS,
+ EEPROM_INVALID_DEVICE_TYPE,
+ i_i2cInfo.deviceType,
+ 0x0 );
+
+ break;
+ };
+
+ if( err )
+ {
+ break;
+ }
+ } while( 0 );
+
+ TRACDCOMP( g_trac_eeprom,
+ EXIT_MRK"eepromPrepareAddress()" );
+
+ return err;
+} // end eepromPrepareAddress
+
+
+// ------------------------------------------------------------------
+// eepromReadAttributes
+// ------------------------------------------------------------------
+errlHndl_t eepromReadAttributes ( TARGETING::Target * i_target,
+ eeprom_addr_t & o_i2cInfo )
+{
+ errlHndl_t err = NULL;
+
+ TRACDCOMP( g_trac_eeprom,
+ ENTER_MRK"eepromReadAttributes()" );
+
+ do
+ {
+ if( 0 == o_i2cInfo.chip )
+ {
+ // Read Attributes from EEPROM_ADDR_INFO0
+ TARGETING::EepromAddrInfo0 eepromData;
+ if( i_target->tryGetAttr<TARGETING::ATTR_EEPROM_ADDR_INFO0>( eepromData ) )
+ {
+ o_i2cInfo.port = eepromData.port;
+ o_i2cInfo.devAddr = eepromData.devAddr;
+ o_i2cInfo.engine = eepromData.engine;
+ // TODO - eventually read out the slave device type
+ o_i2cInfo.deviceType = TWO_BYTE_ADDR;
+ }
+ else
+ {
+ TRACFCOMP( g_trac_eeprom,
+ ERR_MRK"eepromReadAttributes() - ERROR reading attributes for "
+ "chip %d!",
+ o_i2cInfo.chip );
+
+ /*@
+ * @errortype
+ * @reasoncode EEPROM_ADDR_INFO0_NOT_FOUND
+ * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE
+ * @moduleid EEPROM_READATTRIBUTES
+ * @userdata1 EEPROM chip
+ * @userdata2 Attribute Enumeration
+ * @devdesc ATTR_EEPROM_ADDR_INFO0 Attribute was not found
+ */
+ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ EEPROM_READATTRIBUTES,
+ EEPROM_ADDR_INFO0_NOT_FOUND,
+ o_i2cInfo.chip,
+ TARGETING::ATTR_EEPROM_ADDR_INFO0 );
+
+ break;
+ }
+ }
+ else if( 1 == o_i2cInfo.chip )
+ {
+ // Read Attributes from EEPROM_ADDR_INFO1
+ TARGETING::EepromAddrInfo1 eepromData;
+ if( i_target->tryGetAttr<TARGETING::ATTR_EEPROM_ADDR_INFO1>( eepromData ) )
+ {
+ o_i2cInfo.port = eepromData.port;
+ o_i2cInfo.devAddr = eepromData.devAddr;
+ o_i2cInfo.engine = eepromData.engine;
+ // TODO - eventually read out the slave device type
+ o_i2cInfo.deviceType = TWO_BYTE_ADDR;
+ }
+ else
+ {
+ TRACFCOMP( g_trac_eeprom,
+ ERR_MRK"eepromReadAttributes() - ERROR reading attributes for "
+ "chip %d!",
+ o_i2cInfo.chip );
+
+ /*@
+ * @errortype
+ * @reasoncode EEPROM_ADDR_INFO1_NOT_FOUND
+ * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE
+ * @moduleid EEPROM_READATTRIBUTES
+ * @userdata1 EEPROM Chip
+ * @userdata2 Attribute Enum
+ * @devdesc ATTR_EEPROM_ADDR_INFO0 Attribute was not found
+ */
+ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ EEPROM_READATTRIBUTES,
+ EEPROM_ADDR_INFO1_NOT_FOUND,
+ o_i2cInfo.chip,
+ TARGETING::ATTR_EEPROM_ADDR_INFO1 );
+
+ break;
+ }
+ }
+ else
+ {
+ TRACFCOMP( g_trac_eeprom,
+ ERR_MRK"eepromReadAttributes() - Invalid chip (%d) to read "
+ "attributes from!",
+ o_i2cInfo.chip );
+
+ /*@
+ * @errortype
+ * @reasoncode EEPROM_INVALID_CHIP
+ * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE
+ * @moduleid EEPROM_READATTRIBUTES
+ * @userdata1 EEPROM Chip
+ * @userdata2 <UNUSED>
+ * @devdesc Invalid EEPROM chip to access
+ */
+ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ EEPROM_READATTRIBUTES,
+ EEPROM_INVALID_CHIP,
+ o_i2cInfo.chip,
+ 0x0 );
+
+ break;
+ }
+ } while( 0 );
+
+ TRACDCOMP( g_trac_eeprom,
+ EXIT_MRK"eepromReadAttributes()" );
+
+ return err;
+} // end eepromReadAttributes
+
+
+// ------------------------------------------------------------------
+// eepromGetI2CMasterTarget
+// ------------------------------------------------------------------
+errlHndl_t eepromGetI2CMasterTarget ( TARGETING::Target * i_target,
+ TARGETING::Target * &o_target )
+{
+ errlHndl_t err = NULL;
+ o_target = NULL;
+
+ TRACDCOMP( g_trac_eeprom,
+ ENTER_MRK"eepromGetI2CMasterTarget()" );
+
+ do
+ {
+ if( TARGETING::TYPE_DIMM == i_target->getAttr<TARGETING::ATTR_TYPE>() )
+ {
+ TARGETING::TargetService& tS = TARGETING::targetService();
+
+ // For DIMMs we need to get the parent that contains the
+ // I2C Master that talks to the DIMM EEPROM. Read the path
+ // from the attributes
+ TARGETING::EepromAddrInfo0 eepromData;
+ eepromData = i_target->getAttr<TARGETING::ATTR_EEPROM_ADDR_INFO0>();
+
+ // check that the path exists
+ bool exists = false;
+ tS.exists( eepromData.i2cMasterPath,
+ exists );
+
+ if( !exists )
+ {
+ TRACFCOMP( g_trac_eeprom,
+ ERR_MRK"eepromGetI2CMasterTarget() - i2cMasterPath attribute path "
+ "doesn't exist!" );
+
+ /*@
+ * @errortype
+ * @reasoncode EEPROM_DIMM_I2C_MASTER_PATH_ERROR
+ * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE
+ * @moduleid EEPROM_GETI2CMASTERTARGET
+ * @userdata1 Attribute Enum
+ * @userdata2 <UNUSED>
+ * @devdesc DIMM I2C Master Entity path doesn't exist.
+ */
+ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ EEPROM_GETI2CMASTERTARGET,
+ EEPROM_DIMM_I2C_MASTER_PATH_ERROR,
+ TARGETING::ATTR_EEPROM_ADDR_INFO0,
+ 0x0 );
+
+ break;
+ }
+
+ // Since it exists, convert to a target
+ o_target = tS.toTarget( eepromData.i2cMasterPath );
+
+ if( NULL == o_target )
+ {
+ TRACFCOMP( g_trac_eeprom,
+ ERR_MRK"eepromGetI2CMasterTarget() - Parent Processor target "
+ "was NULL!" );
+
+ /*@
+ * @errortype
+ * @reasoncode EEPROM_TARGET_NULL
+ * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE
+ * @moduleid EEPROM_GETI2CMASTERTARGET
+ * @userdata1 <UNUSED>
+ * @userdata2 <UNUSED>
+ * @devdesc Processor Target is NULL.
+ */
+ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ EEPROM_GETI2CMASTERTARGET,
+ EEPROM_TARGET_NULL,
+ 0x0,
+ 0x0 );
+
+ break;
+ }
+ }
+ else
+ {
+ // Since current target is not a DIMM, use the target we have
+ o_target = i_target;
+ }
+ } while( 0 );
+
+ TRACDCOMP( g_trac_eeprom,
+ EXIT_MRK"eepromGetI2CMasterTarget()" );
+
+ return err;
+} // end eepromGetI2CMasterTarget
+
+} // end namespace EEPROM
OpenPOWER on IntegriCloud