diff options
author | Bill Hoffa <wghoffa@us.ibm.com> | 2015-10-15 13:59:58 -0500 |
---|---|---|
committer | Daniel M. Crowell <dcrowell@us.ibm.com> | 2016-03-30 16:24:17 -0400 |
commit | 6b5097872a33a20d4c03f995ca8f1585b9e43e53 (patch) | |
tree | b97d48402b8e54b14d1ce554191bbeb78890d09c /src | |
parent | 550f30129f455317e65610cd90e9d06b2018e4c1 (diff) | |
download | talos-hostboot-6b5097872a33a20d4c03f995ca8f1585b9e43e53.tar.gz talos-hostboot-6b5097872a33a20d4c03f995ca8f1585b9e43e53.zip |
P9 PSIHB Base Interrupt Support
This change includes the following:
- Kernel Updates to handle hypervisor interrupt vector
- Interrupt Resource Provider changes to setup and handle
LSI Based interrupts
- Kernel updates to handle modified interrupt flow for
LSI Based interrupts
- Attribute updates for Scom BAR Registers
Change-Id: If63f246a0090ab8c81c3fa8ac3ab6871a0af2e31
RTC:137561
Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/20692
Tested-by: Jenkins Server
Tested-by: FSP CI Jenkins
Reviewed-by: Andrew J. Geissler <andrewg@us.ibm.com>
Reviewed-by: Prachi Gupta <pragupta@us.ibm.com>
Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/build/citest/etc/bbuild | 2 | ||||
-rw-r--r-- | src/include/kernel/cpumgr.H | 5 | ||||
-rw-r--r-- | src/include/kernel/intmsghandler.H | 26 | ||||
-rw-r--r-- | src/include/usr/intr/interrupt.H | 35 | ||||
-rw-r--r-- | src/include/usr/intr/intr_reasoncodes.H | 14 | ||||
-rw-r--r-- | src/kernel/exception.C | 2 | ||||
-rw-r--r-- | src/kernel/intmsghandler.C | 35 | ||||
-rw-r--r-- | src/kernel/msghandler.C | 4 | ||||
-rw-r--r-- | src/kernel/start.S | 15 | ||||
-rw-r--r-- | src/kernel/syscall.C | 2 | ||||
-rw-r--r-- | src/usr/initservice/extinitsvc/extinitsvctasks.H | 4 | ||||
-rw-r--r-- | src/usr/intr/intrrp.C | 1556 | ||||
-rw-r--r-- | src/usr/intr/intrrp.H | 285 | ||||
-rw-r--r-- | src/usr/intr/test/intrtest.H | 33 | ||||
-rw-r--r-- | src/usr/isteps/istep14/call_proc_exit_cache_contained.C | 13 | ||||
-rw-r--r-- | src/usr/mbox/mailboxsp.C | 76 | ||||
-rwxr-xr-x | src/usr/targeting/common/genHwsvMrwXml.pl | 8 | ||||
-rw-r--r-- | src/usr/targeting/common/xmltohb/attribute_types.xml | 15 | ||||
-rw-r--r-- | src/usr/targeting/common/xmltohb/simics_NIMBUS.system.xml | 9 | ||||
-rwxr-xr-x | src/usr/targeting/common/xmltohb/target_types.xml | 3 |
20 files changed, 1166 insertions, 976 deletions
diff --git a/src/build/citest/etc/bbuild b/src/build/citest/etc/bbuild index 996ad34be..a99905b3e 100644 --- a/src/build/citest/etc/bbuild +++ b/src/build/citest/etc/bbuild @@ -1 +1 @@ -/esw/fips910/Builds/b0323b_1614.910
\ No newline at end of file +/esw/fips910/Builds/b0323b_1614.910 diff --git a/src/include/kernel/cpumgr.H b/src/include/kernel/cpumgr.H index 30009da73..25bb794bf 100644 --- a/src/include/kernel/cpumgr.H +++ b/src/include/kernel/cpumgr.H @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2010,2015 */ +/* Contributors Listed Below - COPYRIGHT 2010,2016 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -170,8 +170,9 @@ class CpuManager * bit 51 - Wake-up from machine check. * bit 60 - LPES(0) = 1 (see ISA). * bit 61 - LPES(1) = 0 (P8 RFC02204 forces to 0) + * bit 62 - HVICE - Hypervisor Virt Interrupt Conditionally Enable */ - static const uint64_t WAKEUP_LPCR_VALUE = 0x0000000000007008; + static const uint64_t WAKEUP_LPCR_VALUE = 0x000000000000700A; /** Desired value for RPR after wakeup. * diff --git a/src/include/kernel/intmsghandler.H b/src/include/kernel/intmsghandler.H index 98d8d5288..8fd4e34b6 100644 --- a/src/include/kernel/intmsghandler.H +++ b/src/include/kernel/intmsghandler.H @@ -46,6 +46,7 @@ class InterruptMsgHdlr : public MessageHandler public: /** + * TODO RTC 150260 * Field values for P8 * @note This is used to calculate the mmio address offset * from the PIR for the interrupt presenter memory mapped registers. @@ -56,19 +57,20 @@ class InterruptMsgHdlr : public MessageHandler */ enum { - P8_PIR_THREADID_MSK = PIR_t::THREAD_MASK, - P8_PIR_COREID_MSK = PIR_t::CORE_MASK, - P8_PIR_CHIPID_MSK = PIR_t::CHIP_MASK, - P8_PIR_NODEID_MSK = PIR_t::GROUP_MASK, + P9_PIR_THREADID_MSK = PIR_t::THREAD_MASK, + P9_PIR_COREID_MSK = PIR_t::CORE_MASK, + P9_PIR_CHIPID_MSK = PIR_t::CHIP_MASK, + P9_PIR_NODEID_MSK = PIR_t::GROUP_MASK, // Logical Shift Left fields for mmio Base address from PIR. // (IP addr bit pos - PIR bit pos) - P8_IP_THREADID_LSL = (12-PIR_t::BITS_AFTER_CORE), - P8_IP_COREID_LSL = (15-PIR_t::BITS_AFTER_CORE), - P8_IP_CHIPID_LSL = (20-PIR_t::BITS_AFTER_CHIP), - P8_IP_NODEID_LSL = (22-PIR_t::BITS_AFTER_GROUP), + P9_IP_THREADID_LSL = (12-PIR_t::BITS_AFTER_CORE), + P9_IP_COREID_LSL = (15-PIR_t::BITS_AFTER_CORE), + P9_IP_CHIPID_LSL = (20-PIR_t::BITS_AFTER_CHIP), + P9_IP_NODEID_LSL = (22-PIR_t::BITS_AFTER_GROUP), XIRR_ADDR_OFFSET = 4, MFRR_ADDR_OFFSET = 12, + ACK_HYPERVISOR_INT_REG_OFFSET = 0x830, INTP_BAR_VALUE = 0xFFFFE000, // upper 32 bits of IPCBAR @@ -109,16 +111,16 @@ class InterruptMsgHdlr : public MessageHandler // The PIR chip id field has 1 extra bit (8 chips), so we need // to shift the node and chip separately offset |= - (i_pir & P8_PIR_NODEID_MSK) << P8_IP_NODEID_LSL; + (i_pir & P9_PIR_NODEID_MSK) << P9_IP_NODEID_LSL; offset |= - (i_pir & P8_PIR_CHIPID_MSK) << P8_IP_CHIPID_LSL; + (i_pir & P9_PIR_CHIPID_MSK) << P9_IP_CHIPID_LSL; // The core and thread id field are adjacent in both the PIR and // the mmio offset, so they can be done in one shift operation. offset |= - (i_pir & (P8_PIR_COREID_MSK | P8_PIR_THREADID_MSK)) - << P8_IP_THREADID_LSL; + (i_pir & (P9_PIR_COREID_MSK | P9_PIR_THREADID_MSK)) + << P9_IP_THREADID_LSL; return offset; } diff --git a/src/include/usr/intr/interrupt.H b/src/include/usr/intr/interrupt.H index 1b24c2eed..1666abd15 100644 --- a/src/include/usr/intr/interrupt.H +++ b/src/include/usr/intr/interrupt.H @@ -51,7 +51,8 @@ namespace INTR enum XISRvalue_t { NO_INTERRUPT = 0, //!< no interrupt present - INTERPROC_XISR = 2, //!< XISR value for IPIs + //TODO RTC 137564 + INTERPROC_XISR = 0xFF, //!< XISR value for IPIs MAX_XISR = 0x00FFFFFF, //!< Max value of the XISR SHUT_DOWN = 0x01000000, //!< INTR presenter sends this when shutting down }; @@ -71,6 +72,33 @@ namespace INTR //Converts to INTERPROC_XISR when registered }; + //These values are HW defined values from the LSI Interrupts status register + // on the PSIHB. These should only be changed if the spec changes. + enum LSIvalue_t + { + LSI_PSI = 0, + LSI_OCC = 1, + LSI_FSIMBOX = 2, + LSI_LPC = 3, + LSI_LCL_FIR = 4, + LSI_GLOBAL = 5, + LSI_TPM = 6, + LSI_LPC_SERIAL0 = 7, + LSI_LPC_SERIAL1 = 8, + LSI_LPC_SERIAL2 = 9, + LSI_LPC_SERIAL3 = 10, + LSI_SBE_OR_I2C = 11, + LSI_DIO = 12, + LSI_PSU = 13, + LSI_LAST_SOURCE, + +//TODO RTC 137564 +// ISN_INTERPROC = 0xF0, //"special" as it isn't part of PSIHB +// //Converts to INTERPROC_XISR when registered +// // + }; + + /** * The XISR value is the logical OR of the Interrup Requestor Source * Number (IRSN) and the Interrrupt Source Number (ISN). @@ -107,12 +135,12 @@ namespace INTR MSG_INTR_ENABLE, //!< Enable external Interrupts MSG_INTR_DISABLE, //!< Disable external interrupts MSG_INTR_SHUTDOWN, //!< Call to shutdown interrupt presenter - MSG_INTR_ENABLE_PSI_INTR, //!< Enable PSI interrupts MSG_INTR_MPIPL_CLEANUP, //!< Clean up interrupts on MPIPL MSG_INTR_ADD_CPU_TIMEOUT, //!< Check for a timeout waiting for a core. MSG_INTR_ADD_HBNODE, //!< Add node info for MPIPL MSG_INTR_EOI, //!< Issue EOI when received MSG_INTR_DRAIN_QUEUE, //!< Allow intrp to drain Q of EOI + MSG_INTR_COALESCE, //!< Pending interrupt to be handled }; /** @@ -181,12 +209,13 @@ namespace INTR */ errlHndl_t disableExternalInterrupts(); + //TODO RTC 150260 /** * Initialize the IRSCReg to enable PSI to present interrupts * @param[in] i_target The target processor * @return error log handle on error */ - errlHndl_t enablePsiIntr(TARGETING::Target * i_target); + //errlHndl_t enablePsiIntr(TARGETING::Target * i_target); /** * Return the interrupt presenter for requested target/thread diff --git a/src/include/usr/intr/intr_reasoncodes.H b/src/include/usr/intr/intr_reasoncodes.H index 31869ac69..8ab758519 100644 --- a/src/include/usr/intr/intr_reasoncodes.H +++ b/src/include/usr/intr/intr_reasoncodes.H @@ -5,7 +5,9 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* COPYRIGHT International Business Machines Corp. 2011,2014 */ +/* Contributors Listed Below - COPYRIGHT 2011,2016 */ +/* [+] 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. */ @@ -42,6 +44,11 @@ namespace INTR MOD_INTR_SYNC_ADDNODE = 0x0A, /**< intrrp.C : IntrRp::addHbNodeToMpiplSyncArea */ MOD_INTR_ADDHBNODE = 0x0B, /**< intrrp.C : INTR::addHbNode */ MOD_INTR_EXTRACTNODEINFO = 0x0C, /**< intrrp.C : INTR::extractHbNodeInfo */ + MOD_INTRRP_SENDEOI = 0x0D, /**< intrrp.C : INTR::sendEOI */ + MOD_INTRRP_MASKINTERRUPT = 0x0E, /**< intrrp.C : INTR::maskInterruptSource */ + MOD_INTRRP_UNMASKINTERRUPT = 0x0F, /**< intrrp.C : INTR::unmaskInterruptSource */ + MOD_INTRRP_HNDLPSUINTERRUPT = 0x10, /**< intrrp.C : INTR::handlePsuInterrupt */ + MOD_INTRRP_RESETINTUNIT = 0x11, /**< intrrp.C : IntrRp::resetIntUnit */ }; enum IntrReasonCode @@ -54,6 +61,11 @@ namespace INTR //termination_rc RC_PERSISTENT_INTERRUPTS = INTR_COMP_ID | 0x06, RC_CANNOT_MAP_MEMORY = INTR_COMP_ID | 0x07, + RC_PSIHB_ESB_EOI_FAIL = INTR_COMP_ID | 0x08, + RC_XIVE_ESB_WRONG_STATE = INTR_COMP_ID | 0x09, + RC_PSU_DOORBELL_TIMEOUT = INTR_COMP_ID | 0x0A, + RC_XIVE_PBUS_QUIESCE_TIMEOUT = INTR_COMP_ID | 0x0B, + RC_MESSAGE_SEND_ERROR = INTR_COMP_ID | 0x0C, }; }; diff --git a/src/kernel/exception.C b/src/kernel/exception.C index 5c16d46cd..686d3012c 100644 --- a/src/kernel/exception.C +++ b/src/kernel/exception.C @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2010,2015 */ +/* Contributors Listed Below - COPYRIGHT 2010,2016 */ /* [+] International Business Machines Corp. */ /* */ /* */ diff --git a/src/kernel/intmsghandler.C b/src/kernel/intmsghandler.C index f203439be..10c1dcfd8 100644 --- a/src/kernel/intmsghandler.C +++ b/src/kernel/intmsghandler.C @@ -5,7 +5,9 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* COPYRIGHT International Business Machines Corp. 2011,2014 */ +/* Contributors Listed Below - COPYRIGHT 2011,2016 */ +/* [+] 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. */ @@ -76,26 +78,22 @@ void InterruptMsgHdlr::handleInterrupt() if( cv_ipc_base_address != 0 ) { - uint64_t xirrAddress = cv_ipc_base_address; - - xirrAddress += mmio_offset(pir); // Add offset for this cpu - xirrAddress += XIRR_ADDR_OFFSET; // Add offset for XIRR register + uint64_t ackHypeInt2RegAddress = cv_ipc_base_address; + ackHypeInt2RegAddress += ACK_HYPERVISOR_INT_REG_OFFSET; // Ignore HRMOR setting - xirrAddress |= 0x8000000000000000ul; - - uint32_t xirr = 0; - printkd ("XirrAddr %lx\n",xirrAddress); + ackHypeInt2RegAddress |= 0x8000000000000000ul; + uint16_t ackHypeInt2Reg = 0; // Reading this register acknowledges the interrupt and deactivates the // external interrupt signal to the processor. The XIRR is now locked // and can't be pre-empted by a "more favored" interrupt. // This is a cache-inhibited load from hypervisor state. - // lwzcix BOP1,Ref_G0,BOP2 - asm volatile("lwzcix %0, 0, %1" - : "=r" (xirr) // output, %0 - : "r" (xirrAddress) // input, %1 - : ); // no impacts + // lhzcix BOP1,Ref_G0,BOP2 + asm volatile("lhzcix %0, 0, %1" + : "=r" (ackHypeInt2Reg) // output, %0 + : "r" (ackHypeInt2RegAddress) // input, %1 + : ); // no impacts if(cv_instance) { @@ -103,8 +101,9 @@ void InterruptMsgHdlr::handleInterrupt() //sendMessage needs a unique key, otherwise it //drops messages. PIR is not unique enough, make - //it (xirr<<32) | PIR - uint64_t l_data0 = pir | (static_cast<uint64_t>(xirr) <<32); + //it (ackHypInt2Reg<<32) | PIR + uint64_t l_data0 = + pir | (static_cast<uint64_t>(ackHypeInt2Reg) <<32); cv_instance->sendMessage(MSG_INTR_EXTERN, reinterpret_cast<void*>(l_data0), NULL, @@ -115,7 +114,6 @@ void InterruptMsgHdlr::handleInterrupt() else { printk("InterrurptMsgHdlr got called before IPC was setup\n"); - // The INTR mmio base address is not yet available via the attributes. // If we get here during an MPIPL then the BAR value could be read // from the ICP BAR SCOM register, however, since this value will @@ -142,9 +140,8 @@ void InterruptMsgHdlr::handleInterrupt() // There should not be any more interrupts until an eoi is sent // by writing the xirr back with the value read. - printk("XIRR @ %lx = %x\n",xirrAddress,xirr); - //If this is an IPI -- clean it up + //TODO RTC 137564 if((xirr & 0x00FFFFFF) == INTERPROC_XISR) { uint64_t mfrrAddress = diff --git a/src/kernel/msghandler.C b/src/kernel/msghandler.C index 5a3beefac..cb051eb88 100644 --- a/src/kernel/msghandler.C +++ b/src/kernel/msghandler.C @@ -5,7 +5,9 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* COPYRIGHT International Business Machines Corp. 2011,2014 */ +/* Contributors Listed Below - COPYRIGHT 2011,2016 */ +/* [+] 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. */ diff --git a/src/kernel/start.S b/src/kernel/start.S index 86c2d1c18..740f961e8 100644 --- a/src/kernel/start.S +++ b/src/kernel/start.S @@ -208,6 +208,7 @@ UNIMPL_INTERRUPT_STUB(hype_data_storage, 0xE00) UNIMPL_INTERRUPT_STUB(hype_inst_storage, 0xE20) STD_INTERRUPT_STUB(hype_emu_assist, 0xE40) UNIMPL_INTERRUPT_STUB(hype_maint, 0xE60) +STD_INTERRUPT_STUB(hypervisor_external, 0xEA0) UNIMPL_INTERRUPT_STUB(perf_monitor, 0xF00) UNIMPL_INTERRUPT_STUB(vector_unavail, 0xF20) UNIMPL_INTERRUPT_STUB(vsx_unavail, 0xF40) @@ -698,6 +699,20 @@ intvect_system_reset_external: b intvect_external + ;// @fn intvect_hypervisor_external + ;// Handle hypervisor external interrupt + ;// This function moves the hypervisor external interrupt regs + ;// into the external interrupt regs and then branches to the + ;// external interrupt handler +intvect_hypervisor_external: + mtsprg1 r1 ;// Save off R1 temporarily. + mfspr r1, HSRR0 ;// Move HSRR0 -> SRR0. + mtsrr0 r1 + mfspr r1, HSRR1 ;// Move HSRR1 -> SRR1. + mtsrr1 r1 + mfsprg1 r1 ;// Restore R1 and use external interrupt handler + b intvect_external + ;// @fn system_call_fast_path ;// Handle fast path system calls. ;// 0x800 = HMER read (HMER -> r3). diff --git a/src/kernel/syscall.C b/src/kernel/syscall.C index 92907c3df..fe59ea0c3 100644 --- a/src/kernel/syscall.C +++ b/src/kernel/syscall.C @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2010,2015 */ +/* Contributors Listed Below - COPYRIGHT 2010,2016 */ /* [+] International Business Machines Corp. */ /* */ /* */ diff --git a/src/usr/initservice/extinitsvc/extinitsvctasks.H b/src/usr/initservice/extinitsvc/extinitsvctasks.H index f0eece8bd..46bd65473 100644 --- a/src/usr/initservice/extinitsvc/extinitsvctasks.H +++ b/src/usr/initservice/extinitsvc/extinitsvctasks.H @@ -96,8 +96,6 @@ const TaskInfo g_exttaskinfolist[] = { } }, - // @todo RTC:126643 P9 interrupt support -#if (0) /** * @brief External interrupt resource provider */ @@ -109,8 +107,6 @@ const TaskInfo g_exttaskinfolist[] = { EXT_IMAGE, // Extended Module } }, -#endif - /** * @brief Mailbox service provider */ diff --git a/src/usr/intr/intrrp.C b/src/usr/intr/intrrp.C index 7a19429aa..f1bacb540 100644 --- a/src/usr/intr/intrrp.C +++ b/src/usr/intr/intrrp.C @@ -58,26 +58,6 @@ using namespace INTR; using namespace TARGETING; -const uint32_t IntrRp::cv_PE_IRSN_COMP_SCOM_LIST[] = -{ - PE0_IRSN_COMP_SCOM_ADDR, - PE1_IRSN_COMP_SCOM_ADDR, - PE2_IRSN_COMP_SCOM_ADDR -}; - -const uint32_t IntrRp::cv_PE_IRSN_MASK_SCOM_LIST[] = -{ - PE0_IRSN_MASK_SCOM_ADDR, - PE1_IRSN_MASK_SCOM_ADDR, - PE2_IRSN_MASK_SCOM_ADDR -}; - -const uint32_t IntrRp::cv_PE_BAR_SCOM_LIST[] = -{ - PE0_BAREN_SCOM_ADDR, - PE1_BAREN_SCOM_ADDR, - PE2_BAREN_SCOM_ADDR -}; trace_desc_t * g_trac_intr = NULL; TRAC_INIT(&g_trac_intr, INTR_TRACE_NAME, 16*KILOBYTE, TRACE::BUFFER_SLOW); @@ -88,69 +68,6 @@ TRAC_INIT(&g_trac_intr, INTR_TRACE_NAME, 16*KILOBYTE, TRACE::BUFFER_SLOW); TASK_ENTRY_MACRO( IntrRp::init ); -/** - * @brief Utility function to get the list of enabled threads - * @return Bitstring of enabled threads - */ -uint64_t get_enabled_threads( void ) -{ - TARGETING::Target* sys = NULL; - TARGETING::targetService().getTopLevelTarget(sys); - assert( sys != NULL ); - uint64_t en_threads = sys->getAttr<TARGETING::ATTR_ENABLED_THREADS>(); - if( en_threads == 0 ) - { - -// Set max thread for VPO, nanosleep() here takes too long in VPO environment -#ifdef CONFIG_VPO_COMPILE - en_threads = 0xFF00000000000000; - sys->setAttr<TARGETING::ATTR_ENABLED_THREADS>(en_threads); - TRACFCOMP( g_trac_intr, "Enabled Threads for VPO = %.16X", en_threads ); - return en_threads; -#endif - - // Read the scratch reg that the SBE setup - // Enabled threads are listed as a bitstring in bits 16:23 - // A value of zero means the SBE hasn't set them up yet - - // Loop for 1 sec (1000 x 1 msec) for this value to be set - uint64_t loop_count = 0; - const uint64_t LOOP_MAX = 1000; - - while( (en_threads == 0) && (loop_count < LOOP_MAX) ) - { - en_threads = mmio_scratch_read(MMIO_SCRATCH_AVP_THREADS); - - if( en_threads == 0 ) - { - // Sleep if value has not been set - nanosleep(0,NS_PER_MSEC); // 1 msec - } - - // Update the counter - loop_count++; - } - - // If LOOP_MAX reached, CRIT_ASSERT - if ( unlikely(loop_count == LOOP_MAX) ) - { - TRACFCOMP( g_trac_intr,"SBE Didn't Set Active Threads"); - crit_assert(0); - } - else - { - en_threads = en_threads << 16; //left-justify the threads - TRACFCOMP( g_trac_intr, - "Enabled Threads = %.16X", - en_threads ); - sys->setAttr<TARGETING::ATTR_ENABLED_THREADS>(en_threads); - } - - } - TRACDCOMP( g_trac_intr, "en_threads=%.16X", en_threads ); - return en_threads; -} - void IntrRp::init( errlHndl_t &io_errlHndl_t ) { errlHndl_t err = NULL; @@ -161,23 +78,9 @@ void IntrRp::init( errlHndl_t &io_errlHndl_t ) io_errlHndl_t = err ; } -// ICPBAR = INTP.ICP_BAR[0:25] in P8 = 0x3FFFF800 + (8*node) + procPos -// P8 Scom address = 0x020109c9 -// -// BaseAddress P8: -// BA[14:43] = ICPBAR (30 bits) -// BA[45:48] = coreID (1-6,9-14) (12 cores) -// BA[49:51] = thread (0-7) -// -// BA+0 = XIRR (poll - Read/Write has no side effects)) -// BA+4 = XIRR (Read locks HW, Write -> EOI to HW)) -// BA+12 = MFRR (1 byte) -// BA+16 = LINKA (4 bytes) -// BA+20 = LINKB (4 bytes) -// BA+24 = LINKC (4 bytes) errlHndl_t IntrRp::_init() { - errlHndl_t err = NULL; + errlHndl_t l_err = NULL; // get the PIR // Which ever cpu core this is running on is the MASTER cpu @@ -186,32 +89,16 @@ errlHndl_t IntrRp::_init() iv_masterCpu = cpuid; iv_masterCpu.threadId = 0; - TRACFCOMP(g_trac_intr,"Master cpu group[%d], chip[%d], core[%d], thread[%d]", + TRACFCOMP(g_trac_intr,"IntrRp::_init() Master cpu group[%d], " + "chip[%d], core[%d], thread[%d]", iv_masterCpu.groupId, iv_masterCpu.chipId, iv_masterCpu.coreId, iv_masterCpu.threadId); - // The base realAddr is the base address for the whole system. - // Therefore the realAddr must be based on the processor - // that would have the lowest BAR value in the system, - // whether it exists or not. In this case n0p0 - + // Do the initialization steps on the master proc chip + // The other proc chips will be setup at a later point TARGETING::Target* procTarget = NULL; TARGETING::targetService().masterProcChipTargetHandle( procTarget ); - uint64_t barValue = 0; - barValue = procTarget->getAttr<TARGETING::ATTR_INTP_BASE_ADDR>(); - - // Mask off group & chip id to get base address - uint64_t realAddr = barValue & ICPBAR_BASE_ADDRESS_MASK; - - TRACFCOMP(g_trac_intr,"INTR: realAddr = %lx",realAddr); - - // VADDR_SIZE is 1MB per chip - max 32 -> 32MB - iv_baseAddr = reinterpret_cast<uint64_t> - (mmio_dev_map(reinterpret_cast<void*>(realAddr),THIRTYTWO_MB)); - - TRACFCOMP(g_trac_intr,"INTR: vAddr = %lx",iv_baseAddr); - // Set up the IPC message Data area TARGETING::Target * sys = NULL; TARGETING::targetService().getTopLevelTarget( sys ); @@ -223,16 +110,22 @@ errlHndl_t IntrRp::_init() KernelIpc::ipc_data_area.hrmor_base = hrmor_base; KernelIpc::ipc_data_area.msg_queue_id = IPC_DATA_AREA_CLEAR; - // Set the BAR scom reg - err = setBAR(procTarget,iv_masterCpu); - - if(!err) + do { - err = checkAddress(iv_baseAddr); - } + //TODO RTC 150562 - updates for multi-chip. My understanding is + // the setting of the BARs + Enables can be done at the point in the IPL + // where Xscoms are enabled. + // Set the Interrupt BAR Scom Registers + l_err = setInterruptBARs(procTarget); - if(!err) - { + if (l_err) + { + TRACFCOMP(g_trac_intr, "IntrRp::_init() Error setting Interrupt BARs."); + break; + } + + //TODO RTC 134431 + #ifdef CONFIG_MPIPL_ENABLED uint8_t is_mpipl = 0; TARGETING::Target * sys = NULL; TARGETING::targetService().getTopLevelTarget(sys); @@ -241,76 +134,218 @@ errlHndl_t IntrRp::_init() is_mpipl) { TRACFCOMP(g_trac_intr,"Disable interupts for MPIPL"); - err = hw_disableIntrMpIpl(); + l_err = hw_disableIntrMpIpl(); - if(err) + if(l_err) { - errlCommit(err,INTR_COMP_ID); - err = NULL; + errlCommit(l_err,INTR_COMP_ID); + l_err = NULL; } } + #endif + TRACFCOMP(g_trac_intr, "IntrRp::_init() Masking Interrupts"); + //Mask off all interrupt sources - these will be enabled as SW entities + // register for specific interrupts via the appropriate message queue + l_err = maskAllInterruptSources(); + if (l_err) + { + TRACFCOMP(g_trac_intr, "IntrRp::_init() Error masking all interrupt sources."); + break; + } - // Set up the interrupt provider registers - // NOTE: It's only possible to set up the master core at this point. - // - // Set up link registers to forward all intrpts to master cpu. - // - // There is one register set per cpu thread. - uint64_t max_threads = cpu_thread_count(); - uint64_t en_threads = get_enabled_threads(); - - PIR_t pir = iv_masterCpu; - for(size_t thread = 0; thread < max_threads; ++thread) + TRACFCOMP(g_trac_intr, "IntrRp::_init() Enabling PSIHB Interrupts"); + //Enable PSIHB Interrupts + l_err = enableInterrupts(); + if (l_err) { - // Skip threads that we shouldn't be starting - if( !(en_threads & (0x8000000000000000>>thread)) ) - { - TRACDCOMP(g_trac_intr, - "IntrRp::_init: Skipping thread %d : en_threads=%X", - thread,en_threads); - continue; - } - pir.threadId = thread; - initInterruptPresenter(pir); + TRACFCOMP(g_trac_intr, "IntrRp::_init() Error enabling Interrupts"); + break; } - // Get the kernel msg queue for ext intr - // Create a task to handle the messages + // Create the kernel msg queue for external interrupts iv_msgQ = msg_q_create(); - msg_intr_q_register(iv_msgQ, realAddr); + msg_intr_q_register(iv_msgQ, + procTarget->getAttr<TARGETING::ATTR_XIVE_THREAD_MGMT1_BAR_ADDR>()); + // Create a task to handle the messages task_create(IntrRp::msg_handler, NULL); // Register event to be called on shutdown INITSERVICE::registerShutdownEvent(iv_msgQ, MSG_INTR_SHUTDOWN, INITSERVICE::INTR_PRIORITY); - } - if(!err) + //The INTRP itself will monitor/handle PSU Interrupts + // so unmask those interrupts + l_err = unmaskInterruptSource(LSI_PSU); + + } while(0); + + return l_err; +} + +void IntrRp::acknowledgeInterrupt() +{ + //A uint16 store from the Acknowledge Hypervisor Interrupt + // offset in the Thread Management BAR space signals + // the interrupt is acknowledged + uint16_t * l_ack_int_ptr = (uint16_t *)iv_xiveTmBar1Address; + l_ack_int_ptr += ACK_HYPERVISOR_INT_REG_OFFSET; + + uint16_t l_ackRead = *l_ack_int_ptr; + TRACDCOMP(g_trac_intr, "IntrRp::acknowledgeInterrupt(), read result: %16x", l_ackRead); +} + +errlHndl_t IntrRp::resetIntUnit() +{ + errlHndl_t l_err = NULL; + uint64_t l_barValue = XIVE_RESET_POWERBUS_QUIESCE_ENABLE; + uint64_t size = sizeof(l_barValue); + uint32_t l_addr = XIVE_RESET_INT_CQ_RST_CTL_SCOM_ADDR; + + TARGETING::Target* procTarget = NULL; + TARGETING::targetService().masterProcChipTargetHandle( procTarget ); + + do { + //First quiesce the power bus + TRACDCOMP(g_trac_intr, "IntrRp::resetIntUnit() - " + "Quiesce the PowerBus Interface"); + l_err = deviceWrite(procTarget, + &l_barValue, + size, + DEVICE_SCOM_ADDRESS(l_addr)); + + if (l_err) + { + TRACFCOMP(g_trac_intr, "IntrRp::resetIntUnit() - " + "Error Quiescing the PowerBus"); + break; + } + + //A short amount of time is needed to let the powerbus quiesce before + // the next step in the reset can occur, so do a short polling loop + // for the indicator the power bus has been quiesced + uint64_t l_quiesceTimeout = XIVE_RESET_POWERBUS_QUIESCE_TIMEOUT; + uint64_t l_timeWaited = 0; + uint64_t reg = 0x0; + + do + { + if (l_timeWaited >= l_quiesceTimeout) + { + TRACFCOMP(g_trac_intr, "IntrRp::resetIntUnit() - Timeout " + "waiting for PowerBus to quiesce"); + /*@ errorlog tag + * @errortype ERRL_SEV_UNRECOVERABLE + * @moduleid INTR::MOD_INTRRP_RESETINTUNIT + ` * @reasoncode INTR::RC_XIVE_PBUS_QUIESCE_TIMEOUT + * @userdata1 XIVE Powerbus Scom Register Address + * @userdata2 XIVE Powerbus Scom Register Data + * + * @devdesc Timeout waiting for Powerbus to Quiesce + */ + l_err = new ERRORLOG::ErrlEntry + ( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, // severity + INTR::MOD_INTRRP_RESETINTUNIT, // moduleid + INTR::RC_XIVE_PBUS_QUIESCE_TIMEOUT, // reason code + l_addr, + reg + ); + + break; + } + + uint64_t scom_len = sizeof(reg); + + //Read the powerbus state + l_err = deviceRead( procTarget, + ®, + scom_len, + DEVICE_SCOM_ADDRESS(l_addr)); + + + if (l_err) + { + //Logging below this loop + break; + } + + + if (reg & POWERBUS_STATE_QUIESCE) + { + //Powerbus Quiesced + break; + } + else + { + nanosleep(0,XIVE_RESET_POWERBUS_QUIESCE_TIMEOUT / 10); + l_timeWaited += XIVE_RESET_POWERBUS_QUIESCE_TIMEOUT / 10; + } + } while(1); + + if (l_err) + { + TRACFCOMP(g_trac_intr, "Error getting Powerbus state"); + break; + } + + TRACDCOMP(g_trac_intr, "Reset XIVE INT unit"); + l_barValue = XIVE_RESET_UNIT_ENABLE; + l_err = deviceWrite(procTarget, + &l_barValue, + size, + DEVICE_SCOM_ADDRESS(l_addr)); + + if (l_err) + { + TRACFCOMP(g_trac_intr, "Error resetting XIVE INT unit"); + break; + } + + } while (0); + + if (l_err) { - // Enable PSI to present interrupts - err = initIRSCReg(procTarget); + TRACFCOMP(g_trac_intr, "Error: Interrupt Engine not reset successfully"); } - return err; + return l_err; } errlHndl_t IntrRp::enableInterrupts() { errlHndl_t err = NULL; + PSIHB_SW_INTERFACES_t * l_psihb_ptr = iv_psiHbBaseAddr; - // Enable the interrupt on master processor core, thread 0 - uint64_t baseAddr = iv_baseAddr + cpuOffsetAddr(iv_masterCpu); - - err = checkAddress(baseAddr); - if(!err) + do { - uint8_t * cppr = reinterpret_cast<uint8_t*>(baseAddr+CPPR_OFFSET); - *cppr = 0xff; - } + //Set bit to route interrupts to CEC instead of FSP + l_psihb_ptr->psihbcr = + (l_psihb_ptr->psihbcr | PSI_BRIDGE_ENABLE_CEC_INTERRUPT); + //Set bit to enable PSIHB Interrupts + l_psihb_ptr->icr = + (l_psihb_ptr->icr | PSI_BRIDGE_INTP_STATUS_CTL_ENABLE); + + //Set Physical Thread Enable register in the PC space + uint64_t * l_ic_ptr = iv_xiveIcBarAddress; + l_ic_ptr += XIVE_IC_BAR_INT_PC_MMIO_REG_OFFSET; + + XIVE_IC_THREAD_CONTEXT_t * l_xive_ic_ptr = + reinterpret_cast<XIVE_IC_THREAD_CONTEXT_t *>(l_ic_ptr); + l_xive_ic_ptr->phys_thread_enable0_set = XIVE_IC_THREAD0_ENABLE; + + //Set bit to configure LSI mode for HB cec interrupts + XIVE_IVPE_THREAD_CONTEXT_t * this_ivpe_ptr = + reinterpret_cast<XIVE_IVPE_THREAD_CONTEXT_t *> (iv_xiveTmBar1Address); + this_ivpe_ptr->cams = XIVE_IVPE_QW3_LSI_ENABLE; + + } while (0); + + //TODO RTC 150260 - Determine if any error checking can be done above, if so + // create/return errorlogs. If not, change the funciton return type. return err; } @@ -343,15 +378,39 @@ void* IntrRp::msg_handler(void * unused) void IntrRp::msgHandler() { + TRACDCOMP(g_trac_intr, ENTER_MRK"IntrRp::msgHandler()"); + while(1) { msg_t* msg = msg_wait(iv_msgQ); // wait for interrupt msg switch(msg->type) { + //Both cases require the same functinality, EXTERN comes from + // the kernel. COALESCE comes from userspace as the final step of + // the EOI path involves a read, if that returns 1 it signifies a + // new interrupt is already pending. So the EOI path will send a + // new COALESCE message to trigger the handling. + case MSG_INTR_COALESCE: case MSG_INTR_EXTERN: { ext_intr_t type = NO_INTERRUPT; + uint32_t ackResponse = + static_cast<uint32_t>(msg->data[0]>>32); + //Check if LSI-Based Interrupt + if ((ackResponse & LSI_INTERRUPT) == LSI_INTERRUPT) + { + TRACDCOMP(g_trac_intr, "IntrRp::msgHandler() " + "- LSI Interrupt Detected"); + //Read LSI Interrupt Status register + PSIHB_SW_INTERFACES_t * l_psihb_ptr = iv_psiHbBaseAddr; + uint64_t lsiIntStatus = l_psihb_ptr->lsiintstatus; + TRACDCOMP(g_trac_intr, "IntrRp::msgHandler() " + "lsiIntStatus 0x%016lx", lsiIntStatus); + LSIvalue_t l_intrType = static_cast<LSIvalue_t> + (__builtin_clzl(lsiIntStatus)); + type = static_cast<ext_intr_t>(l_intrType); + } // xirr was read by interrupt message handler. // Passed in as upper word of data[0] @@ -365,22 +424,29 @@ void IntrRp::msgHandler() uint32_t * xirrAddress = reinterpret_cast<uint32_t*>(baseAddr + XIRR_OFFSET); - // type = XISR = XIRR[8:31] - // priority = XIRR[0:7] - // Use the XISR as the type (for now) - type = static_cast<ext_intr_t>(xirr & XISR_MASK); - TRACFCOMP(g_trac_intr, "External Interrupt received. XIRR=%x, PIR=%x", xirr,pir.word); + //An external interrupt comes from two paths + // 1) kernel space - synchronous - response needed + // 2) User space (coalesce interrupt) - asynchronous + // - no response needed, just free message + if (msg_is_async(msg)) + { + msg_free(msg); + } + else + { + // Acknowlege msg + msg->data[1] = 0; + msg_respond(iv_msgQ, msg); + } - // Acknowlege msg - msg->data[1] = 0; - msg_respond(iv_msgQ, msg); - + //Search if anyone is subscribed to the given + // interrupt source Registry_t::iterator r = iv_registry.find(type); - if(r != iv_registry.end() && - type != INTERPROC_XISR) //handle IPI after EOI, not here + + if(r != iv_registry.end() && type != INTERPROC_XISR) { msg_q_t msgQ = r->second.msgQ; @@ -399,11 +465,6 @@ void IntrRp::msgHandler() " handler. Ignoring it. rc = %d", (uint32_t) type, rc); } - - //Since non IPI EOIs are blocking fashion need to open - //up the interrupt priority to max (CPRR) - uint8_t *cppr = reinterpret_cast<uint8_t*>(xirrAddress); - *cppr = CPPR_ENABLE_ALL; //allow any INTR } else if (type == INTERPROC_XISR) { @@ -414,6 +475,11 @@ void IntrRp::msgHandler() // as well. This is to catch the case where no one // has registered for an IPI. } + else if (type == LSI_PSU) + { + TRACDCOMP(g_trac_intr, "PSU Interrupt Detected"); + handlePsuInterrupt(type); + } else // no queue registered for this interrupt type { // Throw it away for now. @@ -508,82 +574,54 @@ void IntrRp::msgHandler() case MSG_INTR_EOI: { - // Write the XIRR with the same value read earlier - // to signal EOI. XIRR value was stored in data[1] - // Only do this for non IPI types (type is in data[0]) + // Use standrard EOI (End of Interrupt) sequence if(msg->data[0] != INTERPROC_XISR) { - // Passed in as upper word of data[1] - uint32_t xirr = static_cast<uint32_t>(msg->data[1]>>32); - // data[1] (lower word) has the PIR - uint64_t l_data0 = (msg->data[1] & 0xFFFFFFFF); - PIR_t pir = static_cast<PIR_t>(l_data0); - - uint64_t baseAddr = iv_baseAddr + cpuOffsetAddr(pir); - uint32_t * xirrAddress = - reinterpret_cast<uint32_t*>(baseAddr + XIRR_OFFSET); - - xirr |= CPPR_MASK; //set all CPPR bits - allow any INTR - *xirrAddress = xirr; - - TRACDCOMP(g_trac_intr, - "EOI issued. XIRR=%x, PIR=%x", - xirr,pir); + uint64_t intSource = msg->data[0]; + sendEOI(intSource); } msg_free(msg); } break; - - case MSG_INTR_REGISTER_MSGQ: { + msg_q_t l_msgQ = reinterpret_cast<msg_q_t>(msg->data[0]); uint64_t l_type = msg->data[1]; - ISNvalue_t l_intr_type = static_cast<ISNvalue_t> + LSIvalue_t l_intr_type = static_cast<LSIvalue_t> (l_type & 0xFFFF); - errlHndl_t err = registerInterruptISN(l_msgQ,l_type >> 32, - l_intr_type); - if(!err) + errlHndl_t err = registerInterruptXISR(l_msgQ, l_type >> 32, + l_intr_type); + if (err) { - err = initXIVR(l_intr_type, true); + TRACFCOMP(g_trac_intr, + "IntrRp::msgHandler MSG_INTR_REGISTER_MSGQ error " + "registering handler for interrupt type: %lx", + l_intr_type); } - - msg->data[1] = reinterpret_cast<uint64_t>(err); - msg_respond(iv_msgQ,msg); - } - break; - - case MSG_INTR_UNREGISTER_MSGQ: - { - TRACFCOMP(g_trac_intr, - "INTR remove registration of interrupt type = 0x%lx", - msg->data[0]); - ISNvalue_t l_type = static_cast<ISNvalue_t>(msg->data[0]); - msg_q_t msgQ = unregisterInterruptISN(l_type); - - if(msgQ) + else { - //shouldn't get an error since we found a queue - //Just commit it - errlHndl_t err = initXIVR(l_type, false); - if(err) + //Enable (aka unmask) Interrupts for the source being + // registered for + err = unmaskInterruptSource(l_intr_type); + if (err) { - errlCommit(err,INTR_COMP_ID); + TRACFCOMP(g_trac_intr, + "IntrRp::msgHandler MSG_INTR_REGISTER_MSGQ error" + " unmasking interrupt type: %lx", + l_intr_type); } } - msg->data[1] = reinterpret_cast<uint64_t>(msgQ); - - TRACDCOMP(g_trac_intr, - "UNREG: msgQ = 0x%lx", - msg->data[1]); - + msg->data[1] = reinterpret_cast<uint64_t>(err); msg_respond(iv_msgQ,msg); } break; - + case MSG_INTR_UNREGISTER_MSGQ: + //TODO RTC 150260 add functionality + break; case MSG_INTR_ENABLE: { errlHndl_t err = enableInterrupts(); @@ -594,12 +632,13 @@ void IntrRp::msgHandler() case MSG_INTR_DISABLE: { - errlHndl_t err =disableInterrupts(); + errlHndl_t err = disableInterrupts(); msg->data[1] = reinterpret_cast<uint64_t>(err); msg_respond(iv_msgQ,msg); } break; +#ifdef CONFIG_ENABLE_P9_IPI // Called when a new cpu becomes active other than the master // Expect a call for each new core case MSG_INTR_ADD_CPU: @@ -627,7 +666,7 @@ void IntrRp::msgHandler() continue; } pir.threadId = thread; - initInterruptPresenter(pir); + //wh_p9 initInterruptPresenter(pir); sendIPI(pir); } @@ -636,7 +675,7 @@ void IntrRp::msgHandler() reinterpret_cast<void*>(pir.word)); } break; - +#endif case MSG_INTR_ADD_CPU_TIMEOUT: { PIR_t pir = msg->data[0]; @@ -684,46 +723,6 @@ void IntrRp::msgHandler() msg_respond(iv_msgQ, msg); } break; - - case MSG_INTR_ENABLE_PSI_INTR: - { - TARGETING::Target * target = - reinterpret_cast<TARGETING::Target *>(msg->data[0]); - errlHndl_t err = initIRSCReg(target); - msg->data[1] = reinterpret_cast<uint64_t>(err); - msg_respond(iv_msgQ,msg); - } - break; - - case MSG_INTR_ISSUE_SBE_MBOX_WA: - { - //The SBE IPI injection on master winkle wakeup - //can clobber a pending mailbox interrupt in the ICP - //To workaround need to issue EOI on mailbox. If - //mbx intr is not hot this does nothing, if it is - //then the EOI will cause intr to be represented - - //This is safe on FSPless since the PSI intr are - //always setup on master chip - uint64_t baseAddr = iv_baseAddr + - cpuOffsetAddr(iv_masterCpu); - uint32_t * xirrAddress = - reinterpret_cast<uint32_t*>(baseAddr + XIRR_OFFSET); - - //Generate the mailbox IRSN for this group - uint32_t l_irsn = makeXISR(iv_masterCpu, ISN_FSI); - l_irsn |= CPPR_MASK; //set all CPPR bits - allow any INTR - - TRACFCOMP(g_trac_intr, - "MBX SBE WA Issue EOI to %x",l_irsn); - *xirrAddress = l_irsn; //Issue EOI - - // Acknowlege msg - msg->data[1] = 0; - msg_respond(iv_msgQ, msg); - } - break; - case MSG_INTR_SHUTDOWN: { TRACFCOMP(g_trac_intr,"Shutdown event received"); @@ -733,7 +732,7 @@ void IntrRp::msgHandler() } break; - +#ifdef CONFIG_MPIPL_ENABLED //TODO RTC 134431 case MSG_INTR_ADD_HBNODE: // node info for mpipl { errlHndl_t err = addHbNodeToMpiplSyncArea(msg->data[0]); @@ -744,7 +743,7 @@ void IntrRp::msgHandler() msg_free(msg); // async message } break; - +#endif case MSG_INTR_DRAIN_QUEUE: { //The purpose of this message is allow the @@ -761,379 +760,370 @@ void IntrRp::msgHandler() } } +errlHndl_t IntrRp::sendEOI(uint64_t& i_intSource) +{ + //Send an EOI to the Power bus using the PSIHB ESB Space + //This is done with a read to the page specific to the interrupt source. + //Each interrupt source gets one page + uint64_t * l_psiHbPowerBusEoiAddr = + iv_psiHbEsbBaseAddr + ((i_intSource)*PAGE_SIZE)/sizeof(uint64_t); + errlHndl_t l_err = NULL; + do { -errlHndl_t IntrRp::setBAR(TARGETING::Target * i_target, - const PIR_t i_pir) -{ - errlHndl_t err = NULL; + uint64_t eoiRead = *l_psiHbPowerBusEoiAddr; + if (eoiRead != 0) + { + TRACFCOMP(g_trac_intr, ERR_MRK"IntrRp::sendEOI error sending EOI" + " to PSIHB ESB. EOI load returned: %x", eoiRead); + /*@ errorlog tag + * @errortype ERRL_SEV_UNRECOVERABLE + * @moduleid INTR::MOD_INTRRP_SENDEOI + * @reasoncode INTR::RC_PSIHB_ESB_EOI_FAIL + * @userdata1 Value read from EOI load + * @userdata2 Interrupt Source to issue EOI to + * @devdesc Unexpected RC from issuing PSIHB EOI store + */ + l_err = new ERRORLOG::ErrlEntry + ( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, // severity + INTR::MOD_INTRRP_SENDEOI, // moduleid + INTR::RC_PSIHB_ESB_EOI_FAIL, // reason code + eoiRead, // read value + i_intSource // interrupt source number + ); + break; + } - uint64_t barValue = 0; - barValue = i_target->getAttr<TARGETING::ATTR_INTP_BASE_ADDR>(); + TRACDCOMP(g_trac_intr, "IntrRp::sendEOI read response: %lx", eoiRead); - barValue <<= 14; - barValue |= 1ULL << (63 - ICPBAR_EN); + //EOI Part 2 - LSI ESB Internal to the IVPE + uint64_t * l_lsiEoi = iv_xiveIcBarAddress; + l_lsiEoi += XIVE_IC_LSI_EOI_OFFSET; + uint64_t l_intPending = *l_lsiEoi; - TRACFCOMP(g_trac_intr,"INTR: Target %p. ICPBAR value: 0x%016lx", - i_target,barValue); + //If an interrupt is pending, HB userspace will send a message to + // trigger the handling of a 'new' interrupt. In this situation the + // interrupt will not be triggered via the kernel. + if (l_intPending == 1) + { + //First acknowledge the interrupt so it won't be re-presented + acknowledgeInterrupt(); - uint64_t size = sizeof(barValue); + uint64_t l_data0 = LSI_INTERRUPT << 32; + if (iv_msgQ) + { + msg_t * int_msg = msg_allocate(); + int_msg->type = MSG_INTR_COALESCE; + int_msg->data[0] = reinterpret_cast<uint64_t>(l_data0); + int send_rc = msg_send(iv_msgQ, int_msg); + if (send_rc != 0) + { + TRACFCOMP(g_trac_intr, ERR_MRK"IntrRp::sendEOI error " + "sending coalesce message"); + /*@ errorlog tag + * @errortype ERRL_SEV_UNRECOVERABLE + * @moduleid INTR::MOD_INTRRP_SENDEOI + * @reasoncode INTR::RC_MESSAGE_SEND_ERROR + * @userdata1 RC from msg_send command + * @devdesc Error encountered sending coalesce + * message to INTRP + */ + l_err = new ERRORLOG::ErrlEntry + ( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, // severity + INTR::MOD_INTRRP_SENDEOI, // moduleid + INTR::RC_MESSAGE_SEND_ERROR, // reason code + send_rc, + 0 + ); + break; + } + } + } + } while(0); - err = deviceWrite(i_target, - &barValue, - size, - DEVICE_SCOM_ADDRESS(ICPBAR_SCOM_ADDR)); + return l_err; +} - if(err) +errlHndl_t IntrRp::maskAllInterruptSources(void) +{ + errlHndl_t l_err = NULL; + for (uint8_t i = 0; i < LSI_LAST_SOURCE; i++) { - TRACFCOMP(g_trac_intr,ERR_MRK"Unable to set IPCBAR"); + TRACDCOMP(g_trac_intr, "MaskInterruptSource: %d", i); + l_err = maskInterruptSource(i); + if (l_err) + { + TRACFCOMP(g_trac_intr, "Error Masking Interrupt source: %x", i); + break; + } } - return err; + TRACDCOMP(g_trac_intr, EXIT_MRK"MaskAllInterruptSources"); + return l_err; } -errlHndl_t IntrRp::getPsiIRSN(TARGETING::Target * i_target, - uint32_t& o_irsn, uint32_t& o_num) +errlHndl_t IntrRp::maskInterruptSource(uint8_t l_intr_source) { - errlHndl_t err = NULL; + errlHndl_t l_err = NULL; + uint64_t * l_psiHbEsbptr = iv_psiHbEsbBaseAddr; + l_psiHbEsbptr += + (((l_intr_source*PAGE_SIZE)+PSI_BRIDGE_ESB_OFF_OFFSET)/sizeof(uint64_t)); - // Setup PHBISR - // EN.TPC.PSIHB.PSIHB_ISRN_REG set to 0x00030003FFFF0000 - PSIHB_ISRN_REG_t reg; - size_t scom_len = sizeof(uint64_t); - o_num = ISN_HOST; //Hardcoded based on HB knowledge of HW + uint64_t l_maskRead = *l_psiHbEsbptr; + TRACDCOMP(g_trac_intr, "Mask read result: %lx", l_maskRead); - do{ - err = deviceRead - ( i_target, - ®, - scom_len, - DEVICE_SCOM_ADDRESS(PSIHB_ISRN_REG_t::PSIHB_ISRN_REG)); +/* + TODO RTC 150260 - if(err) - { - break; - } + //Perform 2nd read to verify in OFF state + l_maskRead = *l_psiHbEsbptr; + TRACDCOMP(g_trac_intr, "Mask read result: %lx", l_maskRead); - //only calc IRSN if downstream interrupts are enabled - o_irsn = 0; - if(reg.die == 1) //downstream interrupt enable = 1 - { - o_irsn = reg.irsn & reg.mask; - } - }while(0); + if (l_maskRead != ESB_STATE_OFF) + { + TRACFCOMP(g_trac_intr, "Error masking interrupt source: %x." + " ESB state is: %lx.", + l_intr_source, l_maskRead); + l_err = new ERRORLOG::ErrlEntry + ( + ERRORLOG::ERRL_SEV_INFORMATIONAL, // severity + INTR::MOD_INTRRP_MASKINTERRUPT, // moduleid + INTR::RC_XIVE_ESB_WRONG_STATE, // reason code + l_intr_source, + l_maskRead + ); - TRACFCOMP(g_trac_intr,"PSIHB_ISRN: 0x%x",o_irsn); + } +**/ - return err; + return l_err; } -errlHndl_t IntrRp::getNxIRSN(TARGETING::Target * i_target, - uint32_t& o_irsn, uint32_t& o_num) +errlHndl_t IntrRp::unmaskInterruptSource(uint8_t l_intr_source) { - errlHndl_t err = NULL; + errlHndl_t l_err = NULL; + uint64_t * l_psiHbEsbptr = iv_psiHbEsbBaseAddr; + l_psiHbEsbptr += + (((l_intr_source*PAGE_SIZE)+PSI_BRIDGE_ESB_RESET_OFFSET)/sizeof(uint64_t)); - size_t scom_len = sizeof(uint64_t); - uint64_t reg = 0x0; + uint64_t l_unmaskRead = *l_psiHbEsbptr; + TRACDCOMP(g_trac_intr, "Unmask read result: %lx", l_unmaskRead); - do{ - err = deviceRead - ( i_target, - ®, - scom_len, - DEVICE_SCOM_ADDRESS(NX_BUID_SCOM_ADDR)); - - if(err) - { - break; - } +/* TODO RTC 150260 - //only calc IRSN if downstream interrupts are enabled - o_irsn = 0; - if(reg &(1ull << (63-NX_BUID_ENABLE))) //reg has NX_BUID_ENABLE set - { - uint32_t l_mask = ((static_cast<uint32_t>(reg >> NX_IRSN_MASK_SHIFT) - & NX_IRSN_MASK_MASK) | NX_IRSN_UPPER_MASK); - - o_irsn = ((static_cast<uint32_t>(reg >> NX_IRSN_COMP_SHIFT) - & IRSN_COMP_MASK) & l_mask); - - //To get the number of interrupts, we need to "count" the 0 bits - //cheat by extending mask to FFF8 + mask, then invert and add 1 - o_num = (~((~IRSN_COMP_MASK) | l_mask)) +1; - } - }while(0); + //Read 2nd time to verify proper ESB state + l_unmaskRead = *l_psiHbEsbptr; + if (l_unmaskRead != ESB_STATE_RESET) + { + TRACFCOMP(g_trac_intr, "Error unmasking interrupt source: %x." + " ESB state is: %lx.", + l_intr_source, l_unmaskRead); - TRACFCOMP(g_trac_intr,"NX_ISRN: 0x%x, num: 0x%x",o_irsn, o_num); + l_err = new ERRORLOG::ErrlEntry + ( + ERRORLOG::ERRL_SEV_INFORMATIONAL, // severity + INTR::MOD_INTRRP_UNMASKINTERRUPT, // moduleid + INTR::RC_XIVE_ESB_WRONG_STATE, // reason code + l_intr_source, + l_unmaskRead + ); - return err; + } +**/ + return l_err; } -errlHndl_t IntrRp::initIRSCReg(TARGETING::Target * i_target) +errlHndl_t IntrRp::setInterruptBARs(TARGETING::Target * i_target) { - errlHndl_t err = NULL; - - // Only do once for each proc chip - if(std::find(iv_chipList.begin(),iv_chipList.end(),i_target) == - iv_chipList.end()) - { - uint8_t chip = 0; - uint8_t group = 0; + errlHndl_t l_err = NULL; - group = i_target->getAttr<ATTR_FABRIC_NODE_ID>(); - chip = i_target->getAttr<ATTR_FABRIC_CHIP_ID>(); + do { - size_t scom_len = sizeof(uint64_t); - - // Mask off interrupts from isn's on this target - // This also sets the source isn and PIR destination - // such that if an interrupt is pending when when the ISRN - // is written, simics get the right destination for the - // interrupt. err is from deviceWrite(...) - err = maskXIVR(i_target); - - if(!err) + l_err = setPsiHbBAR(i_target); + if (l_err) { - // Setup PHBISR - // EN.TPC.PSIHB.PSIHB_ISRN_REG set to 0x00030003FFFF0000 - PSIHB_ISRN_REG_t reg; - - PIR_t pir(0); - pir.groupId = group; - pir.chipId = chip; - // IRSN must be unique for each processor chip - reg.irsn = makeXISR(pir,0); - reg.die = PSIHB_ISRN_REG_t::ENABLE; - reg.uie = PSIHB_ISRN_REG_t::ENABLE; - reg.mask = PSIHB_ISRN_REG_t::IRSN_MASK; + TRACFCOMP(g_trac_intr, "Error setting PSIHB BAR"); + break; + } - TRACFCOMP(g_trac_intr,"PSIHB_ISRN_REG: 0x%016lx",reg.d64); + l_err = setPsiHbEsbBAR(i_target, true); + if (l_err) + { + TRACFCOMP(g_trac_intr, "Error setting PSIHB ESB BAR"); + break; + } - err = deviceWrite - ( i_target, - ®, - scom_len, - DEVICE_SCOM_ADDRESS(PSIHB_ISRN_REG_t::PSIHB_ISRN_REG)); + l_err = setXiveIcBAR(i_target); + if (l_err) + { + TRACFCOMP(g_trac_intr, "Error setting XIVE IC BAR"); + break; } - if(!err) + l_err = setXiveIvpeTmBAR1(i_target); + if (l_err) { - iv_chipList.push_back(i_target); + TRACFCOMP(g_trac_intr, "Error setting XIVE TM BAR1"); + break; } - } - return err; + } while (0); + + return l_err; } -errlHndl_t IntrRp::initXIVR(enum ISNvalue_t i_isn, bool i_enable) +errlHndl_t IntrRp::handlePsuInterrupt(ext_intr_t i_type) { - errlHndl_t err = NULL; + //TODO FIXME RTC 149698 + // Long term will leverage mask register to avoid + // polling loop below + errlHndl_t l_err = NULL; + uint32_t l_addr = PSI_BRIDGE_PSU_DOORBELL_REG; size_t scom_len = sizeof(uint64_t); - uint64_t scom_addr = 0; + uint64_t reg = 0x0; + uint64_t l_elapsed_time_ns = 0; + TARGETING::Target* procTarget = NULL; + TARGETING::targetService().masterProcChipTargetHandle( procTarget ); - //Don't do any of this for ISN_INTERPROC - if(ISN_INTERPROC != i_isn) + do { - //Setup the XIVR register - PsiHbXivr xivr; - PIR_t pir = intrDestCpuId(); - xivr.pir = pir.word; - xivr.source = i_isn; + l_err = deviceRead(procTarget, + ®, + scom_len, + DEVICE_SCOM_ADDRESS(l_addr)); - switch(i_isn) + if (l_err) { - case ISN_PSI: - xivr.priority = PsiHbXivr::PSI_PRIO; - scom_addr = PsiHbXivr::PSI_XIVR_ADRR; - break; - - case ISN_OCC: - xivr.priority = PsiHbXivr::OCC_PRIO; - scom_addr = PsiHbXivr::OCC_XIVR_ADRR; - break; - - case ISN_FSI: //FSP_MAILBOX - xivr.priority = PsiHbXivr::FSI_PRIO; - scom_addr = PsiHbXivr::FSI_XIVR_ADRR; - break; - - case ISN_LPC: - xivr.priority = PsiHbXivr::LPC_PRIO; - scom_addr = PsiHbXivr::LPC_XIVR_ADRR; - break; - - case ISN_LCL_ERR: - xivr.priority = PsiHbXivr::LCL_ERR_PRIO; - scom_addr = PsiHbXivr::LCL_ERR_XIVR_ADDR; + TRACFCOMP(g_trac_intr, "Error Reading PSU SCOM address: %lx", + l_addr); break; + } - case ISN_HOST: - xivr.priority = PsiHbXivr::HOST_PRIO; - scom_addr = PsiHbXivr::HOST_XIVR_ADRR; + //If the PSU Host Doorbell bit is on, wait for the + // PSU DD to handle + if (reg & PSI_BRIDGE_PSU_HOST_DOORBELL) + { + TRACDCOMP(g_trac_intr, "Host/SBE Mailbox " + "response. Wait for Polling to handle" + " response"); + nanosleep(0,10000); + l_elapsed_time_ns += 10000; + } + else + { + //Polling Complete break; - - default: //Unsupported ISN - TRACFCOMP(g_trac_intr,"Unsupported ISN: 0x%02x",i_isn); + } + if (l_elapsed_time_ns > MAX_PSU_LONG_TIMEOUT_NS) + { + TRACFCOMP(g_trac_intr, "PSU Timeout hit"); /*@ errorlog tag - * @errortype ERRL_SEV_INFORMATIONAL - * @moduleid INTR::MOD_INTR_INIT_XIVR - * @reasoncode INTR::RC_BAD_ISN - * @userdata1 Interrupt type to register - * @userdata2 0 - * - * @devdesc Unsupported ISN Requested - * + * @errortype ERRL_SEV_UNRECOVERABLE + * @moduleid INTR::MOD_INTRRP_HNDLPSUINTERRUPT + * @reasoncode INTR::RC_PSU_DOORBELL_TIMEOUT + * @userdata1 Scom Address with interrupt condition + * @userdata2 Register Value + * @devdesc PSU Doorbell Timeout hit waiting for doorbell + * interrupt condition to be cleared */ - err = new ERRORLOG::ErrlEntry + l_err = new ERRORLOG::ErrlEntry ( - ERRORLOG::ERRL_SEV_INFORMATIONAL, // severity - INTR::MOD_INTR_INIT_XIVR, // moduleid - INTR::RC_BAD_ISN, // reason code - static_cast<uint64_t>(i_isn), - 0 + ERRORLOG::ERRL_SEV_UNRECOVERABLE, // severity + INTR::MOD_INTRRP_HNDLPSUINTERRUPT, // moduleid + INTR::RC_PSU_DOORBELL_TIMEOUT, // reason code + l_addr, + reg ); + break; } - // Init the XIVR on all chips we have setup - // Note that this doesn't handle chips getting added midstream, - // But the current use case only has FSIMbox (1 chip) and - // ATTN (all chips) at stable points in the IPL - if(!err) - { - if(i_enable) - { - iv_isnList.push_back(i_isn); - } - else - { - xivr.priority = PsiHbXivr::PRIO_DISABLED; - - //Remove from isn list - ISNList_t::iterator itr = std::find(iv_isnList.begin(), - iv_isnList.end(), - i_isn); - if(itr != iv_isnList.end()) - { - iv_isnList.erase(itr); - } - } + } while(1); - for(ChipList_t::iterator target_itr = iv_chipList.begin(); - target_itr != iv_chipList.end(); ++target_itr) - { - err = deviceWrite - (*target_itr, - &xivr, - scom_len, - DEVICE_SCOM_ADDRESS(scom_addr)); + do { - if(err) - { - break; - } - } + if (l_err) + { + break; } - } - return err; -} + //Clear the PSU Scom Reg Interrupt Status register + uint64_t l_barValue = 0; + uint64_t size = sizeof(l_barValue); + l_err = deviceWrite(procTarget, + &l_barValue, + size, + DEVICE_SCOM_ADDRESS(l_addr)); -//---------------------------------------------------------------------------- + if (l_err) + { + TRACFCOMP(g_trac_intr, "Error clearing scom - %x", l_addr); + break; + } -// Set priority highest (disabled) ,but with valid PIR -errlHndl_t IntrRp::maskXIVR(TARGETING::Target *i_target) -{ - struct XIVR_INFO - { - ISNvalue_t isn:8; - uint32_t addr; - }; + //Issue standard EOI for the PSU Interupt + uint64_t intSource = i_type; + TRACDCOMP(g_trac_intr, "Sending PSU EOI"); + sendEOI(intSource); - static const XIVR_INFO xivr_info[] = - { - {ISN_PSI, PsiHbXivr::PSI_XIVR_ADRR}, - {ISN_OCC, PsiHbXivr::OCC_XIVR_ADRR}, - {ISN_FSI, PsiHbXivr::FSI_XIVR_ADRR}, - {ISN_LPC, PsiHbXivr::LPC_XIVR_ADRR}, - {ISN_LCL_ERR, PsiHbXivr::LCL_ERR_XIVR_ADDR}, - {ISN_HOST, PsiHbXivr::HOST_XIVR_ADRR} - }; + } while(0); - errlHndl_t err = NULL; - size_t scom_len = sizeof(uint64_t); - PIR_t pir = intrDestCpuId(); - PsiHbXivr xivr; + return l_err; +} - xivr.pir = pir.word; - xivr.priority = PsiHbXivr::PRIO_DISABLED; +errlHndl_t IntrRp::getNxIRSN(TARGETING::Target * i_target, + uint32_t& o_irsn, uint32_t& o_num) +{ + errlHndl_t err = NULL; - for(size_t i = 0; i < sizeof(xivr_info)/sizeof(xivr_info[0]); ++i) - { - xivr.source = xivr_info[i].isn; + size_t scom_len = sizeof(uint64_t); + uint64_t reg = 0x0; - err = deviceWrite - (i_target, - &xivr, - scom_len, - DEVICE_SCOM_ADDRESS(xivr_info[i].addr)); + do{ + err = deviceRead + ( i_target, + ®, + scom_len, + DEVICE_SCOM_ADDRESS(NX_BUID_SCOM_ADDR)); if(err) { break; } - } - return err; -} - -//---------------------------------------------------------------------------- - -errlHndl_t IntrRp::registerInterruptISN(msg_q_t i_msgQ, - uint32_t i_msg_type, - ext_intr_t i_intr_type) -{ - errlHndl_t err = NULL; - //INTERPROC is special -- same for all procs - if(i_intr_type == ISN_INTERPROC) - { - err = registerInterruptXISR(i_msgQ, i_msg_type, - INTERPROC_XISR); - } - else - { - //Register interrupt type on all present procs - for(ChipList_t::iterator target_itr = iv_chipList.begin(); - target_itr != iv_chipList.end(); ++target_itr) + //only calc IRSN if downstream interrupts are enabled + o_irsn = 0; + if(reg &(1ull << (63-NX_BUID_ENABLE))) //reg has NX_BUID_ENABLE set { - uint8_t chip = 0; - uint8_t node = 0; - node = (*target_itr)->getAttr<ATTR_FABRIC_NODE_ID>(); - chip = (*target_itr)->getAttr<ATTR_FABRIC_CHIP_ID>(); + uint32_t l_mask = ((static_cast<uint32_t>(reg >> NX_IRSN_MASK_SHIFT) + & NX_IRSN_MASK_MASK) | NX_IRSN_UPPER_MASK); - PIR_t pir(0); - pir.groupId = node; - pir.chipId = chip; - uint32_t l_irsn = makeXISR(pir, i_intr_type); + o_irsn = ((static_cast<uint32_t>(reg >> NX_IRSN_COMP_SHIFT) + & IRSN_COMP_MASK) & l_mask); - err = registerInterruptXISR(i_msgQ, i_msg_type, l_irsn); - if(err) - { - break; - } + //To get the number of interrupts, we need to "count" the 0 bits + //cheat by extending mask to FFF8 + mask, then invert and add 1 + o_num = (~((~IRSN_COMP_MASK) | l_mask)) +1; } - } + }while(0); + + + TRACFCOMP(g_trac_intr,"NX_ISRN: 0x%x, num: 0x%x",o_irsn, o_num); + return err; } +//---------------------------------------------------------------------------- errlHndl_t IntrRp::registerInterruptXISR(msg_q_t i_msgQ, uint32_t i_msg_type, ext_intr_t i_xisr) { errlHndl_t err = NULL; - Registry_t::iterator r = iv_registry.find(i_xisr); + if(r == iv_registry.end()) { TRACFCOMP(g_trac_intr,"INTR::register intr type 0x%x", i_xisr); @@ -1166,38 +1156,6 @@ errlHndl_t IntrRp::registerInterruptXISR(msg_q_t i_msgQ, return err; } -msg_q_t IntrRp::unregisterInterruptISN(ISNvalue_t i_intr_type) -{ - msg_q_t msgQ = NULL; - - //INTERPROC is special -- same for all procs - if(i_intr_type == ISN_INTERPROC) - { - msgQ = unregisterInterruptXISR(INTERPROC_XISR); - } - else - { - //Unregister interrupt type on all present procs - for(ChipList_t::iterator target_itr = iv_chipList.begin(); - target_itr != iv_chipList.end(); ++target_itr) - { - uint8_t chip = 0; - uint8_t node = 0; - node = (*target_itr)->getAttr<ATTR_FABRIC_NODE_ID>(); - chip = (*target_itr)->getAttr<ATTR_FABRIC_CHIP_ID>(); - - PIR_t pir(0); - pir.groupId = node; - pir.chipId = chip; - uint32_t l_irsn = makeXISR(pir, i_intr_type); - - msgQ = unregisterInterruptXISR(l_irsn); - } - } - - return msgQ; -} - msg_q_t IntrRp::unregisterInterruptXISR(ext_intr_t i_xisr) { msg_q_t msgQ = NULL; @@ -1212,91 +1170,6 @@ msg_q_t IntrRp::unregisterInterruptXISR(ext_intr_t i_xisr) return msgQ; } -void IntrRp::initInterruptPresenter(const PIR_t i_pir) const -{ - uint64_t baseAddr = iv_baseAddr + cpuOffsetAddr(i_pir); - uint8_t * cppr = - reinterpret_cast<uint8_t*>(baseAddr + CPPR_OFFSET); - uint32_t * plinkReg = - reinterpret_cast<uint32_t *>(baseAddr + LINKA_OFFSET); - - TRACDCOMP(g_trac_intr,"PIR 0x%x offset: 0x%lx", - i_pir.word, - cpuOffsetAddr(i_pir)); - - if(i_pir.word == iv_masterCpu.word) - { - *cppr = 0xff; // Allow all interrupts - } - else - { - // Allow Wake-up IPIs only - // link regs route non-IPIs to iv_masterCPU) anyway - // IPC IPIs are only directed at iv_masterCpu - *cppr = IPI_USR_PRIO + 1; - } - - // Links are intended to be set up in rings. If an interrupt ends up - // where it started, it gets rejected by hardware. - // - // According to BOOK IV, The links regs are setup by firmware. - // - // Should be possible to link all interrupt forwarding directly to - // the master core and either make them direct (lspec = 0) or by setting - // the LOOPTRIP bit to stop the forwarding at the masterProc. - // - LinkReg_t linkReg; - linkReg.word = 0; - linkReg.loopTrip = 1; // needed? - linkReg.node = iv_masterCpu.groupId; - linkReg.pchip= iv_masterCpu.chipId; - linkReg.pcore= iv_masterCpu.coreId; - linkReg.tspec= iv_masterCpu.threadId; - - *(plinkReg) = linkReg.word; - *(plinkReg + 1) = linkReg.word; - linkReg.last = 1; - *(plinkReg + 2) = linkReg.word; -} - - - -void IntrRp::disableInterruptPresenter(const PIR_t i_pir) const -{ - uint64_t baseAddr = iv_baseAddr + cpuOffsetAddr(i_pir); - uint8_t * cppr = - reinterpret_cast<uint8_t*>(baseAddr + CPPR_OFFSET); - uint32_t * plinkReg = - reinterpret_cast<uint32_t *>(baseAddr + LINKA_OFFSET); - - // non- side effect xirr register - uint32_t * xirrAddr = - reinterpret_cast<uint32_t *>(baseAddr + XIRR_RO_OFFSET); - - uint32_t xirr = *xirrAddr & 0x00FFFFFF; - - TRACDCOMP(g_trac_intr,"PIR 0x%x offset: 0x%lx", - i_pir.word, - cpuOffsetAddr(i_pir)); - - // Not sure if this will ever happen, but squawk alittle if it does - if(xirr) - { - TRACFCOMP(g_trac_intr, - ERR_MRK - "Pending interrupt found on shutdown. CpuId:0x%x XIRR:0x%x", - i_pir.word, - xirr); - } - - *cppr = 0; // Set priority to most favored (off) - - *plinkReg = 0; // Reset link registers - clear all forwarding - *(plinkReg + 1) = 0; - *(plinkReg + 2) = 0; -} - - void IntrRp::sendIPI(const PIR_t i_pir) const { uint64_t baseAddr = iv_baseAddr + cpuOffsetAddr(i_pir); @@ -1340,7 +1213,6 @@ errlHndl_t IntrRp::checkAddress(uint64_t i_addr) void IntrRp::shutDown(uint64_t i_status) { - errlHndl_t err = NULL; msg_t * rmsg = msg_allocate(); // Call everyone and say shutting down! @@ -1367,51 +1239,25 @@ void IntrRp::shutDown(uint64_t i_status) msg_free(rmsg); - // Reset the PSI regs - // NOTE: there is nothing in the IRSN Proposal.odt document that - // specifies a procedure or order for disabling interrupts. - // @see RTC story 47105 discussion for Firmware & Hardware requirements - // - - //Going to clear the XIVRs first - ISNList_t l_isnList = iv_isnList; - for(ISNList_t::iterator isnItr = l_isnList.begin(); - isnItr != l_isnList.end();++isnItr) - { - //shouldn't get an error since we found a queue - //so just commit it - err = initXIVR((*isnItr), false); - if(err) - { - errlCommit(err,INTR_COMP_ID); - err = NULL; - } - } - - PSIHB_ISRN_REG_t reg; //zeros self - size_t scom_len = sizeof(reg); - - for(ChipList_t::iterator target_itr = iv_chipList.begin(); - target_itr != iv_chipList.end(); ++target_itr) - { - err = deviceWrite - (*target_itr, - ®, - scom_len, - DEVICE_SCOM_ADDRESS(PSIHB_ISRN_REG_t::PSIHB_ISRN_REG)); - - if(err) - { - errlCommit(err,INTR_COMP_ID); - err = NULL; - } - } + //TODO FIXME RTC 149694 - Workaround to set proper PSIHB ESB BAR for PHYP + TARGETING::Target* procTarget = NULL; + TARGETING::targetService().masterProcChipTargetHandle( procTarget ); + TRACDCOMP(g_trac_intr, "Disable PSIHB ESB BAR"); + setPsiHbEsbBAR(procTarget, false); + //Reset PSIHB Interrupt Space + TRACDCOMP(g_trac_intr, "Reset PSIHB Interrupt Space"); + PSIHB_SW_INTERFACES_t * this_psihb_ptr = iv_psiHbBaseAddr; + this_psihb_ptr->icr = PSI_BRIDGE_INTP_STATUS_CTL_RESET; + TRACDCOMP(g_trac_intr, "Reset PSIHB INTR Complete"); - // Reset the IP hardware regiseters + //Reset XIVE Interrupt unit + resetIntUnit(); + // Reset the IP hardware registers iv_cpuList.push_back(iv_masterCpu); +#ifdef CONFIG_ENABLE_P9_IPI size_t threads = cpu_thread_count(); uint64_t en_threads = get_enabled_threads(); @@ -1429,14 +1275,17 @@ void IntrRp::shutDown(uint64_t i_status) continue; } pir.threadId = thread; - disableInterruptPresenter(pir); + //wh_p9 disableInterruptPresenter(pir); } } +#endif TRACFCOMP(g_trac_intr,INFO_MRK"INTR is shutdown"); } //---------------------------------------------------------------------------- +#ifdef CONFIG_MPIPL_ENABLED + errlHndl_t IntrRp::hw_disableRouting(TARGETING::Target * i_proc, INTR_ROUTING_t i_rx_tx) { @@ -1453,7 +1302,8 @@ errlHndl_t IntrRp::hw_disableRouting(TARGETING::Target * i_proc, i_proc, ®, scom_len, - DEVICE_SCOM_ADDRESS(PSIHB_ISRN_REG_t::PSIHB_ISRN_REG) + DEVICE_SCOM_ADDRESS(PSIHB_ISRN_REG_t::PSIHB_STATUS_CTL_REG) + ); if(err) @@ -1478,7 +1328,7 @@ errlHndl_t IntrRp::hw_disableRouting(TARGETING::Target * i_proc, i_proc, ®, scom_len, - DEVICE_SCOM_ADDRESS(PSIHB_ISRN_REG_t::PSIHB_ISRN_REG) + DEVICE_SCOM_ADDRESS(PSIHB_ISRN_REG_t::PSIHB_STATUS_CTL_REG) ); if(err) @@ -1578,9 +1428,11 @@ errlHndl_t IntrRp::hw_disableRouting(TARGETING::Target * i_proc, } while(0); return err; } +#endif //---------------------------------------------------------------------------- +#ifdef CONFIG_MPIPL_ENABLED errlHndl_t IntrRp::hw_resetIRSNregs(TARGETING::Target * i_proc) { errlHndl_t err = NULL; @@ -1661,9 +1513,10 @@ errlHndl_t IntrRp::hw_resetIRSNregs(TARGETING::Target * i_proc) } while(0); return err; } +#endif //---------------------------------------------------------------------------- - +#ifdef CONFIG_MPIPL_ENABLED errlHndl_t IntrRp::blindIssueEOIs(TARGETING::Target * i_proc) { errlHndl_t err = NULL; @@ -1767,7 +1620,7 @@ errlHndl_t IntrRp::blindIssueEOIs(TARGETING::Target * i_proc) } while(0); return err; } - +#endif //---------------------------------------------------------------------------- @@ -1933,7 +1786,7 @@ void IntrRp::disableAllInterrupts(TARGETING::Target* i_core) for(size_t thread = 0; thread < threads; ++thread) { pir.threadId = thread; - disableInterruptPresenter(pir); + //wh_p9 disableInterruptPresenter(pir); } } @@ -2014,7 +1867,7 @@ void IntrRp::drainMpIplInterrupts(TARGETING::TargetHandleList & i_cores) } - +#ifdef CONFIG_MPIPL_ENABLED errlHndl_t IntrRp::hw_disableIntrMpIpl() { errlHndl_t err = NULL; @@ -2162,7 +2015,7 @@ errlHndl_t IntrRp::hw_disableIntrMpIpl() } while(0); return err; } - +#endif errlHndl_t syncNodesError(void * i_p, uint64_t i_len) { @@ -2311,7 +2164,7 @@ errlHndl_t IntrRp::syncNodes(intr_mpipl_sync_t i_sync_type) return err; } - +#ifdef CONFIG_MPIPL_ENABLED errlHndl_t IntrRp::initializeMpiplSyncArea() { errlHndl_t err = NULL; @@ -2371,7 +2224,9 @@ errlHndl_t IntrRp::initializeMpiplSyncArea() } return err; } +#endif +#ifdef CONFIG_MPIPL_ENABLED errlHndl_t IntrRp::addHbNodeToMpiplSyncArea(uint64_t i_hbNode) { errlHndl_t err = NULL; @@ -2420,7 +2275,9 @@ errlHndl_t IntrRp::addHbNodeToMpiplSyncArea(uint64_t i_hbNode) } return err; } +#endif +#ifdef CONFIG_MPIPL_ENABLED errlHndl_t IntrRp::extractHbNodeInfo(void) { errlHndl_t err = NULL; @@ -2488,7 +2345,7 @@ errlHndl_t IntrRp::extractHbNodeInfo(void) return err; } - +#endif //---------------------------------------------------------------------------- // External interfaces @@ -2503,6 +2360,7 @@ errlHndl_t INTR::registerMsgQ(msg_q_t i_msgQ, // Can't add while handling an interrupt, so // send msg instead of direct call msg_q_t intr_msgQ = msg_q_resolve(VFS_ROOT_MSG_INTR); + if(intr_msgQ) { msg_t * msg = msg_allocate(); @@ -2524,7 +2382,6 @@ errlHndl_t INTR::registerMsgQ(msg_q_t i_msgQ, } msg_free(msg); - } else { @@ -2547,6 +2404,7 @@ errlHndl_t INTR::registerMsgQ(msg_q_t i_msgQ, 0 ); } + return err; } @@ -2671,59 +2529,208 @@ errlHndl_t INTR::disableExternalInterrupts() return err; } -errlHndl_t INTR::enablePsiIntr(TARGETING::Target * i_target) +errlHndl_t IntrRp::setPsiHbBAR(TARGETING::Target * i_target) { - errlHndl_t err = NULL; - msg_q_t intr_msgQ = msg_q_resolve(VFS_ROOT_MSG_INTR); - if(intr_msgQ) - { - msg_t * msg = msg_allocate(); - msg->type = MSG_INTR_ENABLE_PSI_INTR; - msg->data[0] = reinterpret_cast<uint64_t>(i_target); + errlHndl_t l_err = NULL; + uint64_t l_baseBarValue = + i_target->getAttr<TARGETING::ATTR_PSI_BRIDGE_BASE_ADDR>(); - msg_sendrecv(intr_msgQ, msg); + do { + //Get base BAR Value from attribute + uint64_t l_barValue = l_baseBarValue; - err = reinterpret_cast<errlHndl_t>(msg->data[1]); - msg_free(msg); - } - else + TRACFCOMP(g_trac_intr,"INTR: Setting PSI BRIDGE Bar Address value for -" + " Target %p. PSI BRIDGE BAR value: 0x%016lx", + i_target,l_barValue); + + //Set base BAR Value + uint64_t size = sizeof(l_barValue); + l_err = deviceWrite(i_target, + &l_barValue, + size, + DEVICE_SCOM_ADDRESS(PSI_BRIDGE_BAR_SCOM_ADDR)); + + if(l_err) + { + TRACFCOMP(g_trac_intr,ERR_MRK"Unable to set PSI BRIDGE BAR Address"); + break; + } + + //Now set the enable bit + l_barValue += PSI_BRIDGE_BAR_ENABLE; + size = sizeof(l_barValue); + + TRACDCOMP(g_trac_intr,"INTR: Setting PSI BRIDGE Bar enable value for Target - %p. PSI BRIDGE BAR value: 0x%016lx", + i_target,l_barValue); + + l_err = deviceWrite(i_target, + &l_barValue, + size, + DEVICE_SCOM_ADDRESS(PSI_BRIDGE_BAR_SCOM_ADDR)); + + if(l_err) + { + TRACFCOMP(g_trac_intr,ERR_MRK"Error enabling PSIHB BAR"); + break; + } + + //Map Memory Internally for HB and store in member variable + void *l_psiHbAddress = + reinterpret_cast<void *>(l_baseBarValue); + iv_psiHbBaseAddr = + reinterpret_cast<PSIHB_SW_INTERFACES_t *> + (mmio_dev_map(l_psiHbAddress, PAGE_SIZE)); + } while(0); + + return l_err; +} + +errlHndl_t IntrRp::setPsiHbEsbBAR(TARGETING::Target * i_target, + bool i_enable) +{ + errlHndl_t l_err = NULL; + uint64_t l_baseBarValue + = i_target->getAttr<TARGETING::ATTR_PSI_HB_ESB_ADDR>(); + + do { + + uint64_t l_barValue = l_baseBarValue; + TRACDCOMP(g_trac_intr,"INTR: Target %p. " + "PSI BRIDGE ESB BAR value: 0x%016lx", + i_target,l_barValue); + + uint64_t size = sizeof(l_barValue); + l_err = deviceWrite(i_target, + &l_barValue, + size, + DEVICE_SCOM_ADDRESS(PSI_BRIDGE_ESB_BAR_SCOM_ADDR)); + + if(l_err) + { + TRACFCOMP(g_trac_intr,ERR_MRK"Unable to set PSIHB ESB BAR "); + break; + } + + //If we are trying to enable this BAR register + if (i_enable) + { + l_barValue += PSI_BRIDGE_ESB_BAR_VALID; + TRACDCOMP(g_trac_intr,"INTR: Target %p. PSI BRIDGE ESB BAR value: 0x%016lx", + i_target,l_barValue); + + size = sizeof(l_barValue); + l_err = deviceWrite(i_target, + &l_barValue, + size, + DEVICE_SCOM_ADDRESS(PSI_BRIDGE_ESB_BAR_SCOM_ADDR)); + + if(l_err) + { + TRACFCOMP(g_trac_intr,ERR_MRK"Error setting PSIHB ESB BAR"); + break; + } + + //Map Memory Internally for HB and store in member variable + void *l_psiHbEoiAddress = + reinterpret_cast<void *>(l_baseBarValue); + iv_psiHbEsbBaseAddr = + reinterpret_cast<uint64_t *> + (mmio_dev_map(l_psiHbEoiAddress, (LSI_LAST_SOURCE)*PAGE_SIZE)); + } + + } while (0); + + return l_err; +} + +errlHndl_t IntrRp::setXiveIvpeTmBAR1(TARGETING::Target * i_target) +{ + errlHndl_t l_err = NULL; + uint64_t l_baseBarValue = + i_target->getAttr<TARGETING::ATTR_XIVE_THREAD_MGMT1_BAR_ADDR>(); + + do { - /*@ errorlog tag - * @errortype ERRL_SEV_INFORMATIONAL - * @moduleid INTR::MOD_INTR_ENABLE_PSI_INTR - * @reasoncode INTR::RC_RP_NOT_INITIALIZED - * @userdata1 MSG_INTR_ENABLE_PSI_INTR - * @userdata2 0 - * - * @devdesc Interrupt resource provider not initialized yet. - * - */ - err = new ERRORLOG::ErrlEntry - ( - ERRORLOG::ERRL_SEV_INFORMATIONAL, // severity - INTR::MOD_INTR_ENABLE_PSI_INTR, // moduleid - INTR::RC_RP_NOT_INITIALIZED, // reason code - static_cast<uint64_t>(MSG_INTR_ENABLE_PSI_INTR), - 0 - ); - } - return err; + uint64_t l_barValue = l_baseBarValue + XIVE_IVPE_TM_BAR1_VALIDATE; + + TRACDCOMP(g_trac_intr,"INTR: Target %p. XIVE IVPE TM BAR1 value: 0x%016lx", + i_target,l_barValue); + + uint64_t size = sizeof(l_barValue); + l_err = deviceWrite(i_target, + &l_barValue, + size, + DEVICE_SCOM_ADDRESS(XIVE_IVPE_TM_BAR1_SCOM_ADDR)); + + if(l_err) + { + TRACFCOMP(g_trac_intr,ERR_MRK"Unable to set XIVE IVPE TM BAR1"); + break; + } + + //Map Memory Internally for HB and store in member variable + void *l_xiveTmBar1Address = + reinterpret_cast<void *>(l_baseBarValue); + iv_xiveTmBar1Address = + reinterpret_cast<uint64_t *> + (mmio_dev_map(l_xiveTmBar1Address, PAGE_SIZE)); + + } while(0); + + return l_err; +} + + +errlHndl_t IntrRp::setXiveIcBAR(TARGETING::Target * i_target) +{ + errlHndl_t l_err = NULL; + uint64_t l_baseBarValue + = i_target->getAttr<TARGETING::ATTR_XIVE_CONTROLLER_BAR_ADDR>(); + + do { + uint64_t l_barValue = l_baseBarValue + XIVE_IC_BAR_VALID; + + TRACDCOMP(g_trac_intr,"INTR: Target %p. XIVE IC BAR value: 0x%016lx", + i_target,l_barValue); + + uint64_t size = sizeof(l_barValue); + l_err = deviceWrite(i_target, + &l_barValue, + size, + DEVICE_SCOM_ADDRESS(XIVE_IC_BAR_SCOM_ADDR)); + + if(l_err) + { + TRACFCOMP(g_trac_intr,ERR_MRK"Unable to set XIVE IC BAR"); + break; + } + + //Map Memory Internally for HB and store in member variable + void *l_xiveIcBarAddress = + reinterpret_cast<void *>(l_baseBarValue); + iv_xiveIcBarAddress = + reinterpret_cast<uint64_t *> + (mmio_dev_map(l_xiveIcBarAddress, 40*PAGE_SIZE)); + + } while(0); + + return l_err; } -uint64_t INTR::getIntpAddr(const TARGETING::Target * i_ex, uint8_t i_thread) +uint64_t INTR::getIntpAddr(const TARGETING::Target * i_ec, uint8_t i_thread) { - const TARGETING::Target * l_proc = getParentChip(i_ex); + const TARGETING::Target * l_proc = getParentChip(i_ec); uint64_t l_intB =l_proc->getAttr<TARGETING::ATTR_INTP_BASE_ADDR>(); PIR_t pir(0); - pir.groupId = l_proc->getAttr<TARGETING::ATTR_FABRIC_NODE_ID>(); + pir.groupId = l_proc->getAttr<TARGETING::ATTR_FABRIC_GROUP_ID>(); pir.chipId = l_proc->getAttr<TARGETING::ATTR_FABRIC_CHIP_ID>(); - pir.coreId = i_ex->getAttr<TARGETING::ATTR_CHIP_UNIT>(); + pir.coreId = i_ec->getAttr<TARGETING::ATTR_CHIP_UNIT>(); pir.threadId = i_thread; return (l_intB+ InterruptMsgHdlr::mmio_offset( - pir.word & (InterruptMsgHdlr::P8_PIR_THREADID_MSK | - InterruptMsgHdlr::P8_PIR_COREID_MSK))); + pir.word & (InterruptMsgHdlr::P9_PIR_THREADID_MSK | + InterruptMsgHdlr::P9_PIR_COREID_MSK))); } void* INTR::IntrRp::handleCpuTimeout(void* _pir) @@ -2797,9 +2804,6 @@ errlHndl_t INTR::addHbNode(uint64_t i_hbNode) return err; } -/* - * Drain interrupt message queue (if present) - */ void INTR::drainQueue() { // send a sync message if queue is found @@ -2808,9 +2812,7 @@ void INTR::drainQueue() { msg_t * msg = msg_allocate(); msg->type = MSG_INTR_DRAIN_QUEUE; - msg_sendrecv(intr_msgQ, msg); - msg_free(msg); } //else no queue, no need to do anything diff --git a/src/usr/intr/intrrp.H b/src/usr/intr/intrrp.H index ca0fa83aa..23fd8c74c 100644 --- a/src/usr/intr/intrrp.H +++ b/src/usr/intr/intrrp.H @@ -92,7 +92,9 @@ namespace INTR IntrRp() : iv_msgQ(NULL), iv_baseAddr(0), - iv_masterCpu(0) {} + iv_masterCpu(0), + iv_psiHbBaseAddr(NULL), + iv_psiHbEsbBaseAddr(NULL) {} /** * Destructor @@ -142,6 +144,7 @@ namespace INTR PE0_IRSN_MASK_SCOM_ADDR = 0x0201201B, //INTR IRSN mask PE0_BAREN_SCOM_ADDR = 0x02012045, //INTR enable/disable + PE1_IRSN_COMP_SCOM_ADDR = 0x0201241A, //INTR IRSN compare PE1_IRSN_MASK_SCOM_ADDR = 0x0201241B, //INTR IRSN mask PE1_BAREN_SCOM_ADDR = 0x02012445, //INTR enable/disable @@ -161,6 +164,56 @@ namespace INTR PSI_HBCR_AND_SCOM_ADDR = 0x02010913, IPI_USR_PRIO = 0x2, //<! IPI priority from USR space + + LSI_INTERRUPT = 0xC000, + + //PSI Host Bridge Constants + PSI_BRIDGE_BAR_SCOM_ADDR = 0x0501290A, + PSI_BRIDGE_BAR_ENABLE = 0x0000000000000001ULL, + PSI_BRIDGE_ENABLE_CEC_INTERRUPT = 0x1000000000000000ULL, + PSI_BRIDGE_ESB_BAR_SCOM_ADDR = 0x05012916, + + //PSI Host Bridge ESB Constants + PSI_BRIDGE_ESB_BAR_VALID = 0x0000000000000001ULL, + PSI_BRIDGE_ESB_OFF_OFFSET = 0xD00, + PSI_BRIDGE_ESB_RESET_OFFSET = 0XC00, + PSI_BRIDGE_PSU_DOORBELL_REG = 0x000D0063, + PSI_BRIDGE_PSU_HOST_DOORBELL = 0x8000000000000000, + + //XIVE Interrupt Controller Constants + XIVE_IC_BAR_SCOM_ADDR = 0x05013010, + XIVE_IC_BAR_VALID = 0x8000000000000000ULL, + XIVE_IC_PHYSICAL_THREAD_ENABLE_OFFSET = 0x400, + XIVE_IC_BAR_INT_PC_MMIO_REG_OFFSET = + XIVE_IC_PHYSICAL_THREAD_ENABLE_OFFSET/sizeof(uint64_t), + XIVE_IC_THREAD0_ENABLE = 0x8000000000000000ULL, + XIVE_IC_ESB_EOI_OFFSET = 0x3000, + XIVE_IC_LSI_EOI_OFFSET = + XIVE_IC_ESB_EOI_OFFSET/sizeof(uint64_t), + + //XIVE IVPE (Presentation Engine) Constants + XIVE_IVPE_TM_BAR1_SCOM_ADDR = 0x05013012, + XIVE_IVPE_TM_BAR1_MMIO_OFFSET = 0x0006020000000000ULL, + XIVE_IVPE_TM_BAR1_VALIDATE = 0x8000000000000000ULL, + XIVE_IVPE_QW3_OFFSET = 0x38, + XIVE_IVPE_QW3_LSI_ENABLE = 0x81000000, + + PSI_BRIDGE_INTP_STATUS_CTL_SCOM_ADDR = 0x0501290E, + PSI_BRIDGE_INTP_STATUS_CTL_ENABLE = 0x8000000000000000ULL, + PSI_BRIDGE_INTP_STATUS_CTL_RESET = 0x4000000000000000ULL, + + XIVE_RESET_INT_CQ_RST_CTL_SCOM_ADDR = 0x05013023, + XIVE_RESET_POWERBUS_QUIESCE_ENABLE = 0x4000000000000000, + XIVE_RESET_POWERBUS_QUIESCE_TIMEOUT = 1000000, //1 millisecond + XIVE_RESET_UNIT_ENABLE = 0x8000000000000000, + ACK_HYPERVISOR_INT_REG_OFFSET = 0x830/sizeof(uint16_t), + POWERBUS_STATE_QUIESCE = 0xC000000000000000, + MAX_PSU_LONG_TIMEOUT_NS = 100000*NS_PER_MSEC, + + ESB_STATE_RESET = 0, + ESB_STATE_OFF = 1, + ESB_STATE_PENDING = 2, + ESB_STATE_QUEUED = 3, }; enum INTR_ROUTING_t @@ -199,88 +252,76 @@ namespace INTR }; }; - /** - * This is the Interrupt Requestoer Source Compare Register. - * See Book IV, PSI chapter. - */ - struct PSIHB_ISRN_REG_t + //Derived from 15.8 PSIHB Software Interfaces of the + // P9 Pervasive Workbook + struct PSIHB_SW_INTERFACES_t { - enum - { - //PSIHB_ISRN_REG_t values. See book IV & P8 scom reg defn. - DISABLE = 0, - ENABLE = 1, - IRSN_MASK = 0x7FFF8, //!< IRSN bits - PSIHB_ISRN_REG = 0x0201091b, //!< ISRN SCOM Address - }; - - union - { - uint64_t d64; - - struct - { - uint64_t irsn:19; //!< IRSN compare reg - uint64_t res1:10; //!< zeros - uint64_t reset:1; //!< ICS Reset - uint64_t die:1; //!< Downstream Interrupt Enable - uint64_t uie:1; //!< Upstream Interrupt Enable - uint64_t mask:19; //!< IRSN Compare Mask - uint64_t res2:13; //!< zeros - } PACKED; - }; - - /** - * Default Contructor - */ - PSIHB_ISRN_REG_t() : d64(0) {} + uint64_t psihbbar; //Host Bridge Base Address Register - 0x0 + uint64_t fspbar; //FSP Base Address Register - 0x8 + uint64_t fspmmr; //FSP Memory Mask Register - 0x10 + uint64_t reserved1; //Unused / Reserved + uint64_t psihbcr; //PSI Host Bridge Ctrl/Status Register - 0x20 + uint64_t psisemr; //PSIHB Status / Error Mask Register - 0x28 + uint64_t reserved2; //Unused / Reserved + uint64_t phbdsr; //PSIHB Debug Setting register - 0x38 + uint64_t phbscr; //PSI Host Bridge Ctrl/Status Register - 0x40 + uint64_t phbccr; //PSI Host Bridge clear ctl/status reg - 0x48 + uint64_t dmaupaddr; //DMA Upper Address Register - 0x50 + uint64_t icr; //Interrupt Control Register - 0x58 + uint64_t esbciaddr; //ESB CI Base Address - 0x60 + uint64_t esbnotifaddr; //ESB Notification Address - 0x68 + uint64_t ivtofforig; //IVT Offset Origin Register - 0x70 + uint64_t lsiintlevel; //LSI Int Level Register (lab use) - 0x78 + uint64_t lsiintstatus; //LSI Interrupt Status register - 0x80 }; - /** - * @brief PsiHbXivr Layout for XIVR registers. - */ - struct PsiHbXivr + //Found in the PC Register Specification Document + struct XIVE_IC_THREAD_CONTEXT_t { - enum - { - PRIO_DISABLED = 0xff, - - OCC_PRIO = 0x30, - FSI_PRIO = 0x20, - LPC_PRIO = 0x40, - LCL_ERR_PRIO = 0x10, - HOST_PRIO = 0x50, - PSI_PRIO = 0x60, - - PSI_XIVR_ADRR = 0x02010910, - OCC_XIVR_ADRR = 0x02010916, - FSI_XIVR_ADRR = 0x02010917, - LPC_XIVR_ADRR = 0x02010918, - LCL_ERR_XIVR_ADDR = 0x02010919, - HOST_XIVR_ADRR = 0x0201091A, - }; - - - union - { - uint64_t u64; - - struct - { - uint64_t res1:8; // zeros - uint64_t pir:14; // interrupt destination (server) - uint64_t linkptr:2; // which link reg in intr presenter - uint64_t priority:8; // intr priority level - uint64_t source:3; // source number - uint64_t res2:4; // zeros - uint64_t intr_pend:25; // interrupt is pending - } PACKED; - }; - - PsiHbXivr() : u64(0) {} + uint64_t tctxt_cfg; // 0x00 + uint64_t tctxt_track; // 0x08 + uint64_t unused0; // 0x10 + uint64_t unused1; // 0x18 + uint64_t ind_thread_context_access0; //0x20 + uint64_t ind_thread_context_access1; //0x28 + uint64_t ind_thread_context_access2; //0x30 + uint64_t ind_thread_context_access3; //0x38 + uint64_t phys_thread_enable0; //0x40 + uint64_t phys_thread_enable0_set; //0x48 + uint64_t phys_thread_enable0_reset; //0x50 + uint64_t unused3; //0x58 + uint64_t phys_thread_enable1; //0x60 + uint64_t phys_thread_enable1_set; //0x68 + uint64_t phys_thread_enable1_reset; //0x70 }; + //Found in External Interrupt Virtualization Engine (XIVE) Document + // in Chapter 4.4 - Per Thread Interrupt Management Area + struct XIVE_IVPE_THREAD_CONTEXT_t + { + uint64_t qw0_0; + uint64_t qw0_1; + uint64_t qw1_0; + uint64_t qw1_1; + uint64_t qw2_0; + uint64_t qw2_1; + uint8_t nsr; //Notification Source Register - 0x0 + uint8_t cppr; //Current processor priority register - 0x1 + uint8_t ipb; //Interrupt pending buffer - 0x2 + uint8_t lsmfb; //logical server most favored backlog - 0x3 + uint8_t ack; //O/S Interrupt Acknowledge Counter - 0x4 + uint8_t inc; //Age increment - 0x5 + uint8_t age; //Thread age since last selected - 0x6 + uint8_t pipr; //Pending Interrupt Priority Register - 0x7 + uint32_t cams; //qw0/1/2/3 - 0x8 + }; + #define PSIHB_SW_INTERFACES_SIZE (sizeof(PSIHB_SW_INTERFACES_t)) + #define XIVE_IVPE_THREAD_CONTEXT_SIZE (sizeof(XIVE_IVPE_THREAD_CONTEXT_t)) + /** + * This is the Interrupt Requester Source Compare Register. + * See Book IV, PSI chapter. + */ struct intr_response_t { msg_q_t msgQ; @@ -318,6 +359,11 @@ namespace INTR Registry_t iv_registry; //!< registered interrupt type uint64_t iv_baseAddr; //!< Base address of hw INTR regs PIR_t iv_masterCpu; //!< Master cpu PIR + + PSIHB_SW_INTERFACES_t *iv_psiHbBaseAddr; //INTR PSIHB regs base addr + uint64_t *iv_psiHbEsbBaseAddr; //INTR PSIHB ESB regs base addr + uint64_t *iv_xiveIcBarAddress; //XIVE Controller regs base addr + uint64_t *iv_xiveTmBar1Address; //Xive Thread mgmt bar reg 1 addr CpuList_t iv_cpuList; //!< Other CPU chips ChipList_t iv_chipList; //!< Proc chips with PSI intr enabled ISNList_t iv_isnList; //!< List of ISN's to clear on shutdown @@ -410,12 +456,91 @@ namespace INTR void sendIPI(const PIR_t i_pir) const; /** - * Set the IPCBAR scom register + * Mask all PSIHB Interrupt Sources which will block any + * interrupts from the PSIHB to be sent to the HB kernel. + * @return Errorlog from masking the sources + */ + errlHndl_t maskAllInterruptSources(void); + + /** + * Mask specific PSIHB Interrupt source + * @param[in] i_intr_source, The interrupt source to be masked + * @return Errorlog from masking the source + */ + errlHndl_t maskInterruptSource(uint8_t i_intr_source); + + /** + * Unmask (enable) specific PSIHB Interrupt source + * @param[in] i_intr_source, The interrupt source to be unmasked + * @return Errorlog from unmasking the source + */ + errlHndl_t unmaskInterruptSource(uint8_t i_intr_source); + + /** + * Set all of the Interrupt BAR scom registers * @param[in] i_target, the Target. - * @param[in] i_pir, The pir for this processor + * @return Errorlog from DeviceWrite + */ + errlHndl_t setInterruptBARs(TARGETING::Target * i_target); + + /** + * Perform HW Functions to acknowledge Interrupt which will + * stop the interrupt from being re-presented by HW + */ + void acknowledgeInterrupt(void); + + /** + * Send EOI (End of Interrupt) sequence + * @param[in] i_intSource, interrupt source to perform EOI for + * @return Errorlog from DeviceWrite + */ + errlHndl_t sendEOI(uint64_t& i_intSource); + + /** + * Handle Interrupt from PSU Source + * - Acknowledge Interrupt + * - Clear Interrupt Condition + * - Issue EOI + * @param[in] i_type, interrupt type encountered + * @return Errorlog from DeviceWrite + */ + errlHndl_t handlePsuInterrupt(ext_intr_t i_type); + + /** + * Set the PSI Host Bridge BAR scom register + * @param[in] i_target, the Target. + * @return Errorlog from DeviceWrite + */ + errlHndl_t setPsiHbBAR(TARGETING::Target * i_target); + + /** + * Set the PSI Host Bridge ESB BAR scom register + * @param[in] i_target, the Target. + * @param[in] i_enable, indicator to enable/disable the BAR + * @return Errorlog from DeviceWrite + */ + errlHndl_t setPsiHbEsbBAR(TARGETING::Target * i_target, + bool i_enable); + + /** + * Set the XIVE Thread Management (TM) BAR1 scom register + * @param[in] i_target, the Target. + * @return Errorlog from DeviceWrite + */ + errlHndl_t setXiveIvpeTmBAR1(TARGETING::Target * i_target); + + /** + * Set the XIVE Interrupt Controller (IC) BAR scom register + * @param[in] i_target, the Target. + * @return Errorlog from DeviceWrite + */ + errlHndl_t setXiveIcBAR(TARGETING::Target * i_target); + + /** + * Reset Interrupt Unit (both the XIVE and PSIHB Interrupt Units) + * @return Errorlog from DeviceWrite */ - errlHndl_t setBAR(TARGETING::Target * i_target, - const PIR_t i_pir); + errlHndl_t resetIntUnit(); /** * Initialize the IRSCReg to enable PSI to present interrupts diff --git a/src/usr/intr/test/intrtest.H b/src/usr/intr/test/intrtest.H index 320f38a12..a1d6ee3bd 100644 --- a/src/usr/intr/test/intrtest.H +++ b/src/usr/intr/test/intrtest.H @@ -5,7 +5,9 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* COPYRIGHT International Business Machines Corp. 2011,2014 */ +/* Contributors Listed Below - COPYRIGHT 2011,2016 */ +/* [+] 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. */ @@ -49,7 +51,7 @@ class IntrTest: public CxxTest::TestSuite */ void test_verifyState( void ) { - +/* TODO RTC 150260 uint32_t * addr = reinterpret_cast<uint32_t *>(iv_masterAddr); if(*addr != 0xFF000000) // XIRR ro reg @@ -95,6 +97,7 @@ class IntrTest: public CxxTest::TestSuite } // Potentially could check all link registers on other chips +**/ } /** @@ -103,6 +106,7 @@ class IntrTest: public CxxTest::TestSuite void test_enableDisable( void ) { +/* TODO RTC 150260 uint32_t * addr = reinterpret_cast<uint32_t *>(iv_masterAddr); errlHndl_t err = INTR::disableExternalInterrupts(); @@ -133,6 +137,7 @@ class IntrTest: public CxxTest::TestSuite { TS_FAIL("INTR not enabled. Addr %p", addr); } +**/ } // This checks the enablePsiIntr. Even though the master proc @@ -141,6 +146,7 @@ class IntrTest: public CxxTest::TestSuite // to test with. void test_enablePsi( void ) { +/* TODO RTC 150260 errlHndl_t err = NULL; if( TARGETING::is_vpo() ) { @@ -156,10 +162,12 @@ class IntrTest: public CxxTest::TestSuite TS_FAIL("Errl from INTER::enablePsiIntr"); errlCommit(err,INTR_COMP_ID); } +**/ } void test_mpipl_node_data( void ) { +/* TODO RTC 150260 errlHndl_t err = NULL; for(uint64_t hb_node = 0; hb_node < MAX_NODES_PER_SYS; ++hb_node) { @@ -221,16 +229,24 @@ class IntrTest: public CxxTest::TestSuite { TS_FAIL("INTR Could not map memory of NODE_DATA_AREA"); } - +**/ } IntrTest() : CxxTest::TestSuite() { +/* TODO RTC 150260 + TARGETING::Target* procTarget = NULL; + TARGETING::targetService().masterProcChipTargetHandle( procTarget ); + // Set the Interrupt BAR Scom Registers + l_err = setInterruptBARs(procTarget); + iv_baseAddr = reinterpret_cast<uint64_t> (mmio_dev_map(reinterpret_cast<void*>(cv_realAddr),THIRTYTWO_MB)); - TRACDCOMP(g_trac_intr,"IntrTest()> iv_baseAddr=0x%.X",iv_baseAddr); + TRACFCOMP(g_trac_intr,"IntrTest()> iv_baseAddr=0x%.X",iv_baseAddr); + + task_affinity_pin(); // pin this task to current cpu task_affinity_migrate_to_master(); // Move to the master cpu @@ -238,7 +254,7 @@ class IntrTest: public CxxTest::TestSuite // Get the master cpu id, thread 0 iv_masterPIR = task_getcpuid(); - TRACDCOMP(g_trac_intr,"IntrTest()> iv_masterPIR=0x%.X",iv_masterPIR); + TRACFCOMP(g_trac_intr,"IntrTest()> iv_masterPIR=0x%.X",iv_masterPIR); iv_masterPIR &= 0xFFFFFFF8; @@ -246,24 +262,31 @@ class IntrTest: public CxxTest::TestSuite iv_masterAddr = InterruptMsgHdlr::mmio_offset(iv_masterPIR) + iv_baseAddr; +**/ }; ~IntrTest() { +/* TODO RTC 150260 mmio_dev_unmap(reinterpret_cast<void*>(iv_baseAddr)); +**/ }; private: +/* TODO RTC 150260 uint64_t iv_baseAddr; uint64_t iv_masterAddr; cpuid_t iv_masterPIR; static const uint64_t cv_realAddr; +**/ }; +/* TODO RTC 150260 //note: this must be changed if the BAR changes const uint64_t IntrTest::cv_realAddr = 0x3ffff80000000ul; +**/ diff --git a/src/usr/isteps/istep14/call_proc_exit_cache_contained.C b/src/usr/isteps/istep14/call_proc_exit_cache_contained.C index a3a11e59e..f62982465 100644 --- a/src/usr/isteps/istep14/call_proc_exit_cache_contained.C +++ b/src/usr/isteps/istep14/call_proc_exit_cache_contained.C @@ -289,14 +289,15 @@ void* call_proc_exit_cache_contained (void *io_pArgs) // End of Add P9 - Fake trigger for memory expansion //Set PSI and FSP BARs, activate the PSI link BAR - uint64_t psi = l_masterProc->getAttr<ATTR_PSI_BRIDGE_BASE_ADDR>(); + //TODO RTC 150260 Re-evaluate if this should be deleted or enabled +// uint64_t psi = l_masterProc->getAttr<ATTR_PSI_BRIDGE_BASE_ADDR>(); uint64_t fsp = l_masterProc->getAttr<ATTR_FSP_BASE_ADDR>(); - psi |= 0x1; //turn on enable bit for PSI, FSP is in PSI Init HWP +// psi |= 0x1; //turn on enable bit for PSI, FSP is in PSI Init HWP - l_errl = deviceWrite( l_masterProc, - &psi, - scom_size, - DEVICE_SCOM_ADDRESS(0x0501290a) ); +// l_errl = deviceWrite( l_masterProc, +// &psi, +// scom_size, +// DEVICE_SCOM_ADDRESS(0x0501290a) ); if ( l_errl ) { // Create IStep error log and cross reference to error that diff --git a/src/usr/mbox/mailboxsp.C b/src/usr/mbox/mailboxsp.C index 9f8a90d24..e3a2c2dbf 100644 --- a/src/usr/mbox/mailboxsp.C +++ b/src/usr/mbox/mailboxsp.C @@ -46,7 +46,7 @@ #include <sys/misc.h> #include <errl/errludprintk.H> #include <errno.h> -#include <sys/time.h> +#include <kernel/console.H> #include <arch/pirformat.H> // Local functions @@ -112,49 +112,6 @@ void* MailboxSp::msg_handler(void * unused) return NULL; } -// helper function to start mailbox message handler -// @todo RTC:126643 Remove poller when interrupts avail -void* MailboxSp::poller(void * unused) -{ - TRACFCOMP(g_trac_mbox, "start MBOX::pollTask"); - Singleton<MailboxSp>::instance().pollTask(); - return NULL; -} - -// @todo RTC:126643 Remove pollTask when interrupts avail -void MailboxSp::pollTask() -{ - int rc = 0; - - msg_q_t mboxQ = msg_q_resolve(VFS_ROOT_MSG_MBOX); - if(mboxQ) - { - //Loop until there is a shutdown request AND quiesced - while(!(iv_shutdown_msg && quiesced())) - { - msg_t * msg = msg_allocate(); - msg->type = MSG_INTR; - msg->data[0] = 0; - msg->data[1] = 0; - - rc = msg_sendrecv(mboxQ, msg); - - msg_free(msg); - - if (rc) - { - TRACFCOMP(g_trac_mbox, ERR_MRK - "MBOX::pollTask msg_sendrecv() failed. errno = %d", - rc); - break; - } - - nanosleep(0, NS_PER_MSEC*100); - } - } -} - - errlHndl_t MailboxSp::_init() { errlHndl_t err = NULL; @@ -197,20 +154,21 @@ errlHndl_t MailboxSp::_init() if(mbxComm) { - // Initialize the mailbox hardware - err = mboxInit(iv_trgt); + //TODO RTC 150260 Move after init after mask issues resolved + // Register to get interrupts for mailbox + err = INTR::registerMsgQ(iv_msgQ, + MSG_INTR, + INTR::LSI_FSIMBOX); + if (err) { return err; } -#if (0) // @todo RTC:126643 - // Register to get interrupts for mailbox - err = INTR::registerMsgQ(iv_msgQ, - MSG_INTR, - INTR::FSP_MAILBOX); -#endif - if(err) + // Initialize the mailbox hardware + err = mboxInit(iv_trgt); + + if (err) { return err; } @@ -242,9 +200,6 @@ errlHndl_t MailboxSp::_init() MSG_MBOX_SHUTDOWN, INITSERVICE::MBOX_PRIORITY); - //@todo RTC:126643 -- poll mbox until interrupts are working - task_create(MailboxSp::poller, NULL); - } // else leave iv_disabled as true; @@ -287,20 +242,21 @@ void MailboxSp::msgHandler() continue; } + printkd("mbox received type: %d\n", (uint32_t) msg->type); + // Now look for other messages switch(msg->type) { // Interrupt from the mailbox hardware case MSG_INTR: { + printkd("MSG_INTR type - handling interrupt\n"); err = handleInterrupt(); -#if 0 // @todo RTC:126643 Remove poller and turn on when interrupts are working + + printkd("MSG_INTR type - sending EOI\n"); // Respond to the interrupt handler regardless of err INTR::sendEOI(iv_msgQ,msg); -#else - msg_respond(iv_msgQ,msg); -#endif // err will be set if scom failed in mbox DD // or MBOX_DATA_WRITE_ERR - serious - assert diff --git a/src/usr/targeting/common/genHwsvMrwXml.pl b/src/usr/targeting/common/genHwsvMrwXml.pl index 0775db90b..6d80bdc07 100755 --- a/src/usr/targeting/common/genHwsvMrwXml.pl +++ b/src/usr/targeting/common/genHwsvMrwXml.pl @@ -3347,8 +3347,14 @@ sub generate_proc 0x0006030203180000 + $nodeSize*$lognode + $chipSize*$logid ); printf( " </attribute>\n" ); + #XIVE - Thread Management Bar Address register 1 + printf( " <attribute><id>XIVE_THREAD_MGMT1_BAR_ADDR</id>\n" ); + printf( " <default>0x%016X</default>\n", + 0x0006020000000000 + $nodeSize*$lognode + $chipSize*$logid ); + printf( " </attribute>\n" ); + #PSI HB - ESP space address - printf( " <attribute><id>PSI_HB_ESP_ADDR</id>\n" ); + printf( " <attribute><id>PSI_HB_ESB_ADDR</id>\n" ); printf( " <default>0x%016X</default>\n", 0x00060302031C0000 + $nodeSize*$lognode + $chipSize*$logid ); printf( " </attribute>\n" ); diff --git a/src/usr/targeting/common/xmltohb/attribute_types.xml b/src/usr/targeting/common/xmltohb/attribute_types.xml index be09f240c..ad989a825 100644 --- a/src/usr/targeting/common/xmltohb/attribute_types.xml +++ b/src/usr/targeting/common/xmltohb/attribute_types.xml @@ -17360,7 +17360,20 @@ firmware notes: Platforms should initialize this attribute to AUTO (0)</descript </attribute> <attribute> - <id>PSI_HB_ESP_ADDR</id> + <id>XIVE_THREAD_MGMT1_BAR_ADDR</id> + <description>XIVE - Thread Management Bar address register 1 + MMIO consumed by HB/PHYP + </description> + <simpleType> + <uint64_t></uint64_t> + </simpleType> + <persistency>non-volatile</persistency> + <readable/> +</attribute> + + +<attribute> + <id>PSI_HB_ESB_ADDR</id> <description>PSIHB - ESB space address - MMIO consumed by PHYP </description> <simpleType> diff --git a/src/usr/targeting/common/xmltohb/simics_NIMBUS.system.xml b/src/usr/targeting/common/xmltohb/simics_NIMBUS.system.xml index c6deca575..3682337c1 100644 --- a/src/usr/targeting/common/xmltohb/simics_NIMBUS.system.xml +++ b/src/usr/targeting/common/xmltohb/simics_NIMBUS.system.xml @@ -217,6 +217,15 @@ <attribute><id>PSI_BRIDGE_BASE_ADDR</id> <default>0x0006030203000000</default> </attribute> + <attribute><id>PSI_HB_ESB_ADDR</id> + <default>0x00060302031C0000</default> + </attribute> + <attribute><id>XIVE_CONTROLLER_BAR_ADDR</id> + <default>0x0006030203100000</default> + </attribute> + <attribute><id>XIVE_THREAD_MGMT1_BAR_ADDR</id> + <default>0x0006020000000000</default> + </attribute> <attribute><id>INTP_BASE_ADDR</id> <default>0x0003FFFF80300000</default> </attribute> diff --git a/src/usr/targeting/common/xmltohb/target_types.xml b/src/usr/targeting/common/xmltohb/target_types.xml index efe6a3d8a..f7ca36667 100755 --- a/src/usr/targeting/common/xmltohb/target_types.xml +++ b/src/usr/targeting/common/xmltohb/target_types.xml @@ -2125,7 +2125,8 @@ <attribute><id>NVIDIA_PHY1_REG_ADDR</id></attribute> <attribute><id>XIVE_CONTROLLER_BAR_ADDR</id></attribute> <attribute><id>XIVE_PRESENTATION_BAR_ADDR</id></attribute> - <attribute><id>PSI_HB_ESP_ADDR</id></attribute> + <attribute><id>PSI_HB_ESB_ADDR</id></attribute> + <attribute><id>XIVE_THREAD_MGMT1_BAR_ADDR</id></attribute> <attribute><id>NX_RNG_ADDR</id></attribute> <!-- end Memory Map --> |