summaryrefslogtreecommitdiffstats
path: root/src/usr/spd
diff options
context:
space:
mode:
authorTerry J. Opie <opiet@us.ibm.com>2012-01-03 15:06:17 -0600
committerA. Patrick Williams III <iawillia@us.ibm.com>2012-01-31 13:06:56 -0600
commite5908dd4c110595e7c11d46009b07aa068dc19cd (patch)
treee0b7647123fbc87f4f459f909bb4f2be0da8f0dd /src/usr/spd
parent39b01da0087097401dea4d9a9f4e483734e751d8 (diff)
downloadtalos-hostboot-e5908dd4c110595e7c11d46009b07aa068dc19cd.tar.gz
talos-hostboot-e5908dd4c110595e7c11d46009b07aa068dc19cd.zip
SPD Device Driver
- JEDEC format for DDR3 - Testcases Change-Id: I8a9bf87335914d5cb824adb92f11546c37e5b423 Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/610 Tested-by: Jenkins Server Reviewed-by: Van H. Lee <vanlee@us.ibm.com> Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com>
Diffstat (limited to 'src/usr/spd')
-rw-r--r--src/usr/spd/dimmspd.datbin0 -> 256 bytes
-rw-r--r--src/usr/spd/makefile36
-rwxr-xr-xsrc/usr/spd/spd.C901
-rwxr-xr-xsrc/usr/spd/spd.H261
-rwxr-xr-xsrc/usr/spd/spdDDR3.H125
-rw-r--r--src/usr/spd/test/makefile28
-rwxr-xr-xsrc/usr/spd/test/spdtest.H413
7 files changed, 1764 insertions, 0 deletions
diff --git a/src/usr/spd/dimmspd.dat b/src/usr/spd/dimmspd.dat
new file mode 100644
index 000000000..8abf344bd
--- /dev/null
+++ b/src/usr/spd/dimmspd.dat
Binary files differ
diff --git a/src/usr/spd/makefile b/src/usr/spd/makefile
new file mode 100644
index 000000000..dc71eb1c8
--- /dev/null
+++ b/src/usr/spd/makefile
@@ -0,0 +1,36 @@
+# IBM_PROLOG_BEGIN_TAG
+# This is an automatically generated prolog.
+#
+# $Source: src/usr/spd/makefile $
+#
+# IBM CONFIDENTIAL
+#
+# COPYRIGHT International Business Machines Corp. 2012
+#
+# 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
+ROOTPATH = ../../..
+MODULE = spd
+
+OBJS = spd.o
+
+SUBDIRS = test.d
+
+DIMM_SPD_DATA = dimmspd.dat
+EXTRA_PARTS = $(addprefix $(IMGDIR)/, $(DIMM_SPD_DATA))
+
+include ${ROOTPATH}/config.mk
+
+${EXTRA_PARTS}: ${IMGDIR}/% : ./%
+ cp -f $^ $@
diff --git a/src/usr/spd/spd.C b/src/usr/spd/spd.C
new file mode 100755
index 000000000..0a1dc5bae
--- /dev/null
+++ b/src/usr/spd/spd.C
@@ -0,0 +1,901 @@
+// IBM_PROLOG_BEGIN_TAG
+// This is an automatically generated prolog.
+//
+// $Source: src/usr/spd/spd.C $
+//
+// IBM CONFIDENTIAL
+//
+// COPYRIGHT International Business Machines Corp. 2012
+//
+// 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 spd.C
+ *
+ * @brief Implementation of the SPD 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 <vfs/vfs.H>
+#include <spd/spdreasoncodes.H>
+#include <spd/spdenums.H>
+
+#include "spd.H"
+#include "spdDDR3.H"
+
+// ----------------------------------------------
+// Globals
+// ----------------------------------------------
+bool g_loadModule = true;
+mutex_t g_spdMutex = MUTEX_INITIALIZER;
+
+// ----------------------------------------------
+// Trace definitions
+// ----------------------------------------------
+trace_desc_t* g_trac_spd = NULL;
+TRAC_INIT( & g_trac_spd, "SPD", 4096 );
+
+// ------------------------
+// Macros for unit testing
+//#define TRACUCOMP(args...) TRACFCOMP(args)
+#define TRACUCOMP(args...)
+//#define TRACSSCOMP(args...) TRACFCOMP(args)
+#define TRACSSCOMP(args...)
+
+
+// ----------------------------------------------
+// Defines
+// ----------------------------------------------
+
+namespace SPD
+{
+
+// Register the perform Op with the routing code for DIMMs.
+DEVICE_REGISTER_ROUTE( DeviceFW::WILDCARD,
+ DeviceFW::SPD,
+ TARGETING::TYPE_DIMM,
+ spdAccess );
+
+// ------------------------------------------------------------------
+// spdRead
+// ------------------------------------------------------------------
+errlHndl_t spdAccess( 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;
+ uint64_t keyword = va_arg( i_args, uint64_t );
+
+ if( DeviceFW::READ == i_opType )
+ {
+ // Read the SPD keyword
+ err = spdGetKeywordValue( keyword,
+ io_buffer,
+ io_buflen,
+ i_target );
+ }
+ else
+ {
+ // Write the SPD keyword
+ err = spdWriteKeywordValue( keyword,
+ io_buffer,
+ io_buflen,
+ i_target );
+ }
+
+ return err;
+} // end spdRead
+
+
+// ------------------------------------------------------------------
+// spdGetKeywordValue
+// ------------------------------------------------------------------
+errlHndl_t spdGetKeywordValue ( uint64_t i_keyword,
+ void * io_buffer,
+ size_t & io_buflen,
+ TARGETING::Target * i_target )
+{
+ errlHndl_t err = NULL;
+
+ TRACSSCOMP( g_trac_spd,
+ ENTER_MRK"spdGetKeywordValue(), io_buflen: %d, keyword: 0x%04x",
+ io_buflen, i_keyword );
+
+ do
+ {
+ // Read the Basic Memory Type
+ uint8_t memType = 0x0;
+ err = spdFetchData( MEM_TYPE_ADDR,
+ MEM_TYPE_ADDR_SZ,
+ &memType,
+ i_target );
+
+ if( err )
+ {
+ break;
+ }
+
+ TRACDCOMP( g_trac_spd,
+ INFO_MRK"Mem Type: %04x",
+ memType );
+
+ // If the user wanted the Basic Memory Type, return this now
+ if( BASIC_MEMORY_TYPE == i_keyword )
+ {
+ io_buflen = MEM_TYPE_ADDR_SZ;
+ memcpy( io_buffer, &memType, io_buflen );
+ break;
+ }
+
+ // Check the Basic Memory Type to be sure its valid before
+ // continuing.
+ if( SPD_DDR3 == memType )
+ {
+ // Read the keyword value
+ err = spdGetValue( i_keyword,
+ io_buffer,
+ io_buflen,
+ i_target,
+ memType );
+
+ if( err )
+ {
+ break;
+ }
+ }
+ else
+ {
+ TRACFCOMP( g_trac_spd,
+ ERR_MRK"Invalid Basic Memory Type (0x%04x)",
+ memType );
+
+ /*@
+ * @errortype
+ * @reasoncode SPD_INVALID_BASIC_MEMORY_TYPE
+ * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE
+ * @moduleid SPD_GET_KEYWORD_VALUE
+ * @userdata1 Basic Memory Type (Byte 2)
+ * @userdata2 Keyword Requested
+ * @devdesc Invalid Basic Memory Type
+ */
+ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ SPD_GET_KEYWORD_VALUE,
+ SPD_INVALID_BASIC_MEMORY_TYPE,
+ memType,
+ i_keyword );
+ }
+ } while( 0 );
+
+ TRACSSCOMP( g_trac_spd,
+ EXIT_MRK"spdGetKeywordValue()" );
+
+ return err;
+}
+
+
+// ------------------------------------------------------------------
+// spdWriteKeywordValue
+// ------------------------------------------------------------------
+errlHndl_t spdWriteKeywordValue ( uint64_t i_keyword,
+ void * io_buffer,
+ size_t & io_buflen,
+ TARGETING::Target * i_target )
+{
+ errlHndl_t err = NULL;
+
+ TRACSSCOMP( g_trac_spd,
+ ENTER_MRK"spdWriteKeywordValue()" );
+
+ do
+ {
+ // TODO - This will be implemented with story 4659
+ TRACFCOMP( g_trac_spd,
+ ERR_MRK"SPD writes are not supported yet!" );
+
+ /*@
+ * @errortype
+ * @reasoncode SPD_NOT_SUPPORTED
+ * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE
+ * @moduleid SPD_WRITE_KEYWORD_VALUE
+ * @userdata1 i_keyword
+ * @userdata2 <UNUSED>
+ * @devdesc SPD Writes are not supported yet.
+ */
+ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ SPD_WRITE_KEYWORD_VALUE,
+ SPD_NOT_SUPPORTED,
+ i_keyword,
+ 0x0 );
+ break;
+ } while( 0 );
+
+ TRACSSCOMP( g_trac_spd,
+ EXIT_MRK"spdWriteKeywordValue()" );
+
+ return err;
+}
+
+
+// ------------------------------------------------------------------
+// spdFetchData
+// ------------------------------------------------------------------
+errlHndl_t spdFetchData ( uint64_t i_byteAddr,
+ size_t i_numBytes,
+ void * o_data,
+ TARGETING::Target * i_target )
+{
+ errlHndl_t err = NULL;
+
+ TRACSSCOMP( g_trac_spd,
+ ENTER_MRK"spdFetchData()" );
+
+ do
+ {
+ // ---------------------------------------------------------------
+ // TODO - For now, we will use a generic name of dimmspd.dat, and
+ // access the file via vfs for all SPD content for ALL DIMMs.
+ //
+ // Unfortunately Fsp will not be able to write into our file
+ // space in PNOR because the files/names will need to be signed.
+ // This means that eventually there will be block of data in PNOR
+ // where each DIMMs, and potential DIMM, information will be at
+ // a given offset.
+ // ---------------------------------------------------------------
+
+ err = spdReadBinaryFile( i_byteAddr,
+ i_numBytes,
+ o_data );
+
+ if( err )
+ {
+ break;
+ }
+ } while( 0 );
+
+ TRACSSCOMP( g_trac_spd,
+ EXIT_MRK"spdFetchData()" );
+
+ return err;
+}
+
+
+// ------------------------------------------------------------------
+// spdGetValue
+// ------------------------------------------------------------------
+errlHndl_t spdGetValue ( uint64_t i_keyword,
+ void * io_buffer,
+ size_t & io_buflen,
+ TARGETING::Target * i_target,
+ uint64_t i_DDRRev )
+{
+ errlHndl_t err = NULL;
+ uint8_t * tmpBuffer = static_cast<uint8_t *>(io_buffer);
+ KeywordData * kwdData;
+ uint32_t arraySize = 0x0;
+
+ TRACSSCOMP( g_trac_spd,
+ ENTER_MRK"spdGetValue()" );
+
+ do
+ {
+ if( SPD_DDR3 == i_DDRRev )
+ {
+ kwdData = ddr3Data;
+ arraySize = (sizeof(ddr3Data)/sizeof(ddr3Data[0]));
+
+ }
+ else
+ {
+ TRACFCOMP( g_trac_spd,
+ ERR_MRK"Unsupported DDRx Revision (0x%04x)",
+ i_DDRRev );
+
+ /*@
+ * @errortype
+ * @reasoncode SPD_INVALID_BASIC_MEMORY_TYPE
+ * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE
+ * @moduleid SPD_GET_VALUE
+ * @userdata1 SPD Keyword
+ * @userdata2 The DDR Revision
+ * @devdesc Invalid DDR Revision
+ */
+ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ SPD_GET_VALUE,
+ SPD_INVALID_BASIC_MEMORY_TYPE,
+ i_keyword,
+ i_DDRRev );
+
+ break;
+ }
+
+ // TODO - A binary_search algorithm will be implemented with
+ // Story 4709.
+ // Loop through the lookup table.
+ bool keywordFound = false;
+ for( uint32_t i = 0; i < arraySize; i++ )
+ {
+ if( kwdData[i].keyword == i_keyword )
+ {
+ keywordFound = true;
+
+ if( kwdData[i].isSpecialCase )
+ {
+ // Handle special cases where data isn't sequential
+ // or is in reverse order from what would be read.
+ err = spdSpecialCases( i_keyword,
+ io_buffer,
+ io_buflen,
+ i_target,
+ i,
+ i_DDRRev );
+
+ break;
+ }
+
+ // Check io_buflen versus size in table
+ err = spdCheckSize( io_buflen,
+ kwdData[i].length,
+ i_keyword );
+
+ if( err )
+ {
+ break;
+ }
+
+ // Read length requested
+ err = spdFetchData( kwdData[i].offset,
+ kwdData[i].length,
+ tmpBuffer,
+ i_target );
+
+ if( err )
+ {
+ break;
+ }
+
+ // if useBitmask set, mask and then shift data
+ if( kwdData[i].useBitMask )
+ {
+ // Any bit mask/shifting will always be on a <1 Byte value
+ // thus, we touch only byte 0.
+ tmpBuffer[0] = tmpBuffer[0] & kwdData[i].bitMask;
+ tmpBuffer[0] = tmpBuffer[0] >> kwdData[i].shift;
+ }
+
+ // Set length read
+ io_buflen = kwdData[i].length;
+ break;
+ }
+ }
+
+ if( err )
+ {
+ break;
+ }
+
+ if( !keywordFound )
+ {
+ TRACFCOMP( g_trac_spd,
+ ERR_MRK"Could not find keyword (0x%04x) in lookup table!",
+ i_keyword );
+
+ /*@
+ * @errortype
+ * @reasoncode SPD_KEYWORD_NOT_FOUND
+ * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE
+ * @moduleid SPD_GET_VALUE
+ * @userdata1 SPD Keyword
+ * @userdata2 <UNUSED>
+ * @devdesc Invalid SPD Keyword
+ */
+ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ SPD_GET_VALUE,
+ SPD_KEYWORD_NOT_FOUND,
+ i_keyword,
+ 0x0 );
+ break;
+ }
+ } while( 0 );
+
+ if( err )
+ {
+ // Signal the caller that there was an error getting
+ // data and that there is no valid data.
+ io_buflen = 0;
+ }
+
+ TRACSSCOMP( g_trac_spd,
+ EXIT_MRK"spdGetValue()" );
+
+ return err;
+}
+
+
+// ------------------------------------------------------------------
+// spdSpecialCases
+// ------------------------------------------------------------------
+errlHndl_t spdSpecialCases ( uint64_t i_keyword,
+ void * io_buffer,
+ size_t & io_buflen,
+ TARGETING::Target * i_target,
+ uint64_t i_entry,
+ uint64_t i_DDRRev )
+{
+ errlHndl_t err = NULL;
+ uint8_t * tmpBuffer = static_cast<uint8_t *>(io_buffer);
+
+ TRACSSCOMP( g_trac_spd,
+ ENTER_MRK"spdSpecialCases()" );
+
+ do
+ {
+ // Handle each of the special cases here
+ if( SPD_DDR3 == i_DDRRev )
+ {
+ switch( i_keyword )
+ {
+ case CAS_LATENCIES_SUPPORTED:
+ // Length 2 bytes
+ // Byte 0x0e [7:0]
+ // Byte 0x0f [6:0] - MSB
+
+ // Check Size of buffer
+ err = spdCheckSize( io_buflen,
+ 2,
+ i_keyword );
+
+ if( err ) break;
+
+ // Get MSB
+ err = spdFetchData( ddr3Data[i_entry].offset,
+ 1, /* Read 1 byte at a time */
+ &tmpBuffer[0],
+ i_target );
+
+ if( err ) break;
+
+ // Mask and shift if needed
+ if( ddr3Data[i_entry].useBitMask )
+ {
+ tmpBuffer[0] = tmpBuffer[0] & ddr3Data[i_entry].bitMask;
+ tmpBuffer[0] = tmpBuffer[0] >> ddr3Data[i_entry].shift;
+ }
+
+ // Get LSB
+ err = spdFetchData( 0x0e,
+ 1, /* Read 1 byte at a time */
+ &tmpBuffer[1],
+ i_target );
+
+ if( err ) break;
+
+ // Set number of bytes read
+ io_buflen = 2;
+ break;
+
+ case TRC_MIN:
+ // Length 2 bytes
+ // Byte 0x15 [7:4] - MSB
+ // Byte 0x17 [7:0]
+
+ // Check Size of buffer
+ err = spdCheckSize( io_buflen,
+ 2,
+ i_keyword );
+
+ if( err ) break;
+
+ // Get MSB
+ err = spdFetchData( ddr3Data[i_entry].offset,
+ 1, /* Read 1 byte at a time */
+ &tmpBuffer[0],
+ i_target );
+
+ if( err ) break;
+
+ // Mask and shift if needed
+ if( ddr3Data[i_entry].useBitMask )
+ {
+ tmpBuffer[0] = tmpBuffer[0] & ddr3Data[i_entry].bitMask;
+ tmpBuffer[0] = tmpBuffer[0] >> ddr3Data[i_entry].shift;
+ }
+
+ // Get LSB
+ err = spdFetchData( 0x17,
+ 1, /* Read 1 byte at a time */
+ &tmpBuffer[1],
+ i_target );
+
+ if( err ) break;
+
+ // Set number of bytes read
+ io_buflen = 2;
+ break;
+
+ case TRAS_MIN:
+ // Length 2 bytes
+ // Byte 0x15 [3:0] - MSB
+ // Byte 0x16 [7:0]
+
+ // Check size of buffer
+ err = spdCheckSize( io_buflen,
+ 2,
+ i_keyword );
+
+ if( err ) break;
+
+ // Get MSB
+ err = spdFetchData( ddr3Data[i_entry].offset,
+ 1, /* Read 1 byte at a time */
+ &tmpBuffer[0],
+ i_target );
+
+ if( err ) break;
+
+ // Mask and shift if needed
+ if( ddr3Data[i_entry].useBitMask )
+ {
+ tmpBuffer[0] = tmpBuffer[0] & ddr3Data[i_entry].bitMask;
+ tmpBuffer[0] = tmpBuffer[0] >> ddr3Data[i_entry].shift;
+ }
+
+ // Get LSB
+ err = spdFetchData( 0x16,
+ 1, /* Read 1 byte at a time */
+ &tmpBuffer[1],
+ i_target );
+
+ if( err ) break;
+
+ // Set number of bytes read
+ io_buflen = 2;
+ break;
+
+ case TRFC_MIN:
+ // Length 2 bytes
+ // Byte 0x18 [7:0]
+ // Byte 0x19 [7:0] - MSB
+
+ // Check size of buffer
+ err = spdCheckSize( io_buflen,
+ 2,
+ i_keyword );
+
+ if( err ) break;
+
+ // Get MSB
+ err = spdFetchData( ddr3Data[i_entry].offset,
+ 1, /* Read 1 byte at a time */
+ &tmpBuffer[0],
+ i_target );
+
+ if( err ) break;
+
+ // Mask and shift if needed
+ if( ddr3Data[i_entry].useBitMask )
+ {
+ tmpBuffer[0] = tmpBuffer[0] & ddr3Data[i_entry].bitMask;
+ tmpBuffer[0] = tmpBuffer[0] >> ddr3Data[i_entry].shift;
+ }
+
+ // Get LSB
+ err = spdFetchData( 0x18,
+ 1, /* Read 1 byte at a time */
+ &tmpBuffer[1],
+ i_target );
+
+ if( err ) break;
+
+ // Set number of bytes read
+ io_buflen = 2;
+ break;
+
+ case TFAW_MIN:
+ // Length 2 bytes
+ // Byte 0x1c [3:0] - MSB
+ // byte 0x1d [7:0]
+
+ // Check size of buffer
+ err = spdCheckSize( io_buflen,
+ 2,
+ i_keyword );
+
+ if( err ) break;
+
+ // Get MSB
+ err = spdFetchData( ddr3Data[i_entry].offset,
+ 1, /* Read 1 byte at a time */
+ &tmpBuffer[0],
+ i_target );
+
+ if( err ) break;
+
+ // Mask and shift if needed
+ if( ddr3Data[i_entry].useBitMask )
+ {
+ tmpBuffer[0] = tmpBuffer[0] & ddr3Data[i_entry].bitMask;
+ tmpBuffer[0] = tmpBuffer[0] >> ddr3Data[i_entry].shift;
+ }
+
+ // Get LSB
+ err = spdFetchData( 0x1d,
+ 1, /* Read 1 byte at a time */
+ &tmpBuffer[1],
+ i_target );
+
+ if( err ) break;
+
+ // Set number of bytes read
+ io_buflen = 2;
+ break;
+
+ case MODULE_MANUFACTURER_ID:
+ // Length 2 bytes
+ // Byte 0x75 [7:0]
+ // Byte 0x76 [7:0] - MSB
+
+
+ // Check size of buffer
+ err = spdCheckSize( io_buflen,
+ 2,
+ i_keyword );
+
+ if( err ) break;
+
+ // Get MSB
+ err = spdFetchData( ddr3Data[i_entry].offset,
+ 1, /* Read 1 byte at a time */
+ &tmpBuffer[0],
+ i_target );
+
+ if( err ) break;
+
+ // Mask and shift if needed
+ if( ddr3Data[i_entry].useBitMask )
+ {
+ tmpBuffer[0] = tmpBuffer[0] & ddr3Data[i_entry].bitMask;
+ tmpBuffer[0] = tmpBuffer[0] >> ddr3Data[i_entry].shift;
+ }
+
+ // Get LSB
+ err = spdFetchData( 0x75,
+ 1, /* Read 1 byte at a time */
+ &tmpBuffer[1],
+ i_target );
+
+ if( err ) break;
+
+ // Set number of bytes read
+ io_buflen = 2;
+ break;
+
+ default:
+ TRACFCOMP( g_trac_spd,
+ ERR_MRK"Unknown keyword (0x%04x) for DDR3 special cases!",
+ i_keyword );
+
+ /*@
+ * @errortype
+ * @reasoncode SPD_INVALID_SPD_KEYWORD
+ * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE
+ * @moduleid SPD_SPECIAL_CASES
+ * @userdata1 SPD Keyword
+ * @userdata2 Table Entry
+ * @devdesc Keyword is not a special case keyword.
+ */
+ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ SPD_SPECIAL_CASES,
+ SPD_INVALID_SPD_KEYWORD,
+ i_keyword,
+ i_entry );
+ break;
+ };
+ }
+ else
+ {
+ TRACFCOMP( g_trac_spd,
+ ERR_MRK"Unsupported DDRx Revision (0x%04x)",
+ i_DDRRev );
+
+ /*@
+ * @errortype
+ * @reasoncode SPD_INVALID_BASIC_MEMORY_TYPE
+ * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE
+ * @moduleid SPD_SPECIAL_CASES
+ * @userdata1 SPD Keyword
+ * @userdata2[0:31] SPD Table entry
+ * @userdata2[32:63] DIMM DDR Revision
+ * @devdesc Invalid DDR Revision
+ */
+ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ SPD_SPECIAL_CASES,
+ SPD_INVALID_BASIC_MEMORY_TYPE,
+ i_keyword,
+ TWO_UINT32_TO_UINT64( i_entry, i_DDRRev) );
+
+ break;
+ }
+ } while( 0 );
+
+ TRACSSCOMP( g_trac_spd,
+ EXIT_MRK"spdSpecialCases()" );
+
+ return err;
+}
+
+
+// ------------------------------------------------------------------
+// spdCheckSize
+// ------------------------------------------------------------------
+errlHndl_t spdCheckSize ( size_t i_bufferSz,
+ size_t i_expBufferSz,
+ uint64_t i_keyword )
+{
+ errlHndl_t err = NULL;
+
+ // Check that the buffer is greater than or equal to the size
+ // we need to get all the keyword data requested.
+ if( i_bufferSz < i_expBufferSz )
+ {
+ TRACFCOMP( g_trac_spd,
+ ERR_MRK"Buffer Size (%d) for keyword (0x%04x) wasn't greater than "
+ "or equal to expected size (%d)",
+ i_bufferSz, i_keyword, i_expBufferSz );
+
+ /*@
+ * @errortype
+ * @reasoncode SPD_INSUFFICIENT_BUFFER_SIZE
+ * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE
+ * @moduleid SPD_CHECK_SIZE
+ * @userdata1 Keyword
+ * @userdata2[0:31] Needed Buffer Size
+ * @userdata2[32:63] Expected Buffer Size
+ * @devdesc Buffer Size provided was not big enough for
+ * the keyword requested.
+ */
+ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ SPD_CHECK_SIZE,
+ SPD_INSUFFICIENT_BUFFER_SIZE,
+ i_keyword,
+ TWO_UINT32_TO_UINT64( i_bufferSz, i_expBufferSz ) );
+ }
+
+ return err;
+}
+
+
+// ------------------------------------------------------------------
+// spdReadBinaryFile
+// ------------------------------------------------------------------
+errlHndl_t spdReadBinaryFile ( uint64_t i_byteAddr,
+ size_t i_numBytes,
+ void * o_data )
+{
+ errlHndl_t err = NULL;
+ const char * fileName = "dimmspd.dat";
+ const char * startAddr = NULL;
+ size_t fileSize;
+
+ TRACSSCOMP( g_trac_spd,
+ ENTER_MRK"spdReadBinaryFile()" );
+
+ do
+ {
+ if( g_loadModule )
+ {
+ mutex_lock( &g_spdMutex );
+
+ if( g_loadModule )
+ {
+ // Load the file
+ TRACUCOMP( g_trac_spd,
+ "Load file" );
+ err = VFS::module_load( fileName );
+
+ if( err )
+ {
+ TRACFCOMP( g_trac_spd,
+ ERR_MRK"Error opening binary SPD file: %s",
+ fileName );
+ mutex_unlock( &g_spdMutex );
+
+ break;
+ }
+
+ g_loadModule = false;
+ }
+ mutex_unlock( &g_spdMutex );
+ }
+
+ // Get the starting address of the file/module
+ TRACUCOMP( g_trac_spd,
+ "Get starting address/size" );
+ err = VFS::module_address( fileName,
+ startAddr,
+ fileSize );
+
+ if( err )
+ {
+ TRACFCOMP( g_trac_spd,
+ ERR_MRK"Error getting starting address of binary SPD file: %s",
+ fileName );
+
+ break;
+ }
+
+ // Check that we can read the amount of data we need to from the
+ // file we just loaded
+ TRACUCOMP( g_trac_spd,
+ "Check Size vs file size" );
+ if( (i_byteAddr + i_numBytes) > fileSize )
+ {
+ TRACFCOMP( g_trac_spd,
+ ERR_MRK"Unable to read %d bytes from %s at offset 0x%08x "
+ "because file size is only %d bytes!",
+ i_numBytes,
+ fileName,
+ i_byteAddr,
+ fileSize );
+ uint64_t tmpData = (i_byteAddr + i_numBytes);
+ tmpData = tmpData << 16;
+ tmpData = tmpData & (fileSize & 0xFFFF);
+
+ /*@
+ * @errortype
+ * @reasoncode SPD_INSUFFICIENT_FILE_SIZE
+ * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE
+ * @moduleid SPD_READ_BINARY_FILE
+ * @userdata1 File Size
+ * @userdata2[0:48] Starting offset into file
+ * @userdata2[49:63] Number of bytes to read
+ * @devdesc File is not sufficiently large to read number of
+ * bytes at offset given without overrunning file.
+ */
+ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ SPD_READ_BINARY_FILE,
+ SPD_INSUFFICIENT_FILE_SIZE,
+ fileSize,
+ tmpData );
+
+ break;
+ }
+
+ // Retrieve the data requested
+ TRACUCOMP( g_trac_spd,
+ "Copy data out of file" );
+ memcpy( o_data, (startAddr + i_byteAddr), i_numBytes );
+ } while( 0 );
+
+ TRACSSCOMP( g_trac_spd,
+ EXIT_MRK"spdReadBinaryFile()" );
+
+ return err;
+}
+
+
+} // end namespace SPD
diff --git a/src/usr/spd/spd.H b/src/usr/spd/spd.H
new file mode 100755
index 000000000..65f85119a
--- /dev/null
+++ b/src/usr/spd/spd.H
@@ -0,0 +1,261 @@
+// IBM_PROLOG_BEGIN_TAG
+// This is an automatically generated prolog.
+//
+// $Source: src/usr/spd/spd.H $
+//
+// IBM CONFIDENTIAL
+//
+// COPYRIGHT International Business Machines Corp. 2012
+//
+// 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
+#ifndef __SPD_H
+#define __SPD_H
+
+/**
+ * @file spd.H
+ *
+ * @brief Provides the interfaces for the SPD device driver
+ *
+ */
+
+// ----------------------------------------------
+// Includes
+// ----------------------------------------------
+#include <errl/errltypes.H>
+
+namespace SPD
+{
+
+/**
+* @brief Miscellaneous enumerations for SPD
+*/
+enum
+{
+ MEM_TYPE_ADDR = 0x2, // DIMM Basic Memory Type address
+ MEM_TYPE_ADDR_SZ = 0x1, // DIMM Basic Memory Type address size
+
+ // Basic Memory Type Enumerations
+ SPD_DDR3 = 0xB,
+ SPD_DDR4 = 0xC, // TODO - Proposed value from draft Spec.
+};
+
+/**
+* @brief Structure to define the lookup table for SPD keywords
+* for DIMMs.
+*/
+struct KeywordData
+{
+ uint16_t keyword; // SPD keyword this data corresponds to
+ uint8_t offset; // Byte offset in the SPD data
+ uint8_t length; // Number of bytes to retrieve
+ bool useBitMask; // Use the bitmask to mask off bits, if true, length must be
+ // l byte, unless it is a "special" case
+ uint8_t bitMask; // Bit mask
+ uint8_t shift; // Used for fields < 1 byte to right justify all values.
+ bool isSpecialCase; // Whether or not this entry is a special case.
+};
+
+
+/**
+*
+* @brief Perform an SPD operation. It follows a pre-defined
+* prototype function in order to be registered with the device
+* driver framework.
+*
+* @param[in] i_opType - Operation Type - See DeviceFW::OperationType in
+* driververif.H
+*
+* @param[in] i_target - DIMM Target device
+*
+* @param [in/out] io_buffer - Pointer to the data that was read from
+* the target device. It will also be used to contain data to
+* be written to the device.
+*
+* @param [in/out] io_buflen - Length of the buffer to be read or written
+* to/from the target. This value should indicate the size of the
+* io_buffer parameter that has been allocated. Being returned it will
+* indicate the number of valid bytes in the buffer being returned.
+*
+* @param [in] i_accessType - Access Type - See DeviceFW::AccessType in
+* usrif.H
+*
+* @param [in] i_args - This is an argument list for the device driver
+* framework.
+*
+* @return errlHndl_t - NULL if successful, otherwise a pointer to the
+* error log.
+*
+*/
+errlHndl_t spdAccess ( DeviceFW::OperationType i_opType,
+ TARGETING::Target * i_target,
+ void * io_buffer,
+ size_t & io_buflen,
+ int64_t i_accessType,
+ va_list i_args );
+
+/**
+ * @brief This function is used to read SPD keywords from collected
+ * SPD data for the given target
+ *
+ * @param[in] i_keyword - The SPD keyword to access.
+ *
+ * @param[in/out] io_buffer - The buffer that will contain the data
+ * read from the SPD data.
+ *
+ * @param[in/out] io_buflen - The requested number of bytes to read.
+ * The actual number of bytes read will be returned.
+ *
+ * @param[in] i_target - The target DIMM to access the data for.
+ *
+ * @return errlHndl_t - NULL if successful, otherwise a pointer to the
+ * error log.
+ */
+errlHndl_t spdGetKeywordValue ( uint64_t i_keyword,
+ void * io_buffer,
+ size_t & io_buflen,
+ TARGETING::Target * i_target );
+
+/**
+ * @brief This function is used to write SPD keyword values.
+ *
+ * @param[in] i_keyword - The SPD keyword to access.
+ *
+ * @param[in/out] io_buffer - The buffer that will contain the data
+ * read from the SPD data.
+ *
+ * @param[in/out] io_buflen - The requested number of bytes to read.
+ * The actual number of bytes read will be returned.
+ *
+ * @param[in] i_target - The target DIMM to access the data for.
+ *
+ * @return errlHndl_t - NULL if successful, otherwise a pointer to the
+ * error log.
+ */
+errlHndl_t spdWriteKeywordValue ( uint64_t i_keyword,
+ void * io_buffer,
+ size_t & io_buflen,
+ TARGETING::Target * i_target );
+
+/**
+ * @param This function is a wrapper for reading the correct keyword.
+ * It will route the read to whatever function has the latest
+ * supported access code.
+ *
+ * @param[in] i_byteAddress - The offset into the JEDEC SPD layout.
+ *
+ * @param[in] i_numbytes - Number of bytes to read.
+ *
+ * @param[out] o_data - The data buffer that will return the data read.
+ *
+ * @param[in] i_target - The target DIMM to access.
+ *
+ * @return errlHndl_t - NULL if successful, otherwise a pointer to the
+ * error log.
+ */
+errlHndl_t spdFetchData ( uint64_t i_byteAddr,
+ size_t i_numBytes,
+ void * o_data,
+ TARGETING::Target * i_target );
+
+/**
+ * @param This function will read the SPD keyword from the appropriate
+ * table.
+ *
+ * @param[in] i_keyword - The SPD keyword to access.
+ *
+ * @param[in/out] io_buffer - The buffer that will contain the data
+ * read from the SPD data.
+ *
+ * @param[in/out] io_buflen - The requested number of bytes to read.
+ * The actual number of bytes read will be returned.
+ *
+ * @param[in] i_target - The target DIMM to access the data for.
+ *
+ * @param[in] i_DDRRev - The DIMM DDR Revision.
+ *
+ * @return errlHndl_t - NULL if successful, otherwise a pointer to the
+ * error log.
+ */
+errlHndl_t spdGetValue ( uint64_t i_keyword,
+ void * io_buffer,
+ size_t & io_buflen,
+ TARGETING::Target * i_target,
+ uint64_t i_DDRRev );
+
+/**
+ * @param This function handles the special case keywords where
+ * the data isn't sequential, or is broken up between two different
+ * offsets within the layout.
+ *
+ * @param[in] i_keyword - The SPD keyword to access.
+ *
+ * @param[in/out] io_buffer - The buffer that will contain the data
+ * read from the SPD data.
+ *
+ * @param[in/out] io_buflen - The requested number of bytes to read.
+ * The actual number of bytes read will be returned.
+ *
+ * @param[in] i_target - The target DIMM to access the data for.
+ *
+ * @param[in] i_entry - The table entry for the keyword to read.
+ *
+ * @return errlHndl_t - NULL if successful, otherwise a pointer to the
+ * error log.
+ */
+errlHndl_t spdSpecialCases ( uint64_t i_keyword,
+ void * io_buffer,
+ size_t & io_buflen,
+ TARGETING::Target * i_target,
+ uint64_t i_entry,
+ uint64_t i_DDRRev );
+
+/**
+ * @brief This function checks to make sure that the buffer allocated
+ * is large enough to hold the data that needs to be returned.
+ *
+ * @param[in] i_bufferSz - The size of the buffer passed in by the caller.
+ *
+ * @param[in] i_expBufferSz - The expected buffer size for the keyword
+ * requested.
+ *
+ * @param[in] i_keyword - The SPD Keyword requested.
+ *
+ * @return errlHndl_t - NULL if successful, otherwise a pointer to the
+ * error log.
+ */
+errlHndl_t spdCheckSize ( size_t i_bufferSz,
+ size_t i_expBufferSz,
+ uint64_t i_keyword );
+
+/**
+ * @brief This function will read a binary file from PNOR. This is
+ * not the long term solution, but mainly for initial testing.
+ *
+ * @param[in] i_byteAddr - The byte offset into the SPD layout.
+ *
+ * @param[in] i_bytes - Number of bytes to access.
+ *
+ * @param[out] o_data - The data buffer containing the data read.
+ *
+ * @return errlHndl_t - NULL if successful, otherwise a pointer to the
+ * error log.
+ */
+errlHndl_t spdReadBinaryFile ( uint64_t i_byteAddr,
+ size_t i_numBytes,
+ void * o_data );
+
+}; // end SPD namespace
+
+#endif // __SPD_H
diff --git a/src/usr/spd/spdDDR3.H b/src/usr/spd/spdDDR3.H
new file mode 100755
index 000000000..4b36b40a9
--- /dev/null
+++ b/src/usr/spd/spdDDR3.H
@@ -0,0 +1,125 @@
+// IBM_PROLOG_BEGIN_TAG
+// This is an automatically generated prolog.
+//
+// $Source: src/usr/spd/spdDDR3.H $
+//
+// IBM CONFIDENTIAL
+//
+// COPYRIGHT International Business Machines Corp. 2012
+//
+// 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
+#ifndef __SPDDDR3_H
+#define __SPDDDR3_H
+
+/**
+ * @file spdDDR3.H
+ *
+ * @brief Provides the enumerations for the DDR 3 fields to read.
+ *
+ */
+
+// ----------------------------------------------
+// Includes
+// ----------------------------------------------
+#include "spd.H"
+
+namespace SPD
+{
+
+/**
+ * @brief Pre-defined lookup table for DDR3 keywords and the
+ * information needed to read that data from the SPD data.
+ */
+KeywordData ddr3Data[] =
+{
+ // ----------------------------------------------------------------------------------
+ // Bit order for each byte is [7:0] as defined by the JEDEC spec (little endian)
+ //
+ // Special cases listed below will be handled out of the normal table lookup
+ // handler code.
+ // ----------------------------------------------------------------------------------
+ // Keyword offset size Use Bitmsk Shift
+ // Bitmsk Number
+ // ----------------------------------------------------------------------------------
+ { CRC_EXCLUDE, 0x00, 0x01, true, 0x80, 0x07, false },
+ { SPD_BYTES_TOTAL, 0x00, 0x01, true, 0x70, 0x04, false },
+ { SPD_BYTES_USED, 0x00, 0x01, true, 0x0F, 0x00, false },
+ { SPD_MAJOR_REVISION, 0x01, 0x01, true, 0xF0, 0x04, false },
+ { SPD_MINOR_REVISION, 0x01, 0x01, true, 0x0F, 0x00, false },
+ { BASIC_MEMORY_TYPE, 0x02, 0x01, false, 0x00, 0x00, false },
+ { MODULE_TYPE, 0x03, 0x01, true, 0x0F, 0x00, false },
+ { BANK_ADDRESS_BITS, 0x04, 0x01, true, 0x70, 0x04, false },
+ { DENSITY, 0x04, 0x01, true, 0x0F, 0x00, false },
+ { ROW_ADDRESS, 0x05, 0x01, true, 0x38, 0x03, false },
+ { COL_ADDRESS, 0x05, 0x01, true, 0x07, 0x00, false },
+ { MODULE_NOMINAL_VOLTAGE, 0x06, 0x01, true, 0x07, 0x00, false },
+ { MODULE_RANKS, 0x07, 0x01, true, 0x38, 0x03, false },
+ { MODULE_DRAM_WIDTH, 0x07, 0x01, true, 0x07, 0x00, false },
+ { ECC_BITS, 0x08, 0x01, true, 0x18, 0x03, false },
+ { MODULE_MEMORY_BUS_WIDTH, 0x08, 0x01, true, 0x07, 0x00, false },
+ { FTB_DIVIDEND, 0x09, 0x01, true, 0xF0, 0x04, false },
+ { FTB_DIVISOR, 0x09, 0x01, true, 0x0F, 0x00, false },
+ { MTB_DIVIDEND, 0x0a, 0x01, false, 0x00, 0x00, false },
+ { MTB_DIVISOR, 0x0b, 0x01, false, 0x00, 0x00, false },
+ { TCK_MIN, 0x0c, 0x01, false, 0x00, 0x00, false },
+ { CAS_LATENCIES_SUPPORTED, 0x0f, 0x02, true, 0x7F, 0x00, true },
+ { MIN_CAS_LATENCY, 0x10, 0x01, false, 0x00, 0x00, false },
+ { TWR_MIN, 0x11, 0x01, false, 0x00, 0x00, false },
+ { TRCD_MIN, 0x12, 0x01, false, 0x00, 0x00, false },
+ { TRRD_MIN, 0x13, 0x01, false, 0x00, 0x00, false },
+ { TRP_MIN, 0x14, 0x01, false, 0x00, 0x00, false },
+ { TRC_MIN, 0x15, 0x02, true, 0xF0, 0x04, true },
+ { TRAS_MIN, 0x15, 0x02, true, 0x0F, 0x00, true },
+ { TRFC_MIN, 0x19, 0x02, false, 0x00, 0x00, true },
+ { TWTR_MIN, 0x1a, 0x01, false, 0x00, 0x00, false },
+ { TRTP_MIN, 0x1b, 0x01, false, 0x00, 0x00, false },
+ { TFAW_MIN, 0x1c, 0x02, true, 0x0F, 0x00, true },
+ { DLL_OFF, 0x1e, 0x01, true, 0x80, 0x07, false },
+ { RZQ_7, 0x1e, 0x01, true, 0x02, 0x01, false },
+ { RZQ_6, 0x1e, 0x01, true, 0x01, 0x00, false },
+ { SDRAM_OPTIONAL_FEATURES, 0x1e, 0x01, false, 0x00, 0x00, false },
+ { PASR, 0x1f, 0x01, true, 0x80, 0x07, false },
+ { ODTS, 0x1f, 0x01, true, 0x08, 0x03, false },
+ { ASR, 0x1f, 0x01, true, 0x04, 0x02, false },
+ { ETR_1X, 0x1f, 0x01, true, 0x02, 0x01, false },
+ { ETR, 0x1f, 0x01, true, 0x01, 0x00, false },
+ { SDRAM_THERMAL_REFRESH_OPTIONS, 0x1f, 0x01, false, 0x00, 0x00, false },
+ { THERMAL_SENSOR_PRESENT, 0x20, 0x01, true, 0x80, 0x07, false },
+ { THERMAL_SENSOR_ACCURACY, 0x20, 0x01, true, 0x7F, 0x00, false },
+ { MODULE_THERMAL_SENSOR, 0x20, 0x01, false, 0x00, 0x00, false },
+ { SDRAM_DEVICE_TYPE_NONSTD, 0x21, 0x01, true, 0x80, 0x07, false },
+ { SDRAM_DEVICE_TYPE, 0x21, 0x01, true, 0x7F, 0x00, false },
+ { TCKMIN_FINE_OFFSET, 0x22, 0x01, false, 0x00, 0x00, false },
+ { TAAMIN_FINE_OFFSET, 0x23, 0x01, false, 0x00, 0x00, false },
+ { TRCDMIN_FINE_OFFSET, 0x24, 0x01, false, 0x00, 0x00, false },
+ { TRPMIN_FINE_OFFSET, 0x25, 0x01, false, 0x00, 0x00, false },
+ { TRPCMIN_FINE_OFFSET, 0x26, 0x01, false, 0x00, 0x00, false },
+ { MODULE_TYPE_SPECIFIC_SECTION, 0x3c, 0x39, false, 0x00, 0x00, false },
+ { MODULE_MANUFACTURER_ID, 0x76, 0x02, false, 0x00, 0x00, true },
+ { MODULE_MANUFACTURING_LOCATION, 0x77, 0x01, false, 0x00, 0x00, false },
+ { MODULE_MANUFACTURING_DATE, 0x78, 0x02, false, 0x00, 0x00, false },
+ { MODULE_SERIAL_NUMBER, 0x7a, 0x04, false, 0x00, 0x00, false },
+ { MODULE_CRC, 0x7e, 0x02, false, 0x00, 0x00, false },
+ { MODULE_PART_NUMBER, 0x80, 0x12, false, 0x00, 0x00, false },
+ { MODULE_REVISION_CODE, 0x92, 0x02, false, 0x00, 0x00, false },
+ { DRAM_MANUFACTURER_ID, 0x94, 0x02, false, 0x00, 0x00, false },
+ { MANUFACTURER_SPECIFIC_DATA, 0x96, 0x1a, false, 0x00, 0x00, false },
+ // ----------------------------------------------------------------------------------
+};
+
+
+}; // end SPD namespace
+
+#endif // __SPDDDR3_H
diff --git a/src/usr/spd/test/makefile b/src/usr/spd/test/makefile
new file mode 100644
index 000000000..58e8fd562
--- /dev/null
+++ b/src/usr/spd/test/makefile
@@ -0,0 +1,28 @@
+# IBM_PROLOG_BEGIN_TAG
+# This is an automatically generated prolog.
+#
+# $Source: src/usr/spd/test/makefile $
+#
+# IBM CONFIDENTIAL
+#
+# COPYRIGHT International Business Machines Corp. 2012
+#
+# 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
+ROOTPATH = ../../../..
+
+MODULE = testspd
+TESTS = *.H
+
+include ${ROOTPATH}/config.mk
diff --git a/src/usr/spd/test/spdtest.H b/src/usr/spd/test/spdtest.H
new file mode 100755
index 000000000..3efa690cc
--- /dev/null
+++ b/src/usr/spd/test/spdtest.H
@@ -0,0 +1,413 @@
+// IBM_PROLOG_BEGIN_TAG
+// This is an automatically generated prolog.
+//
+// $Source: src/usr/spd/test/spdtest.H $
+//
+// IBM CONFIDENTIAL
+//
+// COPYRIGHT International Business Machines Corp. 2012
+//
+// 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
+#ifndef __SPDTEST_H
+#define __SPDTEST_H
+
+/**
+ * @file spdtest.H
+ *
+ * @brief Test cases for SPD code
+ */
+#include <sys/time.h>
+
+#include <cxxtest/TestSuite.H>
+#include <errl/errlmanager.H>
+#include <errl/errlentry.H>
+#include <errl/errltypes.H>
+#include <devicefw/driverif.H>
+#include <targeting/predicates/predicatectm.H>
+
+#include <spd/spdreasoncodes.H>
+#include <spd/spdenums.H>
+#include "../spdDDR3.H"
+#include "../spd.H"
+
+extern trace_desc_t* g_trac_spd;
+
+using namespace TARGETING;
+using namespace SPD;
+
+void getDIMMTargets ( TargetHandleList & o_dimmList )
+{
+ // Get top level system target
+ TARGETING::TargetService& tS = TARGETING::targetService();
+ TARGETING::Target * sysTarget = NULL;
+ tS.getTopLevelTarget( sysTarget );
+ assert( sysTarget != NULL );
+
+ // Get a DIMM Target
+ TARGETING::PredicateCTM predDimm( TARGETING::CLASS_CARD,
+ TARGETING::TYPE_DIMM );
+ tS.getAssociated( o_dimmList,
+ sysTarget,
+ TARGETING::TargetService::CHILD,
+ TARGETING::TargetService::ALL,
+ &predDimm );
+ TRACFCOMP( g_trac_spd,
+ "getDIMMTargets() - found %d DIMMs",
+ o_dimmList.size() );
+ return;
+}
+
+class SPDTest: public CxxTest::TestSuite
+{
+ public:
+
+ /**
+ * @brief This test reads all of the keywords for all of the
+ * DIMMs found.
+ */
+ void testSpdRead ( void )
+ {
+ errlHndl_t err = NULL;
+ uint64_t cmds = 0x0;
+ uint64_t fails = 0x0;
+
+ TRACFCOMP( g_trac_spd,
+ ENTER_MRK"testSpdRead()" );
+
+ do
+ {
+ TARGETING::Target * theTarget = NULL;
+
+ // Get DIMM Targets
+ TargetHandleList dimmList;
+ getDIMMTargets( dimmList );
+
+ if( ( 0 == dimmList.size() ) ||
+ ( NULL == dimmList[0] ) )
+ {
+ TRACFCOMP( g_trac_spd,
+ "testSpdRead - No DIMMs found!" );
+ break;
+ }
+
+ for( uint32_t dimm = 0; dimm < dimmList.size(); dimm++ )
+ {
+ theTarget = dimmList[dimm];
+ uint8_t * theData = NULL;
+ size_t theSize = 0;
+ uint32_t entry = 0x0;
+
+ // Get the DDR revision
+ uint8_t memType = 0x0;
+ size_t memTypeSize = 0x1;
+ err = deviceRead( theTarget,
+ &memType,
+ memTypeSize,
+ DEVICE_SPD_ADDRESS( SPD::BASIC_MEMORY_TYPE ) );
+
+ if( err )
+ {
+ fails++;
+ TS_FAIL( "testSpdRead- Failure reading Basic memory type!" );
+ errlCommit( err,
+ SPD_COMP_ID );
+ continue;
+ }
+
+ for( uint64_t keyword = SPD::SPD_FIRST_KEYWORD;
+ keyword < SPD::SPD_LAST_KEYWORD; keyword++ )
+ {
+ cmds++;
+ if( NULL != theData )
+ {
+ free( theData );
+ theData = NULL;
+ }
+
+ // Get the required size of the buffer
+ theSize = 0;
+ if( SPD_DDR3 == memType )
+ {
+ for( entry = 0;
+ entry < (sizeof(ddr3Data)/sizeof(ddr3Data[0]));
+ entry++ )
+ {
+ if( keyword == ddr3Data[entry].keyword )
+ {
+ theSize = ddr3Data[entry].length;
+ break;
+ }
+ }
+ }
+ else
+ {
+ // Nothing else supported yet!
+ // Not really a fail, just not supported
+ cmds--;
+ continue;
+ }
+
+ if( 0x0 == theSize )
+ {
+ fails++;
+ TS_FAIL( "testSpdRead - Keyword (0x%04x) size = 0x0",
+ entry );
+ continue;
+ }
+
+ // Allocate the buffer
+ theData = static_cast<uint8_t*>(malloc( theSize ));
+
+ err = deviceRead( theTarget,
+ theData,
+ theSize,
+ DEVICE_SPD_ADDRESS( keyword ) );
+
+ if( err )
+ {
+ fails++;
+ TS_FAIL( "testSpdRead - Failure on keyword: %04x",
+ keyword );
+ errlCommit( err,
+ SPD_COMP_ID );
+ continue;
+ }
+
+ // Read was successful, print out first 2 bytes of data read
+ TRACFCOMP( g_trac_spd,
+ "testSpdRead - kwd: 0x%04x, val: %02x%02x, size: %d",
+ keyword, theData[0], theData[1], theSize );
+
+ if( NULL != theData )
+ {
+ free( theData );
+ theData = NULL;
+ }
+ }
+
+ if( err )
+ {
+ break;
+ }
+ }
+
+ if( err )
+ {
+ break;
+ }
+ } while( 0 );
+
+ TRACFCOMP( g_trac_spd,
+ "testSpdRead - %d/%d fails",
+ fails, cmds );
+ }
+
+ /**
+ * @brief Test a SPD Write
+ */
+ void testSpdWrite ( void )
+ {
+ errlHndl_t err = NULL;
+ uint64_t cmds = 0x0;
+ uint64_t fails = 0x0;
+
+ TRACFCOMP( g_trac_spd,
+ ENTER_MRK"testSpdWrite()" );
+
+ do
+ {
+ TARGETING::Target * theTarget = NULL;
+
+ // Get DIMM Targets
+ TargetHandleList dimmList;
+ getDIMMTargets( dimmList );
+
+ if( ( 0 == dimmList.size() ) ||
+ ( NULL == dimmList[0] ) )
+ {
+ TRACFCOMP( g_trac_spd,
+ "testSpdWrite - No DIMMs found!" );
+ break;
+ }
+
+ for( uint32_t dimm = 0; dimm < dimmList.size(); dimm++ )
+ {
+ theTarget = dimmList[dimm];
+ uint8_t * theData = NULL;
+ size_t theSize = 0;
+
+ cmds++;
+ err = deviceWrite( theTarget,
+ theData,
+ theSize,
+ DEVICE_SPD_ADDRESS( SPD_FIRST_KEYWORD ) );
+
+ if( NULL == err )
+ {
+ // No error returned, failure
+ fails++;
+ TS_FAIL( "testSpdWrite - No error returned from deviceWrite()" );
+ continue;
+ }
+ else
+ {
+ delete err;
+ err = NULL;
+ }
+ }
+
+ if( err )
+ {
+ break;
+ }
+ } while( 0 );
+
+ TRACFCOMP( g_trac_spd,
+ "testSpdWrite - %d/%d fails",
+ fails, cmds );
+ }
+
+ /**
+ * @brief Test an invalid Keyword to a DIMM target.
+ */
+ void testSpdInvalidKeyword ( void )
+ {
+ errlHndl_t err = NULL;
+ uint64_t cmds = 0x0;
+ uint64_t fails = 0x0;
+
+ TRACFCOMP( g_trac_spd,
+ ENTER_MRK"testSpdInvalidKeyword()" );
+
+ do
+ {
+ TARGETING::Target * theTarget = NULL;
+
+ // Get DIMM Targets
+ TargetHandleList dimmList;
+ getDIMMTargets( dimmList );
+
+ if( ( 0 == dimmList.size() ) ||
+ ( NULL == dimmList[0] ) )
+ {
+ TRACFCOMP( g_trac_spd,
+ "testSpdInvalidKeyword - No DIMMs found!" );
+ break;
+ }
+
+ for( uint32_t dimm = 0; dimm < dimmList.size(); dimm++ )
+ {
+ theTarget = dimmList[dimm];
+ uint8_t * theData = NULL;
+ size_t theSize = 0x0;
+
+ cmds++;
+ err = deviceRead( theTarget,
+ theData,
+ theSize,
+ DEVICE_SPD_ADDRESS( SPD::SPD_LAST_KEYWORD ) );
+
+ if( NULL == err )
+ {
+ fails++;
+ TS_FAIL( "testSpdInvalidKeyword - No error returned!" );
+ continue;
+ }
+ else
+ {
+ delete err;
+ err = NULL;
+ }
+ }
+
+ if( err )
+ {
+ break;
+ }
+ } while( 0 );
+
+ TRACFCOMP( g_trac_spd,
+ "testSpdInvalidKeyword - %d/%d fails",
+ fails, cmds );
+ }
+
+ /**
+ * @brief Test an invalid size for an SPD read.
+ */
+ void testSpdInvalidSize ( void )
+ {
+ errlHndl_t err = NULL;
+ uint64_t cmds = 0x0;
+ uint64_t fails = 0x0;
+
+ TRACFCOMP( g_trac_spd,
+ ENTER_MRK"testSpdInvalidSize()" );
+
+ do
+ {
+ TARGETING::Target * theTarget = NULL;
+
+ // Get DIMM Targets
+ TargetHandleList dimmList;
+ getDIMMTargets( dimmList );
+
+ if( ( 0 == dimmList.size() ) ||
+ ( NULL == dimmList[0] ) )
+ {
+ TRACFCOMP( g_trac_spd,
+ "testSpdInvalidSize - No DIMMs found!" );
+ break;
+ }
+
+ for( uint32_t dimm = 0; dimm < dimmList.size(); dimm++ )
+ {
+ theTarget = dimmList[dimm];
+ uint8_t * theData = NULL;
+ size_t theSize = 0x0; // Invalid size of 0x0
+
+ cmds++;
+ err = deviceRead( theTarget,
+ theData,
+ theSize,
+ DEVICE_SPD_ADDRESS( SPD::SPD_FIRST_KEYWORD ) );
+
+ if( NULL == err )
+ {
+ fails++;
+ TS_FAIL( "testSpdInvalidSize - No error for invalid size!" );
+ continue;
+ }
+ else
+ {
+ delete err;
+ err = NULL;
+ }
+ }
+
+ if( err )
+ {
+ break;
+ }
+ } while( 0 );
+
+ TRACFCOMP( g_trac_spd,
+ "testSpdInvalidSize - %d/%d fails",
+ fails, cmds );
+ }
+
+
+};
+
+#endif
OpenPOWER on IntegriCloud