diff options
-rw-r--r-- | src/build/citest/etc/patches/p8_pnor.act | 45 | ||||
-rw-r--r-- | src/build/citest/etc/patches/patchlist.txt | 7 | ||||
-rwxr-xr-x | src/build/citest/etc/workarounds.presimsetup | 29 | ||||
-rw-r--r-- | src/usr/intr/intrrp.C | 4 | ||||
-rw-r--r-- | src/usr/intr/test/intrtest.H | 32 | ||||
-rw-r--r-- | src/usr/pnor/pnordd.C | 366 | ||||
-rw-r--r-- | src/usr/pnor/pnordd.H | 82 | ||||
-rw-r--r-- | src/usr/pnor/test/pnorddtest.H | 541 |
8 files changed, 929 insertions, 177 deletions
diff --git a/src/build/citest/etc/patches/p8_pnor.act b/src/build/citest/etc/patches/p8_pnor.act new file mode 100644 index 000000000..86d7b040b --- /dev/null +++ b/src/build/citest/etc/patches/p8_pnor.act @@ -0,0 +1,45 @@ +##### +# LPC Actions through ECCB + +# Catch LPC Read to flash +CAUSE_EFFECT { + LABEL=[LPC Read] + WATCH=[REG(0x000B0020)] #ECCB Control Reg (FW) + # look for a read command + CAUSE: TARGET=[REG(0x000B0020)] OP=[EQUALTO,BUF,MASK] DATA=[LITERAL(64,D4010100 F0000000)] MASK=[LITERAL(64,FFFFFFFF F0000000)] + # push the address into a dummy reg + EFFECT: TARGET=[REG(0xDDDD0000)] OP=[EQUALTO,BUF,MASK] DATA=[REG(0x000B0020)] MASK=[LITERAL(64,00000000 0FFFFFFF)] + # move the address into our PNOR space (5 MB) + EFFECT: TARGET=[REG(0xDDDD0000)] OP=[INCREMENT,MASK] INCVAL=[5242880] MASK=[LITERAL(64,00000000 FFFFFFFF)] + # write the data from mainstore into another dummy reg + EFFECT: TARGET=[MODULE(readMainstore, 0xDDDD0000)] OP=[MODULECALL] DATA=[REG(0xDDDD0001)] + # Copy 32-bits into the ECCB Data Reg (FW) + EFFECT: TARGET=[REG(0x000B0023)] OP=[EQUALTO,BUF,MASK] DATA=[REG(0xDDDD0001)] MASK=[LITERAL(64,FFFFFFFF 00000000)] + # Copy the data into the ECCB Status Reg (FW) bits 6:37 + EFFECT: TARGET=[REG(0x000B0022)] OP=[EQUALTO,BUF,MASK,SHIFT] DATA=[REG(0xDDDD0001)] MASK=[LITERAL(64,03FFFFFF FC000000)] SHIFT=[6] + #ECCB Status Reg (FW) done bit + EFFECT: TARGET=[REG(0x000B0022)] OP=[BIT,ON] BIT=[52] +} + + +# Catch LPC Write to flash +CAUSE_EFFECT { + LABEL=[LPC Write] + WATCH=[REG(0x000B0020)] #ECCB Control Reg (FW) + # look for a read command + CAUSE: TARGET=[REG(0x000B0020)] OP=[EQUALTO,BUF,MASK] DATA=[LITERAL(64,D4000100 F0000000)] MASK=[LITERAL(64,FFFFFFFF F0000000)] + # push the address into a dummy reg + EFFECT: TARGET=[REG(0xDDDD0000)] OP=[EQUALTO,BUF,MASK] DATA=[REG(0x000B0020)] MASK=[LITERAL(64,00000000 0FFFFFFF)] + # move the address into our PNOR space (5 MB) + EFFECT: TARGET=[REG(0xDDDD0000)] OP=[INCREMENT,MASK] INCVAL=[5242880] MASK=[LITERAL(64,00000000 FFFFFFFF)] + # copy the data from mainstore into the dummy reg since it reads 64-bits but we only write 32 + EFFECT: TARGET=[MODULE(readMainstore, 0xDDDD0000)] OP=[MODULECALL] DATA=[REG(0xDDDD0001)] + # Copy 32-bits from the ECCB Data Reg (FW) into a dummy reg + EFFECT: TARGET=[REG(0xDDDD0001)] OP=[EQUALTO,BUF,MASK] DATA=[REG(0x000B0023)] MASK=[LITERAL(64,FFFFFFFF 00000000)] + # write the data from the dummy reg into mainstore + EFFECT: TARGET=[MODULE(writeMainstore, 0xDDDD0000)] OP=[MODULECALL] DATA=[REG(0xDDDD0001)] + #ECCB Status Reg (FW) done bit + EFFECT: TARGET=[REG(0x000B0022)] OP=[BIT,ON] BIT=[52] +} + + diff --git a/src/build/citest/etc/patches/patchlist.txt b/src/build/citest/etc/patches/patchlist.txt new file mode 100644 index 000000000..4ad66ac3f --- /dev/null +++ b/src/build/citest/etc/patches/patchlist.txt @@ -0,0 +1,7 @@ +Enable ECCB-based LPC/PNOR access (temporary) +-RTC: Story 37972 will be used to remove the patches +-CQ: No fips defect because these changes are not permanent +-Files: p8_pnor.act +-Coreq: associated changes are also in workarounds.presimsetup + + diff --git a/src/build/citest/etc/workarounds.presimsetup b/src/build/citest/etc/workarounds.presimsetup index 21c704c8f..b7653947e 100755 --- a/src/build/citest/etc/workarounds.presimsetup +++ b/src/build/citest/etc/workarounds.presimsetup @@ -43,24 +43,29 @@ sed -i -e's/SETENV GFW_P8_VENICE_L3_MB_SIZE.*/SETENV GFW_P8_VENICE_L3_MB_SIZE 8/ #Note: Leave this here as an example -#echo "+++ Update to new simics build." +#echo "+++ Update to new simics build for ECCB support." #mkdir -p $sb/simu/data #egrep -v "WSALIAS HOSTBOOT_LEVEL FIPSLEVEL|WSALIAS HOSTBOOT_LEVEL SIMICSLEVEL" $BACKING_BUILD/src/simu/data/simicsInfo > $sb/simu/data/simicsInfo -#echo "WSALIAS HOSTBOOT_LEVEL FIPSLEVEL env/gfwa/simics-4.2.0/simics-4.2.82/fips/fld36/fi111110b700.42" >> $sb/simu/data/simicsInfo -#echo "WSALIAS HOSTBOOT_LEVEL SIMICSLEVEL env/vtechb/simics-4.2.0/simics-4.2.82/bin" >> $sb/simu/data/simicsInfo +#echo "WSALIAS HOSTBOOT_LEVEL FIPSLEVEL env/gfwb/simics-4.2.0/simics-4.2.83/fips/fld36/fi120201a700.42" >> $sb/simu/data/simicsInfo +#echo "WSALIAS HOSTBOOT_LEVEL SIMICSLEVEL env/vtechb/simics-4.2.0/simics-4.2.83/bin" >> $sb/simu/data/simicsInfo -echo "+++ Add some logic regs for Simics workaround." +echo "+++ Add some scom regs and actions for ECCB fakeout." mkdir -p $sb/simu/data/cec-chip/ -cp --update $BACKING_BUILD/src/simu/data/cec-chip/centaur.chip $sb/simu/data/cec-chip/centaur.chip.orig -grep -v DONE $sb/simu/data/cec-chip/centaur.chip.orig > $sb/simu/data/cec-chip/centaur.chip -echo "INTERNALREGS # List all scom registers" >> $sb/simu/data/cec-chip/centaur.chip -echo " 0xFF00000F, 64 # Simics workaround" >> $sb/simu/data/cec-chip/centaur.chip -echo "END" >> $sb/simu/data/cec-chip/centaur.chip -echo "DONE" >> $sb/simu/data/cec-chip/centaur.chip +cp --update $BACKING_BUILD/src/simu/data/cec-chip/p8.chip $sb/simu/data/cec-chip/p8.chip.orig +grep -v DONE $sb/simu/data/cec-chip/p8.chip.orig > $sb/simu/data/cec-chip/p8.chip +echo "ACTIONS=p8_pnor.act #workarounds.presimsetup" >> $sb/simu/data/cec-chip/p8.chip +echo "SCOMREGS #workarounds.presimsetup" >> $sb/simu/data/cec-chip/p8.chip +echo " 0xDDDD0000,64 # dummy to hold pnor address" >> $sb/simu/data/cec-chip/p8.chip +echo " 0xDDDD0001,64 # dummy to hold pnor data" >> $sb/simu/data/cec-chip/p8.chip +echo "END" >> $sb/simu/data/cec-chip/p8.chip +echo "DONE" >> $sb/simu/data/cec-chip/p8.chip +cp $HOSTBOOTROOT/src/build/citest/etc/patches/p8_pnor.act $sb/simu/data/cec-chip/ +#fixme + echo "+++ Update to new phyp and mambo level." mkdir -p $sb/simu/data cp --update $BACKING_BUILD/src/simu/data/simicsInfo $sb/simu/data/simicsInfo sed -i -e's/^WSALIAS HOSTBOOT_LEVEL MAMBOLEVEL.*/WSALIAS HOSTBOOT_LEVEL MAMBOLEVEL env\/mamboa\/2011_11_10__4.2/' $sb/simu/data/simicsInfo -sed -i -e's/^WSALIAS HOSTBOOT_LEVEL PHYPLEVEL.*/WSALIAS HOSTBOOT_LEVEL PHYPLEVEL env\/phypa\/simics-4.2.0\/simics-4.2.82\/ph111111a700.42/' $sb/simu/data/simicsInfo -sed -i -e's/^WSALIAS HOSTBOOT_LEVEL PHYP_PATCH_LEVEL.*/WSALIAS HOSTBOOT_LEVEL PHYP_PATCH_LEVEL env\/phypa\/simics-4.2.0\/simics-4.2.82\/patches\/ph111111a700.42/' $sb/simu/data/simicsInfo +sed -i -e's/^WSALIAS HOSTBOOT_LEVEL PHYPLEVEL.*/WSALIAS HOSTBOOT_LEVEL PHYPLEVEL env\/phypa\/simics-4.2.0\/simics-4.2.83\/ph120201a700.42/' $sb/simu/data/simicsInfo +sed -i -e's/^WSALIAS HOSTBOOT_LEVEL PHYP_PATCH_LEVEL.*/WSALIAS HOSTBOOT_LEVEL PHYP_PATCH_LEVEL env\/phypa\/simics-4.2.0\/simics-4.2.82\/patches\/ph120201a700.42/' $sb/simu/data/simicsInfo diff --git a/src/usr/intr/intrrp.C b/src/usr/intr/intrrp.C index 9025a3ce8..23aa91777 100644 --- a/src/usr/intr/intrrp.C +++ b/src/usr/intr/intrrp.C @@ -132,13 +132,13 @@ errlHndl_t IntrRp::_init() // TODO Adjust the realAddr if the BAR came from a processor other // than cpuid 0 - TRACDCOMP(g_trac_intr,"INTR: realAddr = %lx",realAddr); + TRACFCOMP(g_trac_intr,"INTR: realAddr = %lx",realAddr); // VADDR_SIZE is 1MB per chip - max 32 -> 32MB iv_baseAddr = reinterpret_cast<uint64_t> (mmio_dev_map(reinterpret_cast<void*>(realAddr),THIRTYTWO_MB)); - TRACDCOMP(g_trac_intr,"INTR: vAddr = %lx",iv_baseAddr); + TRACFCOMP(g_trac_intr,"INTR: vAddr = %lx",iv_baseAddr); err = checkAddress(iv_baseAddr); if(!err) diff --git a/src/usr/intr/test/intrtest.H b/src/usr/intr/test/intrtest.H index 712e97a6e..5135d3371 100644 --- a/src/usr/intr/test/intrtest.H +++ b/src/usr/intr/test/intrtest.H @@ -30,6 +30,10 @@ #include <kernel/console.H> #include <targeting/targetservice.H> #include <targeting/util.H> +#include <sys/time.h> +#include <sys/mmio.h> + +extern trace_desc_t * g_trac_intr; class IntrTest: public CxxTest::TestSuite @@ -67,7 +71,7 @@ class IntrTest: public CxxTest::TestSuite uint64_t offset = (chip << 20) | (thread << 12); uint32_t * addr = - reinterpret_cast<uint32_t *>(cv_baseAddr + offset); + reinterpret_cast<uint32_t *>(iv_baseAddr + offset); if(offset == 0) // Master cpu { @@ -114,7 +118,7 @@ class IntrTest: public CxxTest::TestSuite return; } - uint32_t * addr = reinterpret_cast<uint32_t *>(cv_baseAddr); + uint32_t * addr = reinterpret_cast<uint32_t *>(iv_baseAddr); errlHndl_t err = INTR::disableExternalInterrupts(); @@ -161,8 +165,6 @@ class IntrTest: public CxxTest::TestSuite return; } - extern trace_desc_t * g_trac_intr; - errlHndl_t err = NULL; // Need to register a msgq @@ -177,7 +179,7 @@ class IntrTest: public CxxTest::TestSuite // Force an interrupt by writing to the MFFR on master volatile uint8_t * mfrr = - reinterpret_cast<uint8_t *>(cv_baseAddr+12); + reinterpret_cast<uint8_t *>(iv_baseAddr+12); *(mfrr) = 0x55; *(mfrr) = 0xff; @@ -192,12 +194,28 @@ class IntrTest: public CxxTest::TestSuite } + IntrTest() : CxxTest::TestSuite() + { + iv_baseAddr = reinterpret_cast<uint64_t> + (mmio_dev_map(reinterpret_cast<void*>(cv_realAddr),THIRTYTWO_MB)); + TRACDCOMP(g_trac_intr,"IntrTest()> iv_baseAddr=0x%.X",iv_baseAddr); + }; + + + ~IntrTest() + { + mmio_dev_unmap(reinterpret_cast<void*>(iv_baseAddr)); + }; + private: - static uint64_t cv_baseAddr; + uint64_t iv_baseAddr; + static const uint64_t cv_realAddr; }; -uint64_t IntrTest::cv_baseAddr = 0x20000000000ul; +//note: this must be changed if the BAR changes +const uint64_t IntrTest::cv_realAddr = 0x3fbff9000000ul; + #endif diff --git a/src/usr/pnor/pnordd.C b/src/usr/pnor/pnordd.C index 86f4efd7b..8b7982866 100644 --- a/src/usr/pnor/pnordd.C +++ b/src/usr/pnor/pnordd.C @@ -41,24 +41,16 @@ #include "pnordd.H" #include <pnor/pnorif.H> #include <pnor/pnor_reasoncodes.H> - -// 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 +#include <sys/time.h> // Uncomment this to enable smart writing -#define SMART_WRITE +//#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 +// These are used to cheat and use a chunk of our cache as a PNOR +// iv_mode == MODEL_MEMCPY,MODEL_LPC_MEM 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 +void erase_fake_pnor( uint64_t i_pnorAddr, size_t i_size ); extern trace_desc_t* g_trac_pnor; @@ -97,9 +89,10 @@ errlHndl_t ddRead(DeviceFW::OperationType i_opType, uint64_t l_addr = va_arg(i_args,uint64_t); do{ - //TODO - Fix with Story 34763 + //@todo (RTC:34763) - add support for unaligned data // Ensure we are operating on a 32-bit (4-byte) boundary assert( reinterpret_cast<uint64_t>(io_buffer) % 4 == 0 ); + assert( io_buflen % 4 == 0 ); // Read the flash l_err = Singleton<PnorDD>::instance().readFlash(io_buffer, @@ -147,9 +140,10 @@ errlHndl_t ddWrite(DeviceFW::OperationType i_opType, uint64_t l_addr = va_arg(i_args,uint64_t); do{ - //TODO - Fix with Story 34763 + //@todo (RTC:34763) - add support for unaligned data // Ensure we are operating on a 32-bit (4-byte) boundary assert( reinterpret_cast<uint64_t>(io_buffer) % 4 == 0 ); + assert( io_buflen % 4 == 0 ); // Write the flash l_err = Singleton<PnorDD>::instance().writeFlash(io_buffer, @@ -165,6 +159,7 @@ errlHndl_t ddWrite(DeviceFW::OperationType i_opType, return l_err; } + // Register PNORDD access functions to DD framework DEVICE_REGISTER_ROUTE(DeviceFW::READ, DeviceFW::PNOR, @@ -176,6 +171,8 @@ DEVICE_REGISTER_ROUTE(DeviceFW::WRITE, TARGETING::TYPE_PROC, ddWrite); +}; //namespace PNOR + /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// @@ -194,7 +191,7 @@ errlHndl_t PnorDD::readFlash(void* o_buffer, 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 = verifyFlashAddressRange(l_address, io_buflen); if(l_err) @@ -203,10 +200,12 @@ errlHndl_t PnorDD::readFlash(void* o_buffer, break; } -#ifdef FAST_FAKE_PNOR - read_fake_pnor( i_address, o_buffer, io_buflen ); - break; -#endif + // skip everything in MEMCPY mode + if( MODEL_MEMCPY == iv_mode ) + { + read_fake_pnor( l_address, o_buffer, io_buflen ); + break; + } // LPC is accessed 32-bits at a time... uint32_t* word_ptr = static_cast<uint32_t*>(o_buffer); @@ -215,12 +214,11 @@ errlHndl_t PnorDD::readFlash(void* o_buffer, addr < (i_address+io_buflen); addr += sizeof(uint32_t) ) { - uint32_t read_data = 0; - l_err = readLPC( addr, read_data ); + // flash is mapped directly in the FW space + l_err = readLPC( addr + LPCHC_FW_SPACE, + word_ptr[words_read] ); if( l_err ) { break; } - memcpy( word_ptr+words_read, &read_data, sizeof(uint32_t) ); - words_read++; } io_buflen = words_read*sizeof(uint32_t); @@ -251,19 +249,20 @@ errlHndl_t PnorDD::writeFlash(void* i_buffer, 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 + // skip everything in MEMCPY mode + if( MODEL_MEMCPY == iv_mode ) + { + write_fake_pnor( l_address, i_buffer, io_buflen ); + break; + } // 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. + // we have to erase an 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; + uint32_t cur_addr = static_cast<uint32_t>(l_address); + uint64_t num_blocks = getNumAffectedBlocks(cur_addr,io_buflen); uint64_t bytes_left = io_buflen; // loop through erase blocks until we've gotten through all @@ -279,7 +278,7 @@ errlHndl_t PnorDD::writeFlash(void* i_buffer, (bytes_left-1)/sizeof(uint32_t)+1, word_ptr ); if( l_err ) { break; } - //@todo - How should we handle PNOR errors? + //@todo (RTC:37744) - How should we handle PNOR errors? // move on to the next block if( bytes_left > ERASESIZE_BYTES ) @@ -293,9 +292,9 @@ errlHndl_t PnorDD::writeFlash(void* i_buffer, // 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); + bytes_left = (l_address + io_buflen - cur_addr); } - word_ptr += (bytes_left-1)/sizeof(uint32_t); + word_ptr += ((bytes_left-1)/sizeof(uint32_t))+1; } if( l_err ) { break; } @@ -317,19 +316,33 @@ errlHndl_t PnorDD::writeFlash(void* i_buffer, Private/Protected Methods ********************/ - /** * @brief Constructor */ -PnorDD::PnorDD() +PnorDD::PnorDD( PnorMode_t i_mode ) +: iv_mode(i_mode) { - TRACFCOMP(g_trac_pnor, "PnorDD::PnorDD()> "); mutex_init(&iv_mutex); for( uint64_t x=0; x < (PNORSIZE/ERASESIZE_BYTES); x++ ) { iv_erases[x] = 0; } + + //In the normal case we will choose the mode for the caller + if( MODEL_UNKNOWN == iv_mode ) + { + //Use ECCB scoms to drive LPC, flat memory map behind ECCB, no SPI + //iv_mode = MODEL_FLAT_ECCB; + + //Break into 32-bit LPC ops but use memcpy into cache area + iv_mode = MODEL_LPC_MEM; + + //Override for VPO, use flat model for performance + //@fixme - how?? I can't use targetting yet to tell I'm in VPO... + } + + TRACFCOMP(g_trac_pnor, "PnorDD::PnorDD()> Using mode %d", iv_mode); } /** @@ -351,9 +364,10 @@ errlHndl_t PnorDD::verifyFlashAddressRange(uint64_t i_address, do{ //@todo - Do we really need any checking here? + // if so we should be getting the size told to us by the PNOR RP + // based on the TOC or global data -#ifdef USE_FAKE_PNOR - if((i_address+i_length) > FAKE_PNOR_SIZE) + if((i_address+i_length) > PNORSIZE) { TRACFCOMP( g_trac_pnor, "PnorDD::verifyAddressRange> Invalid Address Requested : i_address=%d", i_address ); /*@ @@ -371,8 +385,6 @@ errlHndl_t PnorDD::verifyFlashAddressRange(uint64_t i_address, TO_UINT64(i_length)); break; } -#endif - }while(0); @@ -387,10 +399,11 @@ errlHndl_t PnorDD::readRegLPC(LpcRegAddr i_addr, { errlHndl_t l_err = NULL; - do { - //@todo - RTC 36901 or 35728 - } while(0); + // add the offset into the LPC register space + uint32_t lpc_addr = i_addr + LPCHC_REG_SPACE; + // call the generic LPC function + l_err = readLPC( lpc_addr, o_data ); return l_err; } @@ -400,16 +413,23 @@ errlHndl_t PnorDD::readRegLPC(LpcRegAddr i_addr, errlHndl_t PnorDD::writeRegLPC(LpcRegAddr i_addr, uint32_t i_data) { - return NULL; //@todo - RTC 36901 or 35728 + errlHndl_t l_err = NULL; + + // add the offset into the LPC register space + uint32_t lpc_addr = i_addr + LPCHC_REG_SPACE; + + // call the generic LPC function + l_err = writeLPC( lpc_addr, i_data ); + return l_err; } /** * @brief Read a SPI Register */ -errlHndl_t PnorDD::readRegSPI(uint32_t i_addr, +errlHndl_t PnorDD::readRegSPI(SpiRegAddr i_addr, uint32_t& o_data) { - //@todo - Finish with Story 35728 + //@todo (RTC:35728) - SPI Support TRACFCOMP( g_trac_pnor, "PnorDD::readRegSPI> Unsupported Operation : i_addr=%d", i_addr ); /*@ * @errortype @@ -424,16 +444,25 @@ errlHndl_t PnorDD::readRegSPI(uint32_t i_addr, PNOR::RC_UNSUPPORTED_OPERATION, TO_UINT64(i_addr), 0); - + + /* Anything more than this?? + + // add the offset into the LPC register space + uint32_t lpc_addr = i_addr + LPC_SPI_REG_OFFSET; + + // call the generic LPC function + l_err = readLPC( lpc_addr, o_data ); + + */ } /** * @brief Write a SPI Register */ -errlHndl_t PnorDD::writeRegSPI(uint32_t i_addr, +errlHndl_t PnorDD::writeRegSPI(SpiRegAddr i_addr, uint32_t i_data) { - //@todo - Finish with Story 35728 + //@todo (RTC:35728) - SPI Support TRACFCOMP( g_trac_pnor, "PnorDD::writeRegSPI> Unsupported Operation : i_addr=%d", i_addr ); /*@ * @errortype @@ -448,6 +477,16 @@ errlHndl_t PnorDD::writeRegSPI(uint32_t i_addr, PNOR::RC_UNSUPPORTED_OPERATION, TO_UINT64(i_addr), 0); + + /* Anything more than this?? + + // add the offset into the LPC register space + uint32_t lpc_addr = i_addr + LPC_SPI_REG_OFFSET; + + // call the generic LPC function + l_err = writeLPC( lpc_addr, i_data ); + + */ } @@ -462,14 +501,19 @@ errlHndl_t PnorDD::readLPC(uint32_t i_addr, 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 = + if( MODEL_LPC_MEM == iv_mode ) + { + read_fake_pnor( i_addr - LPCHC_FW_SPACE, + static_cast<void*>(&o_data), + sizeof(uint32_t) ); + break; + } + + // Note: If we got here then iv_mode is + // either MODEL_FLAT_ECCB or MODEL_REAL + + //@todo (RTC:36950) - add non-master support + TARGETING::Target* scom_target = TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL; // always read/write 64 bits to SCOM @@ -484,21 +528,23 @@ errlHndl_t PnorDD::readLPC(uint32_t i_addr, eccb_cmd.read_op = 1; eccb_cmd.address = i_addr; l_err = deviceOp( DeviceFW::WRITE, - xscom_target, + scom_target, &(eccb_cmd.data64), scom_size, - DEVICE_XSCOM_ADDRESS(ECCB_CTL_REG) ); + DEVICE_SCOM_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 + uint64_t poll_time = 0; + uint64_t loop = 0; + while( poll_time < ECCB_POLL_TIME_NS ) { l_err = deviceOp( DeviceFW::READ, - xscom_target, + scom_target, &(eccb_stat.data64), scom_size, - DEVICE_XSCOM_ADDRESS(ECCB_STAT_REG) ); + DEVICE_SCOM_ADDRESS(ECCB_STAT_REG) ); if( l_err ) { break; } if( eccb_stat.op_done == 1 ) @@ -506,42 +552,49 @@ errlHndl_t PnorDD::readLPC(uint32_t i_addr, break; } - //@fixme - simics doesn't set the done bit yet (RTC 36901) - break; + // want to start out incrementing by small numbers then get bigger + // to avoid a really tight loop in an error case so we'll increase + // the wait each time through + nanosleep( 0, ECCB_POLL_INCR_NS*(++loop) ); + poll_time += ECCB_POLL_INCR_NS*loop; } if( l_err ) { break; } - // check for errors - if( eccb_stat.data64 & LPC_STAT_REG_ERROR_MASK ) + // check for errors or timeout + if( (eccb_stat.data64 & LPC_STAT_REG_ERROR_MASK) + || (eccb_stat.op_done == 0) ) { - TRACFCOMP(g_trac_pnor, "PnorDD::readLPC> Error from LPC Status Register : i_addr=0x%.8X, status=0x%.16X", i_addr, eccb_stat.data64 ); + TRACFCOMP(g_trac_pnor, "PnorDD::readLPC> Error or timeout 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 + * @userdata1[0:31] LPC Address + * @userdata1[32:63] Total poll time (ns) * @userdata2 ECCB Status Register - * @devdesc PnorDD::readLPC> Error from LPC Status Register + * @devdesc PnorDD::readLPC> Error or timeout 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), + TWO_UINT32_TO_UINT64(i_addr,poll_time), eccb_stat.data64); l_err->collectTrace("PNOR"); l_err->collectTrace("XSCOM"); - //@todo - Any cleanup or recovery needed? + //@todo (RTC:37744) - 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 ) @@ -561,16 +614,23 @@ errlHndl_t PnorDD::writeLPC(uint32_t i_addr, { errlHndl_t l_err = NULL; bool need_unlock = false; + + //TRACFCOMP(g_trac_pnor, "writeLPC> %.8X = %.8X", i_addr, i_data ); 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 = + if( MODEL_LPC_MEM == iv_mode ) + { + write_fake_pnor( i_addr - LPCHC_FW_SPACE, + static_cast<void*>(&i_data), + sizeof(uint32_t) ); + break; + } + + // Note: If we got here then iv_mode is + // either MODEL_FLAT_ECCB or MODEL_REAL + + //@todo (RTC:36950) - add non-master support + TARGETING::Target* scom_target = TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL; // always read/write 64 bits to SCOM @@ -582,11 +642,12 @@ errlHndl_t PnorDD::writeLPC(uint32_t i_addr, // write data register uint64_t eccb_data = static_cast<uint64_t>(i_data); + eccb_data = eccb_data << 32; //left-justify my data l_err = deviceOp( DeviceFW::WRITE, - xscom_target, + scom_target, &eccb_data, scom_size, - DEVICE_XSCOM_ADDRESS(ECCB_DATA_REG) ); + DEVICE_SCOM_ADDRESS(ECCB_DATA_REG) ); if( l_err ) { break; } // write command register with LPC address to write @@ -594,21 +655,23 @@ errlHndl_t PnorDD::writeLPC(uint32_t i_addr, eccb_cmd.read_op = 0; eccb_cmd.address = i_addr; l_err = deviceOp( DeviceFW::WRITE, - xscom_target, + scom_target, &(eccb_cmd.data64), scom_size, - DEVICE_XSCOM_ADDRESS(ECCB_CTL_REG) ); + DEVICE_SCOM_ADDRESS(ECCB_CTL_REG) ); if( l_err ) { break; } - // poll for complete and get the data back + // poll for complete StatusReg_t eccb_stat; - while(1) //@fixme - need a timeout value + uint64_t poll_time = 0; + uint64_t loop = 0; + while( poll_time < ECCB_POLL_TIME_NS ) { l_err = deviceOp( DeviceFW::READ, - xscom_target, + scom_target, &(eccb_stat.data64), scom_size, - DEVICE_XSCOM_ADDRESS(ECCB_STAT_REG) ); + DEVICE_SCOM_ADDRESS(ECCB_STAT_REG) ); if( l_err ) { break; } if( eccb_stat.op_done == 1 ) @@ -616,15 +679,19 @@ errlHndl_t PnorDD::writeLPC(uint32_t i_addr, break; } - //@fixme - simics doesn't set the done bit yet : RTC 36901 - break; + // want to start out incrementing by small numbers then get bigger + // to avoid a really tight loop in an error case so we'll increase + // the wait each time through + nanosleep( 0, ECCB_POLL_INCR_NS*(++loop) ); + poll_time += ECCB_POLL_INCR_NS*loop; } if( l_err ) { break; } // check for errors - if( eccb_stat.data64 & LPC_STAT_REG_ERROR_MASK ) + if( (eccb_stat.data64 & LPC_STAT_REG_ERROR_MASK) + || (eccb_stat.op_done == 0) ) { - TRACFCOMP(g_trac_pnor, "PnorDD::writeLPC> Error from LPC Status Register : i_addr=0x%.8X, status=0x%.16X", i_addr, eccb_stat.data64 ); + TRACFCOMP(g_trac_pnor, "PnorDD::writeLPC> Error or timeout from LPC Status Register : i_addr=0x%.8X, status=0x%.16X", i_addr, eccb_stat.data64 ); /*@ * @errortype @@ -632,7 +699,8 @@ errlHndl_t PnorDD::writeLPC(uint32_t i_addr, * @reasoncode PNOR::RC_LPC_ERROR * @userdata1 LPC Address * @userdata2 ECCB Status Register - * @devdesc PnorDD::writeLPC> Error from LPC Status Register + * @devdesc PnorDD::writeLPC> Error or timeout from + * LPC Status Register */ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, PNOR::MOD_PNORDD_WRITELPC, @@ -641,14 +709,14 @@ errlHndl_t PnorDD::writeLPC(uint32_t i_addr, eccb_stat.data64); l_err->collectTrace("PNOR"); l_err->collectTrace("XSCOM"); - //@todo - Any cleanup or recovery needed? + //@todo (RTC:37744) - Any cleanup or recovery needed? break; } // atomic section << mutex_unlock(&iv_mutex); need_unlock = false; -#endif + } while(0); if( need_unlock ) @@ -668,7 +736,7 @@ 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); + TRACFCOMP(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 @@ -681,24 +749,29 @@ errlHndl_t PnorDD::compareAndWriteBlock(uint32_t i_targetAddr, 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) ) + // skip the erase block logic if we're in a memcpy mode + if( (MODEL_MEMCPY == iv_mode) || (MODEL_LPC_MEM == iv_mode) ) { - l_err = writeLPC( addr, i_data[words_written] ); + // 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) ) + { + // flash is mapped directly in the FW space + l_err = writeLPC( addr + LPCHC_FW_SPACE, + i_data[words_written] ); + if( l_err ) { break; } + + words_written++; + } if( l_err ) { break; } - words_written++; + // all done + break; } - 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++ ) @@ -732,7 +805,8 @@ errlHndl_t PnorDD::compareAndWriteBlock(uint32_t i_targetAddr, // otherwise we need to compare our data with what is in flash now else { - l_err = readLPC( block_addr + bword*sizeof(uint32_t), + l_err = readLPC( block_addr + bword*sizeof(uint32_t) + + LPCHC_FW_SPACE, read_data[bword].data ); if( l_err ) { break; } @@ -751,7 +825,15 @@ errlHndl_t PnorDD::compareAndWriteBlock(uint32_t i_targetAddr, // look for any bits that go from 1->0 if( read_data[bword].data & ~(i_data[dword]) ) { - need_erase = true; + need_erase = true; + + // push the user data into the read buffer + // to get written later + read_data[bword].data = i_data[dword]; + + // skip comparing the rest of the block, + // just start writing it + break; } // push the user data into the read buffer @@ -786,7 +868,8 @@ errlHndl_t PnorDD::compareAndWriteBlock(uint32_t i_targetAddr, // 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), + l_err = readLPC( block_addr + bword*sizeof(uint32_t) + + LPCHC_FW_SPACE, read_data[bword].data ); if( l_err ) { break; } } @@ -794,7 +877,8 @@ errlHndl_t PnorDD::compareAndWriteBlock(uint32_t i_targetAddr, else if( (block_addr + bword*sizeof(uint32_t)) >= (i_targetAddr + i_wordsToWrite*sizeof(uint32_t)) ) { - l_err = readLPC( block_addr + bword*sizeof(uint32_t), + l_err = readLPC( block_addr + bword*sizeof(uint32_t) + + LPCHC_FW_SPACE, read_data[bword].data ); if( l_err ) { break; } } @@ -824,15 +908,14 @@ errlHndl_t PnorDD::compareAndWriteBlock(uint32_t i_targetAddr, } // write the word out to the flash - l_err = writeLPC( block_addr + bword_written*sizeof(uint32_t), + l_err = writeLPC( block_addr + bword_written*sizeof(uint32_t) + + LPCHC_FW_SPACE, read_data[bword_written].data ); if( l_err ) { break; } - //@todo - How should we handle PNOR errors? + //@todo (RTC:37744) - How should we handle PNOR errors? } if( l_err ) { break; } -#endif - } while(0); if( read_data ) @@ -872,10 +955,27 @@ errlHndl_t PnorDD::eraseFlash(uint32_t i_address) // 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 ); + + if( MODEL_REAL != iv_mode ) + { + erase_fake_pnor( i_address, ERASESIZE_BYTES ); + break; //all done + } + + //@todo (RTC:35728) - issue some LPC/SPI commands to erase the block + /*@ + * @errortype + * @moduleid PNOR::MOD_PNORDD_ERASEFLASH + * @reasoncode PNOR::RC_UNSUPPORTED_OPERATION + * @userdata1 Model mode + * @userdata2 LPC Address to erase + * @devdesc PnorDD::eraseFlash> No support for MODEL_REAL yet + */ + l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, + PNOR::MOD_PNORDD_ERASEFLASH, + PNOR::RC_UNSUPPORTED_OPERATION, + static_cast<uint64_t>(iv_mode), + i_address); } while(0); return l_err; @@ -883,12 +983,13 @@ errlHndl_t PnorDD::eraseFlash(uint32_t i_address) +/* + This code is used in the MODEL_MEMCPY and MODEL_LPC_MEM modes +*/ -}; //end PNOR namespace - - - -#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 ) { //create a pointer to the offset start. @@ -905,4 +1006,13 @@ void read_fake_pnor( uint64_t i_pnorAddr, void* o_buffer, size_t i_size ) //copy data from memory into the buffer. memcpy(o_buffer, srcPtr, i_size); } -#endif +void erase_fake_pnor( uint64_t i_pnorAddr, 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. + memset( srcPtr, 0, i_size ); +} + + diff --git a/src/usr/pnor/pnordd.H b/src/usr/pnor/pnordd.H index 6b102ea3b..28d4f0b51 100644 --- a/src/usr/pnor/pnordd.H +++ b/src/usr/pnor/pnordd.H @@ -23,19 +23,16 @@ #ifndef __PNOR_PNORDD_H #define __PNOR_PNORDD_H +#include <limits.h> + /** @file pnordd.H * @brief Provides the interfaces to the PNOR Device Driver */ -namespace PNOR -{ - /** - * @brief Type definition for PNOR address + * @brief PNOR Device Driver Class + * Provides access to the PNOR flash via the ECCB/LPC/SPI hardware */ -typedef uint64_t PNORAddress_t; - - class PnorDD { @@ -70,10 +67,18 @@ class PnorDD protected: + enum PnorMode_t { + MODEL_UNKNOWN, //Invalid + MODEL_MEMCPY, //No LPC logic, just do memcpy into cache area + MODEL_LPC_MEM, //Break into 32-bit LPC ops but use memcpy into cache area + MODEL_FLAT_ECCB, //Use ECCB scoms to drive LPC, flat memory map behind ECCB, no SPI + MODEL_REAL, //Code for real hardware or complete sim model + }; + /** * @brief Constructor */ - PnorDD(); + PnorDD( PnorMode_t i_mode = MODEL_UNKNOWN ); /** @@ -128,6 +133,40 @@ class PnorDD uint32_t i_data); /** + * @brief SPI Registers + * These are offsets within the SPI Register Space + */ + enum SpiRegAddr { + SPI_REG_CMD = 0x40, /**< CMD : Command */ + SPI_REG_ADR = 0x44, /**< ADR : Address */ + SPI_REG_ERASMS = 0x48, /**< ERASMS : Small Erase Block Size */ + SPI_REG_ERASLGS = 0x4C, /**< ERALGS : Large Erase Block Size */ + SPI_REG_ADRCBF = 0x80, /**< ADRCBF : First Intf NOR Addr Offset */ + SPI_REG_ADRCMF = 0x84, /**< ADRCMF : First Intf NOR Allocation */ + SPI_REG_ADRCBS = 0x88, /**< ADRCBS : Second Intf NOR Addr Offset */ + SPI_REG_ADRCMS = 0x8C, /**< ADRCMS : Second Intf NOR Allocation */ + }; + + /** + * @brief SPI Op Codes + * OP Codes for the SPI Command Register + */ + enum SpiOpCodes { + SPI_OP_READRAW = 0x03, /**< Read Raw */ + SPI_OP_WRITERAW = 0x02, /**< Write Raw */ + SPI_OP_ERASM = 0x32, /**< Erase Small */ + SPI_OP_ERALG = 0x34, /**< Erase Large */ + SPI_OP_ENWRITPROT = 0x53, /**< Enable WRite Protect */ + SPI_OP_CHIPID = 0x1F, /**< Get Chip ID */ + SPI_OP_STATUS = 0x05, /**< Get Status */ + SPI_OP_TURNOFF = 0x5E, /**< Turn Off */ + SPI_OP_TURNON = 0x50, /**< Turn On */ + SPI_OP_ABORT = 0x6F, /**< Super-Abort */ + SPI_OP_START4BA = 0x37, /**< Start 4BA */ + SPI_OP_END4BA = 0x69, /**< End 4BA */ + }; + + /** * @brief Read a SPI Register * * @parm i_addr Register address, relative to the SPI engine @@ -135,7 +174,7 @@ class PnorDD * * @return Error from operation */ - errlHndl_t readRegSPI(uint32_t i_addr, + errlHndl_t readRegSPI(SpiRegAddr i_addr, uint32_t& o_data); /** @@ -146,7 +185,7 @@ class PnorDD * * @return Error from operation */ - errlHndl_t writeRegSPI(uint32_t i_addr, + errlHndl_t writeRegSPI(SpiRegAddr i_addr, uint32_t i_data); @@ -160,9 +199,16 @@ class PnorDD LPCHC_IO_SPACE = 0xD0010000, /**< LPC Host Controller I/O Space */ LPCHC_REG_SPACE = 0xC0012000, /**< LPC Host Ctlr Register Space */ + LPC_DIRECT_READ_OFFSET = 0xFC000000, + LPC_SPI_REG_OFFSET = 0xF0000C00, + LPC_TOP_OF_FLASH_OFFSET = 0xFFFFFFFF, + ECCB_CTL_REG = 0x000B0020, /**< ECCB Control Reg (FW) */ ECCB_STAT_REG = 0x000B0022, /**< ECCB Status Reg (FW) */ ECCB_DATA_REG = 0x000B0023, /**< ECCB Data Reg (FW) */ + //ECCB_CTL_REG = 0x00090020, /**< ECCB Control Reg (FW) */ + //ECCB_STAT_REG = 0x00090022, /**< ECCB Status Reg (FW) */ + //ECCB_DATA_REG = 0x00090023, /**< ECCB Data Reg (FW) */ // Default Values to set for all operations // 1101.0100.0000.000x.0000.0001.0000.0000.<address> @@ -173,6 +219,9 @@ class PnorDD 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) */ + + ECCB_POLL_TIME_NS = 400000, /**< max time from Manfred Walz is 400ms */ + ECCB_POLL_INCR_NS = 10, /**< minimum increment during poll */ }; @@ -211,7 +260,7 @@ class PnorDD * @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_targetAddr Starting flash address to write * @parm i_wordsToWrite Number of 32-bit words to write * @parm i_data Buffer of data to write * @@ -309,8 +358,17 @@ class PnorDD * track writes by page (=erase block) */ uint8_t iv_erases[PNORSIZE/ERASESIZE_BYTES]; + + /** + * @brief Determine how much of the PNOR logic to use, + * this is required due to different model functionality + * in the current VPO and Simics models + */ + PnorMode_t iv_mode; + + // Needed for testcases + friend class PnorDdTest; }; -}; //end PNOR namespace #endif diff --git a/src/usr/pnor/test/pnorddtest.H b/src/usr/pnor/test/pnorddtest.H index eb874904a..dd7034889 100644 --- a/src/usr/pnor/test/pnorddtest.H +++ b/src/usr/pnor/test/pnorddtest.H @@ -36,11 +36,20 @@ #include <devicefw/userif.H> #include <kernel/console.H> #include <sys/time.h> +#include "../pnordd.H" +#include <list> +#include <targeting/util.H> -#define BASE_SCRATCH_SPACE 2*1024*1024+1024*512 //2.5MB offset in fake PNOR +#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; + +/* + Note - Some of these tests will run against non-singleton instances of the + PNOR DD to allow full testing of the different operating modes while leaving + the default mode in place for performance reasons. That will change when we + get to a complete PNOR model in sim or hardware. + */ class PnorDdTest : public CxxTest::TestSuite { @@ -53,14 +62,12 @@ 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; + TARGETING::Target* l_testTarget = + TARGETING::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; + uint64_t total = 0; do{ TS_TRACE("PnorDdTest::test_readwrite: starting"); @@ -73,12 +80,14 @@ class PnorDdTest : public CxxTest::TestSuite &l_writeData, l_size, DEVICE_PNOR_ADDRESS(0, l_address)); + total++; if (l_err) { TS_FAIL("PnorDdTest::test_readwrite: PNORDD write 1: deviceWrite() failed! Error committed."); errlCommit(l_err,PNOR_COMP_ID); fails++; } + total++; if(l_size != sizeof(uint64_t)) { TS_FAIL("PnorDdTest::test_readwrite: PNORDD write 1: Write length not expected value. Addr: 0x%llx, Exp: %d, Act: %d", l_address, @@ -94,12 +103,14 @@ class PnorDdTest : public CxxTest::TestSuite &l_writeData, l_size, DEVICE_PNOR_ADDRESS(0, l_address)); + total++; if (l_err) { TS_FAIL("PnorDdTest::test_readwrite: PNORDD write 2: deviceWrite() failed! Error committed."); errlCommit(l_err,PNOR_COMP_ID); fails++; } + total++; if(l_size != sizeof(uint64_t)) { TS_FAIL("PnorDdTest::test_readwrite: PNORDD write 2: Write length not expected value. Addr: 0x%llx, Exp: %d, Act: %d", l_address, @@ -115,18 +126,21 @@ class PnorDdTest : public CxxTest::TestSuite &l_readData, l_size, DEVICE_PNOR_ADDRESS(0, l_address)); + total++; if (l_err) { TS_FAIL("PnorDdTest::test_readwrite: PNORDD read 1: deviceRead() failed! Error committed."); errlCommit(l_err,PNOR_COMP_ID); fails++; } + total++; if(l_readData != 0x12345678FEEDB0B0) { 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++; } + total++; 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, @@ -141,20 +155,21 @@ class PnorDdTest : public CxxTest::TestSuite &l_readData, l_size, DEVICE_PNOR_ADDRESS(0, l_address)); + total++; if (l_err) { TS_FAIL("PnorDdTest::test_readwrite: PNORDD read 2: deviceRead() failed! Error committed."); errlCommit(l_err,PNOR_COMP_ID); fails++; - break; } + total++; 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; } + total++; 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, @@ -174,11 +189,12 @@ class PnorDdTest : public CxxTest::TestSuite */ void test_smartwrite(void) { - TARGETING::Target* l_testTarget = MASTER_PROCESSOR_CHIP_TARGET_SENTINEL; + TARGETING::Target* l_testTarget = + TARGETING::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; + uint64_t total = 0; do{ TS_TRACE("PnorDdTest::test_smartwrite: starting"); @@ -191,6 +207,7 @@ class PnorDdTest : public CxxTest::TestSuite &l_writeData, l_size, DEVICE_PNOR_ADDRESS(0, l_address)); + total++; if (l_err) { TS_FAIL("PnorDdTest::test_smartwrite: PNORDD write 1: deviceWrite() failed! Error committed."); @@ -205,6 +222,7 @@ class PnorDdTest : public CxxTest::TestSuite &l_writeData, l_size, DEVICE_PNOR_ADDRESS(0, l_address)); + total++; if (l_err) { TS_FAIL("PnorDdTest::test_smartwrite: PNORDD write 2: deviceWrite() failed! Error committed."); @@ -219,6 +237,7 @@ class PnorDdTest : public CxxTest::TestSuite &l_writeData, l_size, DEVICE_PNOR_ADDRESS(0, l_address+sizeof(uint64_t))); + total++; if (l_err) { TS_FAIL("PnorDdTest::test_smartwrite: PNORDD write 3: deviceWrite() failed! Error committed."); @@ -233,6 +252,7 @@ class PnorDdTest : public CxxTest::TestSuite &l_writeData, l_size, DEVICE_PNOR_ADDRESS(0, l_address)); + total++; if (l_err) { TS_FAIL("PnorDdTest::test_smartwrite: PNORDD write 4: deviceWrite() failed! Error committed."); @@ -240,19 +260,21 @@ class PnorDdTest : public CxxTest::TestSuite fails++; } - // Perform PnorDD read + // Perform PnorDD read of the data we just wrote 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)); + total++; if (l_err) { TS_FAIL("PnorDdTest::test_smartwrite: PNORDD read: deviceRead() failed! Error committed."); errlCommit(l_err,PNOR_COMP_ID); fails++; } + total++; 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", @@ -260,11 +282,499 @@ class PnorDdTest : public CxxTest::TestSuite fails++; } + // Perform PnorDD read of the data after what we just wrote + // verifies that we restored the rest of the block + l_readData = 0; + l_size = sizeof(uint64_t); + l_err = deviceRead(l_testTarget, + &l_readData, + l_size, + DEVICE_PNOR_ADDRESS(0, l_address+sizeof(uint64_t))); + total++; + if (l_err) + { + TS_FAIL("PnorDdTest::test_smartwrite: PNORDD read: deviceRead() failed! Error committed."); + errlCommit(l_err,PNOR_COMP_ID); + fails++; + } + total++; + if(l_readData != 0x1234567887654321) + { + TS_FAIL("PnorDdTest::test_smartwrite: PNORDD read: Read data not expected value. Addr: 0x%llx, ExpData: 0x%llx, ActData: 0x%llx", + l_address, 0x1234567887654321, l_readData); + fails++; + } + + }while(0); + + TRACFCOMP(g_trac_pnor, "PnorDdTest::test_smartwrite> %d/%d fails", fails, total ); + } + + /** + * @brief PNOR DD Cross-Block testcase + * Access some data that crosses an erase block boundary + */ + void test_crossblock(void) + { + TARGETING::Target* l_testTarget = + TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL; + size_t l_size = sizeof(uint64_t); + errlHndl_t l_err = NULL; + uint64_t fails = 0; + uint64_t total = 0; + + do{ + TS_TRACE("PnorDdTest::test_crossblock: starting"); + + // Find the nearest erase-block (4K) boundary + uint64_t l_boundary = (BASE_SCRATCH_SPACE+4096) + - (BASE_SCRATCH_SPACE%4096); + uint64_t l_address = 0; + + // Perform PnorDD Write 1 - write through boundary + l_address = l_boundary - sizeof(uint32_t); + uint64_t l_writeData = 0x6666666699999999; + l_size = sizeof(uint64_t); + l_err = deviceWrite(l_testTarget, + &l_writeData, + l_size, + DEVICE_PNOR_ADDRESS(0, l_address)); + total++; + if (l_err) + { + TS_FAIL("PnorDdTest::test_crossblock: PNORDD write 1: deviceWrite() failed! Error committed."); + errlCommit(l_err,PNOR_COMP_ID); + fails++; + } + + // Perform PnorDD Read 1 - verify previous write + l_address = l_boundary - sizeof(uint32_t); + uint64_t l_readData = 0x0; + l_size = sizeof(uint64_t); + l_err = deviceRead(l_testTarget, + &l_readData, + l_size, + DEVICE_PNOR_ADDRESS(0, l_address)); + total++; + if (l_err) + { + TS_FAIL("PnorDdTest::test_crossblock: PNORDD Read 1: deviceRead() failed! Error committed."); + errlCommit(l_err,PNOR_COMP_ID); + fails++; + } + total++; + if(l_readData != l_writeData) + { + TS_FAIL("PnorDdTest::test_crossblock: 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_crossblock> %d/%d fails", fails, total ); + } + + /** + * @brief PNOR DD readWriteTest modes + * Same as test_readwrite but forcing the use of all supported modes + */ + void test_readwrite_modes(void) + { + PnorDD* pnordd = NULL; + size_t l_size = sizeof(uint64_t); + errlHndl_t l_err = NULL; + uint64_t fails = 0; + uint64_t total = 0; + + do{ + TS_TRACE("PnorDdTest::test_readwrite_modes: starting"); + + // list of all modes to test + std::list<PnorDD::PnorMode_t> supported_modes; + supported_modes.push_back(PnorDD::MODEL_MEMCPY); + supported_modes.push_back(PnorDD::MODEL_LPC_MEM); + if( !TARGETING::is_vpo() ) + { + supported_modes.push_back(PnorDD::MODEL_FLAT_ECCB); + } + + uint64_t scratch_space = BASE_SCRATCH_SPACE; + + // loop through all of the supported modes + for( std::list<PnorDD::PnorMode_t>::iterator m + = supported_modes.begin(); + m != supported_modes.end(); + ++m ) + { + scratch_space += 0x100; + + if( pnordd ) + { + delete pnordd; + } + pnordd = new PnorDD(*m); + + // Perform PnorDD Write 1 + uint64_t l_address = scratch_space; + uint64_t l_writeData = 0x12345678FEEDB0B0; + l_size = sizeof(uint64_t); + l_err = pnordd->writeFlash(&l_writeData, + l_size, + l_address); + total++; + if (l_err) + { + TS_FAIL("PnorDdTest::test_readwrite_modes: PNORDD write 1: writeFlash() failed! Error committed. mode=%d", + *m); + errlCommit(l_err,PNOR_COMP_ID); + fails++; + } + total++; + if(l_size != sizeof(uint64_t)) + { + TS_FAIL("PnorDdTest::test_readwrite_modes: PNORDD write 1: Write length not expected value. Addr: 0x%llx, Exp: %d, Act: %d, mode=%d", + l_address, sizeof(uint64_t), l_size, *m); + fails++; + } + + // Perform PnorDD Write 2 + l_address = scratch_space+0x08; + l_writeData = 0xFEEDBEEF000ABCDE; + l_size = sizeof(uint64_t); + l_err = pnordd->writeFlash(&l_writeData, + l_size, + l_address); + total++; + if (l_err) + { + TS_FAIL("PnorDdTest::test_readwrite_modes: PNORDD write 2: writeFlash() failed! Error committed. mode=%d", + *m); + errlCommit(l_err,PNOR_COMP_ID); + fails++; + } + total++; + if(l_size != sizeof(uint64_t)) + { + TS_FAIL("PnorDdTest::test_readwrite_modes: PNORDD write 2: Write length not expected value. Addr: 0x%llx, Exp: %d, Act: %d, mode=%d", + l_address, sizeof(uint64_t), l_size, *m); + fails++; + } + + // Perform PnorDD read 1 + l_address = scratch_space; + uint64_t l_readData = 0; + l_size = sizeof(uint64_t); + l_err = pnordd->readFlash(&l_readData, + l_size, + l_address); + total++; + if (l_err) + { + TS_FAIL("PnorDdTest::test_readwrite_modes: PNORDD read 1: readFlash() failed! Error committed. mode=%d", + *m); + errlCommit(l_err,PNOR_COMP_ID); + fails++; + } + total++; + if(l_readData != 0x12345678FEEDB0B0) + { + TS_FAIL("PnorDdTest::test_readwrite_modes: PNORDD read 1: Read data not expected value. Addr: 0x%llx, ExpData: 0x12345678FEEDB0B0, ActData: 0x%llx, mode=%d", + l_address, (long long unsigned)l_readData, *m); + fails++; + } + total++; + if(l_size != sizeof(uint64_t)) + { + TS_FAIL("PnorDdTest::test_readwrite_modes: PNORDD read 1: Read length not expected value. Addr: 0x%llx, Exp: %d, Act: %d, mode=%d", + l_address, sizeof(uint64_t), l_size, *m); + fails++; + } + + // Perform PnorDD read 2 + l_address = scratch_space+0x08; + l_size = sizeof(uint64_t); + l_err = pnordd->readFlash(&l_readData, + l_size, + l_address); + total++; + if (l_err) + { + TS_FAIL("PnorDdTest::test_readwrite_modes: PNORDD read 2: readFlash() failed! Error committed. mode=%d", + *m); + errlCommit(l_err,PNOR_COMP_ID); + fails++; + } + total++; + if(l_readData != 0xFEEDBEEF000ABCDE) + { + TS_FAIL("PnorDdTest::test_readwrite_modes: PNORDD read 2: Read data not expected value. Addr: 0x%llx, ExpData: 0xFEEDBEEF000ABCDE, ActData: 0x%llx, mode=%d", + l_address, (long long unsigned)l_readData, *m); + fails++; + } + total++; + if(l_size != sizeof(uint64_t)) + { + TS_FAIL("PnorDdTest::test_readwrite_modes: PNORDD read 2: Read length not expected value. Addr: 0x%llx, Exp: %d, Act: %d, mode=%d", + l_address, sizeof(uint64_t), l_size, *m); + fails++; + } + } + + }while(0); + + TRACFCOMP(g_trac_pnor, "PnorDdTest::test_readwrite_modes> %d/%d fails", fails, total ); + + if( pnordd ) + { + delete pnordd; + } + } + + /** + * @brief PNOR DD smart write/erase test + * Same as test_smartwrite but forcing the use of all supported modes + */ + void test_smartwrite_modes(void) + { + PnorDD* pnordd = NULL; + size_t l_size = sizeof(uint64_t); + errlHndl_t l_err = NULL; + uint64_t fails = 0; + uint64_t total = 0; + + do{ + TS_TRACE("PnorDdTest::test_smartwrite_modes: starting"); + + // list of all modes to test + std::list<PnorDD::PnorMode_t> supported_modes; + supported_modes.push_back(PnorDD::MODEL_MEMCPY); + supported_modes.push_back(PnorDD::MODEL_LPC_MEM); + if( !TARGETING::is_vpo() ) + { + supported_modes.push_back(PnorDD::MODEL_FLAT_ECCB); + } + + uint64_t scratch_space = BASE_SCRATCH_SPACE; + + // loop through all of the supported modes + for( std::list<PnorDD::PnorMode_t>::iterator m + = supported_modes.begin(); + m != supported_modes.end(); + ++m ) + { + scratch_space += 0x100; + + if( pnordd ) + { + delete pnordd; + } + pnordd = new PnorDD(*m); + + // Perform PnorDD Write 1 + uint64_t l_address = scratch_space+0x20; + uint64_t l_writeData = 0xAAAAAAAA55555555; + l_size = sizeof(uint64_t); + l_err = pnordd->writeFlash(&l_writeData, + l_size, + l_address); + total++; + if (l_err) + { + TS_FAIL("PnorDdTest::test_smartwrite_modes: PNORDD write 1: writeFlash() 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 = pnordd->writeFlash(&l_writeData, + l_size, + l_address); + total++; + if (l_err) + { + TS_FAIL("PnorDdTest::test_smartwrite_modes: PNORDD write 2: writeFlash() 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 = pnordd->writeFlash(&l_writeData, + l_size, + l_address+sizeof(uint64_t)); + total++; + if (l_err) + { + TS_FAIL("PnorDdTest::test_smartwrite_modes: PNORDD write 3: writeFlash() 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 = pnordd->writeFlash(&l_writeData, + l_size, + l_address); + total++; + if (l_err) + { + TS_FAIL("PnorDdTest::test_smartwrite_modes: PNORDD write 4: writeFlash() failed! Error committed."); + errlCommit(l_err,PNOR_COMP_ID); + fails++; + } + + // Perform PnorDD read of the data we just wrote + uint64_t l_readData = 0; + l_size = sizeof(uint64_t); + l_err = pnordd->readFlash(&l_readData, + l_size, + l_address); + total++; + if (l_err) + { + TS_FAIL("PnorDdTest::test_smartwrite_modes: PNORDD read: readFlash() failed! Error committed."); + errlCommit(l_err,PNOR_COMP_ID); + fails++; + } + total++; + if(l_readData != l_writeData) + { + TS_FAIL("PnorDdTest::test_smartwrite_modes: PNORDD read: Read data not expected value. Addr: 0x%llx, ExpData: 0x%llx, ActData: 0x%llx", + l_address, l_writeData, l_readData); + fails++; + } + + // Perform PnorDD read of the data after what we just wrote + // verifies that we restored the rest of the block + l_readData = 0; + l_size = sizeof(uint64_t); + l_err = pnordd->readFlash(&l_readData, + l_size, + l_address+sizeof(uint64_t)); + total++; + if (l_err) + { + TS_FAIL("PnorDdTest::test_smartwrite_modes: PNORDD read: readFlash() failed! Error committed."); + errlCommit(l_err,PNOR_COMP_ID); + fails++; + } + total++; + if(l_readData != 0x1234567887654321) + { + TS_FAIL("PnorDdTest::test_smartwrite_modes: PNORDD read: Read data not expected value. Addr: 0x%llx, ExpData: 0x%llx, ActData: 0x%llx", + l_address, 0x1234567887654321, l_readData); + fails++; + } + } + }while(0); + if( pnordd ) + { + delete pnordd; + } + TRACFCOMP(g_trac_pnor, "PnorDdTest::test_smartwrite> %d/%d fails", fails, total ); } - + + /** + * @brief PNOR DD Cross-Block testcase + * Same as test_crossblock but forcing the use of all supported modes + */ + void test_crossblock_modes(void) + { + PnorDD* pnordd = NULL; + size_t l_size = sizeof(uint64_t); + errlHndl_t l_err = NULL; + uint64_t fails = 0; + uint64_t total = 0; + + do{ + TS_TRACE("PnorDdTest::test_crossblock_modes: starting"); + + // list of all modes to test + std::list<PnorDD::PnorMode_t> supported_modes; + supported_modes.push_back(PnorDD::MODEL_MEMCPY); + supported_modes.push_back(PnorDD::MODEL_LPC_MEM); + if( !TARGETING::is_vpo() ) + { + supported_modes.push_back(PnorDD::MODEL_FLAT_ECCB); + } + + uint64_t scratch_space = BASE_SCRATCH_SPACE; + + // loop through all of the supported modes + for( std::list<PnorDD::PnorMode_t>::iterator m + = supported_modes.begin(); + m != supported_modes.end(); + ++m ) + { + scratch_space += 4096; + + if( pnordd ) + { + delete pnordd; + } + pnordd = new PnorDD(*m); + + // Find the nearest erase-block (4K) boundary + uint64_t l_boundary = (BASE_SCRATCH_SPACE+4096) + - (BASE_SCRATCH_SPACE%4096); + uint64_t l_address = 0; + + // Perform PnorDD Write 1 - write through boundary + l_address = l_boundary - sizeof(uint32_t); + uint64_t l_writeData = 0x6666666699999999; + l_size = sizeof(uint64_t); + l_err = pnordd->writeFlash(&l_writeData, + l_size, + l_address); + total++; + if (l_err) + { + TS_FAIL("PnorDdTest::test_crossblock_modes: PNORDD write 1: writeFlash() failed! Error committed."); + errlCommit(l_err,PNOR_COMP_ID); + fails++; + } + + // Perform PnorDD Read 1 - verify previous write + l_address = l_boundary - sizeof(uint32_t); + uint64_t l_readData = 0x0; + l_size = sizeof(uint64_t); + l_err = pnordd->readFlash(&l_readData, + l_size, + l_address); + total++; + if (l_err) + { + TS_FAIL("PnorDdTest::test_crossblock_modes: PNORDD Read 1: readFlash() failed! Error committed."); + errlCommit(l_err,PNOR_COMP_ID); + fails++; + } + total++; + if(l_readData != l_writeData) + { + TS_FAIL("PnorDdTest::test_crossblock_modes: 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); + + if( pnordd ) + { + delete pnordd; + } + + TRACFCOMP(g_trac_pnor, "PnorDdTest::test_crossblock_modes> %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) @@ -283,7 +793,7 @@ Leaving it commented out because the test-case will not dynamically find the ext l_err = deviceRead(l_testTarget, &l_readData, l_size, - DEVICE_PNOR_ADDRESS(0, l_address)); + DEVICE_PNOR_ADDRESS(0, l_address); if (l_err) { TS_FAIL("testPnorDD2: PNORDD read fakeext: deviceRead() failed! Error committed."); @@ -302,7 +812,7 @@ Leaving it commented out because the test-case will not dynamically find the ext l_err = deviceRead(l_testTarget, &l_readData, l_size, - DEVICE_PNOR_ADDRESS(0, l_address)); + DEVICE_PNOR_ADDRESS(0, l_address); if (l_err) { TS_FAIL("testPnorDD2: PNORDD read fakeext: deviceRead() failed! Error committed."); @@ -324,7 +834,6 @@ Leaving it commented out because the test-case will not dynamically find the ext }; */ -}; #endif |