diff options
-rw-r--r-- | src/include/usr/scom/scomreasoncodes.H | 2 | ||||
-rw-r--r-- | src/include/usr/xscom/xscomreasoncodes.H | 5 | ||||
-rw-r--r-- | src/usr/fapi2/test/p9_hwtests.C | 8 | ||||
-rw-r--r-- | src/usr/scom/scom.C | 257 | ||||
-rw-r--r-- | src/usr/scom/test/scomtest.H | 26 | ||||
-rw-r--r-- | src/usr/xscom/test/xscomtest.H | 151 |
6 files changed, 346 insertions, 103 deletions
diff --git a/src/include/usr/scom/scomreasoncodes.H b/src/include/usr/scom/scomreasoncodes.H index 5c39abdeb..6b87dbec2 100644 --- a/src/include/usr/scom/scomreasoncodes.H +++ b/src/include/usr/scom/scomreasoncodes.H @@ -47,6 +47,7 @@ namespace SCOM SCOM_READ_CENTAUR_CACHE = 0x0D, SCOM_CALL_WAKEUP_HYP = 0x0E, SCOM_CALL_WAKEUP_HWP = 0x0F, + SCOM_DO_MULTICAST_WORKAROUND = 0x10, }; enum scomReasonCode @@ -81,6 +82,7 @@ namespace SCOM SCOM_CACHE_SEQ_ERROR = SCOM_COMP_ID | 0x1C, SCOM_INVALID_WAKEUP_PARM = SCOM_COMP_ID | 0x1D, SCOM_UNEXPECTED_FORCE_WAKEUP = SCOM_COMP_ID | 0x1E, + SCOM_UNSUPPORTED_MULTICAST_OP = SCOM_COMP_ID | 0x1F, }; enum UserDetailsTypes diff --git a/src/include/usr/xscom/xscomreasoncodes.H b/src/include/usr/xscom/xscomreasoncodes.H index 33fe9a712..7e1784e36 100644 --- a/src/include/usr/xscom/xscomreasoncodes.H +++ b/src/include/usr/xscom/xscomreasoncodes.H @@ -5,7 +5,9 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* COPYRIGHT International Business Machines Corp. 2011,2014 */ +/* 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. */ @@ -39,6 +41,7 @@ namespace XSCOM XSCOM_DO_OP = 0x07, XSCOM_RT_DO_OP = 0x08, XSCOM_RT_SANITY_CHECK = 0x09, + XSCOM_TEST_XSCOM4 = 0x0A, }; enum xscomReasonCode diff --git a/src/usr/fapi2/test/p9_hwtests.C b/src/usr/fapi2/test/p9_hwtests.C index 6be74f20e..d761f99a5 100644 --- a/src/usr/fapi2/test/p9_hwtests.C +++ b/src/usr/fapi2/test/p9_hwtests.C @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* Contributors Listed Below - COPYRIGHT 2016,2018 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -395,14 +395,16 @@ fapi2::ReturnCode p9_piberrmask_masktest( fapi2::setPIBErrorMask(static_cast<uint8_t>(PIB::PIB_INVALID_ADDRESS)); //Attempt writing to a bad address + // Avoid multicast error by not setting bit 1 FAPI_TRY(fapi2::putScom(i_target, - 0xDEADBEEF, + 0xBADDBEEF, l_scomdata)); //try another scom, this time a get to make sure that // FAPI_TRY does not reset the mask + // Avoid multicast error by not setting bit 1 FAPI_TRY(fapi2::getScom(i_target, - 0xDEADBEEF, + 0xBADDBEEF, l_scomdata)); completionCheck = 1; 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++; diff --git a/src/usr/xscom/test/xscomtest.H b/src/usr/xscom/test/xscomtest.H index fbd6359cd..5bf9eaadd 100644 --- a/src/usr/xscom/test/xscomtest.H +++ b/src/usr/xscom/test/xscomtest.H @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2011,2016 */ +/* Contributors Listed Below - COPYRIGHT 2011,2018 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -62,6 +62,38 @@ const uint32_t g_xscomAddrTableSz = sizeof(g_xscomAddrTable)/sizeof(testXscomAddrData); +// Test table values written through xscom +const testXscomAddrData g_xscomMultiWriteTable[] = +{ + // Scom registers to write + // Scratch reg 3 + {0x20010A89, 0x1000000000000000}, + {0x21010A89, 0x0200000000000000}, + {0x22010A89, 0x0030000000000000}, + {0x23010A89, 0x0004000000000000}, + // Local checkstop regs + {0x10040018, 0x1000000000000000}, // ChipletID 0x10 + {0x20040018, 0x1000000000000000}, // ChipletID 0x20 +}; +const uint32_t g_xscomMultiWriteTableSz = + sizeof(g_xscomMultiWriteTable)/sizeof(testXscomAddrData); + + +// Test table values read through multicast op +const testXscomAddrData g_xscomMultiReadTable[] = +{ + // Scratch reg 3 + // Multicast OR op + {0x41010a89, 0x1234000000000000}, + // Local checkstop regs + // ChipletID 0x10 0x20 + // Multicast BITWISE op + {0x50040018, 0x0000800080000000}, +}; +const uint32_t g_xscomMultiReadTableSz = + sizeof(g_xscomMultiReadTable)/sizeof(testXscomAddrData); + + class XscomTest: public CxxTest::TestSuite { public: @@ -110,10 +142,10 @@ public: l_savedData = l_readData; l_writeData = (l_readData | l_testEntry.data); l_err = deviceWrite(l_testTarget, - &l_writeData, - l_size, - DeviceFW::SCOM, - l_testEntry.addr); + &l_writeData, + l_size, + DeviceFW::SCOM, + l_testEntry.addr); if (l_err) { @@ -352,6 +384,115 @@ public: return; } + + + /** + * @brief XSCOM test #4 + * Write regs and read as multicast to verify + */ + void testXscom4(void) + { + + TARGETING::TargetService& l_targetService = TARGETING::targetService(); + TARGETING::Target* l_testTarget = NULL; + l_targetService.masterProcChipTargetHandle( l_testTarget ); + assert(l_testTarget != NULL); + + size_t l_size = sizeof(uint64_t); + + errlHndl_t l_err = NULL; + uint32_t l_num; + + do { + // Loop thru write table + for( l_num=0; l_num < g_xscomMultiWriteTableSz; l_num++) + { + testXscomAddrData l_testEntry = g_xscomMultiWriteTable[l_num]; + + // Perform an XSCom write + uint64_t l_writeData = l_testEntry.data; + l_err = deviceWrite( l_testTarget, + &l_writeData, + l_size, + DeviceFW::SCOM, + l_testEntry.addr ); + + if (l_err) + { + TS_FAIL("testXscom4: XSCom write: deviceWrite() fails!"); + break; + } + else + { + TS_TRACE("testXscom4: XSCom write, Address 0x%.8X, Data %llx", + l_testEntry.addr, + (long long unsigned)l_writeData); + } + } + + if (l_err) + { + break; + } + + // Read back as multicast, should see combined data + // Multicast OP type (BITWISE / OR) defined in the address + for( l_num=0; l_num < g_xscomMultiReadTableSz; l_num++) + { + testXscomAddrData l_testEntry = g_xscomMultiReadTable[l_num]; + + uint64_t l_readData = 0; + l_err = deviceRead(l_testTarget, + &l_readData, + l_size, + DEVICE_SCOM_ADDRESS(l_testEntry.addr)); + + if (l_err) + { + TS_FAIL("testXscom4: XSCom multicast read back: deviceRead() fails!"); + break; + } + else + { + TS_TRACE("testXscom4: result addr 0x%X data 0x%llX",l_testEntry.addr ,l_readData); + } + + if( l_readData != l_testEntry.data ) + { + TS_FAIL("testXscom4: XSCom multicast read back doesn't match write!"); + /*@ + * @errortype + * @moduleid XSCOM::XSCOM_TEST_XSCOM4 + * @reasoncode XSCOM::XSCOM_DATA_UNMATCHED + * @userdata1 Write value + * @userdata2 Multicast read back value + * @devdesc Read back value doesn't match write + */ + l_err = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_INFORMATIONAL, + XSCOM::XSCOM_TEST_XSCOM4, + XSCOM::XSCOM_DATA_UNMATCHED, + l_testEntry.data, + l_readData); + break; + } + } + + } while(0); + + if (l_err) + { + TS_FAIL("testXscom4 failed! Error committed."); + errlCommit(l_err,XSCOM_COMP_ID); + } + else + { + TS_TRACE("testXscom4 runs successfully!"); + } + return; + } + + }; #endif |