diff options
-rw-r--r-- | src/include/usr/intr/intr_reasoncodes.H | 3 | ||||
-rw-r--r-- | src/usr/intr/intrrp.C | 293 | ||||
-rw-r--r-- | src/usr/intr/intrrp.H | 30 |
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 |