summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorRick Ward <rward15@us.ibm.com>2018-10-03 13:22:01 -0500
committerChristian R. Geddes <crgeddes@us.ibm.com>2018-12-13 14:55:16 -0600
commit8923b2a9a3c9c477c646df3a4c66690a75ab8479 (patch)
tree4436a6b7fbbdae005ef5dce8eac97b25c837662a /src
parentf7cb4b2a4cf432f56d91c12e39e4dae41e8facdf (diff)
downloadtalos-hostboot-8923b2a9a3c9c477c646df3a4c66690a75ab8479.tar.gz
talos-hostboot-8923b2a9a3c9c477c646df3a4c66690a75ab8479.zip
Inband MMIO access to OCMB
This is an untested version of the new MMIO device driver that will give access to the OCMB. It will be tested once the Axone model IPLs in Simics. Change-Id: I4bc1d2f7306f1b238d1d65c24462ac4121266b11 RTC: 189447 RTC: 189220 Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/66941 Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com> Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com> Reviewed-by: Nicholas E. Bofferding <bofferdn@us.ibm.com> Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com> Reviewed-by: Matt Derksen <mderkse1@us.ibm.com> Tested-by: Jenkins OP HW <op-hw-jenkins+hostboot@us.ibm.com> Reviewed-by: Christian R. Geddes <crgeddes@us.ibm.com>
Diffstat (limited to 'src')
-rw-r--r--src/include/sys/mmio.h15
-rw-r--r--src/include/usr/hbotcompid.H7
-rw-r--r--src/include/usr/isteps/istep12list.H1
-rw-r--r--src/include/usr/mmio/mmio.H39
-rw-r--r--src/include/usr/mmio/mmio_reasoncodes.H57
-rw-r--r--src/kernel/machchk.C11
-rw-r--r--src/lib/string_utils.C2
-rw-r--r--src/usr/isteps/istep12/call_proc_dmi_scominit.C20
-rw-r--r--src/usr/mmio/makefile4
-rw-r--r--src/usr/mmio/mmio.C832
-rw-r--r--src/usr/mmio/mmio.H64
-rw-r--r--src/usr/mmio/test/makefile31
-rw-r--r--src/usr/mmio/test/mmiotest.H109
-rwxr-xr-xsrc/usr/targeting/common/xmltohb/attribute_types_hb.xml15
-rw-r--r--src/usr/targeting/common/xmltohb/simics_AXONE.system.xml83
-rw-r--r--src/usr/targeting/common/xmltohb/target_types_hb.xml8
16 files changed, 1253 insertions, 45 deletions
diff --git a/src/include/sys/mmio.h b/src/include/sys/mmio.h
index 75d923e41..e1dfdbf4d 100644
--- a/src/include/sys/mmio.h
+++ b/src/include/sys/mmio.h
@@ -152,11 +152,24 @@ static const uint64_t MMIO_IBSCOM_UE_DETECTED = 0x53434F4D4641494C;
/** Constants used to define IBSCOM MMIO address ranges
*/
-static const uint64_t MMIO_IBSCOM_BASE_MASK = 0x6030220000000;
+static const uint64_t MMIO_IBSCOM_BASE_MASK = 0x0006030220000000;
static const uint64_t MMIO_IBSCOM_DMI_MASK = 0x000000001FFFFFFF;
static const uint64_t MMIO_IBSCOM_CHIP_MASK = 0x00001C0000000000;
static const uint64_t MMIO_IBSCOM_GROUP_MASK = 0x0001700000000000;
+/** Constant used by kernel to signal to OCMB MMIO device driver
+ * that a UE was triggered during the OCMB MMIO Read operation
+ * Value is "OCMBFAIL" in ASCII.
+ */
+static const uint64_t MMIO_OCMB_UE_DETECTED = 0x4F434D424641494C;
+
+/** Constants used to define OCMB MMIO address ranges
+ * OCMB physical memory starts at 3TB + 16GB
+ * 64 OCMBs * 4GB per OCMB = 256GB
+*/
+static const uint64_t MMIO_OCMB_BASE_MASK = 0x0006030400000000; // 3TB + 16GB
+static const uint64_t MMIO_OCMB_BASE_RANGE = 0x00000070FFFFFFFF; // 256GB
+
#ifdef __cplusplus
}
#endif
diff --git a/src/include/usr/hbotcompid.H b/src/include/usr/hbotcompid.H
index 40739f2ba..c9987ac6d 100644
--- a/src/include/usr/hbotcompid.H
+++ b/src/include/usr/hbotcompid.H
@@ -453,6 +453,13 @@ const compId_t EXPSCOM_COMP_ID = 0x3600;
const char EXPSCOM_COMP_NAME[] = "expscom";
//@}
+/** @name MMIO
+ * Hostboot MMIO Interface
+ */
+//@{
+const compId_t MMIO_COMP_ID = 0x3700;
+const char MMIO_COMP_NAME[] = "mmio";
+
/** @name NVRAM
* NVRAM Support component
*/
diff --git a/src/include/usr/isteps/istep12list.H b/src/include/usr/isteps/istep12list.H
index 36927fb43..161c17732 100644
--- a/src/include/usr/isteps/istep12list.H
+++ b/src/include/usr/isteps/istep12list.H
@@ -290,6 +290,7 @@ const DepModInfo g_istep12Dependancies = {
DEP_LIB(libnestmemutils.so),
DEP_LIB(libisteps_io.so),
DEP_LIB(libisteps_mss.so),
+ DEP_LIB(libmmio.so),
NULL
}
};
diff --git a/src/include/usr/mmio/mmio.H b/src/include/usr/mmio/mmio.H
index e340e29e4..b0a9c522e 100644
--- a/src/include/usr/mmio/mmio.H
+++ b/src/include/usr/mmio/mmio.H
@@ -22,50 +22,23 @@
/* permissions and limitations under the License. */
/* */
/* IBM_PROLOG_END_TAG */
-#ifndef __MMIO_H
-#define __MMIO_H
+#ifndef __USR_MMIO_MMIO_H
+#define __USR_MMIO_MMIO_H
/** @file mmio.H
- * @brief Provides the interfaces to perform a MMIO operation
+ * @brief Provides the interface to initialize MMIO operations
* */
namespace MMIO
{
/**
* @brief Memory map OCMBs.
- * This function maps OCMB memory and registers into Hostboot virtual memory..
+ * This function maps OCMB memory and registers it into Hostboot virtual memory.
*
+ * @return nullptr on success, valid error log(errlHndl_t) if an error occurred
*/
-void mmioSetup();
+errlHndl_t mmioSetup();
-/**
- * @brief Complete the MMIO operation.
- * This function performs read or write operations on OCMBs by accessing
- * virtual memory that was previously memory mapped to the OCMBs.
- * It follows a pre-defined function prototype in order to be registered
- * with the device driver framework.
- *
- * @param[in] i_opType Operation type, see driverif.H
- * @param[in] i_target MMIO target
- * @param[in/out] io_buffer Read: Pointer to output data storage
- * Write: Pointer to input data storage
- * @param[in/out] io_buflen Input: Read: size of data to read (in bytes)
- * Write: Size of data to write
- * Output: Read: Size of output data
- * Write: Size of data written
- * @param[in] i_accessType Access type
- * @param[in] i_args This is an argument list for DD framework.
- * In this function, there are two arguments,
- * the offset (bytes) into the device, and the number
- * of bytes to read at a time (device limitation).
- * @return errlHndl_t
- */
-errlHndl_t mmioPerformOp(DeviceFW::OperationType i_opType,
- TARGETING::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/include/usr/mmio/mmio_reasoncodes.H b/src/include/usr/mmio/mmio_reasoncodes.H
new file mode 100644
index 000000000..7e2481934
--- /dev/null
+++ b/src/include/usr/mmio/mmio_reasoncodes.H
@@ -0,0 +1,57 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/include/usr/mmio/mmio_reasoncodes.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2011,2018 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __MMIO_REASONCODES_H
+#define __MMIO_REASONCODES_H
+
+#include <hbotcompid.H>
+
+namespace MMIO
+{
+ enum MMIOModuleId
+ {
+ MOD_MMIO_INVALID = 0x00,
+ MOD_MMIO_SETUP = 0x01,
+ MOD_MMIO_PERFORM_OP = 0x02,
+ MOD_MMIO_GET_PROC_SCOM = 0x03,
+ MOD_MMIO_SET_PROC_SCOM = 0x04,
+ };
+
+ enum MMIOReasonCode
+ {
+ RC_INVALID = MMIO_COMP_ID | 0x00,
+ RC_INVALID_SETUP = MMIO_COMP_ID | 0x01,
+ RC_INVALID_BUFFER = MMIO_COMP_ID | 0x02,
+ RC_INSUFFICIENT_BUFFER = MMIO_COMP_ID | 0x03,
+ RC_INCORRECT_BUFFER_LENGTH = MMIO_COMP_ID | 0x04,
+ RC_INVALID_OFFSET = MMIO_COMP_ID | 0x05,
+ RC_INVALID_OFFSET_ALIGNMENT = MMIO_COMP_ID | 0x06,
+ RC_INVALID_ACCESS_LIMIT = MMIO_COMP_ID | 0x07,
+ RC_BAD_MMIO_READ = MMIO_COMP_ID | 0x08,
+ RC_BAD_MMIO_WRITE = MMIO_COMP_ID | 0x09,
+ RC_PROC_NOT_FOUND = MMIO_COMP_ID | 0x0A,
+ };
+};
+
+#endif
diff --git a/src/kernel/machchk.C b/src/kernel/machchk.C
index 776ede0ce..d17c1ff90 100644
--- a/src/kernel/machchk.C
+++ b/src/kernel/machchk.C
@@ -102,11 +102,22 @@ bool handleLoadUE(task_t* t)
MMIO_IBSCOM_CHIP_MASK |
MMIO_IBSCOM_GROUP_MASK;
+ // Check if address is in OCMB MMIO Range.
+ // Base mask bits are always set for OCMB.
+ // ~Combined mask bits can not be set for OCMB.
+ uint64_t combOcmbMask = MMIO_OCMB_BASE_MASK |
+ MMIO_OCMB_BASE_RANGE;
+
if(((phys & MMIO_IBSCOM_BASE_MASK) == MMIO_IBSCOM_BASE_MASK) &&
((phys & ~combMask) == 0))
{
ueMagicValue = MMIO_IBSCOM_UE_DETECTED;
}
+ else if(((phys & MMIO_OCMB_BASE_MASK) == MMIO_OCMB_BASE_MASK) &&
+ ((phys & ~combOcmbMask) == 0))
+ {
+ ueMagicValue = MMIO_OCMB_UE_DETECTED;
+ }
else
{
printk("MachineCheck::handleUE: Unrecognized address %lx\n",
diff --git a/src/lib/string_utils.C b/src/lib/string_utils.C
index 6e7bcd804..8cb9c2066 100644
--- a/src/lib/string_utils.C
+++ b/src/lib/string_utils.C
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2016,2017 */
+/* Contributors Listed Below - COPYRIGHT 2016,2018 */
/* [+] International Business Machines Corp. */
/* */
/* */
diff --git a/src/usr/isteps/istep12/call_proc_dmi_scominit.C b/src/usr/isteps/istep12/call_proc_dmi_scominit.C
index e6fbadc7e..b875322b4 100644
--- a/src/usr/isteps/istep12/call_proc_dmi_scominit.C
+++ b/src/usr/isteps/istep12/call_proc_dmi_scominit.C
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2015,2017 */
+/* Contributors Listed Below - COPYRIGHT 2015,2018 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -46,6 +46,8 @@
// HWP
#include <p9_io_dmi_scominit.H>
+#include <mmio/mmio.H>
+
using namespace ISTEP;
using namespace ISTEP_ERROR;
using namespace ERRORLOG;
@@ -103,6 +105,22 @@ void* call_proc_dmi_scominit (void *io_pArgs)
}
+ // map OCMBs into Hostboot memory
+ l_err = MMIO::mmioSetup();
+ if ( l_err )
+ {
+ TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
+ "ERROR 0x%.8X: call_proc_dmi_scominit, unable to"
+ " initialize MMIO!",
+ l_err->reasonCode() );
+
+ // Create IStep error log and cross reference to error that occurred
+ l_StepError.addErrorDetails( l_err );
+
+ // Commit Error
+ errlCommit( l_err, ISTEP_COMP_ID );
+ }
+
TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "call_proc_dmi_scominit exit" );
// end task, returning any errorlogs to IStepDisp
diff --git a/src/usr/mmio/makefile b/src/usr/mmio/makefile
index 9b8d03ded..cea686f85 100644
--- a/src/usr/mmio/makefile
+++ b/src/usr/mmio/makefile
@@ -25,6 +25,10 @@
ROOTPATH = ../../..
MODULE = mmio
+EXTRAINCDIR += ${ROOTPATH}/src/import/chips/p9/common/include/
+EXTRAINCDIR += ${ROOTPATH}/src/import/hwpf/fapi2/include/
+EXTRAINCDIR += ${ROOTPATH}/src/include/usr/fapi2/
+
#include unique object modules
OBJS += mmio.o
diff --git a/src/usr/mmio/mmio.C b/src/usr/mmio/mmio.C
index 2b0849aa5..b6dcebbc2 100644
--- a/src/usr/mmio/mmio.C
+++ b/src/usr/mmio/mmio.C
@@ -31,31 +31,845 @@
#include <targeting/common/targetservice.H>
#include <arch/ppc.H>
+#include "mmio.H"
#include <mmio/mmio.H>
+#include <mmio/mmio_reasoncodes.H>
+
+#include <p9a_mc_scom_addresses.H>
+#include <p9a_mc_scom_addresses_fld.H>
+#include <error_info_defs.H>
+
+// Trace definition
+trace_desc_t* g_trac_mmio = NULL;
+TRAC_INIT(&g_trac_mmio, MMIO_COMP_NAME, 2*KILOBYTE, TRACE::BUFFER_SLOW);
namespace MMIO
{
-void mmioSetup()
+// Helper function declarations (definitions at the bottom of this file)
+static
+TARGETING::TargetHandle_t getParentProc(TARGETING::TargetHandle_t i_target);
+static
+errlHndl_t getProcScom(TARGETING::TargetHandle_t i_target,
+ uint64_t i_scomAddr,
+ uint64_t &o_scomData);
+static
+errlHndl_t setProcScom(TARGETING::TargetHandle_t i_target,
+ uint64_t i_scomAddr,
+ uint64_t i_scomData);
+static
+void *mmio_memcpy(void *vdest, const void *vsrc, size_t len);
+
+
+errlHndl_t mmioSetup()
{
+ errlHndl_t l_err = nullptr;
+
+ TRACDCOMP(g_trac_mmio, ENTER_MRK"mmioSetup");
+ // called from istep 12.3
+
+ do
+ {
+ // Get the base BAR address for an OCMB and use it to calculate the base
+ // BAR address for OCMB0 on PROC0 (beginning of reserved physical memory
+ // for all OCMBs).
+ // Each pair of OCMBs uses 8GB of interleaved memory,
+ // the second OCMB's memory starts 2GB after the first's.
+ TARGETING::TargetHandleList l_omiTargetList;
+
+ getAllChiplets(l_omiTargetList, TARGETING::TYPE_OMI);
+ if (l_omiTargetList.size() == 0)
+ {
+ TRACDCOMP(g_trac_mmio,
+ INFO_MRK"mmioSetup: Exiting, non-OMI system");
+ break;
+ }
+
+ auto l_omi = l_omiTargetList[0];
+ auto l_omiParentProc = getParentProc(l_omi);
+ if (l_omiParentProc == nullptr)
+ {
+ TRACFCOMP(g_trac_mmio, ERR_MRK
+ "mmioSetup: Unable to find the parent processor for an"
+ " OMI(0x%X).",
+ l_omi->getAttr<TARGETING::ATTR_HUID>());
+ /*@
+ * @errortype
+ * @moduleid MMIO::MOD_MMIO_SETUP
+ * @reasoncode MMIO::RC_PROC_NOT_FOUND
+ * @userdata1 Target huid
+ * @userdata2 None
+ * @devdesc mmioSetup> Unable to find parent processor for OMI.
+ * @custdesc Unexpected memory subsystem firmware error.
+ */
+ l_err = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ MMIO::MOD_MMIO_SETUP,
+ MMIO::RC_PROC_NOT_FOUND,
+ l_omi->getAttr<TARGETING::ATTR_HUID>(),
+ 0,
+ ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
+
+ break;
+ }
+
+ // There's a 1:1 relationship between OMIs and OCMBs, so we can directly
+ // relate the OMI position and BAR base addr to its associated OCMB.
+
+ // Get the position of the random OCMB. (OCMBs 0-15 will be on proc0,
+ // 16-31 on proc1, etc)
+ auto l_ocmbPos = l_omi->getAttr<TARGETING::ATTR_CHIP_UNIT>();
+ l_ocmbPos += l_omiParentProc->getAttr<TARGETING::ATTR_POSITION>() *
+ fapi2::MAX_OMI_PER_PROC;
+
+ // Get the base BAR address of the OCMB.
+ auto l_ocmbBaseAddr =
+ l_omi->getAttr<TARGETING::ATTR_OMI_INBAND_BAR_BASE_ADDR_OFFSET>();
+
+ // Calculate the base BAR address of OCMB0 on PROC0 by subtracting 8GB
+ // for every pair of OCMBs beyond the first pair, and subtract an
+ // additional 2GB if the initial OCMB is the second in a pair.
+ l_ocmbBaseAddr -= ((l_ocmbPos / 2) * 8 * GIGABYTE) +
+ ((l_ocmbPos % 2) * 2 * GIGABYTE);
+
+ // map 8 OCMBs at a time, set MMIO_VM_ADDR on each OCMB
+ //
+ // loop through all the procs
+ // call mmio_dev_map() on OCMBs 0-7 and 8-15
+ // set VM_ADDR on each OCMB
+ // each pair of OCMBs has their memories interleaved with their
+ // 2GB config sections together and their 2GB mmio sections
+ // together, we will be setting VM_ADDR to point to the cfg
+ // section of each ocmb
+ // Example
+ // 0GB ocmb0 cfg
+ // 2GB ocmb1 cfg
+ // 4GB ocmb0 mmio
+ // 6GB ocmb1 mmio
+ TARGETING::TargetHandleList l_procTargetList;
+
+ getAllChips(l_procTargetList, TARGETING::TYPE_PROC);
+ for (auto & l_procTarget: l_procTargetList)
+ {
+ // map all 16 OCMBs, 8 OCMBs (32GB) at a time
+ uint64_t *l_virtAddr[2] = {nullptr};
+ uint32_t l_procNum =
+ l_procTarget->getAttr<TARGETING::ATTR_POSITION>();
+ uint64_t l_realAddr =
+ l_ocmbBaseAddr + (l_procNum * 2 * THIRTYTWO_GB);
+
+ l_virtAddr[0] = static_cast<uint64_t *>
+ (mmio_dev_map(reinterpret_cast<void *>(l_realAddr),
+ THIRTYTWO_GB));
+ l_realAddr += THIRTYTWO_GB;
+ l_virtAddr[1] = static_cast<uint64_t *>
+ (mmio_dev_map(reinterpret_cast<void *>(l_realAddr),
+ THIRTYTWO_GB));
+
+ // set VM_ADDR on each OCMB
+ TARGETING::TargetHandleList l_ocmbTargetList;
+ l_ocmbTargetList.clear();
+ getChildAffinityTargets(l_ocmbTargetList, l_procTarget,
+ TARGETING::CLASS_UNIT, TARGETING::TYPE_OCMB_CHIP);
+ for (auto & l_ocmbTarget: l_ocmbTargetList)
+ {
+ uint64_t l_ocmbVmAddr = 0;
+ uint32_t l_ocmbNum =
+ l_ocmbTarget->getAttr<TARGETING::ATTR_POSITION>();
+
+ // OCMBs 0-7 in first map, 8-15 in second map
+ l_ocmbVmAddr =
+ reinterpret_cast<uint64_t>(l_virtAddr[l_ocmbNum / 8]);
+
+ // Each pair of OCMBs uses 8GB of interleaved memory,
+ // the second OCMB's memory starts 2GB after the first's
+ l_ocmbVmAddr += ((l_ocmbNum / 2) * 8 * GIGABYTE) +
+ ((l_ocmbNum % 2) * 2 * GIGABYTE);
+
+ l_ocmbTarget->
+ setAttr<TARGETING::ATTR_MMIO_VM_ADDR>(l_ocmbVmAddr);
+ }
+ }
+ } while(0);
+
+ TRACDCOMP(g_trac_mmio, EXIT_MRK"mmioSetup");
+
+ return l_err;
}
// Direct OCMB reads and writes to the device's memory mapped memory.
DEVICE_REGISTER_ROUTE(DeviceFW::WILDCARD,
DeviceFW::MMIO,
TARGETING::TYPE_OCMB_CHIP,
- mmioPerformOp);
-
-errlHndl_t mmioPerformOp(DeviceFW::OperationType i_opType,
- TARGETING::TargetHandle_t i_target,
- void* io_buffer,
- size_t& io_buflen,
- int64_t i_accessType,
- va_list i_args)
+ ocmbMmioPerformOp);
+
+errlHndl_t ocmbMmioPerformOp(DeviceFW::OperationType i_opType,
+ TARGETING::TargetHandle_t i_target,
+ void* io_buffer,
+ size_t& io_buflen,
+ int64_t i_accessType,
+ va_list i_args)
{
errlHndl_t l_err = nullptr;
+ uint64_t l_offset = va_arg(i_args, uint64_t);
+ uint64_t l_accessLimit = va_arg(i_args, uint64_t);
+
+ TRACDCOMP(g_trac_mmio, ENTER_MRK"ocmbMmioPerformOp");
+ TRACDCOMP(g_trac_mmio, INFO_MRK"op=%d, target=0x%.8X",
+ i_opType, i_target);
+ TRACDCOMP(g_trac_mmio, INFO_MRK"buffer=%p, length=%d, accessType=%ld",
+ io_buffer, io_buflen, i_accessType);
+ TRACDCOMP(g_trac_mmio, INFO_MRK"offset=0x%lX, accessLimit=%ld",
+ l_offset, l_accessLimit);
+
+ do
+ {
+ uint64_t l_addr = i_target->getAttr<TARGETING::ATTR_MMIO_VM_ADDR>();
+
+ if (l_addr == 0)
+ {
+ TRACFCOMP(g_trac_mmio, ERR_MRK
+ "ocmbMmioPerformOp: MMIO has not been initialized!");
+
+ /*@
+ * @errortype
+ * @moduleid MMIO::MOD_MMIO_PERFORM_OP
+ * @reasoncode MMIO::RC_INVALID_SETUP
+ * @userdata1[0:31] Target huid
+ * @userdata1[32:63] Data Offset, if >= 4GB then subtract 2GB
+ * (allows offsets to fit in 32 bits)
+ * @userdata2[0:0] Operation Type
+ * @userdata2[28:31] Access Limit
+ * @userdata2[32:63] Buffer Length
+ * @devdesc mmioPerformOp> A MMIO operation was attempted
+ * before MMIO was initialized.
+ * @custdesc Unexpected memory subsystem firmware error.
+ */
+ l_err = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ MMIO::MOD_MMIO_PERFORM_OP,
+ MMIO::RC_INVALID_SETUP,
+ TWO_UINT32_TO_UINT64(
+ i_target->getAttr<TARGETING::ATTR_HUID>(),
+ (l_offset < (4 * GIGABYTE)) ?
+ (l_offset) :
+ (l_offset - (2 * GIGABYTE))),
+ TWO_UINT32_TO_UINT64(
+ (i_opType << 31) | l_accessLimit,
+ io_buflen),
+ ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
+
+ break;
+ }
+
+ if (io_buffer == nullptr)
+ {
+ TRACFCOMP(g_trac_mmio, ERR_MRK
+ "ocmbMmioPerformOp: buffer is invalid!");
+
+ /*@
+ * @errortype
+ * @moduleid MMIO::MOD_MMIO_PERFORM_OP
+ * @reasoncode MMIO::RC_INVALID_BUFFER
+ * @userdata1[0:31] Target huid
+ * @userdata1[32:63] Data Offset, if >= 4GB then subtract 2GB
+ * (allows offsets to fit in 32 bits)
+ * @userdata2[0:0] Operation Type
+ * @userdata2[28:31] Access Limit
+ * @userdata2[32:63] Buffer Length
+ * @devdesc mmioPerformOp> Invalid data buffer for a MMIO
+ * operation.
+ * @custdesc Unexpected memory subsystem firmware error.
+ */
+ l_err = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ MMIO::MOD_MMIO_PERFORM_OP,
+ MMIO::RC_INVALID_BUFFER,
+ TWO_UINT32_TO_UINT64(
+ i_target->getAttr<TARGETING::ATTR_HUID>(),
+ (l_offset < (4 * GIGABYTE)) ?
+ (l_offset) :
+ (l_offset - (2 * GIGABYTE))),
+ TWO_UINT32_TO_UINT64(
+ (i_opType << 31) | l_accessLimit,
+ io_buflen),
+ ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
+
+ break;
+ }
+
+ switch (l_accessLimit) {
+ case 0:
+ l_accessLimit = io_buflen; // no access size restriction
+ case 4:
+ case 8:
+ break; // expected values
+ default:
+ TRACFCOMP(g_trac_mmio, ERR_MRK
+ "ocmbMmioPerformOp: accessLimit(%ld) should be 0, 4 or 8!!!",
+ l_accessLimit);
+
+ /*@
+ * @errortype
+ * @moduleid MMIO::MOD_MMIO_PERFORM_OP
+ * @reasoncode MMIO::RC_INVALID_ACCESS_LIMIT
+ * @userdata1[0:31] Target huid
+ * @userdata1[32:63] Data Offset, if >= 4GB then subtract 2GB
+ * (allows offsets to fit in 32 bits)
+ * @userdata2[0:0] Operation Type
+ * @userdata2[28:31] Access Limit
+ * @userdata2[32:63] Buffer Length
+ * @devdesc mmioPerformOp> Specified access limit was
+ * invalid for a MMIO operation.
+ * @custdesc Unexpected memory subsystem firmware error.
+ */
+ l_err = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ MMIO::MOD_MMIO_PERFORM_OP,
+ MMIO::RC_INVALID_ACCESS_LIMIT,
+ TWO_UINT32_TO_UINT64(
+ i_target->getAttr<TARGETING::ATTR_HUID>(),
+ (l_offset < (4 * GIGABYTE)) ?
+ (l_offset) :
+ (l_offset - (2 * GIGABYTE))),
+ TWO_UINT32_TO_UINT64(
+ (i_opType << 31) | l_accessLimit,
+ io_buflen),
+ ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
+ break;
+ }
+
+ if (l_err)
+ {
+ break;
+ }
+
+ if (io_buflen < l_accessLimit)
+ {
+ TRACFCOMP(g_trac_mmio, ERR_MRK
+ "ocmbMmioPerformOp: buffer is too small for the"
+ " request, buflen=%d, accessLimit=%ld",
+ io_buflen, l_accessLimit);
+
+ /*@
+ * @errortype
+ * @moduleid MMIO::MOD_MMIO_PERFORM_OP
+ * @reasoncode MMIO::RC_INSUFFICIENT_BUFFER
+ * @userdata1[0:31] Target huid
+ * @userdata1[32:63] Data Offset, if >= 4GB then subtract 2GB
+ * (allows offsets to fit in 32 bits)
+ * @userdata2[0:0] Operation Type
+ * @userdata2[28:31] Access Limit
+ * @userdata2[32:63] Buffer Length
+ * @devdesc mmioPerformOp> Data buffer too small for a
+ * MMIO operation.
+ * @custdesc Unexpected memory subsystem firmware error.
+ */
+ l_err = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ MMIO::MOD_MMIO_PERFORM_OP,
+ MMIO::RC_INSUFFICIENT_BUFFER,
+ TWO_UINT32_TO_UINT64(
+ i_target->getAttr<TARGETING::ATTR_HUID>(),
+ (l_offset < (4 * GIGABYTE)) ?
+ (l_offset) :
+ (l_offset - (2 * GIGABYTE))),
+ TWO_UINT32_TO_UINT64(
+ (i_opType << 31) | l_accessLimit,
+ io_buflen),
+ ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
+
+ break;
+ }
+
+ if (io_buflen % l_accessLimit)
+ {
+ TRACFCOMP(g_trac_mmio, ERR_MRK
+ "ocmbMmioPerformOp: buffer length must be a"
+ " multiple of the access limit,"
+ " buflen=%d, accessLimit=%ld",
+ io_buflen, l_accessLimit);
+
+ /*@
+ * @errortype
+ * @moduleid MMIO::MOD_MMIO_PERFORM_OP
+ * @reasoncode MMIO::RC_INCORRECT_BUFFER_LENGTH
+ * @userdata1[0:31] Target huid
+ * @userdata1[32:63] Data Offset, if >= 4GB then subtract 2GB
+ * (allows offsets to fit in 32 bits)
+ * @userdata2[0:0] Operation Type
+ * @userdata2[28:31] Access Limit
+ * @userdata2[32:63] Buffer Length
+ * @devdesc mmioPerformOp> Buffer length not a multiple
+ * of access limit.
+ * @custdesc Unexpected memory subsystem firmware error.
+ */
+ l_err = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ MMIO::MOD_MMIO_PERFORM_OP,
+ MMIO::RC_INCORRECT_BUFFER_LENGTH,
+ TWO_UINT32_TO_UINT64(
+ i_target->getAttr<TARGETING::ATTR_HUID>(),
+ (l_offset < (4 * GIGABYTE)) ?
+ (l_offset) :
+ (l_offset - (2 * GIGABYTE))),
+ TWO_UINT32_TO_UINT64(
+ (i_opType << 31) | l_accessLimit,
+ io_buflen),
+ ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
+
+ break;
+ }
+
+ if (!(((l_offset >= 0) && (l_offset < (2 * GIGABYTE))) ||
+ ((l_offset >= (4 * GIGABYTE)) && (l_offset < (6 * GIGABYTE)))))
+ {
+ TRACFCOMP(g_trac_mmio, ERR_MRK
+ "ocmbMmioPerformOp: offset(0x%lX) must be"
+ " either 0-2G or 4G-6G!",
+ l_offset);
+
+ /*@
+ * @errortype
+ * @moduleid MMIO::MOD_MMIO_PERFORM_OP
+ * @reasoncode MMIO::RC_INVALID_OFFSET
+ * @userdata1[0:31] Target huid
+ * @userdata1[32:63] Data Offset, if >= 4GB then subtract 2GB
+ * (allows offsets to fit in 32 bits)
+ * @userdata2[0:0] Operation Type
+ * @userdata2[28:31] Access Limit
+ * @userdata2[32:63] Buffer Length
+ * @devdesc mmioPerformOp> Invalid offset, requested
+ * address was out of range for a MMIO operation.
+ * @custdesc Unexpected memory subsystem firmware error.
+ */
+ l_err = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ MMIO::MOD_MMIO_PERFORM_OP,
+ MMIO::RC_INVALID_OFFSET,
+ TWO_UINT32_TO_UINT64(
+ i_target->getAttr<TARGETING::ATTR_HUID>(),
+ (l_offset < (4 * GIGABYTE)) ?
+ (l_offset) :
+ (l_offset - (2 * GIGABYTE))),
+ TWO_UINT32_TO_UINT64(
+ (i_opType << 31) | l_accessLimit,
+ io_buflen),
+ ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
+
+ break;
+ }
+
+ if ( ((l_accessLimit == 4) || (l_accessLimit == 8)) &&
+ ((l_offset % l_accessLimit) != 0) )
+ {
+ TRACFCOMP(g_trac_mmio, ERR_MRK
+ "ocmbMmioPerformOp: offset must be aligned with access limit,"
+ " offset=0x%lX, accessLimit=%ld",
+ l_offset, l_accessLimit);
+
+ /*@
+ * @errortype
+ * @moduleid MMIO::MOD_MMIO_PERFORM_OP
+ * @reasoncode MMIO::RC_INVALID_OFFSET_ALIGNMENT
+ * @userdata1[0:31] Target huid
+ * @userdata1[32:63] Data Offset, if >= 4GB then subtract 2GB
+ * (allows offsets to fit in 32 bits)
+ * @userdata2[0:0] Operation Type
+ * @userdata2[28:31] Access Limit
+ * @userdata2[32:63] Buffer Length
+ * @devdesc mmioPerformOp> Requested MMIO address was not
+ * aligned properly for the associated device.
+ * @custdesc Unexpected memory subsystem firmware error.
+ */
+ l_err = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ MMIO::MOD_MMIO_PERFORM_OP,
+ MMIO::RC_INVALID_OFFSET_ALIGNMENT,
+ TWO_UINT32_TO_UINT64(
+ i_target->getAttr<TARGETING::ATTR_HUID>(),
+ (l_offset < (4 * GIGABYTE)) ?
+ (l_offset) :
+ (l_offset - (2 * GIGABYTE))),
+ TWO_UINT32_TO_UINT64(
+ (i_opType << 31) | l_accessLimit,
+ io_buflen),
+ ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
+
+ break;
+ }
+
+ // TODO RTC 201493 - Remove these consts once HW group has defined them.
+ static const uint8_t P9A_MC_DSTLFIR_SUBCHANNEL_A_FAIL_ACTION = 20;
+ static const uint8_t P9A_MC_DSTLFIR_SUBCHANNEL_B_FAIL_ACTION = 21;
+
+ // read or write io_buflen bytes, l_accessLimit bytes at a time
+ uint8_t *mm_ptr = reinterpret_cast<uint8_t *>(l_addr + l_offset);
+ uint8_t *io_ptr = reinterpret_cast<uint8_t *>(io_buffer);
+ size_t bytes_read_or_written = 0;
+ for (size_t i = 0;i < io_buflen;i += l_accessLimit)
+ {
+ if (i_opType == DeviceFW::READ)
+ {
+ mmio_memcpy(io_ptr + i, mm_ptr + i, l_accessLimit);
+ eieio();
+ if (!memcmp(io_ptr + i,
+ &MMIO_OCMB_UE_DETECTED,
+ sizeof(MMIO_OCMB_UE_DETECTED)))
+ {
+ uint64_t scom_data = 0;
+ uint64_t scom_mask = 0;
+
+ TRACFCOMP(g_trac_mmio, ERR_MRK
+ "ocmbMmioPerformOp: unable to complete"
+ " MMIO read, SUE detected");
+
+ /*@
+ * @errortype
+ * @moduleid MMIO::MOD_MMIO_PERFORM_OP
+ * @reasoncode MMIO::RC_BAD_MMIO_READ
+ * @userdata1[0:31] Target huid
+ * @userdata1[32:63] Data Offset, if >= 4GB then subtract
+ * 2GB (allows offsets to fit in 32 bits)
+ * @userdata2[0:0] Operation Type
+ * @userdata2[28:31] Access Limit
+ * @userdata2[32:63] Buffer Length
+ * @devdesc mmioPerformOp> MMIO read of an OCMB
+ * failed.
+ * @custdesc Unexpected memory subsystem firmware
+ * error.
+ */
+ l_err = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ MMIO::MOD_MMIO_PERFORM_OP,
+ MMIO::RC_BAD_MMIO_READ,
+ TWO_UINT32_TO_UINT64(
+ i_target->getAttr<TARGETING::ATTR_HUID>(),
+ (l_offset < (4 * GIGABYTE)) ?
+ (l_offset) :
+ (l_offset - (2 * GIGABYTE))),
+ TWO_UINT32_TO_UINT64(
+ (i_opType << 31) | l_accessLimit,
+ io_buflen),
+ ERRORLOG::ErrlEntry::NO_SW_CALLOUT);
+ // add OCMB to error log
+ l_err->addHwCallout(i_target,
+ HWAS::SRCI_PRIORITY_HIGH,
+ HWAS::DECONFIG,
+ HWAS::GARD_NULL);
+ l_err->addProcedureCallout(HWAS::EPUB_PRC_HB_CODE,
+ HWAS::SRCI_PRIORITY_LOW);
+ const auto plid = l_err->plid();
+
+ auto l_err2 = getProcScom(i_target,
+ P9A_MCC_USTLFIR,
+ scom_data);
+ if (l_err2)
+ {
+ l_err2->plid(plid);
+ errlCommit(l_err2, MMIO_COMP_ID);
+ }
+ else
+ {
+ scom_mask = (1ull << P9A_MC_USTLFIR_CHANA_BAD_DATA) |
+ (1ull << P9A_MC_USTLFIR_CHANB_BAD_DATA);
+ if (scom_data & scom_mask)
+ {
+ // TODO RTC 201588 - Error checking on Explorer side
+ TRACFCOMP(g_trac_mmio, ERR_MRK
+ "ocmbMmioPerformOp: there was an error on"
+ " the Explorer side, P9A_MCC_USTLFIR=0x%lX",
+ scom_data);
+
+ // Clear FIR bits
+ scom_data &= ~scom_mask;
+ l_err2 = setProcScom(i_target,
+ P9A_MCC_USTLFIR,
+ scom_data);
+ if (l_err2)
+ {
+ l_err2->plid(plid);
+ errlCommit(l_err2, MMIO_COMP_ID);
+ }
+ }
+ }
+
+ l_err2 = getProcScom(i_target,
+ P9A_MCC_DSTLFIR,
+ scom_data);
+ if (l_err2)
+ {
+ l_err2->plid(plid);
+ errlCommit(l_err2, MMIO_COMP_ID);
+ }
+ else
+ {
+ scom_mask =
+ (1ull << P9A_MC_DSTLFIR_SUBCHANNEL_A_FAIL_ACTION) |
+ (1ull << P9A_MC_DSTLFIR_SUBCHANNEL_B_FAIL_ACTION);
+ if (scom_data & scom_mask)
+ {
+ // A channel checkstop has occurred.
+ // TODO RTC 201778 - Channel Fail Handling for
+ // Explorer
+ TRACFCOMP(g_trac_mmio, ERR_MRK
+ "ocmbMmioPerformOp: there was an error on"
+ " the Explorer channel, P9A_MCC_DSTLFIR=0x%lX",
+ scom_data);
+ }
+ }
+
+ break;
+ }
+ }
+ else if (i_opType == DeviceFW::WRITE)
+ {
+ mmio_memcpy(mm_ptr + i, io_ptr + i, l_accessLimit);
+ eieio();
+
+ // TODO RTC 201901 - find a better OCMB register to read, should
+ // be able to optimize error handling.
+
+ // do a read on the OCMB after writing to it, since writes and
+ // reads are sequential, the read won't complete until after the
+ // write.
+ uint64_t scom_addr = (4 * GIGABYTE) + 4; // RTC 201901
+ uint8_t l_ocmbReg[8] = {0};
+
+ mmio_memcpy(l_ocmbReg, mm_ptr + scom_addr, sizeof(l_ocmbReg));
+ eieio();
+ if (!memcmp(io_ptr + i,
+ &MMIO_OCMB_UE_DETECTED,
+ sizeof(MMIO_OCMB_UE_DETECTED)))
+ {
+ uint64_t scom_data = 0;
+ uint64_t scom_mask = 0;
+
+ TRACFCOMP(g_trac_mmio, ERR_MRK
+ "ocmbMmioPerformOp: unable to complete MMIO"
+ " write, SUE detected");
+
+ /*@
+ * @errortype
+ * @moduleid MMIO::MOD_MMIO_PERFORM_OP
+ * @reasoncode MMIO::RC_BAD_MMIO_WRITE
+ * @userdata1[0:31] Target huid
+ * @userdata1[32:63] Data Offset, if >= 4GB then subtract
+ * 2GB (allows offsets to fit in 32 bits)
+ * @userdata2[0:0] Operation Type
+ * @userdata2[28:31] Access Limit
+ * @userdata2[32:63] Buffer Length
+ * @devdesc mmioPerformOp> MMIO write of an OCMB
+ * failed.
+ * @custdesc Unexpected memory subsystem firmware
+ * error.
+ */
+ l_err = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ MMIO::MOD_MMIO_PERFORM_OP,
+ MMIO::RC_BAD_MMIO_WRITE,
+ TWO_UINT32_TO_UINT64(
+ i_target->getAttr<TARGETING::ATTR_HUID>(),
+ (l_offset < (4 * GIGABYTE)) ?
+ (l_offset) :
+ (l_offset - (2 * GIGABYTE))),
+ TWO_UINT32_TO_UINT64(
+ (i_opType << 31) | l_accessLimit,
+ io_buflen),
+ ERRORLOG::ErrlEntry::NO_SW_CALLOUT);
+ // add OCMB to error log
+ l_err->addHwCallout(i_target,
+ HWAS::SRCI_PRIORITY_HIGH,
+ HWAS::DECONFIG,
+ HWAS::GARD_NULL);
+ l_err->addProcedureCallout(HWAS::EPUB_PRC_HB_CODE,
+ HWAS::SRCI_PRIORITY_LOW);
+ const auto plid = l_err->plid();
+
+ auto l_err2 = getProcScom(i_target,
+ P9A_MCC_DSTLFIR,
+ scom_data);
+ if (l_err2)
+ {
+ l_err2->plid(plid);
+ errlCommit(l_err2, MMIO_COMP_ID);
+ }
+ else
+ {
+ scom_mask =
+ (1ull << P9A_MC_DSTLFIR_SUBCHANNEL_A_FAIL_ACTION) |
+ (1ull << P9A_MC_DSTLFIR_SUBCHANNEL_B_FAIL_ACTION);
+ if (scom_data & scom_mask)
+ {
+ // A channel checkstop has occurred.
+ // TODO RTC 201778 - Channel Fail Handling for
+ // Explorer
+ TRACFCOMP(g_trac_mmio, ERR_MRK
+ "ocmbMmioPerformOp: there was an error on"
+ " the Explorer channel, P9A_MCC_DSTLFIR=0x%lX",
+ scom_data);
+ }
+ }
+
+ break;
+ }
+ }
+
+ bytes_read_or_written += l_accessLimit;
+ }
+
+ io_buflen = bytes_read_or_written;
+ } while(0);
+
+ if (l_err)
+ {
+ l_err->collectTrace(MMIO_COMP_NAME);
+ }
+
+ TRACDCOMP(g_trac_mmio, EXIT_MRK"mmioPerformOp");
+
+ return l_err;
+}
+
+static
+TARGETING::TargetHandle_t getParentProc(TARGETING::TargetHandle_t i_target)
+{
+ TARGETING::TargetHandle_t proc = nullptr;
+ TARGETING::TargetHandleList list;
+ TARGETING::PredicateCTM pred(TARGETING::CLASS_CHIP,
+ TARGETING::TYPE_PROC);
+
+ TARGETING::TargetService().getAssociated(
+ list,
+ i_target,
+ TARGETING::TargetService::PARENT_BY_AFFINITY,
+ TARGETING::TargetService::ALL,
+ &pred);
+
+ if (list.size() == 1)
+ {
+ proc = list[0];
+ }
+
+ return proc;
+}
+
+static
+errlHndl_t getProcScom(TARGETING::TargetHandle_t i_target,
+ uint64_t i_scomAddr,
+ uint64_t &o_scomData)
+{
+ errlHndl_t l_err = nullptr;
+ auto proc = getParentProc(i_target);
+
+ if (proc == nullptr)
+ {
+ TRACFCOMP(g_trac_mmio, ERR_MRK
+ "getProcScom: Unable to find parent processor for target(0x%X)",
+ i_target->getAttr<TARGETING::ATTR_HUID>());
+
+ /*@
+ * @errortype
+ * @moduleid MMIO::MOD_MMIO_GET_PROC_SCOM
+ * @reasoncode MMIO::RC_PROC_NOT_FOUND
+ * @userdata1 Target huid
+ * @userdata2 SCOM address
+ * @devdesc getProcScom> Unable to find parent processor for target.
+ * @custdesc Unexpected memory subsystem firmware error.
+ */
+ l_err = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ MMIO::MOD_MMIO_GET_PROC_SCOM,
+ MMIO::RC_PROC_NOT_FOUND,
+ i_target->getAttr<TARGETING::ATTR_HUID>(),
+ i_scomAddr,
+ ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
+ }
+ else
+ {
+ auto reqSize = sizeof(o_scomData);
+
+ l_err = DeviceFW::deviceRead(proc,
+ &o_scomData,
+ reqSize,
+ DEVICE_SCOM_ADDRESS(i_scomAddr));
+ }
+
+ return l_err;
+}
+
+static
+errlHndl_t setProcScom(TARGETING::TargetHandle_t i_target,
+ uint64_t i_scomAddr,
+ uint64_t i_scomData)
+{
+ errlHndl_t l_err = nullptr;
+ auto proc = getParentProc(i_target);
+
+ if (proc == nullptr)
+ {
+ TRACFCOMP(g_trac_mmio, ERR_MRK
+ "setProcScom: Unable to find parent processor for target(0x%X)",
+ i_target->getAttr<TARGETING::ATTR_HUID>());
+
+ /*@
+ * @errortype
+ * @moduleid MMIO::MOD_MMIO_SET_PROC_SCOM
+ * @reasoncode MMIO::RC_PROC_NOT_FOUND
+ * @userdata1 Target huid
+ * @userdata2 SCOM address
+ * @devdesc setProcScom> Unable to find parent processor for target.
+ * @custdesc Unexpected memory subsystem firmware error.
+ */
+ l_err = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ MMIO::MOD_MMIO_SET_PROC_SCOM,
+ MMIO::RC_PROC_NOT_FOUND,
+ i_target->getAttr<TARGETING::ATTR_HUID>(),
+ i_scomAddr,
+ ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
+ }
+ else
+ {
+ auto reqSize = sizeof(i_scomData);
+
+ l_err = DeviceFW::deviceWrite(proc,
+ &i_scomData,
+ reqSize,
+ DEVICE_SCOM_ADDRESS(i_scomAddr));
+ }
return l_err;
}
+static
+void *mmio_memcpy(void *vdest, const void *vsrc, size_t len)
+{
+ assert((len % 4) == 0, "Length must be a multiple of 4!");
+ assert((reinterpret_cast<uintptr_t>(vdest) % 4) == 0,
+ "Destination must be 4 byte aligned!");
+
+ // Loop, copying 8 bytes every 5 instructions
+ long *ldest = reinterpret_cast<long *>(vdest);
+ const long *lsrc = reinterpret_cast<const long *>(vsrc);
+
+ while (len >= sizeof(long))
+ {
+ *ldest++ = *lsrc++;
+ len -= sizeof(long);
+ }
+
+ // Loop, copying 4 bytes every 5 instructions
+ int *idest = reinterpret_cast<int *>(ldest);
+ const int *isrc = reinterpret_cast<const int *>(lsrc);
+
+ while (len >= sizeof(int))
+ {
+ *idest++ = *isrc++;
+ len -= sizeof(int);
+ }
+
+ return vdest;
+}
+
}; // end namespace MMIO
diff --git a/src/usr/mmio/mmio.H b/src/usr/mmio/mmio.H
new file mode 100644
index 000000000..d69ade6f7
--- /dev/null
+++ b/src/usr/mmio/mmio.H
@@ -0,0 +1,64 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/mmio/mmio.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2018 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __MMIO_H
+#define __MMIO_H
+
+/** @file mmio.H
+ * @brief Provides interface to perform MMIO operations to Explorer chips
+ * */
+
+namespace MMIO
+{
+/**
+ * @brief Complete the MMIO operation.
+ * This function performs read or write operations on OCMBs by accessing
+ * virtual memory that was previously memory mapped to the OCMBs.
+ * It follows a pre-defined function prototype in order to be registered
+ * with the device driver framework.
+ *
+ * @param[in] i_opType Operation type, see driverif.H
+ * @param[in] i_target MMIO target
+ * @param[in/out] io_buffer Read: Pointer to output data storage
+ * Write: Pointer to input data storage
+ * @param[in/out] io_buflen Input: Read: size of data to read (in bytes)
+ * Write: Size of data to write
+ * Output: Read: Size of output data
+ * Write: Size of data written
+ * @param[in] i_accessType Access type
+ * @param[in] i_args This is an argument list for DD framework.
+ * In this function, there are two arguments,
+ * the offset (bytes) into the device, and the number
+ * of bytes to read at a time (device limitation).
+ * @return errlHndl_t
+ */
+errlHndl_t ocmbMmioPerformOp(DeviceFW::OperationType i_opType,
+ TARGETING::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/mmio/test/makefile b/src/usr/mmio/test/makefile
new file mode 100644
index 000000000..133f3ca44
--- /dev/null
+++ b/src/usr/mmio/test/makefile
@@ -0,0 +1,31 @@
+# IBM_PROLOG_BEGIN_TAG
+# This is an automatically generated prolog.
+#
+# $Source: src/usr/mmio/test/makefile $
+#
+# OpenPOWER HostBoot Project
+#
+# Contributors Listed Below - COPYRIGHT 2011,2018
+# [+] International Business Machines Corp.
+#
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+#
+# IBM_PROLOG_END_TAG
+ROOTPATH = ../../../..
+
+MODULE = testmmio
+TESTS = *.H
+
+
+include ${ROOTPATH}/config.mk
diff --git a/src/usr/mmio/test/mmiotest.H b/src/usr/mmio/test/mmiotest.H
new file mode 100644
index 000000000..f7abd7816
--- /dev/null
+++ b/src/usr/mmio/test/mmiotest.H
@@ -0,0 +1,109 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/mmio/test/mmiotest.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2011,2018 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#include <cxxtest/TestSuite.H>
+#include <errl/errlmanager.H>
+#include <errl/errlentry.H>
+#include <limits.h>
+#include <devicefw/driverif.H>
+#include <mmio/mmio.H>
+
+extern trace_desc_t* g_trac_mmio;
+
+class MmioTest : public CxxTest::TestSuite
+{
+ public:
+
+ /**
+ * @brief Test valid MMIO calls
+ */
+ void test_Valid(void)
+ {
+ TRACFCOMP( g_trac_mmio, "MmioTest::test_Valid> Start" );
+
+ uint64_t fails = 0;
+ uint64_t total = 0;
+ errlHndl_t l_err = nullptr;
+ uint64_t regdata = 0;
+ size_t op_size = sizeof(uint64_t);
+
+// TODO RTC 202533 - enable this test once the Axone model is IPLing
+// successfully in Simics.
+#if 0
+ // Get OCMB target, return if there is no OCMB
+ TARGETING::TargetHandle_t ocmb_target = nullptr;
+ TARGETING::TargetHandleList ocmb_target_list;
+ getAllChips(ocmb_target_list, TARGETING::TYPE_OCMB_CHIP);
+ if (ocmb_target_list.size() == 0)
+ {
+ TRACFCOMP(g_trac_fsiscom, "MmioTest::test_Valid> Target is NULL");
+ TS_INFO("MmioTest::test_Valid> Target is NULL");
+ return;
+ }
+ ocmb_target = ocmb_target_list[0];
+
+ // read
+ ++total;
+ l_err = MMIO::mmioPerformOp(
+ DeviceFW::READ,
+ ocmb_target,
+ &regdata,
+ op_size,
+ 0x0,
+ op_size);
+ if(l_err != nullptr)
+ {
+ TRACFCOMP(g_trac_mmio,
+ "MmioTest::test_Valid> Error for read, RC=0x%04X",
+ ERRL_GETRC_SAFE(l_err));
+ TS_FAIL("MmioTest::test_Valid> Error for read, RC=0x%04X",
+ ERRL_GETRC_SAFE(l_err));
+ ++fails;
+ errlCommit(l_err, MMIO_COMP_ID);
+ }
+
+ // write
+ ++total;
+ l_err = MMIO::mmioPerformOp(
+ DeviceFW::WRITE,
+ ocmb_target,
+ &regdata,
+ op_size,
+ 0x08,
+ op_size);
+ if(l_err != nullptr)
+ {
+ TRACFCOMP(g_trac_mmio,
+ "MmioTest::test_Valid> Error for write, RC=0x%04X",
+ ERRL_GETRC_SAFE(l_err));
+ TS_FAIL("MmioTest::test_Valid> Error for write, RC=0x%04X",
+ ERRL_GETRC_SAFE(l_err));
+ ++fails;
+ errlCommit(l_err, MMIO_COMP_ID);
+ }
+#endif
+
+ TRACFCOMP(g_trac_mmio, "Mmio::test_Valid> %d/%d fails", fails, total);
+ };
+};
diff --git a/src/usr/targeting/common/xmltohb/attribute_types_hb.xml b/src/usr/targeting/common/xmltohb/attribute_types_hb.xml
index bffa2e9cb..5af080a45 100755
--- a/src/usr/targeting/common/xmltohb/attribute_types_hb.xml
+++ b/src/usr/targeting/common/xmltohb/attribute_types_hb.xml
@@ -750,6 +750,21 @@
</attribute>
<attribute>
+ <id>MMIO_VM_ADDR</id>
+ <description>
+ Virtual memory address this device has been mapped to.
+ </description>
+ <simpleType>
+ <uint64_t>
+ <default>0</default>
+ </uint64_t>
+ </simpleType>
+ <persistency>volatile-zeroed</persistency>
+ <readable/>
+ <writeable/>
+ </attribute>
+
+ <attribute>
<id>MPIPL_HB_MDRT_COUNT</id>
<description>Actual MDRT count in Memory Preserving IPL mode.</description>
<simpleType>
diff --git a/src/usr/targeting/common/xmltohb/simics_AXONE.system.xml b/src/usr/targeting/common/xmltohb/simics_AXONE.system.xml
index 11145d5b6..19386b554 100644
--- a/src/usr/targeting/common/xmltohb/simics_AXONE.system.xml
+++ b/src/usr/targeting/common/xmltohb/simics_AXONE.system.xml
@@ -7373,6 +7373,14 @@
<id>TYPE</id>
<default>OMI</default>
</attribute>
+ <!-- TODO RTC 201493 - Need to remove these sets (all 16 of them) of
+ OMI_INBAND_BAR_BASE_ADDR_OFFSET once p9a_omi_setup_bars
+ is working -->
+ <attribute>
+ <id>OMI_INBAND_BAR_BASE_ADDR_OFFSET</id>
+ <!-- 3TB + 16GB -->
+ <default>0x30400000000</default>
+ </attribute>
</targetInstance>
<targetInstance>
@@ -7439,6 +7447,11 @@
<id>TYPE</id>
<default>OMI</default>
</attribute>
+ <attribute>
+ <id>OMI_INBAND_BAR_BASE_ADDR_OFFSET</id>
+ <!-- 3TB + 18GB -->
+ <default>0x30480000000</default>
+ </attribute>
</targetInstance>
<targetInstance>
@@ -7505,6 +7518,11 @@
<id>TYPE</id>
<default>OMI</default>
</attribute>
+ <attribute>
+ <id>OMI_INBAND_BAR_BASE_ADDR_OFFSET</id>
+ <!-- 3TB + 24GB -->
+ <default>0x30600000000</default>
+ </attribute>
</targetInstance>
<targetInstance>
@@ -7571,6 +7589,11 @@
<id>TYPE</id>
<default>OMI</default>
</attribute>
+ <attribute>
+ <id>OMI_INBAND_BAR_BASE_ADDR_OFFSET</id>
+ <!-- 3TB + 26GB -->
+ <default>0x30680000000</default>
+ </attribute>
</targetInstance>
<targetInstance>
@@ -7637,6 +7660,11 @@
<id>TYPE</id>
<default>OMI</default>
</attribute>
+ <attribute>
+ <id>OMI_INBAND_BAR_BASE_ADDR_OFFSET</id>
+ <!-- 3TB + 32GB -->
+ <default>0x30800000000</default>
+ </attribute>
</targetInstance>
<targetInstance>
@@ -7703,6 +7731,11 @@
<id>TYPE</id>
<default>OMI</default>
</attribute>
+ <attribute>
+ <id>OMI_INBAND_BAR_BASE_ADDR_OFFSET</id>
+ <!-- 3TB + 34GB -->
+ <default>0x30880000000</default>
+ </attribute>
</targetInstance>
<targetInstance>
@@ -7769,6 +7802,11 @@
<id>TYPE</id>
<default>OMI</default>
</attribute>
+ <attribute>
+ <id>OMI_INBAND_BAR_BASE_ADDR_OFFSET</id>
+ <!-- 3TB + 40GB -->
+ <default>0x30A00000000</default>
+ </attribute>
</targetInstance>
<targetInstance>
@@ -7835,6 +7873,11 @@
<id>TYPE</id>
<default>OMI</default>
</attribute>
+ <attribute>
+ <id>OMI_INBAND_BAR_BASE_ADDR_OFFSET</id>
+ <!-- 3TB + 42GB -->
+ <default>0x30A80000000</default>
+ </attribute>
</targetInstance>
<targetInstance>
@@ -7901,6 +7944,11 @@
<id>TYPE</id>
<default>OMI</default>
</attribute>
+ <attribute>
+ <id>OMI_INBAND_BAR_BASE_ADDR_OFFSET</id>
+ <!-- 3TB + 48GB -->
+ <default>0x30C00000000</default>
+ </attribute>
</targetInstance>
<targetInstance>
@@ -7967,6 +8015,11 @@
<id>TYPE</id>
<default>OMI</default>
</attribute>
+ <attribute>
+ <id>OMI_INBAND_BAR_BASE_ADDR_OFFSET</id>
+ <!-- 3TB + 50GB -->
+ <default>0x30C80000000</default>
+ </attribute>
</targetInstance>
<targetInstance>
@@ -8033,6 +8086,11 @@
<id>TYPE</id>
<default>OMI</default>
</attribute>
+ <attribute>
+ <id>OMI_INBAND_BAR_BASE_ADDR_OFFSET</id>
+ <!-- 3TB + 56GB -->
+ <default>0x30E00000000</default>
+ </attribute>
</targetInstance>
<targetInstance>
@@ -8099,6 +8157,11 @@
<id>TYPE</id>
<default>OMI</default>
</attribute>
+ <attribute>
+ <id>OMI_INBAND_BAR_BASE_ADDR_OFFSET</id>
+ <!-- 3TB + 58GB -->
+ <default>0x30E80000000</default>
+ </attribute>
</targetInstance>
<targetInstance>
@@ -8165,6 +8228,11 @@
<id>TYPE</id>
<default>OMI</default>
</attribute>
+ <attribute>
+ <id>OMI_INBAND_BAR_BASE_ADDR_OFFSET</id>
+ <!-- 3TB + 64GB -->
+ <default>0x31000000000</default>
+ </attribute>
</targetInstance>
<targetInstance>
@@ -8231,6 +8299,11 @@
<id>TYPE</id>
<default>OMI</default>
</attribute>
+ <attribute>
+ <id>OMI_INBAND_BAR_BASE_ADDR_OFFSET</id>
+ <!-- 3TB + 66GB -->
+ <default>0x31080000000</default>
+ </attribute>
</targetInstance>
<targetInstance>
@@ -8297,6 +8370,11 @@
<id>TYPE</id>
<default>OMI</default>
</attribute>
+ <attribute>
+ <id>OMI_INBAND_BAR_BASE_ADDR_OFFSET</id>
+ <!-- 3TB + 72GB -->
+ <default>0x31200000000</default>
+ </attribute>
</targetInstance>
<targetInstance>
@@ -8363,6 +8441,11 @@
<id>TYPE</id>
<default>OMI</default>
</attribute>
+ <attribute>
+ <id>OMI_INBAND_BAR_BASE_ADDR_OFFSET</id>
+ <!-- 3TB + 74GB -->
+ <default>0x31280000000</default>
+ </attribute>
</targetInstance>
<!-- ===================================================================== -->
diff --git a/src/usr/targeting/common/xmltohb/target_types_hb.xml b/src/usr/targeting/common/xmltohb/target_types_hb.xml
index eaf0ca0b6..c1217328d 100644
--- a/src/usr/targeting/common/xmltohb/target_types_hb.xml
+++ b/src/usr/targeting/common/xmltohb/target_types_hb.xml
@@ -85,6 +85,14 @@
</targetTypeExtension>
<targetTypeExtension>
+ <id>chip-ocmb</id>
+ <attribute>
+ <default>0</default>
+ <id>MMIO_VM_ADDR</id>
+ </attribute>
+ </targetTypeExtension>
+
+ <targetTypeExtension>
<id>chip-processor</id>
<attribute>
<id>ASSUME_SBE_QUIESCED</id>
OpenPOWER on IntegriCloud