summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorThi Tran <thi@us.ibm.com>2011-06-11 15:49:38 -0500
committerA. Patrick Williams III <iawillia@us.ibm.com>2011-06-17 13:57:06 -0500
commitcdaabfdbec148d9ce85f422507c596a8ae6ced08 (patch)
treebc8edbc339263a4c4b9c71f3298ff6043af1decb /src
parentb301c77be3ab2b9c097f2e3df47e96a907221ed9 (diff)
downloadtalos-hostboot-cdaabfdbec148d9ce85f422507c596a8ae6ced08.tar.gz
talos-hostboot-cdaabfdbec148d9ce85f422507c596a8ae6ced08.zip
Initial XSCOM delivery
Change-Id: I80278bf2e03b4e6403d9a36b8782b225dba29fe3 Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/144 Tested-by: Jenkins Server Reviewed-by: MIKE J. JONES <mjjones@us.ibm.com> Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com>
Diffstat (limited to 'src')
-rw-r--r--src/include/usr/devicefw/driverif.H7
-rw-r--r--src/include/usr/hbotcompid.H15
-rw-r--r--src/include/usr/xscom/xscomreasoncodes.H22
-rw-r--r--src/makefile5
-rw-r--r--src/usr/makefile3
-rw-r--r--src/usr/scom/makefile8
-rw-r--r--src/usr/scom/scom.C46
-rw-r--r--src/usr/scom/scom.H41
-rw-r--r--src/usr/scom/test/makefile6
-rw-r--r--src/usr/scom/test/scomtest.H30
-rw-r--r--src/usr/xscom/makefile8
-rw-r--r--src/usr/xscom/test/makefile6
-rw-r--r--src/usr/xscom/test/xscomtest.H113
-rw-r--r--src/usr/xscom/xscom.C309
-rw-r--r--src/usr/xscom/xscom.H233
15 files changed, 849 insertions, 3 deletions
diff --git a/src/include/usr/devicefw/driverif.H b/src/include/usr/devicefw/driverif.H
index a3c5b37b6..c7f094d8a 100644
--- a/src/include/usr/devicefw/driverif.H
+++ b/src/include/usr/devicefw/driverif.H
@@ -56,6 +56,13 @@ namespace DeviceFW
WILDCARD = -1,
};
+ /** Construct the device addressing parameters for XSCOM device ops.
+ * @param[in] i_address - XSCom address to operate on.
+ */
+ #define DEVICE_XSCOM_ADDRESS(i_address) \
+ DeviceFW::XSCOM, static_cast<uint64_t>((i_address))
+
+
/** @class InvalidParameterType
* @brief Unused type to cause compiler fails for invalid template types.
*
diff --git a/src/include/usr/hbotcompid.H b/src/include/usr/hbotcompid.H
index b99e91c35..e6be3adc8 100644
--- a/src/include/usr/hbotcompid.H
+++ b/src/include/usr/hbotcompid.H
@@ -46,5 +46,20 @@ const compId_t DEVFW_COMP_ID = 0x0200;
const char DEVFW_COMP_NAME[] = "devfw";
//@}
+/** @name SCOM
+ * SCOM component
+ */
+//@{
+const compId_t SCOM_COMP_ID = 0x0300;
+const char SCOM_COMP_NAME[] = "scom";
+//@}
+
+/** @name XSCOM
+ * XSCOM component
+ */
+//@{
+const compId_t XSCOM_COMP_ID = 0x0400;
+const char XSCOM_COMP_NAME[] = "xscom";
+//@}
#endif
diff --git a/src/include/usr/xscom/xscomreasoncodes.H b/src/include/usr/xscom/xscomreasoncodes.H
new file mode 100644
index 000000000..552b517e9
--- /dev/null
+++ b/src/include/usr/xscom/xscomreasoncodes.H
@@ -0,0 +1,22 @@
+#ifndef __XSCOM_REASONCODES_H
+#define __XSCOM_REASONCODES_H
+
+#include <hbotcompid.H>
+
+namespace XSCOM
+{
+ enum xscomModuleId
+ {
+ XSCOM_PERFORM_OP = 0x00,
+ XSCOM_SANITY_CHECK = 0x01,
+ };
+
+ enum xscomReasonCode
+ {
+ XSCOM_STATUS_ERR = XSCOM_COMP_ID | 0x01,
+ XSCOM_INVALID_DATA_BUFFER = XSCOM_COMP_ID | 0x02,
+ XSCOM_INVALID_OP_TYPE = XSCOM_COMP_ID | 0x03,
+ };
+};
+
+#endif
diff --git a/src/makefile b/src/makefile
index f3bb5dfe8..351caa289 100644
--- a/src/makefile
+++ b/src/makefile
@@ -15,10 +15,11 @@ DIRECT_BOOT_OBJECTS = start.o kernel.o taskmgr.o cpumgr.o syscall.o \
RUNTIME_OBJECTS =
-BASE_MODULES = trace errl devicefw
+BASE_MODULES = trace errl devicefw scom xscom
DIRECT_BOOT_MODULES = example
RUNTIME_MODULES =
-TESTCASE_MODULES = cxxtest testerrl testdevicefw testsyslib
+TESTCASE_MODULES = cxxtest testerrl testdevicefw testsyslib \
+ testscom testxscom
RELOCATABLE_IMAGE_LDFLAGS = -pie --export-dynamic
diff --git a/src/usr/makefile b/src/usr/makefile
index 64c9dea42..c1a57cddb 100644
--- a/src/usr/makefile
+++ b/src/usr/makefile
@@ -1,6 +1,7 @@
ROOTPATH = ../..
OBJS = module_init.o
-SUBDIRS = example.d trace.d cxxtest.d testcore.d errl.d devicefw.d
+SUBDIRS = example.d trace.d cxxtest.d testcore.d errl.d devicefw.d \
+ scom.d xscom.d
include ${ROOTPATH}/config.mk
diff --git a/src/usr/scom/makefile b/src/usr/scom/makefile
new file mode 100644
index 000000000..777b4a2fd
--- /dev/null
+++ b/src/usr/scom/makefile
@@ -0,0 +1,8 @@
+ROOTPATH = ../../..
+MODULE = scom
+
+OBJS = scom.o
+
+SUBDIRS = test.d
+
+include ${ROOTPATH}/config.mk
diff --git a/src/usr/scom/scom.C b/src/usr/scom/scom.C
new file mode 100644
index 000000000..43357a85f
--- /dev/null
+++ b/src/usr/scom/scom.C
@@ -0,0 +1,46 @@
+/**
+ * @file scom.C
+ *
+ * @brief Implementation of SCOM operations
+ */
+
+/*****************************************************************************/
+// I n c l u d e s
+/*****************************************************************************/
+#include <devicefw/driverif.H>
+#include <trace/interface.H>
+#include <errl/errlentry.H>
+#include <errl/errlmanager.H>
+#include "scom.H"
+
+namespace SCOM
+{
+
+// Register SCom access functions to DD framework
+DEVICE_REGISTER_ROUTE(DeviceFW::WILDCARD,
+ DeviceFW::SCOM,
+ DeviceFW::PROCESSOR,
+ scomPerformOp);
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+errlHndl_t scomPerformOp(DeviceFW::OperationType i_opType,
+ DeviceFW::TargetHandle_t i_target,
+ void* io_buffer,
+ size_t& io_buflen,
+ int64_t i_accessType,
+ va_list i_args)
+{
+ errlHndl_t l_err = NULL;
+
+ //@todo - For now, just call XSCOM
+ l_err = deviceOp(i_opType,
+ i_target,
+ io_buffer,
+ io_buflen,
+ DEVICE_XSCOM_ADDRESS(va_arg(i_args,uint64_t)));
+
+ return l_err;
+}
+
+} // end namespace
diff --git a/src/usr/scom/scom.H b/src/usr/scom/scom.H
new file mode 100644
index 000000000..332883d00
--- /dev/null
+++ b/src/usr/scom/scom.H
@@ -0,0 +1,41 @@
+#ifndef __SCOM_H
+#define __SCOM_H
+
+/** @file scom.H
+ * @brief Provides the interfaces to perform a SCom
+ */
+
+namespace SCOM
+{
+
+/**
+ * @brief Performs an SCom operation
+ * This function performs an SCom Read/Write operation. It follows a
+ * pre-defined prototype functions in order to be registered with the
+ * device-driver framework.
+ *
+ * @param[in] i_opType Operation type, see DeviceFW::OperationType
+ * in driverif.H
+ * @param[in] i_target SCom target
+ * @param[in/out] io_buffer Read: pointer to output data storage
+ * Write: pointer to data to be written
+ * @param[in/out] io_buflen Input: size of io_buffer (in bytes)
+ * Output: Read: size of output data
+ * Write: size of data written
+ * @param[in] i_accessType Select from DeviceFW::AccessType enum
+ * (usrif.H)
+ * @param[in] i_args This is an argument list for DD framework.
+ * In this function, there's only one argument,
+ * which is the SCom address value.
+ *
+ * @return errlHndl_t
+ */
+errlHndl_t scomPerformOp(DeviceFW::OperationType i_opType,
+ DeviceFW::TargetHandle_t i_target,
+ void* io_buffer,
+ size_t& io_buflen,
+ int64_t i_accessType,
+ va_list i_args);
+}; // End namespace
+
+#endif
diff --git a/src/usr/scom/test/makefile b/src/usr/scom/test/makefile
new file mode 100644
index 000000000..298f91b6e
--- /dev/null
+++ b/src/usr/scom/test/makefile
@@ -0,0 +1,6 @@
+ROOTPATH = ../../../..
+
+MODULE = testscom
+TESTS = *.H
+
+include ${ROOTPATH}/config.mk
diff --git a/src/usr/scom/test/scomtest.H b/src/usr/scom/test/scomtest.H
new file mode 100644
index 000000000..6082db403
--- /dev/null
+++ b/src/usr/scom/test/scomtest.H
@@ -0,0 +1,30 @@
+#ifndef __SCOMTEST_H
+#define __SCOMTEST_H
+
+/**
+ * @file scomtest.H
+ *
+ * @brief Test case for SCOM code
+*/
+
+#include <cxxtest/TestSuite.H>
+#include <errl/errlmanager.H>
+#include <errl/errlentry.H>
+#include <errl/errltypes.H>
+#include <devicefw/userif.H>
+
+class ScomTest: public CxxTest::TestSuite
+{
+public:
+
+ /**
+ * @brief SCOM test #1
+ * TBD
+ */
+ void testScom1(void)
+ {
+ return;
+ }
+};
+
+#endif
diff --git a/src/usr/xscom/makefile b/src/usr/xscom/makefile
new file mode 100644
index 000000000..557920fdc
--- /dev/null
+++ b/src/usr/xscom/makefile
@@ -0,0 +1,8 @@
+ROOTPATH = ../../..
+MODULE = xscom
+
+OBJS = xscom.o
+
+SUBDIRS = test.d
+
+include ${ROOTPATH}/config.mk
diff --git a/src/usr/xscom/test/makefile b/src/usr/xscom/test/makefile
new file mode 100644
index 000000000..57e9ca832
--- /dev/null
+++ b/src/usr/xscom/test/makefile
@@ -0,0 +1,6 @@
+ROOTPATH = ../../../..
+
+MODULE = testxscom
+TESTS = *.H
+
+include ${ROOTPATH}/config.mk
diff --git a/src/usr/xscom/test/xscomtest.H b/src/usr/xscom/test/xscomtest.H
new file mode 100644
index 000000000..4351487e9
--- /dev/null
+++ b/src/usr/xscom/test/xscomtest.H
@@ -0,0 +1,113 @@
+#ifndef __XCOMTEST_H
+#define __XCOMTEST_H
+
+/**
+ * @file xscomtest.H
+ *
+ * @brief Test case for XSCOM code
+*/
+
+#include <cxxtest/TestSuite.H>
+#include <errl/errlmanager.H>
+#include <errl/errlentry.H>
+#include <errl/errltypes.H>
+#include <devicefw/userif.H>
+
+// Address and data to read/write
+struct testXscomAddrData
+{
+ uint32_t addr;
+ uint64_t data;
+};
+
+// Test table values
+//@todo - Select scratch register so chip doesn't get messed-up
+const testXscomAddrData g_xscomAddrTable[] =
+{
+ {0x08030007, 0x8000000000000001},
+ {0x08010587, 0x9000000000000003},
+
+};
+const uint32_t g_xscomAddrTableSz =
+ sizeof(g_xscomAddrTable)/sizeof(testXscomAddrData);
+
+
+class XscomTest: public CxxTest::TestSuite
+{
+public:
+
+ /**
+ * @brief XSCOM test #1
+ * Write value and read back to verify
+ */
+ void testXscom1(void)
+ {
+
+ //@todo - Replace printk with traces
+
+ DeviceFW::TargetHandle_t l_testTarget = 0; //@todo - Fix this
+ size_t l_size = sizeof(uint64_t);
+
+ // Loop thru table
+ for( uint32_t l_num=0; l_num < g_xscomAddrTableSz; l_num++)
+ {
+ testXscomAddrData l_testEntry = g_xscomAddrTable[l_num];
+
+ // Perform XSComOM read
+ uint64_t l_data = 0;
+ errlHndl_t l_err = deviceRead(l_testTarget,
+ &l_data,
+ l_size,
+ DEVICE_SCOM_ADDRESS(l_testEntry.addr));
+ if (l_err)
+ {
+ printk("\ntestXscom1: XSCom read: deviceRead() fails (1) !\n");
+ }
+ else
+ {
+ printk("\ntestXscom1: XSCom read (1) Address 0x%.8X, Data %llx\n\n\n",
+ l_testEntry.addr,
+ (long long unsigned)l_data);
+ }
+
+ // Perform an XSCom write
+ l_err = deviceWrite(l_testTarget,
+ &l_testEntry.data,
+ l_size,
+ DeviceFW::SCOM,
+ l_testEntry.addr);
+
+ if (l_err)
+ {
+ printk("\ntestXscom1: XSCom write: deviceWrite() fails!\n");
+ break;
+ }
+ else
+ {
+ printk("\ntestXscom1: XSCom write Address 0x%.8X, Data %llx\n",
+ l_testEntry.addr,
+ (long long unsigned)l_testEntry.data);
+ }
+
+ // Read back
+ l_data = 0;
+ l_err = deviceRead(l_testTarget,
+ &l_data,
+ l_size,
+ DEVICE_SCOM_ADDRESS(l_testEntry.addr));
+ if (l_err)
+ {
+ printk("\ntestXscom1: XSCom read: deviceRead() fails (2) !\n");
+ }
+ else
+ {
+ printk("\ntestXscom1: XSCom read (2) Address 0x%.8X, Data %llx\n\n\n",
+ l_testEntry.addr,
+ (long long unsigned)l_data);
+ }
+ }
+ return;
+ }
+};
+
+#endif
diff --git a/src/usr/xscom/xscom.C b/src/usr/xscom/xscom.C
new file mode 100644
index 000000000..b07eb5747
--- /dev/null
+++ b/src/usr/xscom/xscom.C
@@ -0,0 +1,309 @@
+/**
+ * @file xscom.C
+ *
+ * @brief Implementation of SCOM operations
+ */
+
+/*****************************************************************************/
+// I n c l u d e s
+/*****************************************************************************/
+#include <sys/mmio.h>
+#include <sys/task.h>
+#include <sys/sync.h>
+#include <string.h>
+#include <devicefw/driverif.H>
+#include <trace/interface.H>
+#include <errl/errlentry.H>
+#include <errl/errlmanager.H>
+#include <xscom/xscomreasoncodes.H>
+#include "xscom.H"
+
+// Trace definition
+trace_desc_t* g_trac_xscom = NULL;
+TRAC_INIT(&g_trac_xscom, "XSCOM", 4096);
+
+namespace XSCOM
+{
+
+// Register XSCcom access functions to DD framework
+DEVICE_REGISTER_ROUTE(DeviceFW::WILDCARD,
+ DeviceFW::XSCOM,
+ DeviceFW::PROCESSOR,
+ xscomPerformOp);
+
+/**
+ * @brief Internal routine that reset XSCOM status bits
+ * of HMER register before an XSCOM operation
+ *
+ * @return None
+ */
+void resetHMERStatus()
+{
+
+ // mtspr on the HMER is an AND write.
+ // This is not set the bits value to 1s, it's clearing
+ // the xscom status bits while leaving the rest of the bits
+ // in the register alone.
+ HMER hmer(-1);
+
+ hmer.mXSComDone = 0;
+ hmer.mXSComFail = 0;
+ hmer.mXSComStatus = 0;
+ // This call always returns 0, no checking needed
+ mmio_hmer_write(hmer);
+ return;
+}
+
+/**
+ * @brief Internal routine that monitor XSCOM Fail and XSCOM Done
+ * status bits of HMER register
+ *
+ * @return None
+ */
+HMER waitForHMERStatus()
+{
+ HMER hmer;
+
+ do
+ {
+ hmer = mmio_hmer_read();
+ }
+ while(!hmer.mXSComFail && !hmer.mXSComDone);
+ return hmer;
+}
+
+
+/**
+ * @brief Internal routine that checks to see if retry is
+ * possible on an XSCOM error
+ *
+ * @return true if retry is possible; false otherwise.
+ */
+bool XSComRetry(const HMER i_hmer)
+{
+ bool l_retry = false;
+ switch (i_hmer.mXSComStatus)
+ {
+ // Should retry if parity or timeout error.
+ case HMER::XSCOM_PARITY_ERROR:
+ case HMER::XSCOM_TIMEOUT:
+ l_retry = true;
+ break;
+ default:
+ break;
+ }
+ return l_retry;
+}
+
+/**
+ * @brief Internal routine that verifies the validity of input parameters
+ * for an XSCOM access.
+ *
+ * @param[in] i_opType Operation type, see DeviceFW::OperationType
+ * in driverif.H
+ * @param[in] i_target XSCom target
+ * @param[in/out] i_buffer Read: Pointer to output data storage
+ * Write: Pointer to input data storage
+ * @param[in/out] i_buflen Input: size of io_buffer (in bytes)
+ * Output:
+ * Read: Size of output data
+ * Write: Size of data written
+ * @param[in] i_args This is an argument list for DD framework.
+ * In this function, there's only one argument,
+ * which is the MMIO XSCom address
+ * @return errlHndl_t
+ */
+errlHndl_t xscomOpSanityCheck(const DeviceFW::OperationType i_opType,
+ const DeviceFW::TargetHandle_t i_target,
+ const void* i_buffer,
+ const size_t& i_buflen,
+ const va_list i_args)
+{
+ errlHndl_t l_err = NULL;
+
+ do
+ {
+ // Verify data buffer
+ if ( (i_buflen < XSCOM_BUFFER_SIZE) ||
+ (i_buffer == NULL) )
+ {
+ /*@
+ * @errortype
+ * @moduleid XSCOM_SANITY_CHECK
+ * @reasoncode XSCOM_INVALID_DATA_BUFFER
+ * @userdata1 Buffer size
+ * @userdata2 XSCom address
+ * @devdesc XSCOM buffer size < 8 bytes or NULL data buffer
+ */
+ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ XSCOM_SANITY_CHECK,
+ XSCOM_INVALID_DATA_BUFFER,
+ i_buflen,
+ va_arg(i_args,uint64_t));
+ break;
+ }
+
+ // Verify OP type
+ if ( (i_opType != DeviceFW::READ) &&
+ (i_opType != DeviceFW::WRITE) )
+ {
+ /*@
+ * @errortype
+ * @moduleid XSCOM_SANITY_CHECK
+ * @reasoncode XSCOM_INVALID_OP_TYPE
+ * @userdata1 Operation type
+ * @userdata2 XSCom address
+ * @devdesc XSCOM invalid operation type
+ */
+ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ XSCOM_SANITY_CHECK,
+ XSCOM_INVALID_OP_TYPE,
+ i_opType,
+ va_arg(i_args,uint64_t));
+ break;
+ }
+
+
+ } while(0);
+
+ return l_err;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+errlHndl_t xscomPerformOp(DeviceFW::OperationType i_opType,
+ DeviceFW::TargetHandle_t i_target,
+ void* io_buffer,
+ size_t& io_buflen,
+ int64_t i_accessType,
+ va_list i_args)
+{
+ errlHndl_t l_err = NULL;
+ HMER l_hmer;
+ mutex_t* l_XSComMutex;
+
+ // Retry loop
+ bool l_retry = false;
+ uint8_t l_retryCtr = 0;
+ do
+ {
+ // XSCOM operation sanity check
+ l_err = xscomOpSanityCheck(i_opType, i_target, io_buffer,
+ io_buflen, i_args);
+ if (l_err)
+ {
+ break;
+ }
+
+ // Set to buffer len to 0 until successfully access
+ io_buflen = 0;
+
+ // Setup the address
+ // @todo: Hard code chipId and Base address for now
+ XSComChipId_t l_chipId = 0;
+ XSComBase_t l_XSComBaseAddr = 0x300000000000; // Node0,chip0, Simics map
+ XSComP8Address l_mmioAddr(va_arg(i_args,uint64_t), l_chipId,
+ l_XSComBaseAddr);
+
+ // Re-init l_retry for loop
+ l_retry = false;
+
+ // Pin this thread to current CPU
+ task_affinity_pin();
+
+ // Lock other XSCom in this same thread from running
+ l_XSComMutex = mmio_xscom_mutex();
+ mutex_lock(l_XSComMutex);
+
+ // Single XSCom read
+ // Keep MMIO reading until XSCOM successfully done or error
+ do
+ {
+ // Reset status
+ resetHMERStatus();
+
+ // Calculate MMIO addr
+ uint64_t l_page = l_mmioAddr.page();
+ uint64_t l_offset_64 = (l_mmioAddr.offset()/sizeof(uint64_t));
+ uint64_t* l_virtAddr = static_cast<uint64_t*>
+ (mmio_map(reinterpret_cast<void*>(l_page), 1));
+
+ // The dereferencing should handle Cache inhibited internally
+ // Use local variable and memcpy to avoid unaligned memory access
+ uint64_t l_data = 0;
+ if (i_opType == DeviceFW::READ)
+ {
+ l_data = *(l_virtAddr + l_offset_64);
+ memcpy(io_buffer, &l_data, sizeof(l_data));
+ }
+ else
+ {
+ memcpy(&l_data, io_buffer, sizeof(l_data));
+ *(l_virtAddr + l_offset_64) = l_data;
+ }
+
+ // @todo - Need to un-map for now
+ mmio_unmap(l_virtAddr, 1);
+
+ TRACFCOMP(g_trac_xscom, "xscomPerformOp: OpType 0x%.8X, Address %llx, Page %llx; Offset %llx; VirtAddr %llx; l_virtAddr+l_offset %llx",
+ i_opType, static_cast<uint64_t>(l_mmioAddr), l_page,
+ l_offset_64, l_virtAddr, l_virtAddr + l_offset_64);
+
+ // Check for error or done
+ l_hmer = waitForHMERStatus();
+
+ } while (l_hmer.mXSComStatus == HMER::XSCOM_BLOCKED); // Single read
+
+ // Unlock
+ mutex_unlock(l_XSComMutex);
+
+ // Done, un-pin
+ task_affinity_unpin();
+
+ // Handle error
+ if (l_hmer.mXSComStatus != HMER::XSCOM_GOOD)
+ {
+ /*@
+ * @errortype
+ * @moduleid XSCOM_PERFORM_OP
+ * @reasoncode XSCOM_STATUS_ERR
+ * @userdata1 HMER value
+ * @userdata2 XSCom address
+ * @devdesc XSCom access error
+ */
+ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ XSCOM_PERFORM_OP,
+ XSCOM_STATUS_ERR,
+ l_hmer,
+ l_mmioAddr);
+
+ // @todo - Collect more FFDC: HMER value, target ID, other registers?
+
+ // Retry
+ if (l_retryCtr <= MAX_XSCOM_RETRY)
+ {
+ l_retryCtr++;
+ // If retry is possible, commit error as informational.
+ l_retry = XSComRetry(l_hmer);
+ if (l_retry == true)
+ {
+ l_err->setSev(ERRORLOG::ERRL_SEV_INFORMATIONAL);
+ // Commit/delete error
+ errlCommit(l_err);
+ }
+ }
+ }
+ else
+ {
+ // No error, set output buffer size.
+ // Always 8 bytes for XSCOM, but we want to make it consistent
+ // with all other device drivers
+ io_buflen = XSCOM_BUFFER_SIZE;
+ }
+
+ } while (l_retry == true); // End retry loop
+
+ return l_err;
+}
+
+} // end namespace
diff --git a/src/usr/xscom/xscom.H b/src/usr/xscom/xscom.H
new file mode 100644
index 000000000..613ab2d01
--- /dev/null
+++ b/src/usr/xscom/xscom.H
@@ -0,0 +1,233 @@
+#ifndef __XSCOM_H
+#define __XSCOM_H
+
+/** @file xscom.H
+ * @brief Provides the interfaces to perform XSCom
+ */
+
+#include <stdint.h>
+#include <limits.h>
+
+/**
+ * @brief Max number of retries if XSCOM fails with certain errors
+ */
+#define MAX_XSCOM_RETRY 1
+
+/**
+ * @brief Type definition for XSCom address and Chip ID
+ */
+typedef uint32_t XSComAddress_t;
+typedef uint16_t XSComChipId_t;
+typedef uint64_t XSComBase_t;
+
+namespace XSCOM
+{
+
+#define XSCOM_BUFFER_SIZE 8 // 8 bytes
+
+/**
+ * @brief Performs an XSCom access operation
+ * This function performs an XSCom access operation. It follows a pre-defined
+ * prototype functions in order to be registered with the device-driver
+ * framework.
+ *
+ * @param[in] i_opType Operation type, see DeviceFW::OperationType
+ * in driverif.H
+ * @param[in] i_target XSCom target
+ * @param[in/out] io_buffer Read: Pointer to output data storage
+ * Write: Pointer to input data storage
+ * @param[in/out] io_buflen Input: size of io_buffer (in bytes)
+ * Output:
+ * Read: Size of output data
+ * Write: Size of data written
+ * @param[in] i_accessType DeviceFW::AccessType enum (usrif.H)
+ * @param[in] i_args This is an argument list for DD framework.
+ * In this function, there's only one argument,
+ * which is the MMIO XSCom address
+ * @return errlHndl_t
+ */
+errlHndl_t xscomPerformOp(DeviceFW::OperationType i_opType,
+ DeviceFW::TargetHandle_t i_target,
+ void* io_buffer,
+ size_t& io_buflen,
+ int64_t i_accessType,
+ va_list i_args);
+
+/**
+ * @brief Abstracts HMER register of a P8/Salerno chip
+ */
+class HMER
+{
+
+public:
+
+ /**
+ * @brief Constructor
+ */
+ ALWAYS_INLINE inline HMER()
+ {
+ mRegister = 0;
+ }
+
+ /**
+ * @brief Constructor that takes in a value
+ */
+ explicit ALWAYS_INLINE inline HMER(uint64_t val)
+ {
+ mRegister = val;
+ }
+
+ /**
+ * @brief Conversion operator
+ */
+ ALWAYS_INLINE inline operator uint64_t() const
+ {
+ return mRegister;
+ }
+
+ /**
+ * @brief Operator=
+ */
+ ALWAYS_INLINE inline uint64_t operator = (uint64_t val)
+ {
+ return mRegister = val;
+ }
+
+ /**
+ * @brief XSCom status values
+ */
+ enum XSComStatus
+ {
+ XSCOM_GOOD = 0,
+ XSCOM_BLOCKED = 1,
+ XSCOM_OFFLINE = 2,
+ XSCOM_PARTIAL = 3,
+ XSCOM_BAD_ADDRESS = 4,
+ XSCOM_CLOCK_ERROR = 5,
+ XSCOM_PARITY_ERROR = 6,
+ XSCOM_TIMEOUT= 7,
+ };
+
+ // Layout of HMER register parts
+ union
+ {
+ uint64_t mRegister;
+ struct
+ {
+ uint64_t :8;
+ uint64_t mXSComFail:1;
+ uint64_t mXSComDone:1;
+ uint64_t :11;
+ uint64_t mXSComStatus:3;
+ uint64_t :40;
+ };
+ };
+};
+
+/**
+ * @brief This class contains necessary information to build an XSCOM
+ * address for a P8/Salerno chip.
+ */
+class XSComP8Address
+{
+ public:
+ /**
+ * @brief Constructor of XSComP8Address class
+ *
+ * @param[in] i_addr PCB address of the register being accessed
+ *
+ * @param[in] i_chipId Chip number of the processor chip that
+ * holds the register being accessed.
+ *
+ * @param[in] i_mXSComBase Base address of XSCom address range.
+ *
+ * @return None
+ */
+ ALWAYS_INLINE inline XSComP8Address(const XSComAddress_t i_addr,
+ const XSComChipId_t i_chipId,
+ const XSComBase_t i_mXSComBase);
+
+ /**
+ * @brief Conversion operator
+ */
+ ALWAYS_INLINE inline operator uint64_t() const;
+
+ /**
+ * @brief Return the page-aligned value of the address
+ *
+ * @return uint64_t
+ */
+ ALWAYS_INLINE inline uint64_t page() const;
+
+ /**
+ * @brief Return the address' byte offset from the aligned page
+ *
+ * @return uint64_t
+ */
+ ALWAYS_INLINE inline uint64_t offset() const;
+
+ private:
+ /**
+ * @brief Disabled copy constructor and assignment operator
+ */
+ XSComP8Address(const XSComP8Address& i_right);
+ XSComP8Address& operator=(const XSComP8Address& right);
+
+ // Layout of XSCOM address parts
+ union
+ {
+ uint64_t mMmioAddress; // mMmio address
+ struct
+ {
+ uint64_t mReserved1:18; // Not currently used (0:17)
+ uint64_t mBaseAddress:5; // Base address (18:22)
+ uint64_t mChipId:6; // Targeted chip ID (23:28)
+ uint64_t mSComAddrHi:27; // PCB Address High (29:55)
+ uint64_t mCacheLine:1; // Cached line (56)
+ uint64_t mSComAddrLo:4; // PCB Address low (57:60)
+ uint64_t mAlign:3; // Align (61:63)
+ } mAddressParts;
+ };
+
+}; // End XSComP8Address class
+
+//-----------------------------------------------------------------------
+// In-line functions
+//-----------------------------------------------------------------------
+
+////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////
+XSComP8Address::XSComP8Address(const XSComAddress_t i_addr,
+ const XSComChipId_t i_chipId,
+ const XSComBase_t i_mXSComBase)
+:mMmioAddress(i_mXSComBase)
+{
+ mAddressParts.mChipId = i_chipId;
+ mAddressParts.mSComAddrHi = i_addr >> 4; // Get 27-bits
+ mAddressParts.mSComAddrLo = i_addr; // Get 4 bits
+}
+
+////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////
+XSComP8Address::operator uint64_t() const
+{
+ return mMmioAddress;
+}
+
+////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////
+uint64_t XSComP8Address::page() const
+{
+ return ((mMmioAddress/PAGE_SIZE) * PAGE_SIZE);
+}
+
+////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////
+uint64_t XSComP8Address::offset() const
+{
+ return (mMmioAddress % PAGE_SIZE);
+}
+
+};
+
+#endif
OpenPOWER on IntegriCloud