summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDan Crowell <dcrowell@us.ibm.com>2012-01-20 15:05:21 -0600
committerDaniel M. Crowell <dcrowell@us.ibm.com>2012-02-16 09:00:57 -0600
commit10bc99ba760ce7e67b005b7b61f884581c75d6ad (patch)
tree200a48511b3f83b22e4c9f2c400fb108e2abc9f9 /src
parentc948c7adaf78a9925298e597493201fddd8102a7 (diff)
downloadtalos-hostboot-10bc99ba760ce7e67b005b7b61f884581c75d6ad.tar.gz
talos-hostboot-10bc99ba760ce7e67b005b7b61f884581c75d6ad.zip
RTC Story 34595
-Add first pass of LPC logic to PNOR driver -Add interfaces to handle future SPI changes -Remove support for MMRD/PMRW modes from driver and RP Code will still use our fake PNOR image in memory but it will exercise more of the full driver path by reading/writing in 32-bit chunks. Change-Id: I753c71926bd9e67d22ac06c3204a0daf8b2f222e Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/637 Tested-by: Jenkins Server Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Diffstat (limited to 'src')
-rw-r--r--src/include/usr/pnor/pnor_reasoncodes.H30
-rw-r--r--src/usr/pnor/pnordd.C756
-rw-r--r--src/usr/pnor/pnordd.H284
-rw-r--r--src/usr/pnor/pnorrp.C42
-rw-r--r--src/usr/pnor/pnorrp.H6
-rw-r--r--src/usr/pnor/test/pnorddtest.H262
6 files changed, 1132 insertions, 248 deletions
diff --git a/src/include/usr/pnor/pnor_reasoncodes.H b/src/include/usr/pnor/pnor_reasoncodes.H
index d16c6d7f1..0269f6cbc 100644
--- a/src/include/usr/pnor/pnor_reasoncodes.H
+++ b/src/include/usr/pnor/pnor_reasoncodes.H
@@ -29,16 +29,26 @@ namespace PNOR
{
enum PNORModuleId
{
- MOD_PNORRP_WAITFORMESSAGE = 0x01, /**< pnorrp.C : PnorRP::waitForMessage */
- MOD_PNORRP_COMPUTEDEVICEADDR = 0x02, /**< pnorrp.C : PnorRP::computeDeviceAddr */
- MOD_PNORRP_GETSECTIONINFO = 0x03, /**< pnorrp.C : PnorRP::getSectionInfo */
- MOD_PNORRP_COMPUTESECTION = 0x04, /**< pnorrp.C : PnorRP::computeSection */
- MOD_PNORRP_INITDAEMON = 0x05, /**< pnorrp.C : PnorRP::initDaemon */
- MOD_PNORRP_READTOC = 0x06, /**< pnorrp.C : PnorRP::readTOC */
- MOD_PNORRP_READFROMDEVICE = 0x07, /**< pnorrp.C : PnorRP::readFromDevice */
- MOD_PNORRP_WRITETODEVICE = 0x08, /**< pnorrp.C : PnorRP::writeToDevice */
+ MOD_PNORRP_WAITFORMESSAGE = 0x01, /**< pnorrp.C : PnorRP::waitForMessage */
+ MOD_PNORRP_COMPUTEDEVICEADDR = 0x02, /**< pnorrp.C : PnorRP::computeDeviceAddr */
+ MOD_PNORRP_GETSECTIONINFO = 0x03, /**< pnorrp.C : PnorRP::getSectionInfo */
+ MOD_PNORRP_COMPUTESECTION = 0x04, /**< pnorrp.C : PnorRP::computeSection */
+ MOD_PNORRP_INITDAEMON = 0x05, /**< pnorrp.C : PnorRP::initDaemon */
+ MOD_PNORRP_READTOC = 0x06, /**< pnorrp.C : PnorRP::readTOC */
+ MOD_PNORRP_READFROMDEVICE = 0x07, /**< pnorrp.C : PnorRP::readFromDevice */
+ MOD_PNORRP_WRITETODEVICE = 0x08, /**< pnorrp.C : PnorRP::writeToDevice */
- MOD_PNORDD_VERIFYADDRESSRANGE = 0x11 /**< pnordd.C : PnorDD::verifyAddressRange */
+ MOD_PNORDD_VERIFYADDRESSRANGE = 0x11, /**< pnordd.C : PnorDD::verifyAddressRange */
+ MOD_PNORDD_READFLASH = 0x12, /**< pnordd.C : PnorDD::readFlash */
+ MOD_PNORDD_WRITEFLASH = 0x13, /**< pnordd.C : PnorDD::writeFlash */
+ MOD_PNORDD_READREGLPC = 0x14, /**< pnordd.C : PnorDD::readRegLPC */
+ MOD_PNORDD_WRITEREGLPC = 0x15, /**< pnordd.C : PnorDD::writeRegLPC */
+ MOD_PNORDD_READREGSPI = 0x16, /**< pnordd.C : PnorDD::readRegSPI */
+ MOD_PNORDD_WRITEREGSPI = 0x17, /**< pnordd.C : PnorDD::writeRegSPI */
+ MOD_PNORDD_READLPC = 0x18, /**< pnordd.C : PnorDD::readLPC */
+ MOD_PNORDD_WRITELPC = 0x19, /**< pnordd.C : PnorDD::writeLPC */
+ MOD_PNORDD_ERASEFLASH = 0x1A, /**< pnordd.C : PnorDD::eraseFlash */
+ MOD_PNORDD_COMPAREANDWRITEBLOCK = 0x1B, /**< pnordd.C : PnorDD::compareAndWriteBlock */
};
enum PNORReasonCode
@@ -49,6 +59,8 @@ namespace PNOR
RC_EXTERNAL_ERROR = PNOR_COMP_ID | 0x04,
RC_STARTUP_FAIL = PNOR_COMP_ID | 0x05,
RC_INVALID_ASYNC_MESSAGE = PNOR_COMP_ID | 0x06,
+ RC_UNSUPPORTED_OPERATION = PNOR_COMP_ID | 0x07,
+ RC_LPC_ERROR = PNOR_COMP_ID | 0x08,
};
};
diff --git a/src/usr/pnor/pnordd.C b/src/usr/pnor/pnordd.C
index 7708dcd1d..86f4efd7b 100644
--- a/src/usr/pnor/pnordd.C
+++ b/src/usr/pnor/pnordd.C
@@ -42,17 +42,29 @@
#include <pnor/pnorif.H>
#include <pnor/pnor_reasoncodes.H>
-#define FAKE_PNOR_START 5*1024*1024
-#define FAKE_PNOR_END 8*1024*1024
-#define FAKE_PNOR_SIZE 3*1024*1024
+// Uncomment this to use the fake PNOR implementation (vs the LPC path)
+// @todo - Switch with RTC 36901
+#define USE_FAKE_PNOR
+
+// Uncomment this to skip the LPC code and just do page copies
+//#define FAST_FAKE_PNOR
+
+// Uncomment this to enable smart writing
+#define SMART_WRITE
+
+#ifdef USE_FAKE_PNOR
+#define FAKE_PNOR_START 5*MEGABYTE
+#define FAKE_PNOR_END 8*MEGABYTE
+#define FAKE_PNOR_SIZE 3*MEGABYTE
+void write_fake_pnor( uint64_t i_pnorAddr, void* i_buffer, size_t i_size );
+void read_fake_pnor( uint64_t i_pnorAddr, void* o_buffer, size_t i_size );
+#endif
extern trace_desc_t* g_trac_pnor;
namespace PNOR
{
-
-
/**
* @brief Performs an PNOR Read Operation
* This function performs a PNOR Read operation. It follows a pre-defined
@@ -85,9 +97,14 @@ errlHndl_t ddRead(DeviceFW::OperationType i_opType,
uint64_t l_addr = va_arg(i_args,uint64_t);
do{
- l_err = Singleton<PnorDD>::instance().read(io_buffer,
- io_buflen,
- l_addr);
+ //TODO - Fix with Story 34763
+ // Ensure we are operating on a 32-bit (4-byte) boundary
+ assert( reinterpret_cast<uint64_t>(io_buffer) % 4 == 0 );
+
+ // Read the flash
+ l_err = Singleton<PnorDD>::instance().readFlash(io_buffer,
+ io_buflen,
+ l_addr);
if(l_err)
{
break;
@@ -130,9 +147,14 @@ errlHndl_t ddWrite(DeviceFW::OperationType i_opType,
uint64_t l_addr = va_arg(i_args,uint64_t);
do{
- l_err = Singleton<PnorDD>::instance().write(io_buffer,
- io_buflen,
- l_addr);
+ //TODO - Fix with Story 34763
+ // Ensure we are operating on a 32-bit (4-byte) boundary
+ assert( reinterpret_cast<uint64_t>(io_buffer) % 4 == 0 );
+
+ // Write the flash
+ l_err = Singleton<PnorDD>::instance().writeFlash(io_buffer,
+ io_buflen,
+ l_addr);
if(l_err)
{
break;
@@ -157,118 +179,135 @@ DEVICE_REGISTER_ROUTE(DeviceFW::WRITE,
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
-errlHndl_t setLSCAccessMode(lscMode i_mode)
-{
- errlHndl_t l_err = NULL;
-
- do{
- l_err = Singleton<PnorDD>::instance().setAccessMode(i_mode);
- if(l_err)
- {
- break;
- }
-
- }while(0);
-
- return l_err;
-}
/**
- * @brief Read PNOR
+ * @brief Performs a PNOR Read Operation
*/
-errlHndl_t PnorDD::read(void* o_buffer,
- size_t& io_buflen,
- uint64_t i_address)
+errlHndl_t PnorDD::readFlash(void* o_buffer,
+ size_t& io_buflen,
+ uint64_t i_address)
{
- //TRACDCOMP(g_trac_pnor, "PnorDD::read(i_address=0x%llx)> ", i_address);
+ //TRACDCOMP(g_trac_pnor, "PnorDD::readFlash(i_address=0x%llx)> ", i_address);
errlHndl_t l_err = NULL;
do{
//mask off chip select for now, will probably break up fake PNOR into
//multiple fake chips eventually
- uint64_t l_address = i_address & 0x00000000FFFFFFFF;
+ uint64_t l_address = i_address & 0x00000000FFFFFFFF;
- l_err = verifyAddressRange(l_address, io_buflen);
+ l_err = verifyFlashAddressRange(l_address, io_buflen);
if(l_err)
{
io_buflen = 0;
break;
}
- //create a pointer to the offset start.
- char * srcPtr = (char *)(FAKE_PNOR_START+l_address);
-
- //@TODO: likely need a mutex around HW access
-
- //copy data from memory into the buffer.
- memcpy(o_buffer, srcPtr, io_buflen);
+#ifdef FAST_FAKE_PNOR
+ read_fake_pnor( i_address, o_buffer, io_buflen );
+ break;
+#endif
+
+ // LPC is accessed 32-bits at a time...
+ uint32_t* word_ptr = static_cast<uint32_t*>(o_buffer);
+ uint64_t words_read = 0;
+ for( uint32_t addr = i_address;
+ addr < (i_address+io_buflen);
+ addr += sizeof(uint32_t) )
+ {
+ uint32_t read_data = 0;
+ l_err = readLPC( addr, read_data );
+ if( l_err ) { break; }
+ memcpy( word_ptr+words_read, &read_data, sizeof(uint32_t) );
+ words_read++;
+ }
+ io_buflen = words_read*sizeof(uint32_t);
+ if( l_err ) { break; }
}while(0);
return l_err;
}
/**
- * @brief Write PNOR
+ * @brief Performs a PNOR Write Operation
*/
-errlHndl_t PnorDD::write(void* i_buffer,
- size_t& io_buflen,
- uint64_t i_address)
+errlHndl_t PnorDD::writeFlash(void* i_buffer,
+ size_t& io_buflen,
+ uint64_t i_address)
{
- //TRACDCOMP(g_trac_pnor, "PnorDD::write(i_address=0x%llx)> ", i_address);
+ //TRACDCOMP(g_trac_pnor, "PnorDD::writeFlash(i_address=0x%llx)> ", i_address);
errlHndl_t l_err = NULL;
- do{
+ do{
+ TRACDCOMP(g_trac_pnor,"PNOR write %.8X", i_address);
+
//mask off chip select for now, will probably break up fake PNOR into
//multiple fake chips eventually
- uint64_t l_address = i_address & 0x00000000FFFFFFFF;
-
-
- l_err = verifyAddressRange(l_address, io_buflen);
- if(l_err)
+ uint64_t l_address = i_address & 0x00000000FFFFFFFF;
+
+ // make sure this is a valid address
+ l_err = verifyFlashAddressRange(l_address, io_buflen);
+ if(l_err) { break; }
+
+
+#ifdef FAST_FAKE_PNOR
+ write_fake_pnor( i_address, i_buffer, io_buflen );
+ break;
+#endif
+
+ // LPC is accessed 32-bits at a time, but we also need to be
+ // smart about handling erases. In NOR flash we can set bits
+ // without an erase but we cannot clear them. When we erase
+ // we have to erase and entire block of data at a time.
+ uint32_t* word_ptr = static_cast<uint32_t*>(i_buffer);
+ uint64_t num_blocks = getNumAffectedBlocks(i_address,io_buflen);
+ uint32_t cur_addr = i_address;
+ uint64_t bytes_left = io_buflen;
+
+ // loop through erase blocks until we've gotten through all
+ // affected blocks
+ for( uint64_t block = 0;
+ block < num_blocks;
+ ++block )
{
- io_buflen = 0;
- break;
+ TRACDCOMP( g_trac_pnor, "Block %d: bytes_left=%d, cur_addr=0x%.8X", block, bytes_left, cur_addr );
+
+ // write a single block of data out to flash efficiently
+ l_err = compareAndWriteBlock( cur_addr,
+ (bytes_left-1)/sizeof(uint32_t)+1,
+ word_ptr );
+ if( l_err ) { break; }
+ //@todo - How should we handle PNOR errors?
+
+ // move on to the next block
+ if( bytes_left > ERASESIZE_BYTES )
+ {
+ bytes_left -= ERASESIZE_BYTES;
+ cur_addr += ERASESIZE_BYTES;
+ }
+ else
+ {
+ // final block of partial data
+ // align cur_addr to the beginning of the block
+ cur_addr = findEraseBlock(cur_addr+bytes_left);
+ // figure out the remaining data in the last block
+ bytes_left = (i_address - cur_addr);
+ }
+ word_ptr += (bytes_left-1)/sizeof(uint32_t);
}
-
- //create a pointer to the offset start.
- char * destPtr = (char *)(FAKE_PNOR_START+l_address);
-
- //@TODO: likely need a mutex around HW access
-
- //copy data from memory into the buffer.
- memcpy(destPtr, i_buffer, io_buflen);
-
+ if( l_err ) { break; }
}while(0);
- return l_err;
-}
-
-/**
- * @brief Set PNOR to desired mode
- */
-errlHndl_t PnorDD::setAccessMode(lscMode i_mode)
-{
- errlHndl_t l_err = NULL;
- TRACFCOMP(g_trac_pnor, "PnorDD::setAccessMode(0x%llx)> ", i_mode);
-
- do{
- //@TODO: real impelementation needed
-
- //Once we have a 'real' implementation, it will likely drive the need for mutexes
- //throughout the PnorDD interfaces, to avoid issues with weak consistency or a
- //read/write occuring while we're updating the mode, but
- //skipping that until it's actually needed.
-
- //Eventually need to actually change HW state here.
- //For now, just record the new mode.
- iv_lscMode = i_mode;
-
-
- }while(0);
+ // keeping track of every actual byte written is complicated and it can
+ // be misleading in the cases where we end up erasing and writing an
+ // entire block, instead just return zero for any failures
+ if( l_err )
+ {
+ io_buflen = 0;
+ }
return l_err;
}
@@ -283,10 +322,14 @@ errlHndl_t PnorDD::setAccessMode(lscMode i_mode)
* @brief Constructor
*/
PnorDD::PnorDD()
-: iv_lscMode(MMRD)
{
TRACFCOMP(g_trac_pnor, "PnorDD::PnorDD()> ");
+ mutex_init(&iv_mutex);
+ for( uint64_t x=0; x < (PNORSIZE/ERASESIZE_BYTES); x++ )
+ {
+ iv_erases[x] = 0;
+ }
}
/**
@@ -298,20 +341,25 @@ PnorDD::~PnorDD()
//Nothing to do for now
}
-errlHndl_t PnorDD::verifyAddressRange(uint64_t i_address,
- size_t& i_length)
+/**
+ * @brief Verify flash request is in appropriate address range
+ */
+errlHndl_t PnorDD::verifyFlashAddressRange(uint64_t i_address,
+ size_t& i_length)
{
errlHndl_t l_err = NULL;
do{
+ //@todo - Do we really need any checking here?
+#ifdef USE_FAKE_PNOR
if((i_address+i_length) > FAKE_PNOR_SIZE)
{
TRACFCOMP( g_trac_pnor, "PnorDD::verifyAddressRange> Invalid Address Requested : i_address=%d", i_address );
/*@
* @errortype
* @moduleid PNOR::MOD_PNORDD_VERIFYADDRESSRANGE
- * @reasoncode PNOR::RC_INVALID_SECTION
+ * @reasoncode PNOR::RC_INVALID_ADDRESS
* @userdata1 Requested Address
* @userdata2 Requested Length
* @devdesc PnorDD::verifyAddressRange> Invalid Address requested
@@ -323,7 +371,7 @@ errlHndl_t PnorDD::verifyAddressRange(uint64_t i_address,
TO_UINT64(i_length));
break;
}
-
+#endif
}while(0);
@@ -331,6 +379,530 @@ errlHndl_t PnorDD::verifyAddressRange(uint64_t i_address,
return l_err;
}
+/**
+ * @brief Read a LPC Host Controller Register
+ */
+errlHndl_t PnorDD::readRegLPC(LpcRegAddr i_addr,
+ uint32_t& o_data)
+{
+ errlHndl_t l_err = NULL;
+
+ do {
+ //@todo - RTC 36901 or 35728
+ } while(0);
+
+ return l_err;
+}
+
+/**
+ * @brief Write a LPC Host Controller Register
+ */
+errlHndl_t PnorDD::writeRegLPC(LpcRegAddr i_addr,
+ uint32_t i_data)
+{
+ return NULL; //@todo - RTC 36901 or 35728
+}
+
+/**
+ * @brief Read a SPI Register
+ */
+errlHndl_t PnorDD::readRegSPI(uint32_t i_addr,
+ uint32_t& o_data)
+{
+ //@todo - Finish with Story 35728
+ TRACFCOMP( g_trac_pnor, "PnorDD::readRegSPI> Unsupported Operation : i_addr=%d", i_addr );
+ /*@
+ * @errortype
+ * @moduleid PNOR::MOD_PNORDD_READREGSPI
+ * @reasoncode PNOR::RC_UNSUPPORTED_OPERATION
+ * @userdata1 Requested Address
+ * @userdata2 <unused>
+ * @devdesc PnorDD::readRegSPI> Unsupported Operation
+ */
+ return new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ PNOR::MOD_PNORDD_READREGSPI,
+ PNOR::RC_UNSUPPORTED_OPERATION,
+ TO_UINT64(i_addr),
+ 0);
+
+}
+
+/**
+ * @brief Write a SPI Register
+ */
+errlHndl_t PnorDD::writeRegSPI(uint32_t i_addr,
+ uint32_t i_data)
+{
+ //@todo - Finish with Story 35728
+ TRACFCOMP( g_trac_pnor, "PnorDD::writeRegSPI> Unsupported Operation : i_addr=%d", i_addr );
+ /*@
+ * @errortype
+ * @moduleid PNOR::MOD_PNORDD_WRITEREGSPI
+ * @reasoncode PNOR::RC_UNSUPPORTED_OPERATION
+ * @userdata1 Requested Address
+ * @userdata2 <unused>
+ * @devdesc PnorDD::writeRegSPI> Unsupported Operation
+ */
+ return new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ PNOR::MOD_PNORDD_WRITEREGSPI,
+ PNOR::RC_UNSUPPORTED_OPERATION,
+ TO_UINT64(i_addr),
+ 0);
+
+}
+
+
+/**
+ * @brief Read an address from LPC space
+ */
+errlHndl_t PnorDD::readLPC(uint32_t i_addr,
+ uint32_t& o_data)
+{
+ errlHndl_t l_err = NULL;
+ bool need_unlock = false;
+
+ do {
+#ifdef USE_FAKE_PNOR
+ read_fake_pnor( i_addr, static_cast<void*>(&o_data),
+ sizeof(uint32_t) );
+#else
+ //@todo - fill in with RTC 36901
+
+ //@fixme - add non-master support (RTC 36950)
+ TARGETING::Target* xscom_target =
+ TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL;
+
+ // always read/write 64 bits to SCOM
+ size_t scom_size = sizeof(uint64_t);
+
+ // atomic section >>
+ mutex_lock(&iv_mutex);
+ need_unlock = true;
+
+ // write command register with LPC address to read
+ ControlReg_t eccb_cmd;
+ eccb_cmd.read_op = 1;
+ eccb_cmd.address = i_addr;
+ l_err = deviceOp( DeviceFW::WRITE,
+ xscom_target,
+ &(eccb_cmd.data64),
+ scom_size,
+ DEVICE_XSCOM_ADDRESS(ECCB_CTL_REG) );
+ if( l_err ) { break; }
+
+ // poll for complete and get the data back
+ StatusReg_t eccb_stat;
+ while(1) //@fixme - need a timeout value
+ {
+ l_err = deviceOp( DeviceFW::READ,
+ xscom_target,
+ &(eccb_stat.data64),
+ scom_size,
+ DEVICE_XSCOM_ADDRESS(ECCB_STAT_REG) );
+ if( l_err ) { break; }
+
+ if( eccb_stat.op_done == 1 )
+ {
+ break;
+ }
+
+ //@fixme - simics doesn't set the done bit yet (RTC 36901)
+ break;
+ }
+ if( l_err ) { break; }
+
+ // check for errors
+ if( eccb_stat.data64 & LPC_STAT_REG_ERROR_MASK )
+ {
+ TRACFCOMP(g_trac_pnor, "PnorDD::readLPC> Error from LPC Status Register : i_addr=0x%.8X, status=0x%.16X", i_addr, eccb_stat.data64 );
+
+ /*@
+ * @errortype
+ * @moduleid PNOR::MOD_PNORDD_READLPC
+ * @reasoncode PNOR::RC_LPC_ERROR
+ * @userdata1 LPC Address
+ * @userdata2 ECCB Status Register
+ * @devdesc PnorDD::readLPC> Error from LPC Status Register
+ */
+ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ PNOR::MOD_PNORDD_READLPC,
+ PNOR::RC_LPC_ERROR,
+ TWO_UINT32_TO_UINT64(0,i_addr),
+ eccb_stat.data64);
+ l_err->collectTrace("PNOR");
+ l_err->collectTrace("XSCOM");
+ //@todo - Any cleanup or recovery needed?
+ break;
+ }
+
+ // atomic section <<
+ mutex_unlock(&iv_mutex);
+ need_unlock = false;
+
+ // copy data out to caller's buffer
+ o_data = eccb_stat.read_data;
+#endif
+ } while(0);
+
+ if( need_unlock )
+ {
+ mutex_unlock(&iv_mutex);
+ need_unlock = false;
+ }
+
+ return l_err;
+}
+
+/**
+ * @brief Write an address from LPC space
+ */
+errlHndl_t PnorDD::writeLPC(uint32_t i_addr,
+ uint32_t i_data)
+{
+ errlHndl_t l_err = NULL;
+ bool need_unlock = false;
+
+ do {
+#ifdef USE_FAKE_PNOR
+ write_fake_pnor( i_addr, static_cast<void*>(&i_data),
+ sizeof(uint32_t) );
+#else
+ //@todo - fill in with RTC 36901
+
+ //@fixme - add non-master support (RTC 36950)
+ TARGETING::Target* xscom_target =
+ TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL;
+
+ // always read/write 64 bits to SCOM
+ size_t scom_size = sizeof(uint64_t);
+
+ // atomic section >>
+ mutex_lock(&iv_mutex);
+ need_unlock = true;
+
+ // write data register
+ uint64_t eccb_data = static_cast<uint64_t>(i_data);
+ l_err = deviceOp( DeviceFW::WRITE,
+ xscom_target,
+ &eccb_data,
+ scom_size,
+ DEVICE_XSCOM_ADDRESS(ECCB_DATA_REG) );
+ if( l_err ) { break; }
+
+ // write command register with LPC address to write
+ ControlReg_t eccb_cmd;
+ eccb_cmd.read_op = 0;
+ eccb_cmd.address = i_addr;
+ l_err = deviceOp( DeviceFW::WRITE,
+ xscom_target,
+ &(eccb_cmd.data64),
+ scom_size,
+ DEVICE_XSCOM_ADDRESS(ECCB_CTL_REG) );
+ if( l_err ) { break; }
+
+ // poll for complete and get the data back
+ StatusReg_t eccb_stat;
+ while(1) //@fixme - need a timeout value
+ {
+ l_err = deviceOp( DeviceFW::READ,
+ xscom_target,
+ &(eccb_stat.data64),
+ scom_size,
+ DEVICE_XSCOM_ADDRESS(ECCB_STAT_REG) );
+ if( l_err ) { break; }
+
+ if( eccb_stat.op_done == 1 )
+ {
+ break;
+ }
+
+ //@fixme - simics doesn't set the done bit yet : RTC 36901
+ break;
+ }
+ if( l_err ) { break; }
+
+ // check for errors
+ if( eccb_stat.data64 & LPC_STAT_REG_ERROR_MASK )
+ {
+ TRACFCOMP(g_trac_pnor, "PnorDD::writeLPC> Error from LPC Status Register : i_addr=0x%.8X, status=0x%.16X", i_addr, eccb_stat.data64 );
+
+ /*@
+ * @errortype
+ * @moduleid PNOR::MOD_PNORDD_WRITELPC
+ * @reasoncode PNOR::RC_LPC_ERROR
+ * @userdata1 LPC Address
+ * @userdata2 ECCB Status Register
+ * @devdesc PnorDD::writeLPC> Error from LPC Status Register
+ */
+ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ PNOR::MOD_PNORDD_WRITELPC,
+ PNOR::RC_LPC_ERROR,
+ TWO_UINT32_TO_UINT64(0,i_addr),
+ eccb_stat.data64);
+ l_err->collectTrace("PNOR");
+ l_err->collectTrace("XSCOM");
+ //@todo - Any cleanup or recovery needed?
+ break;
+ }
+
+ // atomic section <<
+ mutex_unlock(&iv_mutex);
+ need_unlock = false;
+#endif
+ } while(0);
+
+ if( need_unlock )
+ {
+ mutex_unlock(&iv_mutex);
+ need_unlock = false;
+ }
+
+ return l_err;
+}
+
+/**
+ * @brief Compare the existing data in 1 erase block of the flash with
+ * the incoming data and write or erase as needed
+ */
+errlHndl_t PnorDD::compareAndWriteBlock(uint32_t i_targetAddr,
+ uint32_t i_wordsToWrite,
+ uint32_t* i_data)
+{
+ TRACDCOMP(g_trac_pnor,"compareAndWriteBlock(0x%.8X,%d,%p)", i_targetAddr, i_wordsToWrite, i_data);
+ errlHndl_t l_err = NULL;
+
+ // remember any data we read so we don't have to reread it later
+ typedef struct
+ {
+ uint32_t data;
+ bool wasRead;
+ bool diff;
+ } readflag_t;
+ readflag_t* read_data = NULL;
+
+ do {
+#ifndef SMART_WRITE
+ // LPC is accessed 32-bits at a time...
+ uint64_t words_written = 0;
+ for( uint32_t addr = i_targetAddr;
+ addr < (i_targetAddr+i_wordsToWrite*sizeof(uint32_t));
+ addr += sizeof(uint32_t) )
+ {
+ l_err = writeLPC( addr, i_data[words_written] );
+ if( l_err ) { break; }
+
+ words_written++;
+ }
+ o_bytesWritten = words_written*sizeof(uint32_t);
+ if( l_err ) { break; }
+
+
+#else
+
+ // remember any data we read so we don't have to reread it later
+ read_data = new readflag_t[ERASESIZE_WORD32];
+ for( size_t x = 0; x < ERASESIZE_WORD32; x++ )
+ {
+ read_data[x].wasRead = false;
+ read_data[x].diff = false;
+ }
+
+ // remember if we need to erase the block or not
+ bool need_erase = false;
+
+ // walk through every word of data to see what changed
+ const uint32_t block_addr = findEraseBlock(i_targetAddr);
+ for( uint64_t bword = 0; bword < ERASESIZE_WORD32; bword++ )
+ {
+ // note: bword is the offset into the flash block
+ read_data[bword].diff = false;
+
+ // no need to check data before where the write starts
+ if( (block_addr + bword*sizeof(uint32_t)) < i_targetAddr )
+ {
+ continue;
+ }
+ // no need to check data after where the write ends
+ else if( (block_addr + bword*sizeof(uint32_t)) >=
+ (i_targetAddr + i_wordsToWrite*sizeof(uint32_t)) )
+ {
+ // done looking now
+ break;
+ }
+ // otherwise we need to compare our data with what is in flash now
+ else
+ {
+ l_err = readLPC( block_addr + bword*sizeof(uint32_t),
+ read_data[bword].data );
+ if( l_err ) { break; }
+
+ read_data[bword].wasRead = true;
+
+ // dword is the offset into the input data
+ uint64_t dword = (block_addr + bword*sizeof(uint32_t));
+ dword -= i_targetAddr; //offset into user data
+ dword = dword / sizeof(uint32_t); //convert bytes to words
+
+ // look for any bits being changed (using XOR)
+ if( read_data[bword].data ^ i_data[dword] )
+ {
+ read_data[bword].diff = true;
+
+ // look for any bits that go from 1->0
+ if( read_data[bword].data & ~(i_data[dword]) )
+ {
+ need_erase = true;
+ }
+
+ // push the user data into the read buffer
+ // to get written later
+ read_data[bword].data = i_data[dword];
+ }
+ }
+ }
+ if( l_err ) { break; }
+
+ // erase the block if we need to
+ if( need_erase )
+ {
+ // first we need to save off any data we didn't read yet
+ // that is not part of the data we are writing
+ for( uint64_t bword = 0; bword < ERASESIZE_WORD32; bword++ )
+ {
+ // mark the word as different to force a write below
+ read_data[bword].diff = true;
+
+ // skip what we already read
+ if( read_data[bword].wasRead )
+ {
+ continue;
+ }
+
+ // dword is the offset into the input data
+ uint64_t dword = (block_addr + bword*sizeof(uint32_t));
+ dword -= i_targetAddr; //offset into user data
+ dword = dword / sizeof(uint32_t); //convert bytes to words
+
+ // restore the data before the write section
+ if( (block_addr + bword*sizeof(uint32_t)) < i_targetAddr )
+ {
+ l_err = readLPC( block_addr + bword*sizeof(uint32_t),
+ read_data[bword].data );
+ if( l_err ) { break; }
+ }
+ // restore the data after the write section
+ else if( (block_addr + bword*sizeof(uint32_t)) >=
+ (i_targetAddr + i_wordsToWrite*sizeof(uint32_t)) )
+ {
+ l_err = readLPC( block_addr + bword*sizeof(uint32_t),
+ read_data[bword].data );
+ if( l_err ) { break; }
+ }
+ // otherwise we will use the write data directly
+ else
+ {
+ read_data[bword].data = i_data[dword];
+ }
+ }
+ if( l_err ) { break; }
+
+ // erase the flash
+ l_err = eraseFlash( block_addr );
+ if( l_err ) { break; }
+ }
+
+ // walk through every word again to write the data back out
+ uint64_t bword_written = 0;
+ for( bword_written = 0;
+ bword_written < ERASESIZE_WORD32;
+ bword_written++ )
+ {
+ // only write what we have to
+ if( !(read_data[bword_written].diff) )
+ {
+ continue;
+ }
+
+ // write the word out to the flash
+ l_err = writeLPC( block_addr + bword_written*sizeof(uint32_t),
+ read_data[bword_written].data );
+ if( l_err ) { break; }
+ //@todo - How should we handle PNOR errors?
+ }
+ if( l_err ) { break; }
+
+#endif
+
+ } while(0);
+
+ if( read_data )
+ {
+ delete[] read_data;
+ }
+
+ return l_err;
+}
+
+/**
+ * @brief Erase a block of flash
+ */
+errlHndl_t PnorDD::eraseFlash(uint32_t i_address)
+{
+ errlHndl_t l_err = NULL;
+
+ do {
+ if( findEraseBlock(i_address) != i_address )
+ {
+ /*@
+ * @errortype
+ * @moduleid PNOR::MOD_PNORDD_ERASEFLASH
+ * @reasoncode PNOR::RC_LPC_ERROR
+ * @userdata1 LPC Address
+ * @userdata2 Nearest Erase Boundary
+ * @devdesc PnorDD::eraseFlash> Address not on erase boundary
+ */
+ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ PNOR::MOD_PNORDD_ERASEFLASH,
+ PNOR::RC_LPC_ERROR,
+ TWO_UINT32_TO_UINT64(0,i_address),
+ findEraseBlock(i_address));
+ break;
+ }
+
+ // log the erase of this block
+ iv_erases[i_address/ERASESIZE_BYTES]++;
+ TRACFCOMP(g_trac_pnor, "PnorDD::eraseFlash> Block 0x%.8X has %d erasures", i_address, iv_erases[i_address/ERASESIZE_BYTES] );
+
+ //@todo - issue some LPC/SPI commands to erase the block RTC 35728
+ char* ptr = (char*)(FAKE_PNOR_START+i_address);
+ memset( ptr, 0, ERASESIZE_BYTES );
+ } while(0);
+
+ return l_err;
+}
+
+
}; //end PNOR namespace
+
+
+
+#ifdef USE_FAKE_PNOR
+void write_fake_pnor( uint64_t i_pnorAddr, void* i_buffer, size_t i_size )
+{
+ //create a pointer to the offset start.
+ char * destPtr = (char *)(FAKE_PNOR_START+i_pnorAddr);
+
+ //copy data from memory into the buffer.
+ memcpy(destPtr, i_buffer, i_size);
+}
+void read_fake_pnor( uint64_t i_pnorAddr, void* o_buffer, size_t i_size )
+{
+ //create a pointer to the offset start.
+ char * srcPtr = (char *)(FAKE_PNOR_START+i_pnorAddr);
+
+ //copy data from memory into the buffer.
+ memcpy(o_buffer, srcPtr, i_size);
+}
+#endif
diff --git a/src/usr/pnor/pnordd.H b/src/usr/pnor/pnordd.H
index 8d3b7a9a9..6b102ea3b 100644
--- a/src/usr/pnor/pnordd.H
+++ b/src/usr/pnor/pnordd.H
@@ -30,89 +30,285 @@
namespace PNOR
{
-//Not sure if this is the right place for these enums, open to suggestions.
/**
- * PNOR Modes
+ * @brief Type definition for PNOR address
*/
-enum lscMode
+typedef uint64_t PNORAddress_t;
+
+
+class PnorDD
{
- MMRD = 0, /**< Indicates PNOR is in MMRD Mode */
- PMWR, /**< Indicates PNOR is in PMWR Mode */
- LAST_MODE,
-};
+ public:
+ /**
+ * @brief Performs a PNOR Read Operation
+ *
+ * @parm o_buffer Buffer to read data into
+ * @parm io_buflen Input: Number of bytes to read,
+ * Output: Number of bytes actually read
+ * @parm i_address Offset into flash to read
+ *
+ * @return Error from operation
+ */
+ errlHndl_t readFlash(void* o_buffer,
+ size_t& io_buflen,
+ uint64_t i_address);
+ /**
+ * @brief Performs a PNOR Write Operation
+ *
+ * @parm i_buffer Buffer to write data from
+ * @parm io_buflen Input: Number of bytes to write,
+ * Output: Number of bytes actually written
+ * @parm i_address Offset into flash to write
+ *
+ * @return Error from operation
+ */
+ errlHndl_t writeFlash(void* i_buffer,
+ size_t& io_buflen,
+ uint64_t i_address);
-/**
- * @brief Type definition for PNOR address
- */
-typedef uint64_t PNORAddress_t;
+ protected:
+ /**
+ * @brief Constructor
+ */
+ PnorDD();
-//@TODO: comment args
-/**
- * @brief External interface for setting LSC mode
- */
-errlHndl_t setLSCAccessMode(lscMode i_mode);
+ /**
+ * @brief Destructor
+ */
+ ~PnorDD();
+ /**
+ * @brief Verify flash request is in appropriate address range
+ *
+ * @i_address Flash address being operated on
+ * @i_length Length of chunk being operated on
+ *
+ * @return Error if requested address range is invalid
+ */
+ errlHndl_t verifyFlashAddressRange(uint64_t i_address,
+ size_t& i_length);
-class PnorDD
-{
+ /**
+ * @brief LPC HC Registers
+ * These are offsets within the LPC Host Controller Register Space
+ */
+ enum LpcRegAddr {
+ LPC_REG_BAR0 = 0x00, /**< BAR0 : OPB register */
+ LPC_REG_BAR1 = 0x04, /**< BAR1 : LPC I/O space */
+ LPC_REG_BAR2 = 0x08, /**< BAR2 : LPC Memory space */
+ LPC_REG_BAR3 = 0x0C, /**< BAR3 : LPC Firmware space */
+ };
+
+ /**
+ * @brief Read a LPC Host Controller Register
+ *
+ * @parm i_addr Register address, relative to the
+ * LPC Host Controller Register Space
+ * @parm o_data Buffer to read data into
+ *
+ * @return Error from operation
+ */
+ errlHndl_t readRegLPC(LpcRegAddr i_addr,
+ uint32_t& o_data);
- public:
- //@TODO: comment args
/**
- * @brief Performs an PNOR Read Operation
+ * @brief Write a LPC Host Controller Register
+ *
+ * @parm i_addr Register address, relative to the
+ * LPC Host Controller Register Space
+ * @parm o_data Data to write
+ *
+ * @return Error from operation
*/
- errlHndl_t read(void* o_buffer,
- size_t& io_buflen,
- uint64_t i_address);
+ errlHndl_t writeRegLPC(LpcRegAddr i_addr,
+ uint32_t i_data);
- //@TODO: comment args
/**
- * @brief Performs an PNOR Write Operation
+ * @brief Read a SPI Register
+ *
+ * @parm i_addr Register address, relative to the SPI engine
+ * @parm o_data Buffer to read data into
+ *
+ * @return Error from operation
*/
- errlHndl_t write(void* i_buffer,
- size_t& io_buflen,
- uint64_t i_address);
+ errlHndl_t readRegSPI(uint32_t i_addr,
+ uint32_t& o_data);
- //@TODO: comment args
/**
- * @brief Set LSC to desired access mode
+ * @brief Write a SPI Register
+ *
+ * @parm i_addr Register address, relative to the SPI engine
+ * @parm o_data Data to write
+ *
+ * @return Error from operation
*/
- errlHndl_t setAccessMode(lscMode i_mode);
+ errlHndl_t writeRegSPI(uint32_t i_addr,
+ uint32_t i_data);
+ /**
+ * @brief Some general constants
+ *
+ */
+ enum {
+ LPCHC_FW_SPACE = 0xF0000000, /**< LPC Host Controller FW Space */
+ LPCHC_MEM_SPACE = 0xE0000000, /**< LPC Host Controller Mem Space */
+ LPCHC_IO_SPACE = 0xD0010000, /**< LPC Host Controller I/O Space */
+ LPCHC_REG_SPACE = 0xC0012000, /**< LPC Host Ctlr Register Space */
+
+ ECCB_CTL_REG = 0x000B0020, /**< ECCB Control Reg (FW) */
+ ECCB_STAT_REG = 0x000B0022, /**< ECCB Status Reg (FW) */
+ ECCB_DATA_REG = 0x000B0023, /**< ECCB Data Reg (FW) */
+
+ // Default Values to set for all operations
+ // 1101.0100.0000.000x.0000.0001.0000.0000.<address>
+ LPC_CTL_REG_DEFAULT = 0xD400010000000000,
+
+ LPC_STAT_REG_ERROR_MASK = 0xFC0000000007F700, /**< Error Bits */
+
+ PNORSIZE = 3 * MEGABYTE, //@fixme - read from TOC instead
+ ERASESIZE_BYTES = 4 * KILOBYTE, /**< Minimum Erase Block (bytes) */
+ ERASESIZE_WORD32 = ERASESIZE_BYTES/(sizeof(uint32_t)), /**< Erase Block (32-bit words) */
+ };
+
- protected:
/**
- * @brief Constructor
+ * @brief Read an address from LPC space
+ *
+ * @parm i_addr Absolute LPC Address
+ * @parm o_data Buffer to read data into
+ *
+ * @return Error from operation
*/
- PnorDD();
+ errlHndl_t readLPC(uint32_t i_addr,
+ uint32_t& o_data);
+ /**
+ * @brief Write an address from LPC space
+ *
+ * @parm i_addr Absolute LPC Address
+ * @parm o_data Data to write
+ *
+ * @return Error from operation
+ */
+ errlHndl_t writeLPC(uint32_t i_addr,
+ uint32_t i_data);
/**
- * @brief Destructor
+ * @brief Erase a block of flash
+ *
+ * @parm i_address Offset into flash to erase, aligned to erase block
+ *
+ * @return Error from operation
*/
- ~PnorDD();
+ errlHndl_t eraseFlash(uint32_t i_address);
+
+ /**
+ * @brief Compare the existing data in 1 erase block of the flash with
+ * the incoming data and write or erase as needed
+ *
+ * @parm i_targetAddr Starting address to write
+ * @parm i_wordsToWrite Number of 32-bit words to write
+ * @parm i_data Buffer of data to write
+ *
+ * @return Error from operation
+ */
+ errlHndl_t compareAndWriteBlock(uint32_t i_targetAddr,
+ uint32_t i_wordsToWrite,
+ uint32_t* i_data);
+
+ /**
+ * @brief Determine the nearest flash address aligned to an erase block
+ *
+ * @parm i_address Offset into flash
+ *
+ * @return Block-aligned flash address
+ */
+ uint32_t findEraseBlock(uint32_t i_address)
+ {
+ return (i_address - i_address%ERASESIZE_BYTES);
+ };
- //@TODO: comment args
/**
- * Verify Request is in appropriate address range
+ * @brief Determine the number of erase blocks that are included in
+ * the given range
+ *
+ * @parm i_address Offset into flash
+ * @parm i_byteSize Number of bytes in range
*
+ * @return Number of full or partial erase blocks
*/
- errlHndl_t verifyAddressRange(uint64_t i_address,
- size_t& i_length);
+ uint32_t getNumAffectedBlocks(uint32_t i_address,
+ size_t i_byteSize)
+ {
+ uint32_t blocks = 0;
+ uint32_t addr = i_address;
+ while( findEraseBlock(addr) < (i_address+i_byteSize) )
+ {
+ blocks++;
+ addr += ERASESIZE_BYTES;
+ }
+ return blocks;
+ };
- private:
+ /**
+ * @brief ECCB Control Register Layout
+ */
+ union ControlReg_t
+ {
+ uint64_t data64;
+ struct
+ {
+ // unused sections should be set to zero
+ uint64_t magic1 : 8; /**< 0:7 = b11010100 per spec */
+ uint64_t unused1 : 7; /**< 8:14 */
+ uint64_t read_op : 1; /**< 15 = set for read operation */
+ uint64_t unused2 : 7; /**< 16:22 */
+ uint64_t addr_len : 3; /**< 23:25 = 100 means 4 byte */
+ uint64_t unused3 : 6; /**< 26:31 */
+ uint64_t address : 32; /**< 32:63 = LPC Address */
+ };
+
+ ControlReg_t() : data64(LPC_CTL_REG_DEFAULT) {};
+ };
/**
- * PNOR Mode Flag
+ * @brief ECCB Status Register Layout
*/
- lscMode iv_lscMode;
+ union StatusReg_t
+ {
+ uint64_t data64;
+ struct
+ {
+ uint64_t pib_errors : 6; /**< 0:5 */
+ uint64_t read_data : 32; /**< 6:37 */
+ uint64_t unused1 : 6; /**< 38:43 */
+ uint64_t busy : 1; /**< 44 = Operation Busy */
+ uint64_t errors1 : 7; /**< 45:51 */
+ uint64_t op_done : 1; /**< 52 */
+ uint64_t errors2 : 3; /**< 53:55 */
+ uint64_t unused2 : 8; /**< 56:63 */
+ };
+ StatusReg_t() : data64(0) {};
+ };
+ private: // Variables
+ /**
+ * @brief Mutex to prevent concurrent PNOR accesses
+ */
+ mutex_t iv_mutex;
+
+ /**
+ * @brief Track PNOR erases for wear monitoring
+ * (making this static so tools can find it easier)
+ * track writes by page (=erase block)
+ */
+ uint8_t iv_erases[PNORSIZE/ERASESIZE_BYTES];
};
}; //end PNOR namespace
diff --git a/src/usr/pnor/pnorrp.C b/src/usr/pnor/pnorrp.C
index e6987d553..481653ac7 100644
--- a/src/usr/pnor/pnorrp.C
+++ b/src/usr/pnor/pnorrp.C
@@ -33,6 +33,7 @@
#include <sys/mm.h>
#include <errno.h>
#include <initservice/initserviceif.H>
+#include "pnordd.H"
// Trace definition
trace_desc_t* g_trac_pnor = NULL;
@@ -313,8 +314,7 @@ errlHndl_t PnorRP::readTOC()
iv_TOC[side][id].id = id;
iv_TOC[side][id].side = (PNOR::SideSelect)side;
iv_TOC[side][id].chip = 0;
- iv_TOC[side][id].mmrdAddr = 0;
- iv_TOC[side][id].pmrwAddr = 0;
+ iv_TOC[side][id].flashAddr = 0;
iv_TOC[side][id].virtAddr = 0;
iv_TOC[side][id].size = 0;
iv_TOC[side][id].eccProtected = 0;
@@ -322,10 +322,10 @@ errlHndl_t PnorRP::readTOC()
}
//@todo - Add in some dummy values for now
- // Will update under Story 3547
+ // Will update under Story 3871
// assume 1 chip with only 1 side for now, no sideless
- // TOC starts at offset zero in MMRD mode
+ // TOC starts at offset zero
// put some random sizes in here
iv_TOC[PNOR::SIDE_A][PNOR::TOC].size = 8 + 8 + PNOR::NUM_SECTIONS*sizeof(TOCEntry_t);
@@ -339,21 +339,16 @@ errlHndl_t PnorRP::readTOC()
iv_TOC[PNOR::SIDE_A][PNOR::HB_EXT_CODE].virtAddr = iv_TOC[PNOR::SIDE_A][PNOR::TOC].virtAddr + iv_TOC[PNOR::SIDE_A][PNOR::TOC].size;
iv_TOC[PNOR::SIDE_A][PNOR::GLOBAL_DATA].virtAddr = iv_TOC[PNOR::SIDE_A][PNOR::HB_EXT_CODE].virtAddr + iv_TOC[PNOR::SIDE_A][PNOR::HB_EXT_CODE].size;
iv_TOC[PNOR::SIDE_A][PNOR::HB_DATA].virtAddr = iv_TOC[PNOR::SIDE_A][PNOR::GLOBAL_DATA].virtAddr + iv_TOC[PNOR::SIDE_A][PNOR::GLOBAL_DATA].size;
- // MMRD offsets
- iv_TOC[PNOR::SIDE_A][PNOR::TOC].mmrdAddr = 0;
- iv_TOC[PNOR::SIDE_A][PNOR::HB_EXT_CODE].mmrdAddr = iv_TOC[PNOR::SIDE_A][PNOR::TOC].mmrdAddr + iv_TOC[PNOR::SIDE_A][PNOR::TOC].size;
- iv_TOC[PNOR::SIDE_A][PNOR::GLOBAL_DATA].mmrdAddr = iv_TOC[PNOR::SIDE_A][PNOR::HB_EXT_CODE].mmrdAddr + iv_TOC[PNOR::SIDE_A][PNOR::HB_EXT_CODE].size;
- iv_TOC[PNOR::SIDE_A][PNOR::HB_DATA].mmrdAddr = iv_TOC[PNOR::SIDE_A][PNOR::GLOBAL_DATA].mmrdAddr + iv_TOC[PNOR::SIDE_A][PNOR::GLOBAL_DATA].size;
- // PMRW offsets - no ECC support yet so just equal to MMRD
- iv_TOC[PNOR::SIDE_A][PNOR::TOC].pmrwAddr = iv_TOC[PNOR::SIDE_A][PNOR::TOC].mmrdAddr;
- iv_TOC[PNOR::SIDE_A][PNOR::HB_EXT_CODE].pmrwAddr = iv_TOC[PNOR::SIDE_A][PNOR::HB_EXT_CODE].mmrdAddr;
- iv_TOC[PNOR::SIDE_A][PNOR::GLOBAL_DATA].pmrwAddr = iv_TOC[PNOR::SIDE_A][PNOR::GLOBAL_DATA].mmrdAddr;
- iv_TOC[PNOR::SIDE_A][PNOR::HB_DATA].pmrwAddr = iv_TOC[PNOR::SIDE_A][PNOR::HB_DATA].mmrdAddr;
+ // flash
+ iv_TOC[PNOR::SIDE_A][PNOR::TOC].flashAddr = 0;
+ iv_TOC[PNOR::SIDE_A][PNOR::HB_EXT_CODE].flashAddr = iv_TOC[PNOR::SIDE_A][PNOR::TOC].flashAddr + iv_TOC[PNOR::SIDE_A][PNOR::TOC].size;
+ iv_TOC[PNOR::SIDE_A][PNOR::GLOBAL_DATA].flashAddr = iv_TOC[PNOR::SIDE_A][PNOR::HB_EXT_CODE].flashAddr + iv_TOC[PNOR::SIDE_A][PNOR::HB_EXT_CODE].size;
+ iv_TOC[PNOR::SIDE_A][PNOR::HB_DATA].flashAddr = iv_TOC[PNOR::SIDE_A][PNOR::GLOBAL_DATA].flashAddr + iv_TOC[PNOR::SIDE_A][PNOR::GLOBAL_DATA].size;
//@todo - end fake data
//@todo - load flash layout (how many chips)
- //@todo - read TOC on each chip/bank/whatever
+ //@todo - read TOC on each chip/bank/whatever
TRACUCOMP(g_trac_pnor, "< PnorRP::readTOC" );
return l_errhdl;
@@ -391,17 +386,14 @@ void PnorRP::waitForMessage()
eff_addr = (uint8_t*)message->data[0];
user_addr = (uint8_t*)message->data[1];
- //@todo - assuming MMRD mode for now (Story 3548)
- l_errhdl = computeDeviceAddr( eff_addr, PNOR::MMRD, dev_offset, chip_select, needs_ecc );
+ //figure out the real pnor offset
+ l_errhdl = computeDeviceAddr( eff_addr, dev_offset, chip_select, needs_ecc );
if( l_errhdl )
{
status_rc = -EFAULT; /* Bad address */
}
else
{
- //@todo - handle MMRD/PMRW mode
- // if MMRD then needs_ecc = false
-
switch(message->type)
{
case( MSG_MM_RP_READ ):
@@ -594,7 +586,6 @@ errlHndl_t PnorRP::writeToDevice( uint64_t i_offset,
* @brief Convert a virtual address into the PNOR device address
*/
errlHndl_t PnorRP::computeDeviceAddr( void* i_vaddr,
- PNOR::lscMode i_mode,
uint64_t& o_offset,
uint64_t& o_chip,
bool& o_ecc )
@@ -639,14 +630,7 @@ errlHndl_t PnorRP::computeDeviceAddr( void* i_vaddr,
o_chip = iv_TOC[side][id].chip;
o_ecc = iv_TOC[side][id].eccProtected;
o_offset = l_vaddr - iv_TOC[side][id].virtAddr; //offset into pnor
- if( PNOR::MMRD == i_mode )
- {
- o_offset += iv_TOC[side][id].mmrdAddr;
- }
- else
- {
- o_offset += iv_TOC[side][id].pmrwAddr;
- }
+ o_offset += iv_TOC[side][id].flashAddr;
TRACUCOMP( g_trac_pnor, "< PnorRP::computeDeviceAddr: o_offset=0x%X, o_chip=%d", o_offset, o_chip );
return l_errhdl;
diff --git a/src/usr/pnor/pnorrp.H b/src/usr/pnor/pnorrp.H
index 79d2728a2..6d387c203 100644
--- a/src/usr/pnor/pnorrp.H
+++ b/src/usr/pnor/pnorrp.H
@@ -29,7 +29,6 @@
#include <builtins.h>
#include <errl/errlentry.H>
#include <vmmconst.h>
-#include "pnordd.H"
/**
* PNOR Resource Provider
@@ -116,8 +115,7 @@ class PnorRP
uint64_t virtAddr; /**< Virtual address for the start of the section */
- uint32_t mmrdAddr; /**< Address in MMRD mode (no ECC) */
- uint32_t pmrwAddr; /**< Address in PMRW mode (with ECC) */
+ uint32_t flashAddr; /**< Address in flash */
uint32_t size; /**< Actual size of content in bytes (not including ECC) */
uint8_t chip; /**< Chip Select */
@@ -192,7 +190,6 @@ class PnorRP
* @brief Convert a virtual address into the PNOR device address
*
* @param[in] i_vaddr Virtual address of page
- * @param[in] i_mode PNOR Controller mode
* @param[out] o_offset Offset into PNOR chip
* @param[out] o_chip Which PNOR chip
* @param[out] o_ecc true=data is ECC-protected
@@ -200,7 +197,6 @@ class PnorRP
* @return Error if VA is bad
*/
errlHndl_t computeDeviceAddr( void* i_vaddr,
- PNOR::lscMode i_mode,
uint64_t& o_offset,
uint64_t& o_chip,
bool& o_ecc );
diff --git a/src/usr/pnor/test/pnorddtest.H b/src/usr/pnor/test/pnorddtest.H
index d8eb4af63..eb874904a 100644
--- a/src/usr/pnor/test/pnorddtest.H
+++ b/src/usr/pnor/test/pnorddtest.H
@@ -34,13 +34,14 @@
#include <errl/errlentry.H>
#include <pnor/pnorif.H>
#include <devicefw/userif.H>
+#include <kernel/console.H>
+#include <sys/time.h>
#define BASE_SCRATCH_SPACE 2*1024*1024+1024*512 //2.5MB offset in fake PNOR
extern trace_desc_t* g_trac_pnor;
using namespace TARGETING;
-
class PnorDdTest : public CxxTest::TestSuite
{
public:
@@ -52,95 +53,218 @@ class PnorDdTest : public CxxTest::TestSuite
*/
void test_readwrite(void)
{
- //@TODO: make this table driven so it can test more values
- //@TODO: Add some more interesting tests
-
- TARGETING::Target* l_testTarget = MASTER_PROCESSOR_CHIP_TARGET_SENTINEL;
- size_t l_size = sizeof(uint64_t);
- errlHndl_t l_err = NULL;
- uint64_t fails = 0;
- uint64_t total = 4;
-
- do{
- TS_TRACE("PnorDdTest::test_readwrite: starting");
-
- // Perform PnorDD Write 1
- uint64_t l_address = BASE_SCRATCH_SPACE+0x100;
- uint64_t l_writeData = 0x12345678FEEDB0B0;
- l_err = deviceWrite(l_testTarget,
- &l_writeData,
- l_size,
- DEVICE_PNOR_ADDRESS(0, l_address));
- if (l_err)
+ //@TODO: make this table driven so it can test more values
+ //@TODO: Add some more interesting tests
+
+ TARGETING::Target* l_testTarget = MASTER_PROCESSOR_CHIP_TARGET_SENTINEL;
+ size_t l_size = sizeof(uint64_t);
+ errlHndl_t l_err = NULL;
+ uint64_t fails = 0;
+ uint64_t total = 8;
+
+ do{
+ TS_TRACE("PnorDdTest::test_readwrite: starting");
+
+ // Perform PnorDD Write 1
+ uint64_t l_address = BASE_SCRATCH_SPACE+0x100;
+ uint64_t l_writeData = 0x12345678FEEDB0B0;
+ l_size = sizeof(uint64_t);
+ l_err = deviceWrite(l_testTarget,
+ &l_writeData,
+ l_size,
+ DEVICE_PNOR_ADDRESS(0, l_address));
+ if (l_err)
{
- TS_FAIL("PnorDdTest::test_readwrite: PNORDD write 1: deviceWrite() failed! Error committed.");
- fails++;
- break;
+ TS_FAIL("PnorDdTest::test_readwrite: PNORDD write 1: deviceWrite() failed! Error committed.");
+ errlCommit(l_err,PNOR_COMP_ID);
+ fails++;
}
-
-
- // Perform PnorDD Write 2
- l_address = BASE_SCRATCH_SPACE+0x108;
- l_writeData = 0xFEEDBEEF000ABCDE;
- l_err = deviceWrite(l_testTarget,
- &l_writeData,
- l_size,
- DEVICE_PNOR_ADDRESS(0, l_address));
- if (l_err)
+ if(l_size != sizeof(uint64_t))
{
- TS_FAIL("PnorDdTest::test_readwrite: PNORDD write 2: deviceWrite() failed! Error committed.");
- fails++;
- break;
+ TS_FAIL("PnorDdTest::test_readwrite: PNORDD write 1: Write length not expected value. Addr: 0x%llx, Exp: %d, Act: %d", l_address,
+ sizeof(uint64_t), l_size);
+ fails++;
}
- // Perform PnorDD read 1
- l_address = BASE_SCRATCH_SPACE+0x100;
- uint64_t l_readData = 0;
- l_err = deviceRead(l_testTarget,
- &l_readData,
- l_size,
- DEVICE_PNOR_ADDRESS(0, l_address));
- if (l_err)
+ // Perform PnorDD Write 2
+ l_address = BASE_SCRATCH_SPACE+0x108;
+ l_writeData = 0xFEEDBEEF000ABCDE;
+ l_size = sizeof(uint64_t);
+ l_err = deviceWrite(l_testTarget,
+ &l_writeData,
+ l_size,
+ DEVICE_PNOR_ADDRESS(0, l_address));
+ if (l_err)
{
- TS_FAIL("PnorDdTest::test_readwrite: PNORDD read 1: deviceRead() failed! Error committed.");
- fails++;
- break;
+ TS_FAIL("PnorDdTest::test_readwrite: PNORDD write 2: deviceWrite() failed! Error committed.");
+ errlCommit(l_err,PNOR_COMP_ID);
+ fails++;
}
- else if(l_readData != 0x12345678FEEDB0B0)
+ if(l_size != sizeof(uint64_t))
{
- TS_FAIL("PnorDdTest::test_readwrite: PNORDD read 1: Read data not expected value. Addr: 0x%llx, ExpData: 0x12345678FEEDB0B0, ActData: 0x%llx",
- l_address, (long long unsigned)l_readData);
- fails++;
- break;
+ TS_FAIL("PnorDdTest::test_readwrite: PNORDD write 2: Write length not expected value. Addr: 0x%llx, Exp: %d, Act: %d", l_address,
+ sizeof(uint64_t), l_size);
+ fails++;
}
- // Perform PnorDD read 2
- l_address = BASE_SCRATCH_SPACE+0x108;
- l_err = deviceRead(l_testTarget,
- &l_readData,
- l_size,
- DEVICE_PNOR_ADDRESS(0, l_address));
- if (l_err)
+ // Perform PnorDD read 1
+ l_address = BASE_SCRATCH_SPACE+0x100;
+ uint64_t l_readData = 0;
+ l_size = sizeof(uint64_t);
+ l_err = deviceRead(l_testTarget,
+ &l_readData,
+ l_size,
+ DEVICE_PNOR_ADDRESS(0, l_address));
+ if (l_err)
{
- TS_FAIL("PnorDdTest::test_readwrite: PNORDD read 2: deviceRead() failed! Error committed.");
- break;
+ TS_FAIL("PnorDdTest::test_readwrite: PNORDD read 1: deviceRead() failed! Error committed.");
+ errlCommit(l_err,PNOR_COMP_ID);
+ fails++;
}
- else if(l_readData != 0xFEEDBEEF000ABCDE)
+ if(l_readData != 0x12345678FEEDB0B0)
{
- TS_FAIL("PnorDdTest::test_readwrite: PNORDD read 2: Read data not expected value. Addr: 0x%llx, ExpData: 0xFEEDBEEF000ABCDE, ActData: 0x%llx",
- l_address, (long long unsigned)l_readData );
- fails++;
- break;
+ TS_FAIL("PnorDdTest::test_readwrite: PNORDD read 1: Read data not expected value. Addr: 0x%llx, ExpData: 0x12345678FEEDB0B0, ActData: 0x%llx",
+ l_address, (long long unsigned)l_readData);
+ fails++;
+ }
+ if(l_size != sizeof(uint64_t))
+ {
+ TS_FAIL("PnorDdTest::test_readwrite: PNORDD read 1: Read length not expected value. Addr: 0x%llx, Exp: %d, Act: %d", l_address,
+ sizeof(uint64_t), l_size);
+ fails++;
}
- }while(0);
+ // Perform PnorDD read 2
+ l_address = BASE_SCRATCH_SPACE+0x108;
+ l_size = sizeof(uint64_t);
+ l_err = deviceRead(l_testTarget,
+ &l_readData,
+ l_size,
+ DEVICE_PNOR_ADDRESS(0, l_address));
+ if (l_err)
+ {
+ TS_FAIL("PnorDdTest::test_readwrite: PNORDD read 2: deviceRead() failed! Error committed.");
+ errlCommit(l_err,PNOR_COMP_ID);
+ fails++;
+ break;
+ }
+ if(l_readData != 0xFEEDBEEF000ABCDE)
+ {
+ TS_FAIL("PnorDdTest::test_readwrite: PNORDD read 2: Read data not expected value. Addr: 0x%llx, ExpData: 0xFEEDBEEF000ABCDE, ActData: 0x%llx",
+ l_address, (long long unsigned)l_readData );
+ fails++;
+ break;
+ }
+ if(l_size != sizeof(uint64_t))
+ {
+ TS_FAIL("PnorDdTest::test_readwrite: PNORDD read 2: Read length not expected value. Addr: 0x%llx, Exp: %d, Act: %d", l_address,
+ sizeof(uint64_t), l_size);
+ fails++;
+ }
+ }while(0);
- TRACFCOMP(g_trac_pnor, "PnorDdTest::test_readwrite> %d/%d fails", fails, total );
+ TRACFCOMP(g_trac_pnor, "PnorDdTest::test_readwrite> %d/%d fails", fails, total );
};
+ /**
+ * @brief PNOR DD smart write/erase test
+ * Write some data to PNOR to force an erase
+ */
+ void test_smartwrite(void)
+ {
+ TARGETING::Target* l_testTarget = MASTER_PROCESSOR_CHIP_TARGET_SENTINEL;
+ size_t l_size = sizeof(uint64_t);
+ errlHndl_t l_err = NULL;
+ uint64_t fails = 0;
+ uint64_t total = 8;
+
+ do{
+ TS_TRACE("PnorDdTest::test_smartwrite: starting");
+
+ // Perform PnorDD Write 1
+ uint64_t l_address = BASE_SCRATCH_SPACE+0x120;
+ uint64_t l_writeData = 0xAAAAAAAA55555555;
+ l_size = sizeof(uint64_t);
+ l_err = deviceWrite(l_testTarget,
+ &l_writeData,
+ l_size,
+ DEVICE_PNOR_ADDRESS(0, l_address));
+ if (l_err)
+ {
+ TS_FAIL("PnorDdTest::test_smartwrite: PNORDD write 1: deviceWrite() failed! Error committed.");
+ errlCommit(l_err,PNOR_COMP_ID);
+ fails++;
+ }
+
+ // Perform PnorDD Write 2 - no erase
+ l_writeData = 0xAAAAAAAAFFFFFFFF;
+ l_size = sizeof(uint64_t);
+ l_err = deviceWrite(l_testTarget,
+ &l_writeData,
+ l_size,
+ DEVICE_PNOR_ADDRESS(0, l_address));
+ if (l_err)
+ {
+ TS_FAIL("PnorDdTest::test_smartwrite: PNORDD write 2: deviceWrite() failed! Error committed.");
+ errlCommit(l_err,PNOR_COMP_ID);
+ fails++;
+ }
+
+ // Perform PnorDD Write 3 - put some words after the next write
+ l_writeData = 0x1234567887654321;
+ l_size = sizeof(uint64_t);
+ l_err = deviceWrite(l_testTarget,
+ &l_writeData,
+ l_size,
+ DEVICE_PNOR_ADDRESS(0, l_address+sizeof(uint64_t)));
+ if (l_err)
+ {
+ TS_FAIL("PnorDdTest::test_smartwrite: PNORDD write 3: deviceWrite() failed! Error committed.");
+ errlCommit(l_err,PNOR_COMP_ID);
+ fails++;
+ }
+
+ // Perform PnorDD Write 4 - requires erase
+ l_writeData = 0x8888888811111111;
+ l_size = sizeof(uint64_t);
+ l_err = deviceWrite(l_testTarget,
+ &l_writeData,
+ l_size,
+ DEVICE_PNOR_ADDRESS(0, l_address));
+ if (l_err)
+ {
+ TS_FAIL("PnorDdTest::test_smartwrite: PNORDD write 4: deviceWrite() failed! Error committed.");
+ errlCommit(l_err,PNOR_COMP_ID);
+ fails++;
+ }
+
+ // Perform PnorDD read
+ uint64_t l_readData = 0;
+ l_size = sizeof(uint64_t);
+ l_err = deviceRead(l_testTarget,
+ &l_readData,
+ l_size,
+ DEVICE_PNOR_ADDRESS(0, l_address));
+ if (l_err)
+ {
+ TS_FAIL("PnorDdTest::test_smartwrite: PNORDD read: deviceRead() failed! Error committed.");
+ errlCommit(l_err,PNOR_COMP_ID);
+ fails++;
+ }
+ if(l_readData != l_writeData)
+ {
+ TS_FAIL("PnorDdTest::test_smartwrite: PNORDD read: Read data not expected value. Addr: 0x%llx, ExpData: 0x%llx, ActData: 0x%llx",
+ l_address, l_writeData, l_readData);
+ fails++;
+ }
+
+ }while(0);
+ TRACFCOMP(g_trac_pnor, "PnorDdTest::test_smartwrite> %d/%d fails", fails, total );
+ }
+
/*Not really a real test, just using to verify ext image is loading properly.
Leaving it commented out because the test-case will not dynamically find the extended image based on the TOC
// void testPnorDD2(void)
OpenPOWER on IntegriCloud