summaryrefslogtreecommitdiffstats
path: root/src/usr
diff options
context:
space:
mode:
authorDan Crowell <dcrowell@us.ibm.com>2011-07-25 16:22:38 -0500
committerDaniel M. Crowell <dcrowell@us.ibm.com>2011-07-28 16:25:20 -0500
commitd7e9478f1de907b1b3d4923b507964222cb224fe (patch)
treee33c23c92e29eec270a7738c6286c03983584f23 /src/usr
parent8d82f5f4dde24bb6f944607c59d314b9f5003ae9 (diff)
downloadtalos-hostboot-d7e9478f1de907b1b3d4923b507964222cb224fe.tar.gz
talos-hostboot-d7e9478f1de907b1b3d4923b507964222cb224fe.zip
PNOR Resource Provider (RTC:3387)
Change-Id: Ifa47ad581c7d403b927708497b565d858b31ee0f Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/213 Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com> Tested-by: Jenkins Server
Diffstat (limited to 'src/usr')
-rw-r--r--src/usr/initservice/baseinitsvc/initsvctasks.H4
-rw-r--r--src/usr/makefile2
-rw-r--r--src/usr/pnor/makefile8
-rw-r--r--src/usr/pnor/pnorrp.C317
-rw-r--r--src/usr/pnor/pnorrp.H171
-rw-r--r--src/usr/pnor/test/makefile6
-rw-r--r--src/usr/pnor/test/pnorrptest.H38
7 files changed, 543 insertions, 3 deletions
diff --git a/src/usr/initservice/baseinitsvc/initsvctasks.H b/src/usr/initservice/baseinitsvc/initsvctasks.H
index e11e8aff3..bf9c925f4 100644
--- a/src/usr/initservice/baseinitsvc/initsvctasks.H
+++ b/src/usr/initservice/baseinitsvc/initsvctasks.H
@@ -52,10 +52,10 @@ const TaskInfo g_taskinfolist[] = {
* @brief PNOR Driver Task
*/
{
- "libpnordd.so" , // taskname
+ "libpnor.so" , // taskname
NULL, // no pointer to fn
{
- NONE, // don't start
+ START_TASK, // start
BASE_IMAGE, // Base Module
START_PNORDD_ERRL_ID, // module id for errorlog
}
diff --git a/src/usr/makefile b/src/usr/makefile
index 2056bfa28..cfd8aba1a 100644
--- a/src/usr/makefile
+++ b/src/usr/makefile
@@ -4,6 +4,6 @@ OBJS = module_init.o
SUBDIRS = example.d trace.d cxxtest.d testcore.d errl.d devicefw.d \
scom.d xscom.d targeting.d initservice.d hwpf.d \
- ecmddatabuffer.d isteps.d
+ ecmddatabuffer.d isteps.d pnor.d
include ${ROOTPATH}/config.mk
diff --git a/src/usr/pnor/makefile b/src/usr/pnor/makefile
new file mode 100644
index 000000000..d52765cd1
--- /dev/null
+++ b/src/usr/pnor/makefile
@@ -0,0 +1,8 @@
+ROOTPATH = ../../..
+MODULE = pnor
+
+OBJS = pnorrp.o
+
+SUBDIRS = test.d
+
+include ${ROOTPATH}/config.mk
diff --git a/src/usr/pnor/pnorrp.C b/src/usr/pnor/pnorrp.C
new file mode 100644
index 000000000..73edaacdb
--- /dev/null
+++ b/src/usr/pnor/pnorrp.C
@@ -0,0 +1,317 @@
+#include "pnorrp.H"
+#include <sys/rp.h>
+#include <pnor/pnor_reasoncodes.H>
+#include <initservice/taskargs.H>
+#include <sys/msg.h>
+#include <kernel/block.H>
+#include <trace/interface.H>
+#include <errl/errlentry.H>
+#include <errl/errlmanager.H>
+#include <targeting/targetservice.H>
+#include <devicefw/userif.H>
+#include <limits.h>
+#include <string.h>
+
+// Trace definition
+trace_desc_t* g_trac_pnor = NULL;
+TRAC_INIT(&g_trac_pnor, "PNOR", 4096);
+
+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 */
+ "XXX", /**< NUM_SECTIONS : Used as invalid entry */
+};
+
+
+/**
+ * @brief set up _start() task entry procedure for PNOR daemon
+ */
+TASK_ENTRY_MACRO( PnorRP::init );
+
+
+/********************
+ Public Methods
+ ********************/
+
+/**
+ * @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 )
+{
+ Singleton<PnorRP>::instance().getSectionInfo(i_section,i_side,o_info);
+}
+
+
+/**
+ * STATIC
+ * @brief Static Initializer
+ */
+void PnorRP::init( void* i_taskArgs )
+{
+ TRACFCOMP(g_trac_pnor, "PnorRP::init> " );
+ INITSERVICE::TaskArgs::TaskArgs* args = (INITSERVICE::TaskArgs::TaskArgs*)i_taskArgs;
+ uint64_t rc = 0;
+ if( Singleton<PnorRP>::instance().didStartupFail(rc) )
+ {
+ args->postReturnCode(rc);
+ }
+}
+
+
+/********************
+ Helper Methods
+ ********************/
+
+/**
+ * @brief Static function wrapper to pass into task_create
+ */
+void wait_for_message( void* unused )
+{
+ Singleton<PnorRP>::instance().waitForMessage();
+}
+
+
+/********************
+ Private/Protected Methods
+ ********************/
+
+/**
+ * @brief Constructor
+ */
+PnorRP::PnorRP()
+: iv_msgQ(NULL)
+,iv_block(NULL)
+{
+ // setup everything in a separate function
+ initDaemon();
+}
+
+/**
+ * @brief Destructor
+ */
+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;
+}
+
+/**
+ * @brief Initialize the daemon
+ */
+void PnorRP::initDaemon()
+{
+ // read the TOC in the PNOR to compute the sections
+ readTOC();
+
+ // create a message queue
+ iv_msgQ = msg_q_create();
+
+ // create a Block, passing in the message queue
+ //@fixme iv_block = new Block( 0, 0 );
+
+ // start task to wait on the queue
+ task_create( wait_for_message, NULL );
+}
+
+
+/**
+ * @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 )
+{
+ // cheat for now
+
+
+ //@todo - when we get a real PNOR image
+
+}
+
+
+
+/**
+ * @brief Read the TOC and store section information
+ */
+void PnorRP::readTOC()
+{
+ // Zero out my table
+ for( PNOR::SectionId id = PNOR::FIRST_SECTION;
+ id < PNOR::NUM_SECTIONS;
+ id = (PNOR::SectionId) (id + 1) )
+ {
+ 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;
+ }
+
+ // 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
+}
+
+
+
+/**
+ * @brief Message receiver
+ */
+void PnorRP::waitForMessage()
+{
+ msg_t* message = NULL;
+ uint8_t* user_addr = NULL;
+ uint8_t* eff_addr = NULL;
+ uint64_t dev_offset = 0;
+ uint64_t chip_select = 0xF;
+ bool needs_ecc = false;
+
+ while(1)
+ {
+ 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;
+
+ switch(message->type)
+ {
+ case( RP::READ_PAGE ):
+ readFromDevice( dev_offset, chip_select, user_addr );
+ break;
+ case( RP::WRITE_PAGE ):
+ writeToDevice( dev_offset, chip_select, true, 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 );
+ /*@
+ * @errortype
+ * @moduleid PNOR::PNORRP_WAITFORMESSAGE
+ * @reasoncode PNOR::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);
+ errlCommit(l_err);
+ //@fixme - kill calling task?, commit log
+ }
+ }
+ }
+
+}
+
+
+/**
+ * @brief Retrieve 1 page of data from the PNOR device
+ */
+void PnorRP::readFromDevice( uint64_t i_offset,
+ uint64_t i_chip,
+ void* o_dest )
+{
+ TARGETING::Target* pnor_target = TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL; //@fixme
+
+ size_t read_size = PAGESIZE;
+ errlHndl_t l_err = DeviceFW::deviceRead(pnor_target,
+ o_dest,
+ read_size,
+ DEVICE_PNOR_ADDRESS(i_offset,i_chip) );
+ errlCommit(l_err);
+ //@fixme - commit log
+
+}
+
+/**
+ * @brief Write 1 page of data to the PNOR device
+ */
+void PnorRP::writeToDevice( uint64_t i_offset,
+ uint64_t i_chip,
+ bool i_ecc,
+ void* i_src )
+{
+ TARGETING::Target* pnor_target = TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL; //@fixme
+
+ // apply ECC to data if needed
+ void* data_to_write = i_src;
+ void* ecc_buffer = NULL;
+ if( i_ecc )
+ {
+ ecc_buffer = (void*)new uint8_t[PAGESIZE];
+ applyECC( i_src, ecc_buffer );
+ data_to_write = 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);
+
+}
+
+/**
+ * @brief Convert a virtual address into the PNOR device address
+ */
+void PnorRP::computeDeviceAddr( void* i_vaddr,
+ uint64_t& o_offset,
+ uint64_t& o_chip )
+{
+ //@fixme
+ o_offset = ((uint64_t)i_vaddr) - iv_block->getBaseAddress();
+ o_chip = 0;
+}
+
+
+/**
+ * @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 )
+{
+ //@todo - fill this in
+ memcpy( o_ecc, i_orig, PAGESIZE );
+}
+
+/**
+ * @brief Retrieve the section Id based on the virtual address
+ */
+PNOR::SectionId PnorRP::sectionFromAddr( void* i_addr )
+{
+ //@fixme - how do I do this?
+ return PNOR::INVALID_SECTION;
+}
+
+
diff --git a/src/usr/pnor/pnorrp.H b/src/usr/pnor/pnorrp.H
new file mode 100644
index 000000000..013e37c37
--- /dev/null
+++ b/src/usr/pnor/pnorrp.H
@@ -0,0 +1,171 @@
+#ifndef __PNOR_PNORRP_H
+#define __PNOR_PNORRP_H
+
+#include <pnor/pnorif.H>
+#include <sys/msg.h>
+#include <stdint.h>
+#include <builtins.h>
+class Block;
+
+/**
+ * PNOR Resource Provider
+ */
+class PnorRP
+{
+ public:
+ /**
+ * @brief Static Initializer
+ * @param[in] Task Args pointer passed by init service
+ */
+ static void init( void* i_taskArgs );
+
+ /**
+ * @brief Return the size and address of a given section of PNOR data
+ * Called by external PNOR::getSectionInfo()
+ *
+ * @param[in] i_section PNOR section
+ * @param[in] i_side Side select
+ * @param[out] o_info Location and size information
+ *
+ * @return size_t Offset of section in bytes
+ */
+ void getSectionInfo( PNOR::SectionId i_section,
+ PNOR::SideSelect i_side,
+ PNOR::SectionInfo_t& o_info );
+
+ protected:
+ /**
+ * @brief Constructor
+ */
+ PnorRP();
+
+ /**
+ * @brief Destructor
+ */
+ ~PnorRP();
+
+
+ private:
+
+ /**
+ * Table of Contents entry
+ */
+ 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 size_act; /**< Actual size of content in bytes */
+ char fuse_tbd[96]; /**< Remainder is TBD depending on FUSE requirements */
+ };
+
+ /**
+ * Cached copy of section data
+ */
+ PNOR::SectionInfo_t iv_TOC[PNOR::NUM_SECTIONS+1];
+
+ /**
+ * Pointer to the message queue where we receive messages
+ */
+ msg_q_t iv_msgQ;
+
+ /**
+ * Remember that we failed during initial startup
+ */
+ uint64_t iv_startupRC;
+
+ /**
+ * Memory Block associated with my PNOR memory space
+ */
+ Block* iv_block;
+
+ /**
+ * @brief Initialize the daemon, called by constructor
+ */
+ void initDaemon();
+
+ /**
+ * @brief Read the TOC and store section information
+ */
+ void readTOC();
+
+ /**
+ * @brief Message receiver
+ */
+ void waitForMessage();
+
+ /**
+ * @brief Retrieve 1 page of data from the PNOR device
+ *
+ * @param[in] i_offset Offset into PNOR chip
+ * @param[in] i_chip Which PNOR chip
+ * @param[out] o_dest Buffer to copy data into
+ */
+ void readFromDevice( uint64_t i_offset,
+ uint64_t i_chip,
+ void* o_dest );
+
+ /**
+ * @brief Write 1 page of data to 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 before writing
+ * @param[in] i_src Buffer to copy data from
+ */
+ void writeToDevice( uint64_t i_offset,
+ uint64_t i_chip,
+ bool i_ecc,
+ void* i_src );
+
+ /**
+ * @brief Convert a virtual address into the PNOR device address
+ *
+ * @param[in] i_vaddr Virtual address of page
+ * @param[out] o_offset Offset into PNOR chip
+ * @param[out] o_chip Which PNOR chip
+ */
+ void computeDeviceAddr( void* i_vaddr,
+ uint64_t& o_offset,
+ uint64_t& o_chip );
+
+ /**
+ * @brief Apply ECC algorithm to data
+ *
+ * @param[in] i_orig Original data to write
+ * @param[in] o_ecc Data after applying ECC
+ */
+ void applyECC( void* i_orig,
+ void* o_ecc );
+
+ /**
+ * @brief Retrieve the section Id based on the virtual address
+ *
+ * @param[in] i_addr Virtual address of page within section
+ *
+ * @return SectionId Id of matching section, =INVALID_SECTION if no match
+ */
+ PNOR::SectionId sectionFromAddr( void* i_addr );
+
+ /**
+ * @brief Returns true if the initial startup failed for some reason
+ * @param[out] Return code
+ * @return true if startup failed
+ */
+ bool didStartupFail( uint64_t& o_rc )
+ {
+ if( iv_startupRC )
+ {
+ o_rc = iv_startupRC;
+ return true;
+ }
+ return false;
+ };
+
+
+ // allow local helper function to call private methods
+ friend void wait_for_message( void* unused );
+};
+
+
+#endif
diff --git a/src/usr/pnor/test/makefile b/src/usr/pnor/test/makefile
new file mode 100644
index 000000000..a499d93c4
--- /dev/null
+++ b/src/usr/pnor/test/makefile
@@ -0,0 +1,6 @@
+ROOTPATH = ../../../..
+
+MODULE = pnorrptest
+TESTS = *.H
+
+include ${ROOTPATH}/config.mk
diff --git a/src/usr/pnor/test/pnorrptest.H b/src/usr/pnor/test/pnorrptest.H
new file mode 100644
index 000000000..e9375d3c2
--- /dev/null
+++ b/src/usr/pnor/test/pnorrptest.H
@@ -0,0 +1,38 @@
+#ifndef __PNORRPTEST_H
+#define __PNORRPTEST_H
+
+/**
+ * @file pnorrptest.H
+ *
+ * @brief Test case for PNOR Resource Provider
+*/
+
+#include <cxxtest/TestSuite.H>
+#include <errl/errlmanager.H>
+#include <errl/errlentry.H>
+#include <errl/errltypes.H>
+#include <pnor/pnorif.H>
+
+extern trace_desc_t* g_trac_pnor;
+
+
+class PnorRpTest : public CxxTest::TestSuite
+{
+ public:
+
+ /**
+ * @brief PNOR RP test #1
+ * Description
+ */
+ void testXX(void)
+ {
+ };
+
+ //@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
+
+};
+
+
+#endif
OpenPOWER on IntegriCloud