summaryrefslogtreecommitdiffstats
path: root/src/usr/intr
diff options
context:
space:
mode:
authorBill Hoffa <wghoffa@us.ibm.com>2015-10-15 13:59:58 -0500
committerDaniel M. Crowell <dcrowell@us.ibm.com>2016-03-30 16:24:17 -0400
commit6b5097872a33a20d4c03f995ca8f1585b9e43e53 (patch)
treeb97d48402b8e54b14d1ce554191bbeb78890d09c /src/usr/intr
parent550f30129f455317e65610cd90e9d06b2018e4c1 (diff)
downloadtalos-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/usr/intr')
-rw-r--r--src/usr/intr/intrrp.C1556
-rw-r--r--src/usr/intr/intrrp.H285
-rw-r--r--src/usr/intr/test/intrtest.H33
3 files changed, 1012 insertions, 862 deletions
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,
+ &reg,
+ 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,
- &reg,
- 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,
- &reg,
- 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,
- &reg,
- 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,
+ &reg,
+ 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,
+ &reg,
+ 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,
- &reg,
- 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,
&reg,
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,
&reg,
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;
+**/
OpenPOWER on IntegriCloud