summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBill Hoffa <wghoffa@us.ibm.com>2018-01-09 13:04:33 -0600
committerChristian R. Geddes <crgeddes@us.ibm.com>2018-01-15 21:31:09 -0500
commitf7a5547478eae53e6623164b8faacfaf6e721cb1 (patch)
treed4c1d20fbc5dee0157e8c2fc8d28e150e474a746
parentc1c9e46c08466cb6edaa3939e5238a5cb742634d (diff)
downloadtalos-hostboot-f7a5547478eae53e6623164b8faacfaf6e721cb1.tar.gz
talos-hostboot-f7a5547478eae53e6623164b8faacfaf6e721cb1.zip
Interrupt Handling Flow Change to Prevent Deadlock
- Previously the End of Interrupt (EOI) message was sent after the registered interrupt handler completed handling of the defect. Instead of this, now the INTRP will immediately mask the current interrupt source and issue the HW EOI to allow other interrupt sources to present. - Later when the registered interrupt handler sends INTRP its EOI message the INTRP will unmask the source and issue the necessary HW EOI to fully clear the interrupt Change-Id: I01c99ca9fdd0cedcf3d313127a8d56f5cda66bc7 CQ: SW413511 Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/51691 Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com> Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com> Tested-by: Jenkins OP HW <op-hw-jenkins+hostboot@us.ibm.com> Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com> Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com> Reviewed-by: Christian R. Geddes <crgeddes@us.ibm.com>
-rw-r--r--src/include/usr/intr/intr_reasoncodes.H3
-rw-r--r--src/usr/intr/intrrp.C293
-rw-r--r--src/usr/intr/intrrp.H30
3 files changed, 208 insertions, 118 deletions
diff --git a/src/include/usr/intr/intr_reasoncodes.H b/src/include/usr/intr/intr_reasoncodes.H
index 8ab758519..4101e2380 100644
--- a/src/include/usr/intr/intr_reasoncodes.H
+++ b/src/include/usr/intr/intr_reasoncodes.H
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2016 */
+/* Contributors Listed Below - COPYRIGHT 2011,2018 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -49,6 +49,7 @@ namespace INTR
MOD_INTRRP_UNMASKINTERRUPT = 0x0F, /**< intrrp.C : INTR::unmaskInterruptSource */
MOD_INTRRP_HNDLPSUINTERRUPT = 0x10, /**< intrrp.C : INTR::handlePsuInterrupt */
MOD_INTRRP_RESETINTUNIT = 0x11, /**< intrrp.C : IntrRp::resetIntUnit */
+ MOD_INTRRP_XIVE_SENDEOI = 0x12,
};
enum IntrReasonCode
diff --git a/src/usr/intr/intrrp.C b/src/usr/intr/intrrp.C
index 7396e5009..e961f6395 100644
--- a/src/usr/intr/intrrp.C
+++ b/src/usr/intr/intrrp.C
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2017 */
+/* Contributors Listed Below - COPYRIGHT 2011,2018 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -970,7 +970,11 @@ void IntrRp::msgHandler()
{
uint64_t intSource = msg->data[0];
PIR_t l_pir = msg->data[1];
- sendEOI(intSource, l_pir);
+ //The physical HW EOI is issued as the defect is
+ // discovered. At this point we just need to remove
+ // the pending interrupt obj and unmasking the
+ // interrupt source to properly handle new ints
+ completeInterruptProcessing(intSource, l_pir);
}
msg_free(msg);
}
@@ -1192,6 +1196,70 @@ void IntrRp::msgHandler()
}
}
+errlHndl_t IntrRp::sendXiveEOI(uint64_t& i_intSource, PIR_t& i_pir)
+{
+ errlHndl_t l_err = NULL;
+
+ do {
+ //The XIVE HW is expecting these MMIO accesses to come from the
+ // core/thread they were setup (master core, thread 0)
+ // These functions will ensure this code executes there
+ task_affinity_pin();
+ task_affinity_migrate_to_master();
+
+ //LSI ESB Internal to the IVPE of the Master Proc
+ volatile uint64_t * l_lsiEoi = iv_masterHdlr->xiveIcBarAddr;
+ l_lsiEoi += XIVE_IC_LSI_EOI_OFFSET;
+ uint64_t l_intPending = *l_lsiEoi;
+
+ //MMIO Complete, rest of code can run on any thread
+ task_affinity_unpin();
+
+ //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)
+ {
+ TRACFCOMP(g_trac_intr, "IntrRp::Need to acknowledge interrupt\n");
+ //First acknowledge the interrupt so it won't be re-presented
+ acknowledgeInterrupt();
+
+ 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_XIVE_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_XIVE_SENDEOI, // moduleid
+ INTR::RC_MESSAGE_SEND_ERROR, // reason code
+ send_rc,
+ 0
+ );
+ break;
+ }
+ }
+ }
+ } while(0);
+
+ return l_err;
+}
+
errlHndl_t IntrRp::sendEOI(uint64_t& i_intSource, PIR_t& i_pir)
{
intr_hdlr_t* l_proc = NULL;
@@ -1217,52 +1285,6 @@ errlHndl_t IntrRp::sendEOI(uint64_t& i_intSource, PIR_t& i_pir)
}
do {
-
- //Check if we found a matching proc handler for the interrupt to EOI
- if (l_proc == NULL)
- {
- TRACFCOMP(g_trac_intr, ERR_MRK"IntrRp::sendEOI couldn't find proc"
- " handler that matches pir: 0x%lx", i_pir);
- break;
- }
- else
- {
- //Make object to search pending interrupt
- // list for
- std::pair<PIR_t, ext_intr_t> l_intr = std::make_pair(
- i_pir,
- static_cast<ext_intr_t>(i_intSource));
-
- //See if an interrupt with from Proc with
- // the same PIR + interrupt source are
- // still being processed
- auto l_found = std::find_if(
- iv_pendingIntr.begin(),
- iv_pendingIntr.end(),
- [&l_intr](auto k)->bool
- {
- return (k.first == l_intr.first) &&
- (k.second == l_intr.second);
- });
-
- if (l_found == iv_pendingIntr.end())
- {
- TRACFCOMP(g_trac_intr, ERR_MRK"IntrRp::msgHandler() Pending"
- "Interrupt NOT found for pir: 0x%lx,"
- " interrupt type: %d. Ignoring.",
- i_pir, static_cast<ext_intr_t>(i_intSource));
- }
- else
- {
- //Delete pending interrupt for source type
- TRACFCOMP(g_trac_intr, "IntrRp::sendEOI() Removing pending"
- " interrupt for pir: 0x%lx, interrupt type: %d",
- i_pir, static_cast<ext_intr_t>(i_intSource));
- iv_pendingIntr.erase(l_found);
- }
- }
-
-
//The XIVE HW is expecting these MMIO accesses to come from the
// core/thread they were setup (master core, thread 0)
// These functions will ensure this code executes there
@@ -1305,60 +1327,8 @@ errlHndl_t IntrRp::sendEOI(uint64_t& i_intSource, PIR_t& i_pir)
TRACDCOMP(g_trac_intr, "IntrRp::sendEOI read response: %lx", eoiRead);
- //The XIVE HW is expecting these MMIO accesses to come from the
- // core/thread they were setup (master core, thread 0)
- // These functions will ensure this code executes there
- task_affinity_pin();
- task_affinity_migrate_to_master();
-
- //EOI Part 2 - LSI ESB Internal to the IVPE of the Master Proc
- volatile uint64_t * l_lsiEoi = iv_masterHdlr->xiveIcBarAddr;
- l_lsiEoi += XIVE_IC_LSI_EOI_OFFSET;
- uint64_t l_intPending = *l_lsiEoi;
-
- //MMIO Complete, rest of code can run on any thread
- task_affinity_unpin();
-
- //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)
- {
- TRACFCOMP(g_trac_intr, "IntrRp::Need to acknowledge interrupt\n");
- //First acknowledge the interrupt so it won't be re-presented
- acknowledgeInterrupt();
+ l_err = sendXiveEOI(i_intSource, i_pir);
- 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);
return l_err;
@@ -1469,6 +1439,15 @@ void IntrRp::handleExternalInterrupt()
//Add to list of interrupts in flight
iv_pendingIntr.push_back(l_intr);
+ uint64_t intSource = l_intr.second;
+
+ //Mask off current interrupt source
+ maskInterruptSource(intSource, *targ_itr);
+
+ //Send EOI so other interrupt sources other than the one
+ // masked previously can be presented
+ sendXiveEOI(intSource, l_pir);
+
//Call function to route the interrupt
//to the appropriate handler
routeInterrupt((*targ_itr), static_cast<ext_intr_t>(i),
@@ -1510,8 +1489,10 @@ errlHndl_t IntrRp::maskInterruptSource(uint8_t i_intr_source,
volatile uint64_t l_maskRead = *l_psiHbEsbptr;
eieio();
- //Perform 2nd read to verify in OFF state - the read returns the previous
- // esb state, so a 2nd read is required to know it is in the off state
+ //Perform 2nd read to verify in OFF state using query offset
+ l_psiHbEsbptr = i_chip->psiHbEsbBaseAddr +
+ (((i_intr_source*PAGE_SIZE)+PSI_BRIDGE_ESB_QUERY_OFFSET)
+ /sizeof(uint64_t));
l_maskRead = *l_psiHbEsbptr;
if (l_maskRead != ESB_STATE_OFF)
@@ -1570,7 +1551,8 @@ errlHndl_t IntrRp::maskInterruptSource(uint8_t l_intr_source)
}
errlHndl_t IntrRp::unmaskInterruptSource(uint8_t l_intr_source,
- intr_hdlr_t *i_proc)
+ intr_hdlr_t *i_proc,
+ bool i_force_unmask)
{
bool l_masked = false;
errlHndl_t l_err = NULL;
@@ -1588,7 +1570,7 @@ errlHndl_t IntrRp::unmaskInterruptSource(uint8_t l_intr_source,
}
}
- if (l_masked == true)
+ if (l_masked == true || i_force_unmask == true)
{
for(ChipList_t::iterator targ_itr = iv_chipList.begin();
targ_itr != iv_chipList.end(); ++targ_itr)
@@ -1602,9 +1584,11 @@ errlHndl_t IntrRp::unmaskInterruptSource(uint8_t l_intr_source,
volatile uint64_t l_unmaskRead = *l_psiHbEsbptr;
eieio();
- //Perform 2nd read to verify in RESET state - the read returns the
- // previous esb state, so a 2nd read is required to know it is in
- // the off state
+ //Perform 2nd read to verify in RESET state using query offset
+ l_psiHbEsbptr = (*targ_itr)->psiHbEsbBaseAddr +
+ (((l_intr_source*PAGE_SIZE)+PSI_BRIDGE_ESB_QUERY_OFFSET)
+ /sizeof(uint64_t));
+
l_unmaskRead = *l_psiHbEsbptr;
if (l_unmaskRead != ESB_STATE_RESET)
@@ -1752,17 +1736,100 @@ errlHndl_t IntrRp::handlePsuInterrupt(ext_intr_t i_type,
break;
}
- //Issue standard EOI for the PSU Interupt
+ //Interrupt Processing is complete - re-enable
+ // this interrupt source
uint64_t intSource = i_type;
- TRACFCOMP(g_trac_intr, "Sending PSU EOI");
-
- sendEOI(intSource, i_pir);
+ TRACFCOMP(g_trac_intr, "handlePsuInterrupt - Calling completeInterruptProcessing");
+ completeInterruptProcessing(intSource, i_pir);
} while(0);
return l_err;
}
+void IntrRp::completeInterruptProcessing(uint64_t& i_intSource, PIR_t& i_pir)
+
+{
+ intr_hdlr_t* l_proc = NULL;
+
+ //Find target handle for Proc to remove pending interrupt for
+ for (ChipList_t::iterator targ_itr = iv_chipList.begin();
+ targ_itr != iv_chipList.end(); ++targ_itr)
+ {
+ uint64_t l_groupId = (*targ_itr)->proc->getAttr
+ <TARGETING::ATTR_FABRIC_GROUP_ID>();
+ uint64_t l_chipId = (*targ_itr)->proc->getAttr
+ <TARGETING::ATTR_FABRIC_CHIP_ID>();
+
+ //Core + Thread IDs not important so use 0's
+ PIR_t l_pir = PIR_t(l_groupId, l_chipId, 0, 0);
+
+ if (l_pir == i_pir)
+ {
+ l_proc = *targ_itr;
+ break;
+ }
+ }
+
+ do {
+
+ //Check if we found a matching proc handler for the interrupt to remove
+ // This is needed so the iNTRRP will honor new interrupts from this
+ // source
+ if (l_proc == NULL)
+ {
+ TRACFCOMP(g_trac_intr, ERR_MRK"IntrRp::completeInterruptProcessing:"
+ " couldn't find proc handler that matches pir: 0x%lx", i_pir);
+ break;
+ }
+ else
+ {
+ //Make object to search pending interrupt
+ // list for
+ std::pair<PIR_t, ext_intr_t> l_intr = std::make_pair(
+ i_pir,
+ static_cast<ext_intr_t>(i_intSource));
+
+ //See if an interrupt with from Proc with
+ // the same PIR + interrupt source are
+ // still being processed
+ auto l_found = std::find_if( iv_pendingIntr.begin(),
+ iv_pendingIntr.end(),
+ [&l_intr](auto k)->bool
+ {
+ return (k.first == l_intr.first) &&
+ (k.second == l_intr.second);
+ });
+
+ //Remove Interrupt source from pending interrupt list
+ if (l_found == iv_pendingIntr.end())
+ {
+ TRACFCOMP(g_trac_intr,ERR_MRK"IntrRp::completeInterruptHandling()"
+ " Pending Interrupt NOT found for pir:"
+ " 0x%lx, interrupt type: %d. Ignoring.",
+ i_pir, static_cast<ext_intr_t>(i_intSource));
+ }
+ else
+ {
+ TRACFCOMP(g_trac_intr, "IntrRp::completeInterruptProcessing()"
+ " Removing pending interrupt for pir: 0x%lx,"
+ "interrupt type: %d", i_pir,
+ static_cast<ext_intr_t>(i_intSource));
+ iv_pendingIntr.erase(l_found);
+ }
+
+ //Enable this interrupt source again
+ unmaskInterruptSource(i_intSource, l_proc, true);
+
+ //Send final EOI to enable interrupts for this source again
+ sendEOI(i_intSource, i_pir);
+ }
+
+ } while(0);
+
+ return;
+}
+
errlHndl_t IntrRp::getNxIRSN(TARGETING::Target * i_target,
uint32_t& o_irsn, uint32_t& o_num)
{
@@ -3828,7 +3895,7 @@ errlHndl_t INTR::IntrRp::enableSlaveProcInterrupts(TARGETING::Target * i_target)
} while(0);
- TRACFCOMP(g_trac_intr, INFO_MRK"Slave Proc Interrupt Routing setup complete\n");
+ TRACFCOMP(g_trac_intr, INFO_MRK"Slave Proc Interrupt Routing setup complete");
return l_err;
}
diff --git a/src/usr/intr/intrrp.H b/src/usr/intr/intrrp.H
index 12fb453f2..3d6e0b667 100644
--- a/src/usr/intr/intrrp.H
+++ b/src/usr/intr/intrrp.H
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2017 */
+/* Contributors Listed Below - COPYRIGHT 2011,2018 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -182,6 +182,7 @@ namespace INTR
//PSI Host Bridge ESB Constants
PSI_BRIDGE_ESB_BAR_VALID = 0x0000000000000001ULL,
PSI_BRIDGE_ESB_NOTIFY_VALID = 0x0000000000000001ULL,
+ PSI_BRIDGE_ESB_QUERY_OFFSET = 0x800,
PSI_BRIDGE_ESB_OFF_OFFSET = 0xD00,
PSI_BRIDGE_ESB_RESET_OFFSET = 0XC00,
PSI_BRIDGE_PSU_DOORBELL_REG = 0x000D0063,
@@ -380,7 +381,7 @@ namespace INTR
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
- MaskList_t iv_maskList; //!< List of interrput sources which
+ MaskList_t iv_maskList; //!< List of interrupt sources which
// are masked
PendingIntrList_t iv_pendingIntr; //!< List of pending interrupts
// That haven't been EOI'ed
@@ -525,7 +526,8 @@ namespace INTR
* @return Errorlog from unmasking the source
*/
errlHndl_t unmaskInterruptSource(uint8_t i_intr_source,
- intr_hdlr_t *i_proc);
+ intr_hdlr_t *i_proc,
+ bool i_force_unmask=false);
/**
* Set all of the Interrupt BAR scom registers specific
@@ -558,11 +560,31 @@ namespace INTR
* @param[in] i_intSource, interrupt source to perform EOI for
* @param[in] i_pir, The PIR value for the proc where the
* interrupt condtion occurred
- * @return Errorlog from DeviceWriste
+ * @return Errorlog from DeviceWrite
*/
errlHndl_t sendEOI(uint64_t& i_intSource, PIR_t& i_pir);
/**
+ * Send the XIVE portion of the EOI (End of Interrupt) sequence
+ * @param[in] i_intSource, interrupt source to perform EOI for
+ * @param[in] i_pir, The PIR value for the proc where the
+ * interrupt condtion occurred
+ * @return Errorlog from DeviceWrite
+ */
+ errlHndl_t sendXiveEOI(uint64_t& i_intSource, PIR_t& i_pir);
+
+ /**
+ * Function completes interrupt processing
+ * - Unmasks interrupt source
+ * - Sends XIVE EOI
+ * @param[in] i_intSource, interrupt source to perform EOI for
+ * @param[in] i_pir, The PIR value for the proc where the
+ * interrupt condtion occurred
+ **/
+ void completeInterruptProcessing(uint64_t& i_intSource,
+ PIR_t& i_pir);
+
+ /**
* Route Interrupt to correct listener
* @param[in] i_proc, the proc intrp handler
* @param[in] i_type, the interrupt type
OpenPOWER on IntegriCloud