summaryrefslogtreecommitdiffstats
path: root/src/usr/scom
diff options
context:
space:
mode:
authorCorey Swenson <cswenson@us.ibm.com>2018-09-06 13:31:35 -0500
committerDaniel M. Crowell <dcrowell@us.ibm.com>2018-11-09 09:30:00 -0600
commit40039bb5fddf5efd1b01429ef011b68be999dce3 (patch)
treed509be93e473fc292bd51658b377954785d1117a /src/usr/scom
parentfffa79ecb0c701ee029eae8ffb33483701e4c117 (diff)
downloadtalos-hostboot-40039bb5fddf5efd1b01429ef011b68be999dce3.tar.gz
talos-hostboot-40039bb5fddf5efd1b01429ef011b68be999dce3.zip
Extend multicast workaround and add tests
- Add support for multicast OR op type - Add xscom and scom multicast tests - Avoid false fails by not setting multicast bit in bad address tests Change-Id: I32ea5b1b68a1a2f0d92c2b82b5ab1b932ddb54af RTC:198114 Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/65778 Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com> Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com> Tested-by: Jenkins OP HW <op-hw-jenkins+hostboot@us.ibm.com> Reviewed-by: Matt Derksen <mderkse1@us.ibm.com> Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com> Reviewed-by: Christian R. Geddes <crgeddes@us.ibm.com> Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Diffstat (limited to 'src/usr/scom')
-rw-r--r--src/usr/scom/scom.C257
-rw-r--r--src/usr/scom/test/scomtest.H26
2 files changed, 189 insertions, 94 deletions
diff --git a/src/usr/scom/scom.C b/src/usr/scom/scom.C
index 2dcf4a3c0..1a4ba857f 100644
--- a/src/usr/scom/scom.C
+++ b/src/usr/scom/scom.C
@@ -362,7 +362,7 @@ errlHndl_t checkIndirectAndDoScom(DeviceFW::OperationType i_opType,
SCOM_INVALID_FORM,
i_addr,
get_huid(i_target),
- true /*Add HB Software Callout*/);
+ ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
break;
}
@@ -786,7 +786,7 @@ errlHndl_t doForm1IndirectScom(DeviceFW::OperationType i_opType,
SCOM_FORM_1_READ_REQUEST,
i_addr,
i_opType,
- true /*Add HB SW Callout*/);
+ ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
break;
}
@@ -811,7 +811,7 @@ errlHndl_t doForm1IndirectScom(DeviceFW::OperationType i_opType,
SCOM_FORM_1_INVALID_DATA,
i_addr,
l_io_buffer,
- true /*Add HB SW Callout*/);
+ ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
break;
}
@@ -1269,12 +1269,16 @@ errlHndl_t doMulticastWorkaround( DeviceFW::OperationType i_opType,
errlHndl_t l_err = nullptr;
uint64_t* l_summaryReg = reinterpret_cast<uint64_t*>(io_buffer);
- constexpr uint64_t IS_MULTICAST = 0x40000000;
- constexpr uint64_t MULTICAST_GROUP = 0x07000000;
- constexpr uint64_t IS_PCBSLAVE = 0x000F0000;
- constexpr uint64_t CHIPLET_BYTE = 0xFF000000;
- constexpr uint64_t MULTICAST_OP = 0x38000000;
+ // Some masks for parsing the address
+ constexpr uint64_t IS_MULTICAST = 0x40000000;
+ constexpr uint64_t MULTICAST_GROUP = 0x07000000;
+ constexpr uint64_t GROUP_ZERO = 0x00000000;
+ constexpr uint64_t GROUP_ONE = 0x01000000;
+ constexpr uint64_t IS_PCBSLAVE = 0x000F0000;
+ constexpr uint64_t CHIPLET_BYTE = 0xFF000000;
+ constexpr uint64_t MULTICAST_OP = 0x38000000;
constexpr uint64_t MULTICAST_OP_BITWISE = 0x10000000;
+ constexpr uint64_t MULTICAST_OP_OR = 0x00000000;
#ifndef __HOSTBOOT_RUNTIME
// Some P9-specific chiplet values to make things more efficient
@@ -1286,108 +1290,177 @@ errlHndl_t doMulticastWorkaround( DeviceFW::OperationType i_opType,
constexpr uint64_t P9_LAST_EC = 0x3F;
#endif
- // Skip calls to the SENTINEL since we don't have the
- // ability to find its children
- if( TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL
- == i_target )
- {
- o_didWorkaround = false;
- return nullptr;
- }
+ o_didWorkaround = false;
- // Only perform this workaround for:
- // - reads
- // - multicast registers
- // - scom is not part of pcb slave
- // - multicast read option XXX 'bit-wise'
- // - multicast group0 'all functional chiplets'
- if( !((DeviceFW::READ == i_opType)
- && ((IS_MULTICAST & i_addr) == IS_MULTICAST)
- && ((IS_PCBSLAVE & i_addr) != IS_PCBSLAVE)
- && ((MULTICAST_OP & i_addr) == MULTICAST_OP_BITWISE)
- && ((MULTICAST_GROUP & i_addr) == 0)) )
+ do
{
- o_didWorkaround = false;
- return nullptr;
- }
- TRACFCOMP( g_trac_scom, "doMulticastWorkaround on %.8X for %.8X", TARGETING::get_huid(i_target), i_addr );
- // Loop around every functional pervasive target
- TARGETING::TargetHandleList l_chiplets;
- TARGETING::getChildChiplets( l_chiplets,
- i_target,
- TARGETING::TYPE_PERV,
- true );
- for( auto l_chiplet : l_chiplets )
- {
- uint64_t l_data = 0;
- uint64_t l_addr = (i_addr & ~CHIPLET_BYTE);
- uint64_t l_unit = l_chiplet->getAttr<TARGETING::ATTR_CHIP_UNIT>();
+ // Skip calls to the SENTINEL since we don't have the
+ // ability to find its children
+ if( TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL == i_target )
+ {
+ break;
+ }
-#ifndef __HOSTBOOT_RUNTIME
- // filter out some chiplets that aren't running yet
- if( !g_useSlaveCores
- && (((l_unit >= P9_FIRST_EQ) && (l_unit <= P9_LAST_EQ))
- || ((l_unit >= P9_FIRST_EC) && (l_unit <= P9_LAST_EC))
- )
- )
+ bool l_opIsBitwise = false;
+ bool l_opIsOr = false;
+ bool l_groupIsZero = false;
+ bool l_groupIsOne = false;
+
+ // Only perform this workaround for:
+ // - reads
+ // - multicast registers
+ // - scom is not part of pcb slave
+ if( (DeviceFW::READ == i_opType)
+ && ((IS_MULTICAST & i_addr) == IS_MULTICAST)
+ && ((IS_PCBSLAVE & i_addr) != IS_PCBSLAVE) )
{
- // Only access the master ec/eq
- static const TARGETING::Target* l_masterCore =
- TARGETING::getMasterCore();
- uint64_t l_ecNum =
- l_masterCore->getAttr<TARGETING::ATTR_CHIP_UNIT>();
- bool l_fused = TARGETING::is_fused_mode();
- if( !((l_unit == l_ecNum) //master
- || (l_fused && (l_unit == l_ecNum+1))) ) //fused-pair
+ l_opIsBitwise = ((MULTICAST_OP & i_addr) == MULTICAST_OP_BITWISE);
+ l_opIsOr = ((MULTICAST_OP & i_addr) == MULTICAST_OP_OR);
+ l_groupIsZero = ((MULTICAST_GROUP & i_addr) == GROUP_ZERO);
+ l_groupIsOne = ((MULTICAST_GROUP & i_addr) == GROUP_ONE);
+
+ // - multicast read option XXX 'bit-wise'
+ // - multicast read option XXX 'or'
+ // - multicast group0 'all functional chiplets'
+ // - multicast group1 'all functional cores'
+ if( (l_opIsBitwise || l_opIsOr) &&
+ (l_groupIsZero || l_groupIsOne) )
{
- continue;
+ TRACFCOMP( g_trac_scom, "doMulticastWorkaround on %.8X for %.8X", TARGETING::get_huid(i_target), i_addr );
}
- auto l_eqNum = 0x10 + l_ecNum/4;
- if( l_unit == l_eqNum )
+ // Not a supported multicast op
+ else
{
- continue;
+ TRACFCOMP(g_trac_scom, "doMulticastWorkaround Multicast op has unsupported group 0x%X",(MULTICAST_OP & i_addr));
+
+ /*@
+ * @errortype
+ * @moduleid SCOM::SCOM_DO_MULTICAST_WORKAROUND
+ * @reasoncode SCOM::SCOM_UNSUPPORTED_MULTICAST_OP
+ * @userdata1 Address
+ * @userdata1 Target huid
+ * @devdesc Unsupported multicast op
+ */
+ l_err = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ SCOM_DO_MULTICAST_WORKAROUND,
+ SCOM_UNSUPPORTED_MULTICAST_OP,
+ i_addr,
+ get_huid(i_target),
+ ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
+
+ break;
}
}
- if( !g_useMemChiplets
- && ((l_unit >= P9_FIRST_MC) && (l_unit <= P9_LAST_MC)) )
+ // Common path when not a multicast op
+ else
{
- // Only access the mem chiplets if we're not in async mode
- // because we don't start clocks until later on in that case
- auto l_syncMode =
- i_target->getAttr<TARGETING::ATTR_MC_SYNC_MODE>();
- if( l_syncMode == TARGETING::MC_SYNC_MODE_NOT_IN_SYNC )
- {
- continue;
- }
+ break;
}
-#endif
- l_addr |= (l_unit << 24);
- io_buflen = sizeof(uint64_t);
- l_err = deviceOp(i_opType,
- i_target,
- &l_data,
- io_buflen,
- DEVICE_XSCOM_ADDRESS_NO_ERROR(l_addr));
- // just ignore any errors, we expect they will happen
- if( l_err )
+ TARGETING::TargetHandleList l_chiplets;
+ if( l_groupIsZero )
{
- delete l_err;
- l_err = nullptr;
+ // Get every functional pervasive target
+ TARGETING::getChildChiplets( l_chiplets,
+ i_target,
+ TARGETING::TYPE_PERV,
+ true );
}
- // if any bits are set, set this unit's bit in summary reg
- // note: this is good enough for the use-case we have now
- // but a better implementation would be to actually
- // check the select regs as well so we know which bit(s)
- // are the trigger
- else if( l_data & 0x8000000000000000 )
+ else if( l_groupIsOne )
{
- *l_summaryReg |= (0x8000000000000000 >> l_unit);
+ // Get every functional core target
+ TARGETING::getChildChiplets( l_chiplets,
+ i_target,
+ TARGETING::TYPE_CORE,
+ true );
}
- }
- o_didWorkaround = true;
+ // Loop through the chiplets, perform the xscom reads, combine results
+ for( auto l_chiplet : l_chiplets )
+ {
+ uint64_t l_data = 0;
+ uint64_t l_addr = (i_addr & ~CHIPLET_BYTE);
+ // Use CHIPLET_ID for unit, is equal to CHIP_UNIT for TYPE_PERV
+ uint64_t l_unit = l_chiplet->getAttr<TARGETING::ATTR_CHIPLET_ID>();
+
+#ifndef __HOSTBOOT_RUNTIME
+ // filter out some chiplets that aren't running yet
+ if( !g_useSlaveCores
+ && (((l_unit >= P9_FIRST_EQ) && (l_unit <= P9_LAST_EQ))
+ || ((l_unit >= P9_FIRST_EC) && (l_unit <= P9_LAST_EC))
+ )
+ )
+ {
+ // Only access the master ec/eq
+ static const TARGETING::Target* l_masterCore =
+ TARGETING::getMasterCore();
+ uint64_t l_ecNum =
+ l_masterCore->getAttr<TARGETING::ATTR_CHIP_UNIT>();
+ bool l_fused = TARGETING::is_fused_mode();
+ if( !((l_unit == l_ecNum) //master
+ || (l_fused && (l_unit == l_ecNum+1))) ) //fused-pair
+ {
+ continue;
+ }
+ auto l_eqNum = 0x10 + l_ecNum/4;
+ if( l_unit == l_eqNum )
+ {
+ continue;
+ }
+ }
+ if( !g_useMemChiplets
+ && ((l_unit >= P9_FIRST_MC) && (l_unit <= P9_LAST_MC)) )
+ {
+ // Only access the mem chiplets if we're not in async mode
+ // because we don't start clocks until later on in that case
+ auto l_syncMode =
+ i_target->getAttr<TARGETING::ATTR_MC_SYNC_MODE>();
+ if( l_syncMode == TARGETING::MC_SYNC_MODE_NOT_IN_SYNC )
+ {
+ continue;
+ }
+ }
+#endif
+
+ l_addr |= (l_unit << 24);
+ io_buflen = sizeof(uint64_t);
+ l_err = deviceOp(i_opType,
+ i_target,
+ &l_data,
+ io_buflen,
+ DEVICE_XSCOM_ADDRESS_NO_ERROR(l_addr));
+ // just ignore any errors, we expect they will happen
+ if( l_err )
+ {
+ delete l_err;
+ l_err = nullptr;
+ continue;
+ }
+
+ if( l_opIsBitwise )
+ {
+ // if any bits are set, set this unit's bit in summary reg
+ // note: this is good enough for the use-case we have now
+ // but a better implementation would be to actually
+ // check the select regs as well so we know which bit(s)
+ // are the trigger
+ if( l_data & 0x8000000000000000 )
+ {
+ *l_summaryReg |= (0x8000000000000000 >> l_unit);
+ }
+ }
+ else if( l_opIsOr )
+ {
+ *l_summaryReg |= l_data;
+ }
+ }
+
+ o_didWorkaround = true;
+
+ } while (0);
+
return l_err;
}
diff --git a/src/usr/scom/test/scomtest.H b/src/usr/scom/test/scomtest.H
index 6a64b37b5..6da3d9f9e 100644
--- a/src/usr/scom/test/scomtest.H
+++ b/src/usr/scom/test/scomtest.H
@@ -1621,9 +1621,19 @@ public:
TARGETING::Target* target;
uint64_t addr;
uint64_t data;
+ bool write;
+ bool read;
} test_data[] = {
- { scom_targets[PROC1], 0x02010803, 0x1234567887654321}, // addr: CXA FIR Mask Register
- { scom_targets[PROC1], 0x02011083, 0x1122334455667788}, // addr: PBI CQ FIR Mask Register
+ { scom_targets[PROC1], 0x02010803, 0x1234567887654321, 1, 1}, // addr: CXA FIR Mask Register
+ { scom_targets[PROC1], 0x02011083, 0x1122334455667788, 1, 1}, // addr: PBI CQ FIR Mask Register
+ { scom_targets[PROC1], 0x20010A89, 0x1000000000000000, 1, 0}, // addr: Scratch reg 3
+ { scom_targets[PROC1], 0x20110A89, 0x0200000000000000, 1, 0}, // addr: Scratch reg 3
+ { scom_targets[PROC1], 0x20210A89, 0x0030000000000000, 1, 0}, // addr: Scratch reg 3
+ { scom_targets[PROC1], 0x20310A89, 0x0004000000000000, 1, 0}, // addr: Scratch reg 3
+ { scom_targets[PROC1], 0x10040018, 0x1000000000000000, 1, 0}, // addr: Local checkstop chipletID 0x10
+ { scom_targets[PROC1], 0x20040018, 0x1000000000000000, 1, 0}, // addr: Local checkstop chipletID 0x20
+ { scom_targets[PROC1], 0x41010a89, 0x1234000000000000, 0, 1}, // addr: Scratch reg 3 multicast read (OR type)
+ { scom_targets[PROC1], 0x50040018, 0x0000800080000000, 0, 1}, // addr: Local checkstop multicast read (BITWISE type)
};
const uint64_t NUM_ADDRS = sizeof(test_data)/sizeof(test_data[0]);
@@ -1641,6 +1651,12 @@ public:
continue;
}
+ //only run if write is specified
+ if(test_data[x].write == false)
+ {
+ continue;
+ }
+
op_size = sizeof(uint64_t);
total++;
@@ -1667,6 +1683,12 @@ public:
continue;
}
+ //only run if read is specified
+ if(test_data[x].read == false)
+ {
+ continue;
+ }
+
op_size = sizeof(uint64_t);
total++;
OpenPOWER on IntegriCloud