From df4b0117660700e195864b761dfe92dd3467c686 Mon Sep 17 00:00:00 2001 From: Dan Crowell Date: Fri, 29 Jul 2011 13:22:18 -0500 Subject: More PNOR RP work - Task 3440 (Story 3330) Also includes testcase work for Task 3388 Change-Id: Ib4ff920f351554fe457c171f601a38809ca6ac6f Functional PNOR RP code that works with the PNOR DD. Still missing the complete path but should be ready for use by the next level up. Task 3440 Change-Id: Id32a919f88da636c341116444e557387beaccdb2 Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/230 Tested-by: Jenkins Server Reviewed-by: Douglas R. Gilbert Reviewed-by: ADAM R. MUHLE --- .gitignore | 1 + src/include/usr/devicefw/devfwreasoncodes.H | 2 +- src/include/usr/devicefw/userif.H | 10 +- src/include/usr/pnor/pnor_reasoncodes.H | 9 +- src/include/usr/pnor/pnorif.H | 32 +- src/kernel/syscall.C | 38 +-- src/usr/devicefw/associator.C | 2 + src/usr/errl/errlentry.C | 1 + src/usr/errl/errlmanager.C | 7 +- src/usr/pnor/pnorrp.C | 446 ++++++++++++++++++++++------ src/usr/pnor/pnorrp.H | 119 ++++++-- src/usr/pnor/test/pnorrptest.H | 282 +++++++++++++++++- 12 files changed, 793 insertions(+), 156 deletions(-) diff --git a/.gitignore b/.gitignore index 6c1e1f27d..752aaf5ee 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ *.swp customrc *.CKP +*.log diff --git a/src/include/usr/devicefw/devfwreasoncodes.H b/src/include/usr/devicefw/devfwreasoncodes.H index 0f55f063d..16493ca5b 100644 --- a/src/include/usr/devicefw/devfwreasoncodes.H +++ b/src/include/usr/devicefw/devfwreasoncodes.H @@ -7,7 +7,7 @@ namespace DeviceFW { enum DevFwModuleId { - DEVFW_MOD_ASSOCIATOR = 0x00, + DEVFW_MOD_ASSOCIATOR = 0x01, }; enum DevFwReasonCode diff --git a/src/include/usr/devicefw/userif.H b/src/include/usr/devicefw/userif.H index c1bbd864b..6c261caab 100644 --- a/src/include/usr/devicefw/userif.H +++ b/src/include/usr/devicefw/userif.H @@ -42,13 +42,13 @@ namespace DeviceFW /** * Construct a PNOR DD address * address = 0000_0000_0000_000c_aaaa_aaaa_aaaa_aaaa - * c=side, a=address - * @param[in] chip Chip Select - * @param[in] addr Offset (from zero) into selected flash chip + * c=chip, a=address + * @param[in] i_chip Chip Select + * @param[in] i_addr Offset (from zero) into selected flash chip * @return 64-bit address to pass into PNOR device commands */ - #define DEVICE_PNOR_ADDRESS( chip, addr ) \ - DeviceFW::PNOR, ((static_cast(chip)<<32)|static_cast(addr)) + #define DEVICE_PNOR_ADDRESS( i_chip, i_addr ) \ + DeviceFW::PNOR, ((static_cast(i_chip)<<32)|static_cast(i_addr)) /** diff --git a/src/include/usr/pnor/pnor_reasoncodes.H b/src/include/usr/pnor/pnor_reasoncodes.H index 48ba21c00..0e7f002e4 100644 --- a/src/include/usr/pnor/pnor_reasoncodes.H +++ b/src/include/usr/pnor/pnor_reasoncodes.H @@ -7,12 +7,17 @@ namespace PNOR { enum PNORModuleId { - PNORRP_WAITFORMESSAGE = 0x01, + 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 */ }; enum PNORReasonCode { - INVALID_MESSAGE = PNOR_COMP_ID | 0x01, + RC_INVALID_MESSAGE = PNOR_COMP_ID | 0x01, + RC_INVALID_ADDRESS = PNOR_COMP_ID | 0x02, + RC_INVALID_SECTION = PNOR_COMP_ID | 0x03, }; }; diff --git a/src/include/usr/pnor/pnorif.H b/src/include/usr/pnor/pnorif.H index 1b551d8ee..49f4e7879 100644 --- a/src/include/usr/pnor/pnorif.H +++ b/src/include/usr/pnor/pnorif.H @@ -3,6 +3,7 @@ #include #include +#include namespace PNOR { @@ -14,7 +15,7 @@ enum SectionId { TOC, /**< Table of Contents */ GLOBAL_DATA, /**< Global Data */ - SBE_IPL, /**< Self-Boot Enginer IPL image */ + SBE_IPL, /**< Self-Boot Engine IPL image */ HB_BASE_CODE, /**< Hostboot Base Image */ HB_DATA, /**< Hostboot Data */ HB_ERRLOGS, /**< Hostboot Error log Repository */ @@ -32,27 +33,30 @@ enum SectionId INVALID_SECTION = NUM_SECTIONS, /**< Used for error cases, initialization */ }; +/** + * Select a side of flash to access + */ +enum SideSelect +{ + SIDE_A, /**< A-side of flash */ + SIDE_B, /**< B-side of flash */ + SIDELESS, /**< Sideless data */ +}; + /** * Information about a section of PNOR */ struct SectionInfo_t { SectionId id; /**< Identifier for this section */ + SideSelect side; /**< Identifier for the side of flash */ const char* name; /**< Name of the section */ + uint64_t vaddr; /**< Virtual address for the start of the section */ uint64_t size; /**< Actual size of content in bytes */ bool eccProtected; /**< Section is ECC protected */ }; -/** - * Select a side of flash to access - */ -enum SideSelect -{ - SIDE_A = 0xA, /**< A-side of flash */ - SIDE_B = 0xB, /**< B-side of flash */ - SIDELESS = 0xF, /**< Sideless data */ -}; @@ -63,11 +67,11 @@ enum SideSelect * @param[in] i_side Side select * @param[out] o_info Location and size information * - * @return size_t Offset of section in bytes + * @return errlHndl_t Error log if request was invalid */ -void getSectionInfo( SectionId i_section, - SideSelect i_side, - SectionInfo_t& o_info ); +errlHndl_t getSectionInfo( SectionId i_section, + SideSelect i_side, + SectionInfo_t& o_info ); } diff --git a/src/kernel/syscall.C b/src/kernel/syscall.C index 5f80e0c19..6242c4bcb 100644 --- a/src/kernel/syscall.C +++ b/src/kernel/syscall.C @@ -66,32 +66,32 @@ namespace Systemcalls syscall syscalls[] = { - &TaskYield, - &TaskStart, - &TaskEnd, + &TaskYield, // TASK_YIELD + &TaskStart, // TASK_START + &TaskEnd, // TASK_END - &MsgQCreate, - &MsgQDestroy, - &MsgQRegisterRoot, - &MsgQResolveRoot, + &MsgQCreate, // MSGQ_CREATE + &MsgQDestroy, // MSGQ_DESTROY + &MsgQRegisterRoot, // MSGQ_REGISTER_ROOT + &MsgQResolveRoot, // MSGQ_RESOLVE_ROOT - &MsgSend, - &MsgSendRecv, - &MsgRespond, - &MsgWait, + &MsgSend, // MSG_SEND + &MsgSendRecv, // MSG_SENDRECV + &MsgRespond, // MSG_RESPOND + &MsgWait, // MSG_WAIT - &MmioMap, - &MmioUnmap, + &MmioMap, // MMIO_MAP + &MmioUnmap, // MMIO_UNMAP - &TimeNanosleep, + &TimeNanosleep, // TIME_NANOSLEEP - &FutexWait, - &FutexWake, + &FutexWait, // FUTEX_WAIT + &FutexWake, // FUTEX_WAKE - &Shutdown, + &Shutdown, // MISC_SHUTDOWN - &CpuCoreType, - &CpuDDLevel, + &CpuCoreType, // MISC_CPUCORETYPE + &CpuDDLevel, // MISC_CPUDDLEVEL }; }; diff --git a/src/usr/devicefw/associator.C b/src/usr/devicefw/associator.C index 80ca6d9b6..8919e0a07 100644 --- a/src/usr/devicefw/associator.C +++ b/src/usr/devicefw/associator.C @@ -76,6 +76,7 @@ namespace DeviceFW if(((targets.flag) && (i_targetType != WILDCARD)) || ((!targets.flag) && (i_targetType == WILDCARD))) { + TRACFCOMP(g_traceBuffer, "Invalid registration type was given to register a device : i_opType=%d, i_accType=%d, i_targetType=%d", i_opType, i_accType, i_targetType ); /*@ * @errortype * @moduleid DEVFW_MOD_ASSOCIATOR @@ -211,6 +212,7 @@ namespace DeviceFW // Call function if one was found, create error otherwise. if (NULL == l_devRoute) { + TRACFCOMP(g_traceBuffer, "A device driver operation was attempted for which no driver has been registered : i_opType=%d, i_accessType=%d, l_devType=%d", i_opType, i_accessType, l_devType ); /*@ * @errortype * @moduleid DEVFW_MOD_ASSOCIATOR diff --git a/src/usr/errl/errlentry.C b/src/usr/errl/errlentry.C index fcff1c204..40138051c 100644 --- a/src/usr/errl/errlentry.C +++ b/src/usr/errl/errlentry.C @@ -42,6 +42,7 @@ iv_user2(i_user2), iv_sections(NULL) { iv_logId = theErrlManager::instance().getUniqueErrId(); + TRACFCOMP(ERRORLOG::g_trac_errl, "Error %d created : modid=%X, rc=%X", iv_logId, iv_modId, iv_reasonCode); } /////////////////////////////////////////////////////////////////////////////// diff --git a/src/usr/errl/errlmanager.C b/src/usr/errl/errlmanager.C index 9a7a848f2..10eccbc66 100644 --- a/src/usr/errl/errlmanager.C +++ b/src/usr/errl/errlmanager.C @@ -51,9 +51,12 @@ void ErrlManager::commitErrLog(errlHndl_t& io_err) } else { + TRACFCOMP( g_trac_errl, "commitErrLog()> Reasoncode=%X, Id=%d", io_err->reasonCode(), io_err->logId() ); + + //@fixme - an id is already assigned in the constructor, which one do we want? // Assign a unique error ID to the committed log - uint32_t l_errId = getUniqueErrId(); - io_err->setLogId(l_errId); + //uint32_t l_errId = getUniqueErrId(); + //io_err->setLogId(l_errId); // @todo: // - Flatten error into PNOR diff --git a/src/usr/pnor/pnorrp.C b/src/usr/pnor/pnorrp.C index 73edaacdb..7a9992c15 100644 --- a/src/usr/pnor/pnorrp.C +++ b/src/usr/pnor/pnorrp.C @@ -3,33 +3,39 @@ #include #include #include -#include #include -#include #include #include #include #include #include +#include // Trace definition trace_desc_t* g_trac_pnor = NULL; -TRAC_INIT(&g_trac_pnor, "PNOR", 4096); +TRAC_INIT(&g_trac_pnor, "PNOR", 4096); //4K +// Easy macro replace for unit testing +//#define TRACUCOMP(args...) TRACFCOMP(args) +#define TRACUCOMP(args...) + +/** + * Eyecatcher strings for PNOR TOC entries + */ const char* cv_EYECATCHER[] = { - "TOC", /**< PNOR_TOC : Table of Contents */ - "GLOBAL", /**< PNOR_GLOBAL_DATA : Global Data */ - "SBE", /**< PNOR_SBE_IPL : Self-Boot Enginer IPL image */ - "HBB", /**< PNOR_HB_BASE_CODE : Hostboot Base Image */ - "HBD", /**< PNOR_HB_DATA : Hostboot Data */ - "XXX", /**< PNOR_HB_ERRLOGS : Hostboot Error log Repository */ - "HBI", /**< PNOR_HB_EXT_CODE : Hostboot Extended Image */ - "HBR", /**< PNOR_HB_RUNTIME : Hostboot Runtime Image */ - "OPAL", /**< PNOR_PAYLOAD : HAL/OPAL */ - "PFWL", /**< PNOR_PFW_LITE_CODE : PFW-lite */ - "OCC", /**< PNOR_OCC_CODE : OCC Code Image */ - "PART", /**< PNOR_KVM_PART_INFO : KVM Partition Information */ - "XXX", /**< PNOR_CODE_UPDATE : Code Update Overhead */ + "TOC", /**< PNOR::TOC : Table of Contents */ + "GLOBAL", /**< PNOR::GLOBAL_DATA : Global Data */ + "SBE", /**< PNOR::SBE_IPL : Self-Boot Enginer IPL image */ + "HBB", /**< PNOR::HB_BASE_CODE : Hostboot Base Image */ + "HBD", /**< PNOR::HB_DATA : Hostboot Data */ + "XXX", /**< PNOR::HB_ERRLOGS : Hostboot Error log Repository */ + "HBI", /**< PNOR::HB_EXT_CODE : Hostboot Extended Image */ + "HBR", /**< PNOR::HB_RUNTIME : Hostboot Runtime Image */ + "OPAL", /**< PNOR::PAYLOAD : HAL/OPAL */ + "PFWL", /**< PNOR::PFW_LITE_CODE : PFW-lite */ + "OCC", /**< PNOR::OCC_CODE : OCC Code Image */ + "PART", /**< PNOR::KVM_PART_INFO : KVM Partition Information */ + "XXX", /**< PNOR::CODE_UPDATE : Code Update Overhead */ "XXX", /**< NUM_SECTIONS : Used as invalid entry */ }; @@ -47,11 +53,11 @@ TASK_ENTRY_MACRO( PnorRP::init ); /** * @brief Return the size and address of a given section of PNOR data */ -void PNOR::getSectionInfo( PNOR::SectionId i_section, - PNOR::SideSelect i_side, - PNOR::SectionInfo_t& o_info ) +errlHndl_t PNOR::getSectionInfo( PNOR::SectionId i_section, + PNOR::SideSelect i_side, + PNOR::SectionInfo_t& o_info ) { - Singleton::instance().getSectionInfo(i_section,i_side,o_info); + return Singleton::instance().getSectionInfo(i_section,i_side,o_info); } @@ -61,7 +67,7 @@ void PNOR::getSectionInfo( PNOR::SectionId i_section, */ void PnorRP::init( void* i_taskArgs ) { - TRACFCOMP(g_trac_pnor, "PnorRP::init> " ); + TRACUCOMP(g_trac_pnor, "PnorRP::init> " ); INITSERVICE::TaskArgs::TaskArgs* args = (INITSERVICE::TaskArgs::TaskArgs*)i_taskArgs; uint64_t rc = 0; if( Singleton::instance().didStartupFail(rc) ) @@ -80,6 +86,7 @@ void PnorRP::init( void* i_taskArgs ) */ void wait_for_message( void* unused ) { + TRACUCOMP(g_trac_pnor, "wait_for_message> " ); Singleton::instance().waitForMessage(); } @@ -93,10 +100,14 @@ void wait_for_message( void* unused ) */ PnorRP::PnorRP() : iv_msgQ(NULL) -,iv_block(NULL) +,iv_startupRC(0) { + TRACFCOMP(g_trac_pnor, "PnorRP::PnorRP> " ); + // setup everything in a separate function initDaemon(); + + TRACFCOMP(g_trac_pnor, "< PnorRP::PnorRP " ); } /** @@ -104,11 +115,12 @@ PnorRP::PnorRP() */ PnorRP::~PnorRP() { + TRACFCOMP(g_trac_pnor, "PnorRP::~PnorRP> " ); + // delete the message queue we created msg_q_destroy( iv_msgQ ); - //@fixme - do we need to delete the Block we allocated? - //delete iv_block; + TRACFCOMP(g_trac_pnor, "< PnorRP::~PnorRP" ); } /** @@ -116,6 +128,8 @@ PnorRP::~PnorRP() */ void PnorRP::initDaemon() { + TRACUCOMP(g_trac_pnor, "PnorRP::initDaemon> " ); + // read the TOC in the PNOR to compute the sections readTOC(); @@ -123,25 +137,61 @@ void PnorRP::initDaemon() iv_msgQ = msg_q_create(); // create a Block, passing in the message queue - //@fixme iv_block = new Block( 0, 0 ); + //@todo iv_block = new Block( 0, 0 ); // start task to wait on the queue task_create( wait_for_message, NULL ); + + TRACUCOMP(g_trac_pnor, "< PnorRP::initDaemon" ); } /** * @brief Return the size and address of a given section of PNOR data */ -void PnorRP::getSectionInfo( PNOR::SectionId i_section, - PNOR::SideSelect i_side, - PNOR::SectionInfo_t& o_info ) +errlHndl_t PnorRP::getSectionInfo( PNOR::SectionId i_section, + PNOR::SideSelect i_side, + PNOR::SectionInfo_t& o_info ) { - // cheat for now + //TRACDCOMP(g_trac_pnor, "PnorRP::getSectionInfo> i_section=%d, i_side=%X", i_section, i_side ); + errlHndl_t errhdl = NULL; + + PNOR::SectionId id = i_section; + // Zero-length means the section is invalid + if( 0 == iv_TOC[i_side][id].size ) + { + TRACFCOMP( g_trac_pnor, "PnorRP::getSectionInfo> Invalid Section Requested : i_section=%d, i_side=%d", i_section, i_side ); + TRACFCOMP(g_trac_pnor, "o_info={ id=%d, size=%d }", iv_TOC[i_side][i_section].id, iv_TOC[i_side][i_section].size ); + /*@ + * @errortype + * @moduleid PNOR::MOD_PNORRP_GETSECTIONINFO + * @reasoncode PNOR::RC_INVALID_SECTION + * @userdata1 Requested Section + * @userdata2 Requested Side + * @devdesc PnorRP::waitForMessage> Invalid Address for read/write + */ + errhdl = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, + PNOR::MOD_PNORRP_GETSECTIONINFO, + PNOR::RC_INVALID_SECTION, + TO_UINT64(i_section), + TO_UINT64(i_side)); + + // set the return valid to our invalid data + id = PNOR::INVALID_SECTION; + } - //@todo - when we get a real PNOR image - + TRACFCOMP( g_trac_pnor, "i_section=%d, i_side=%d : id=%d", i_section, i_side, iv_TOC[i_side][i_section].id ); + + // copy my data into the external format + o_info.id = iv_TOC[i_side][i_section].id; + o_info.side = iv_TOC[i_side][i_section].side; + o_info.name = cv_EYECATCHER[i_section]; + o_info.vaddr = iv_TOC[i_side][i_section].virtAddr; + o_info.size = iv_TOC[i_side][i_section].size; + o_info.eccProtected = iv_TOC[i_side][i_section].eccProtected; + + return errhdl; } @@ -151,28 +201,60 @@ void PnorRP::getSectionInfo( PNOR::SectionId i_section, */ void PnorRP::readTOC() { + TRACUCOMP(g_trac_pnor, "PnorRP::readTOC>" ); + // Zero out my table - for( PNOR::SectionId id = PNOR::FIRST_SECTION; - id < PNOR::NUM_SECTIONS; - id = (PNOR::SectionId) (id + 1) ) + for( uint64_t side = 0; side < NUM_SIDES; side++ ) { - iv_TOC[id].id = id; - iv_TOC[id].name = cv_EYECATCHER[PNOR::INVALID_SECTION]; - iv_TOC[id].vaddr = 0; - iv_TOC[id].size = 0; - iv_TOC[id].eccProtected = false; + for( PNOR::SectionId id = PNOR::FIRST_SECTION; + id <= PNOR::NUM_SECTIONS; //include extra entry for error paths + id = (PNOR::SectionId) (id + 1) ) + { + 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].virtAddr = 0; + iv_TOC[side][id].size = 0; + iv_TOC[side][id].eccProtected = false; + } } - // Add a special entry for error paths - iv_TOC[PNOR::INVALID_SECTION].id = PNOR::INVALID_SECTION; - iv_TOC[PNOR::INVALID_SECTION].name = cv_EYECATCHER[PNOR::INVALID_SECTION]; - iv_TOC[PNOR::INVALID_SECTION].vaddr = 0; - iv_TOC[PNOR::INVALID_SECTION].size = 0; - iv_TOC[PNOR::INVALID_SECTION].eccProtected = false; - - //@todo - load flash layout - - //@todo - read TOC if we haven't yet + //@todo - Add in some dummy values for now + + // assume 1 chip with only 1 side for now, no sideless + // TOC starts at offset zero in MMRD mode + + // put some random sizes in here + iv_TOC[PNOR::SIDE_A][PNOR::TOC].size = 8 + 8 + PNOR::NUM_SECTIONS*sizeof(TOCEntry_t); + iv_TOC[PNOR::SIDE_A][PNOR::HB_EXT_CODE].size = 500*1024; //500K + iv_TOC[PNOR::SIDE_A][PNOR::GLOBAL_DATA].size = PAGESIZE; //4K + iv_TOC[PNOR::SIDE_A][PNOR::HB_DATA].size = 2*PAGESIZE; //8K + + // fake PNOR will look like this: TOC::HB_EXT_CODE:GLOBAL_DATA:HB_DATA + // virtual addresses + iv_TOC[PNOR::SIDE_A][PNOR::TOC].virtAddr = BASE_VADDR + 0; + 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 = BASE_VADDR + 0; + iv_TOC[PNOR::SIDE_A][PNOR::HB_EXT_CODE].pmrwAddr = iv_TOC[PNOR::SIDE_A][PNOR::TOC].virtAddr + iv_TOC[PNOR::SIDE_A][PNOR::TOC].size; + iv_TOC[PNOR::SIDE_A][PNOR::GLOBAL_DATA].pmrwAddr = 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].pmrwAddr = iv_TOC[PNOR::SIDE_A][PNOR::GLOBAL_DATA].virtAddr + 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 + + TRACUCOMP(g_trac_pnor, "< PnorRP::readTOC" ); } @@ -182,6 +264,9 @@ void PnorRP::readTOC() */ void PnorRP::waitForMessage() { + TRACFCOMP(g_trac_pnor, "PnorRP::waitForMessage>" ); + + errlHndl_t l_err = NULL; msg_t* message = NULL; uint8_t* user_addr = NULL; uint8_t* eff_addr = NULL; @@ -191,43 +276,68 @@ void PnorRP::waitForMessage() while(1) { + TRACUCOMP(g_trac_pnor, "PnorRP::waitForMessage> waiting for message" ); message = msg_wait( iv_msgQ ); if( message ) { user_addr = (uint8_t*)message->data[0]; eff_addr = (uint8_t*)message->data[1]; - computeDeviceAddr( eff_addr, dev_offset, chip_select ); - needs_ecc = iv_TOC[sectionFromAddr(eff_addr)].eccProtected; + l_err = computeDeviceAddr( eff_addr, MMRD_MODE, dev_offset, chip_select, needs_ecc ); + //@todo - assuming MMRD mode for now + if( l_err ) + { + errlCommit(l_err); + //@todo - kill calling task?, commit log + + if( !msg_is_async(message) ) + { + TRACUCOMP( g_trac_pnor, "sending response...\n" ); + msg_respond( iv_msgQ, message ); //@todo - what goes in response message? + } + continue; // go wait for another message + } + + //@todo - handle MMRD/PMRW mode + // if MMRD then needs_ecc = false switch(message->type) { case( RP::READ_PAGE ): - readFromDevice( dev_offset, chip_select, user_addr ); + readFromDevice( dev_offset, chip_select, needs_ecc, user_addr ); break; case( RP::WRITE_PAGE ): - writeToDevice( dev_offset, chip_select, true, user_addr ); + writeToDevice( dev_offset, chip_select, needs_ecc, user_addr ); break; default: - TRACFCOMP( g_trac_pnor, "PnorRP::waitForMessage> Unrecognized message type user_addr=%p, eff_addr=%p, msgtype=%d", user_addr, eff_addr, message->type ); + TRACFCOMP( g_trac_pnor, "PnorRP::waitForMessage> Unrecognized message type : user_addr=%p, eff_addr=%p, msgtype=%d", user_addr, eff_addr, message->type ); /*@ * @errortype - * @moduleid PNOR::PNORRP_WAITFORMESSAGE - * @reasoncode PNOR::INVALID_MESSAGE + * @moduleid PNOR::MOD_PNORRP_WAITFORMESSAGE + * @reasoncode PNOR::RC_INVALID_MESSAGE * @userdata1 Message type * @userdata2 User memory address * @devdesc PnorRP::waitForMessage> Unrecognized message type */ - errlHndl_t l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, - PNOR::PNORRP_WAITFORMESSAGE, - PNOR::INVALID_MESSAGE, - (uint64_t)message->type, - (uint64_t)user_addr); + l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, + PNOR::MOD_PNORRP_WAITFORMESSAGE, + PNOR::RC_INVALID_MESSAGE, + TO_UINT64(message->type), + (uint64_t)user_addr); errlCommit(l_err); - //@fixme - kill calling task?, commit log + //@todo - kill calling task?, commit log + continue; // go wait for another message + } + + if( !msg_is_async(message) ) + { + TRACUCOMP( g_trac_pnor, "sending response...\n" ); + msg_respond( iv_msgQ, message ); //@todo - what goes in response message? } } } + + TRACFCOMP(g_trac_pnor, "< PnorRP::waitForMessage" ); } @@ -236,18 +346,43 @@ void PnorRP::waitForMessage() */ void PnorRP::readFromDevice( uint64_t i_offset, uint64_t i_chip, + bool i_ecc, void* o_dest ) { - TARGETING::Target* pnor_target = TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL; //@fixme + TRACUCOMP(g_trac_pnor, "PnorRP::readFromDevice> i_offset=0x%X, i_chip=%d", i_offset, i_chip ); + TARGETING::Target* pnor_target = TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL; //@todo + + void* data_to_read = o_dest; + uint8_t* ecc_buffer = NULL; size_t read_size = PAGESIZE; + if( i_ecc ) + { + ecc_buffer = new uint8_t[PAGESIZE_PLUS_ECC]; + data_to_read = ecc_buffer; + read_size = PAGESIZE_PLUS_ECC; + } + errlHndl_t l_err = DeviceFW::deviceRead(pnor_target, - o_dest, + data_to_read, read_size, - DEVICE_PNOR_ADDRESS(i_offset,i_chip) ); - errlCommit(l_err); - //@fixme - commit log + DEVICE_PNOR_ADDRESS(i_chip,i_offset) ); + if( l_err ) + { + TRACFCOMP(g_trac_pnor, "PnorRP::readFromDevice> Error from device : RC=%X", l_err->reasonCode() ); + errlCommit(l_err); + //@todo - anything else? + } + + // remove the ECC data + if( i_ecc ) + { + l_err = stripECC( data_to_read, o_dest ); + //@todo - handle ECC error + delete[] ecc_buffer; + } + TRACUCOMP(g_trac_pnor, "< PnorRP::readFromDevice" ); } /** @@ -258,60 +393,199 @@ void PnorRP::writeToDevice( uint64_t i_offset, bool i_ecc, void* i_src ) { - TARGETING::Target* pnor_target = TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL; //@fixme + TRACUCOMP(g_trac_pnor, "PnorRP::writeToDevice> i_offset=%X, i_chip=%d", i_offset, i_chip ); + + TARGETING::Target* pnor_target = TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL; //@todo // apply ECC to data if needed void* data_to_write = i_src; - void* ecc_buffer = NULL; + uint8_t* ecc_buffer = NULL; if( i_ecc ) { - ecc_buffer = (void*)new uint8_t[PAGESIZE]; + ecc_buffer = new uint8_t[PAGESIZE]; applyECC( i_src, ecc_buffer ); - data_to_write = ecc_buffer; + data_to_write = (void*)ecc_buffer; } size_t write_size = PAGESIZE; errlHndl_t l_err = DeviceFW::deviceWrite(pnor_target, data_to_write, write_size, - DEVICE_PNOR_ADDRESS(i_offset,i_chip) ); - errlCommit(l_err); + DEVICE_PNOR_ADDRESS(i_chip,i_offset) ); + if( l_err ) + { + TRACFCOMP(g_trac_pnor, "PnorRP::readFromDevice> Error from device : RC=%X", l_err->reasonCode() ); + errlCommit(l_err); + //@todo - anything else? + } + if( ecc_buffer ) + { + delete[] ecc_buffer; + } + + TRACUCOMP(g_trac_pnor, "< PnorRP::writeToDevice" ); } /** * @brief Convert a virtual address into the PNOR device address */ -void PnorRP::computeDeviceAddr( void* i_vaddr, - uint64_t& o_offset, - uint64_t& o_chip ) +errlHndl_t PnorRP::computeDeviceAddr( void* i_vaddr, + ControllerMode i_mode, + uint64_t& o_offset, + uint64_t& o_chip, + bool& o_ecc ) { - //@fixme - o_offset = ((uint64_t)i_vaddr) - iv_block->getBaseAddress(); - o_chip = 0; + errlHndl_t l_err = NULL; + o_offset = 0; + o_chip = 99; + uint64_t l_vaddr = (uint64_t)i_vaddr; + + // make sure this is one of our addresses + if( !((l_vaddr >= BASE_VADDR) + && (l_vaddr < LAST_VADDR)) ) + { + TRACFCOMP( g_trac_pnor, "PnorRP::computeDeviceAddr> Virtual Address outside known PNOR range : i_vaddr=%p", i_vaddr ); + /*@ + * @errortype + * @moduleid PNOR::MOD_PNORRP_WAITFORMESSAGE + * @reasoncode PNOR::RC_INVALID_MESSAGE + * @userdata1 Virtual Address + * @userdata2 Base PNOR Address + * @devdesc PnorRP::computeDeviceAddr> Virtual Address outside + * known PNOR range + */ + l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, + PNOR::MOD_PNORRP_COMPUTEDEVICEADDR, + PNOR::RC_INVALID_ADDRESS, + l_vaddr, + BASE_VADDR); + return l_err; + } + + // find the matching section + PNOR::SideSelect side = PNOR::SIDE_A; + PNOR::SectionId id = PNOR::INVALID_SECTION; + l_err = computeSection( l_vaddr, side, id ); + if( l_err ) + { + return l_err; + } + + // pull out the information we need to return from our global copy + 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( MMRD_MODE == i_mode ) + { + o_offset += iv_TOC[side][id].mmrdAddr; + } + else + { + o_offset += iv_TOC[side][id].pmrwAddr; + } + + TRACUCOMP( g_trac_pnor, "< PnorRP::computeDeviceAddr: o_offset=0x%X, o_chip=%d", o_offset, o_chip ); + return l_err; } /** * @brief Apply ECC algorithm to data, assumes size of 1 page - * - * @param[in] i_orig Original data to write - * @param[in] o_ecc Data after applying ECC */ void PnorRP::applyECC( void* i_orig, void* o_ecc ) { + TRACFCOMP(g_trac_pnor, "> PnorRP::applyECC" ); + //@todo - fill this in memcpy( o_ecc, i_orig, PAGESIZE ); + + TRACFCOMP(g_trac_pnor, "< PnorRP::applyECC" ); +} + +/** + * @brief Apply ECC algorithm to data, assumes logical size of 1 page + */ +errlHndl_t PnorRP::stripECC( void* i_orig, + void* o_data ) +{ + TRACFCOMP(g_trac_pnor, "> PnorRP::stripECC" ); + + //@todo - fill this in + memcpy( o_data, i_orig, PAGESIZE ); + + TRACFCOMP(g_trac_pnor, "< PnorRP::stripECC" ); + return NULL; } /** - * @brief Retrieve the section Id based on the virtual address + * @brief Static instance function for testcase only */ -PNOR::SectionId PnorRP::sectionFromAddr( void* i_addr ) +PnorRP& PnorRP::getInstance() { - //@fixme - how do I do this? - return PNOR::INVALID_SECTION; + return Singleton::instance(); } +/** + * @brief Figure out which section a VA belongs to + */ +errlHndl_t PnorRP::computeSection( uint64_t i_vaddr, + PNOR::SideSelect& o_side, + PNOR::SectionId& o_id ) +{ + errlHndl_t errhdl = NULL; + + o_id = PNOR::INVALID_SECTION; + + // first figure out which side it is on (slight performance boost) + if( (i_vaddr >= SIDEA_VADDR) + && (i_vaddr < (SIDEA_VADDR + SIDE_SIZE)) ) + { + o_side = PNOR::SIDE_A; + } + else if( (i_vaddr >= SIDEB_VADDR) + && (i_vaddr < (SIDEB_VADDR + SIDE_SIZE)) ) + { + o_side = PNOR::SIDE_B; + } + else if( (i_vaddr >= SIDELESS_VADDR) + && (i_vaddr < (SIDELESS_VADDR + SIDE_SIZE)) ) + { + o_side = PNOR::SIDELESS; + } + else + { + TRACFCOMP( g_trac_pnor, "PnorRP::computeSection> Invalid virtual address : i_vaddr=%X", i_vaddr ); + /*@ + * @errortype + * @moduleid PNOR::MOD_PNORRP_COMPUTESECTION + * @reasoncode PNOR::RC_INVALID_ADDRESS + * @userdata1 Requested Virtual Address + * @userdata2 + * @devdesc PnorRP::computeSection> Invalid Address + */ + errhdl = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, + PNOR::MOD_PNORRP_COMPUTESECTION, + PNOR::RC_INVALID_ADDRESS, + i_vaddr, + 0); + return errhdl; + } + + // loop through all sections to find a matching id + for( PNOR::SectionId id = PNOR::FIRST_SECTION; + id < PNOR::NUM_SECTIONS; + id = (PNOR::SectionId) (id + 1) ) + { + if( (i_vaddr >= iv_TOC[o_side][id].virtAddr) + && (i_vaddr < (iv_TOC[o_side][id].virtAddr + iv_TOC[o_side][id].size)) ) + { + o_id = iv_TOC[o_side][id].id; + break; + } + } + + return errhdl; +} diff --git a/src/usr/pnor/pnorrp.H b/src/usr/pnor/pnorrp.H index 013e37c37..dccce8cd5 100644 --- a/src/usr/pnor/pnorrp.H +++ b/src/usr/pnor/pnorrp.H @@ -5,7 +5,8 @@ #include #include #include -class Block; +#include +#include /** * PNOR Resource Provider @@ -27,11 +28,11 @@ class PnorRP * @param[in] i_side Side select * @param[out] o_info Location and size information * - * @return size_t Offset of section in bytes + * @return errlHndl_t Error log if request was invalid */ - void getSectionInfo( PNOR::SectionId i_section, - PNOR::SideSelect i_side, - PNOR::SectionInfo_t& o_info ); + errlHndl_t getSectionInfo( PNOR::SectionId i_section, + PNOR::SideSelect i_side, + PNOR::SectionInfo_t& o_info ); protected: /** @@ -47,22 +48,69 @@ class PnorRP private: + /** + * PNOR Constants + */ + enum + { + BASE_VADDR = 0x80000000, /**< 2GB */ + + NUM_SIDES = 3, /**< A, B, Sideless */ + + SIDE_SIZE = 0x2000000, /**< Allocate 32 MB of VA per side */ + + SIDEA_VADDR = BASE_VADDR, /**< Base address of Side A */ + SIDEB_VADDR = SIDEA_VADDR + SIDE_SIZE, /**< Base address of Side B */ + SIDELESS_VADDR = SIDEA_VADDR + SIDE_SIZE*2, /**< Base address of Sideless data */ + + LAST_VADDR = BASE_VADDR + SIDE_SIZE*NUM_SIDES, /**< End of our VA range */ + + /** Real number of bytes required to read 1 logical page */ + PAGESIZE_PLUS_ECC = PAGESIZE * (9/8), // 8 bytes of data + 1 byte of ECC + }; + /** * Table of Contents entry + * This matches the PNOR binary layout @todo this will change */ struct TOCEntry_t { char name[8]; /**< Null terminated ascii string */ - uint64_t offset; /**< Offset to region from zero */ - uint64_t size; /**< Size of region in bytes */ + uint64_t offset; /**< Offset to region from zero (relative to chip) */ + uint64_t size; /**< Size of region in bytes (with or without ECC?) */ uint64_t size_act; /**< Actual size of content in bytes */ char fuse_tbd[96]; /**< Remainder is TBD depending on FUSE requirements */ + //@todo - need a chip select here I think? + }; + + /** + * Mode that PNOR controller is using + */ + enum ControllerMode + { + MMRD_MODE, /**< MMRD - Read-Only, ECC is hidden by hardware */ + PMRW_MODE, /**< PMRW - Write-able mode, ECC must be handled on reads/writes */ + }; + + /** + * Internal information to deal with the sections of PNOR + */ + struct SectionData_t { + PNOR::SectionId id; /**< Identifier for this section */ + PNOR::SideSelect side; /** Side Select */ + + uint64_t chip; /**< Chip Select */ + uint64_t mmrdAddr; /**< Address in MMRD mode (no ECC) */ + uint64_t pmrwAddr; /**< Address in PMRW mode (with ECC) */ + uint64_t virtAddr; /**< Virtual address for the start of the section */ + uint64_t size; /**< Actual size of content in bytes (not including ECC) */ + bool eccProtected; /**< Section is ECC protected */ }; /** * Cached copy of section data */ - PNOR::SectionInfo_t iv_TOC[PNOR::NUM_SECTIONS+1]; + SectionData_t iv_TOC[NUM_SIDES][PNOR::NUM_SECTIONS+1]; /** * Pointer to the message queue where we receive messages @@ -74,11 +122,6 @@ class PnorRP */ uint64_t iv_startupRC; - /** - * Memory Block associated with my PNOR memory space - */ - Block* iv_block; - /** * @brief Initialize the daemon, called by constructor */ @@ -95,18 +138,20 @@ class PnorRP void waitForMessage(); /** - * @brief Retrieve 1 page of data from the PNOR device + * @brief Retrieve 1 logical page of data from the PNOR device * * @param[in] i_offset Offset into PNOR chip * @param[in] i_chip Which PNOR chip + * @param[in] i_ecc true=apply ECC after reading * @param[out] o_dest Buffer to copy data into */ void readFromDevice( uint64_t i_offset, uint64_t i_chip, + bool i_ecc, void* o_dest ); /** - * @brief Write 1 page of data to the PNOR device + * @brief Write 1 logical page of data to the PNOR device * * @param[in] i_offset Offset into PNOR chip * @param[in] i_chip Which PNOR chip @@ -122,12 +167,31 @@ 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 + * + * @return Error if VA is bad */ - void computeDeviceAddr( void* i_vaddr, - uint64_t& o_offset, - uint64_t& o_chip ); + errlHndl_t computeDeviceAddr( void* i_vaddr, + ControllerMode i_mode, + uint64_t& o_offset, + uint64_t& o_chip, + bool& o_ecc ); + + /** + * @brief Figure out which section a VA belongs to + * + * @param[in] i_vaddr Virtual address of page + * @param[out] o_side Which side of the flash + * @param[out] o_id Which section of PNOR + * + * @return Error if VA is bad + */ + errlHndl_t computeSection( uint64_t i_vaddr, + PNOR::SideSelect& o_side, + PNOR::SectionId& o_id ); /** * @brief Apply ECC algorithm to data @@ -139,13 +203,15 @@ class PnorRP void* o_ecc ); /** - * @brief Retrieve the section Id based on the virtual address + * @brief Apply ECC algorithm to data, assumes size of 1 page * - * @param[in] i_addr Virtual address of page within section + * @param[in] i_orig Original data that was read + * @param[in] o_data Data after removing ECC * - * @return SectionId Id of matching section, =INVALID_SECTION if no match + * @return Error if ECC is incorrect */ - PNOR::SectionId sectionFromAddr( void* i_addr ); + errlHndl_t stripECC( void* i_orig, + void* o_data ); /** * @brief Returns true if the initial startup failed for some reason @@ -156,6 +222,7 @@ class PnorRP { if( iv_startupRC ) { + //@patrick : Weak consistency bug? Will need some sort of lwsync / isync coordinating reading / setting of iv_startupRC if the daemonized task could be setting this. o_rc = iv_startupRC; return true; } @@ -165,6 +232,14 @@ class PnorRP // allow local helper function to call private methods friend void wait_for_message( void* unused ); + + // allow testcase to see inside + friend class PnorRpTest; + + /** + * @brief Static instance function for testcase only + */ + static PnorRP& getInstance(); }; diff --git a/src/usr/pnor/test/pnorrptest.H b/src/usr/pnor/test/pnorrptest.H index e9375d3c2..c2c5cccd9 100644 --- a/src/usr/pnor/test/pnorrptest.H +++ b/src/usr/pnor/test/pnorrptest.H @@ -12,6 +12,10 @@ #include #include #include +#include +#include +#include +#include "../pnorrp.H" extern trace_desc_t* g_trac_pnor; @@ -21,16 +25,284 @@ class PnorRpTest : public CxxTest::TestSuite public: /** - * @brief PNOR RP test #1 - * Description + * @brief PNOR RP test - Section Info + * Look for mismatches in section information from expected */ - void testXX(void) + void test_getSectionInfo(void) { + TRACFCOMP(g_trac_pnor, "PnorRpTest::test_getSectionInfo> Start" ); + uint64_t fails = 0; + uint64_t total = 0; + PNOR::SectionInfo_t info; + errlHndl_t errhdl = NULL; + + struct ExpVals_t { + uint64_t size; + uint64_t vaddr; + }; + const ExpVals_t exp_data[] = { + /* TOC */ { 0x690, 0x80000000 }, + /* GLOBAL_DATA */ { PAGESIZE, 0x8007D690 }, + /* SBE_IPL */ { 0, 0 }, + /* HB_BASE_CODE */ { 0, 0 }, + /* HB_DATA */ { 2*PAGESIZE, 0x8007E690 }, + /* HB_ERRLOGS */ { 0, 0 }, + /* HB_EXT_CODE */ { 0x7D000, 0x80000690 }, + /* HB_RUNTIME */ { 0, 0 }, + /* PAYLOAD */ { 0, 0 }, + /* PFW_LITE_CODE */ { 0, 0 }, + /* OCC_CODE */ { 0, 0 }, + /* KVM_PART_INFO */ { 0, 0 }, + /* CODE_UPDATE */ { 0, 0 }, + }; + + for( PNOR::SectionId id = PNOR::FIRST_SECTION; + id < PNOR::NUM_SECTIONS; + id = (PNOR::SectionId) (id + 1) ) + { + total++; + errhdl = PNOR::getSectionInfo( id, PNOR::SIDE_A, info ); + if( errhdl ) + { + if( exp_data[id].size != 0 ) + { + TRACFCOMP(g_trac_pnor, "PnorRpTest::test_getSectionInfo> ERROR : getSectionInfo returned error for %d : RC=%X", id, errhdl->reasonCode() ); + TS_FAIL( "PnorRpTest::test_getSectionInfo> ERROR : Unexpected error log" ); + fails++; + errlCommit(errhdl); + } + else + { + delete errhdl; + } + } + + // Look for expected size + total++; + if( info.size != exp_data[id].size ) + { + TRACFCOMP(g_trac_pnor, "PnorRpTest::test_getSectionInfo> ERROR : Mismatched size for section %d : id=%d, exp=%d, actual=%d", id, info.id, exp_data[id].size, info.size ); + TS_FAIL( "PnorRpTest::test_getSectionInfo> ERROR : Mismatched Size" ); + fails++; + } + + // Look for expected vaddr + total++; + if( info.vaddr != exp_data[id].vaddr ) + { + TRACFCOMP(g_trac_pnor, "PnorRpTest::test_getSectionInfo> ERROR : Mismatched vaddr for section %d : id=%d, exp=%d, actual=%d", id, info.id, exp_data[id].vaddr, info.vaddr ); + TS_FAIL( "PnorRpTest::test_getSectionInfo> ERROR : Mismatched vaddr" ); + fails++; + } + } + + + TRACFCOMP(g_trac_pnor, "PnorRpTest::test_getSectionInfo> %d/%d fails", fails, total ); + }; + + /** + * @brief PNOR RP test - Read/Write Page + * Use message interface to read and write individual pages + */ + void test_messageReadWrite(void) + { + TRACFCOMP(g_trac_pnor, "PnorRpTest::test_messageReadWrite> Start" ); + uint64_t fails = 0; + uint64_t total = 0; + int rc = 0; + + msg_q_t mq = PnorRP::getInstance().iv_msgQ; + + + // allocate some space to play with + uint64_t data1_r[PAGESIZE/sizeof(uint64_t)]; + uint64_t data2_r[PAGESIZE/sizeof(uint64_t)]; + uint64_t data_tmp[PAGESIZE/sizeof(uint64_t)]; + + // use the HB_DATA as scratch space + PNOR::SectionInfo_t info; + PNOR::getSectionInfo( PNOR::HB_DATA, PNOR::SIDE_A, info ); + + msg_t* msg = msg_allocate(); + + // read the first page + total++; + msg->type = RP::READ_PAGE; + msg->data[0] = (uint64_t)data1_r; //data[0] = address to copy into (user buffer) + msg->data[1] = info.vaddr; //data[1] = address to copy from (effective address) + rc = msg_sendrecv( mq, msg ); + if( rc ) + { + TRACFCOMP(g_trac_pnor, "PnorRpTest::test_messageReadWrite> ERROR : error from msg_sendrecv(READ_PAGE):1" ); + TS_FAIL( "PnorRpTest::test_messageReadWrite> ERROR : error from msg_sendrecv(READ_PAGE):1, rc=%d", rc ); + fails++; + } + + // read the second page + total++; + msg->type = RP::READ_PAGE; + msg->data[0] = (uint64_t)data2_r; //data[0] = address to copy into (user buffer) + msg->data[1] = info.vaddr + PAGESIZE; //data[1] = address to copy from (effective address) + rc = msg_sendrecv( mq, msg ); + if( rc ) + { + TRACFCOMP(g_trac_pnor, "PnorRpTest::test_messageReadWrite> ERROR : error from msg_sendrecv(READ_PAGE):2" ); + TS_FAIL( "PnorRpTest::test_messageReadWrite> ERROR : error from msg_sendrecv(READ_PAGE):2, rc=%d", rc ); + fails++; + } + + // put some data into the first page + for( uint64_t x = 0; x < (PAGESIZE/sizeof(uint64_t)); x++ ) + { + data_tmp[x] = x; + } + + // write the changed page back out + total++; + msg->type = RP::WRITE_PAGE; + msg->data[0] = (uint64_t)data_tmp; //data[0] = address to copy from (user buffer) + msg->data[1] = info.vaddr; //data[1] = address to copy into (effective address) + rc = msg_sendrecv( mq, msg ); + if( rc ) + { + TRACFCOMP(g_trac_pnor, "PnorRpTest::test_messageReadWrite> ERROR : error from msg_sendrecv(WRITE_PAGE):1" ); + TS_FAIL( "PnorRpTest::test_messageReadWrite> ERROR : error from msg_sendrecv(WRITE_PAGE):1, rc=%d", rc ); + fails++; + } + + // read the first page again + total++; + msg->type = RP::READ_PAGE; + msg->data[0] = (uint64_t)data1_r; //data[0] = address to copy into (user buffer) + msg->data[1] = info.vaddr; //data[1] = address to copy from (effective address) + rc = msg_sendrecv( mq, msg ); + if( rc ) + { + TRACFCOMP(g_trac_pnor, "PnorRpTest::test_messageReadWrite> ERROR : error from msg_sendrecv(READ_PAGE):3" ); + TS_FAIL( "PnorRpTest::test_messageReadWrite> ERROR : error from msg_sendrecv(READ_PAGE):3, rc=%d", rc ); + fails++; + } + + // compare to what we wrote + total++; + if( memcmp( data_tmp, data1_r, PAGESIZE ) ) + { + TRACFCOMP(g_trac_pnor, "PnorRpTest::test_messageReadWrite> ERROR : Data mismatch in page0" ); + TS_FAIL( "PnorRpTest::test_messageReadWrite> ERROR : Data mismatch in page0" ); + fails++; + uint64_t* act_data = data1_r; + for( uint64_t x = 0; x < 4; x++ ) + { + TRACFCOMP( g_trac_pnor, "ACT:%2d : %.16X %.16X %.16X %.16X", x, act_data[x*4], act_data[x*4+1], act_data[x*4+2], act_data[x*4+3] ); + TRACFCOMP( g_trac_pnor, "EXP:%2d : %.16X %.16X %.16X %.16X", x, act_data[x*4], act_data[x*4+1], act_data[x*4+2], act_data[x*4+3] ); + } + } + + // read the second page again + total++; + msg->type = RP::READ_PAGE; + msg->data[0] = (uint64_t)data_tmp; //data[0] = address to copy into (user buffer) + msg->data[1] = info.vaddr + PAGESIZE; //data[1] = address to copy from (effective address) + rc = msg_sendrecv( mq, msg ); + if( rc ) + { + TRACFCOMP(g_trac_pnor, "PnorRpTest::test_messageReadWrite> ERROR : error from msg_sendrecv(READ_PAGE):4" ); + TS_FAIL( "PnorRpTest::test_messageReadWrite> ERROR : error from msg_sendrecv(READ_PAGE):4, rc=%d", rc ); + fails++; + } + + // compare to what we read the first time + total++; + if( memcmp( data_tmp, data2_r, PAGESIZE ) ) + { + TRACFCOMP(g_trac_pnor, "PnorRpTest::test_messageReadWrite> ERROR : Data mismatch in page1" ); + TS_FAIL( "PnorRpTest::test_messageReadWrite> ERROR : Data mismatch in page1" ); + fails++; + uint64_t* act_data = data_tmp; + for( uint64_t x = 0; x < 4; x++ ) + { + TRACFCOMP( g_trac_pnor, "ACT:%2d : %.16X %.16X %.16X %.16X", x, act_data[x*4], act_data[x*4+1], act_data[x*4+2], act_data[x*4+3] ); + TRACFCOMP( g_trac_pnor, "EXP:%2d : %.16X %.16X %.16X %.16X", x, act_data[x*4], act_data[x*4+1], act_data[x*4+2], act_data[x*4+3] ); + } + } + + msg_free(msg); + + TRACFCOMP(g_trac_pnor, "PnorRpTest::test_messageReadWrite> %d/%d fails", fails, total ); + }; + + /** + * @brief PNOR RP test - Read/Write Addresses + * do read/modify/write/read to different virtual addresses + */ + void test_AddrReadWrite(void) + { + return; //@todo - enable this after Task 3445 + TRACFCOMP( g_trac_pnor, "PnorRpTest::test_AddrReadWrite> Start" ); + uint64_t fails = 0; + uint64_t total = 0; + uint64_t* ptr = NULL; + + // read a bunch of addresses + ptr = new uint64_t[16]; + for( uint64_t addr = 0; + addr < 20; + addr += 2048 ) // loop at 2K (half-page) intervals + { + TRACFCOMP( g_trac_pnor, "PnorRpTest::test_AddrReadWrite> addr=%X", addr ); + total++; + memcpy( ptr, (void*)(0x80000000+addr), 16*sizeof(uint64_t) ); + } + delete[] ptr; + + // setup a bunch of interesting addresses to read/write from + uint64_t test_addrs[] = { + 0x8007E690, // chip0-HB_DATA + 0x8207E690, // chip1-HB_DATA + 0x8007E790, // chip0-HB_DATA+0x100 + 0x8207E890, // chip1-HB_DATA+0x200 + }; + uint64_t test_vals[] = { + 0x1111222233334444, + 0xA5A5A5A5A5A5A5A5, + 0x5566778899AABBCC, + 0xBEEFBEEFBEEFBEEF, + }; + + // loop around and do alternating writes and reads + for( uint64_t x = 0; x < (sizeof(test_addrs)/sizeof(test_addrs[0])); x++ ) + { + TRACFCOMP( g_trac_pnor, "PnorRpTest::test_AddrReadWrite> x1=%d", x ); + total++; + ptr = (uint64_t*) test_addrs[x]; + *ptr = test_vals[x]; + // verify we can write data + if( *ptr != test_vals[x] ) + { + TRACFCOMP( g_trac_pnor, "PnorRpTest::test_AddrReadWrite> ERROR : Data mismatch in first write of address 0x%p : exp=0x%X, act=0x%X", ptr, test_vals[x], *ptr ); + TS_FAIL( "PnorRpTest::test_AddrReadWrite> ERROR : Data mismatch in first write" ); + fails++; + } + } + for( uint64_t x = 0; x < (sizeof(test_addrs)/sizeof(test_addrs[0])); x++ ) + { + TRACFCOMP( g_trac_pnor, "PnorRpTest::test_AddrReadWrite> x2=%d", x ); + total++; + ptr = (uint64_t*) test_addrs[x]; + // make sure we don't write on top of each other + if( *ptr != test_vals[x] ) + { + TRACFCOMP( g_trac_pnor, "PnorRpTest::test_AddrReadWrite> ERROR : Data mismatch in second read of address 0x%p : exp=0x%X, act=0x%X", ptr, test_vals[x], *ptr ); + TS_FAIL( "PnorRpTest::test_AddrReadWrite> ERROR : Data mismatch in second read" ); + fails++; + } + } + + TRACFCOMP(g_trac_pnor, "PnorRpTest::test_AddrReadWrite> %d/%d fails", fails, total ); }; //@todo - import config data from build and compare to section info - //@todo - do read/modify/write/read to different virtual addresses - //@todo - send messages to do read/write of individual pages + }; -- cgit v1.2.1