summaryrefslogtreecommitdiffstats
path: root/src/usr/intr/intrrp.C
diff options
context:
space:
mode:
Diffstat (limited to 'src/usr/intr/intrrp.C')
-rw-r--r--src/usr/intr/intrrp.C428
1 files changed, 391 insertions, 37 deletions
diff --git a/src/usr/intr/intrrp.C b/src/usr/intr/intrrp.C
index 989f47979..f667220f3 100644
--- a/src/usr/intr/intrrp.C
+++ b/src/usr/intr/intrrp.C
@@ -36,16 +36,19 @@
#include <sys/misc.h>
#include <kernel/console.H>
#include <sys/task.h>
-#include <targeting/common/targetservice.H>
#include <vmmconst.h>
+#include <targeting/common/targetservice.H>
#include <targeting/common/attributes.H>
+#include <targeting/common/utilFilter.H>
#include <devicefw/userif.H>
#include <sys/time.h>
#include <sys/vfs.h>
+#include <hwas/common/hwasCallout.H>
#define INTR_TRACE_NAME INTR_COMP_NAME
using namespace INTR;
+using namespace TARGETING;
trace_desc_t * g_trac_intr = NULL;
TRAC_INIT(&g_trac_intr, INTR_TRACE_NAME, KILOBYTE, TRACE::BUFFER_SLOW);
@@ -161,6 +164,12 @@ errlHndl_t IntrRp::_init()
INITSERVICE::INTR_PRIORITY);
}
+ if(!err)
+ {
+ // Enable PSI to present interrupts
+ err = initIRSCReg(procTarget);
+ }
+
return err;
}
@@ -263,7 +272,7 @@ void IntrRp::msgHandler()
}
msg_free(rmsg);
}
- else if (type == INTERPROC)
+ else if (type == INTERPROC_XISR)
{
// Ignore "spurious" IPIs (handled below).
@@ -278,13 +287,13 @@ void IntrRp::msgHandler()
TRACFCOMP(g_trac_intr,ERR_MRK
"External Interrupt recieved type = %d, but "
"nothing registered to handle it. "
- "Ignoreing it.",
+ "Ignoring it.",
(uint32_t)type);
}
// Handle IPIs special since they're used for waking up
// cores and have special clearing requirements.
- if (type == INTERPROC)
+ if (type == INTERPROC_XISR)
{
// Clear IPI request.
volatile uint8_t * mfrr =
@@ -331,8 +340,15 @@ void IntrRp::msgHandler()
{
msg_q_t l_msgQ = reinterpret_cast<msg_q_t>(msg->data[0]);
uint64_t l_type = msg->data[1];
- ext_intr_t l_intr_type = static_cast<ext_intr_t>(l_type & 0xFFFF);
- errlHndl_t err = registerInterrupt(l_msgQ,l_type >> 32,l_intr_type);
+ ISNvalue_t l_intr_type = static_cast<ISNvalue_t>
+ (l_type & 0xFFFF);
+
+ errlHndl_t err = registerInterruptISN(l_msgQ,l_type >> 32,
+ l_intr_type);
+ if(!err)
+ {
+ err = initXIVR(l_intr_type, true);
+ }
msg->data[1] = reinterpret_cast<uint64_t>(err);
msg_respond(iv_msgQ,msg);
@@ -344,14 +360,18 @@ void IntrRp::msgHandler()
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);
- msg_q_t msgQ = NULL;
- ext_intr_t type = static_cast<ext_intr_t>(msg->data[0]);
- Registry_t::iterator r = iv_registry.find(type);
- if(r != iv_registry.end())
+ if(msgQ)
{
- msgQ = r->second.msgQ;
- iv_registry.erase(r);
+ //shouldn't get an error since we found a queue
+ //Just commit it
+ errlHndl_t err = initXIVR(l_type, false);
+ if(err)
+ {
+ errlCommit(err,INTR_COMP_ID);
+ }
}
msg->data[1] = reinterpret_cast<uint64_t>(msgQ);
@@ -405,6 +425,16 @@ void IntrRp::msgHandler()
}
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_SHUTDOWN:
{
TRACFCOMP(g_trac_intr,"Shutdown event received");
@@ -454,47 +484,293 @@ errlHndl_t IntrRp::setBAR(TARGETING::Target * i_target,
}
+errlHndl_t IntrRp::initIRSCReg(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 node = 0;
+
+ i_target->tryGetAttr<ATTR_FABRIC_NODE_ID>(node);
+ i_target->tryGetAttr<ATTR_FABRIC_CHIP_ID>(chip);
+
+ size_t scom_len = sizeof(uint64_t);
+
+ // Setup PHBISR
+ // EN.TPC.PSIHB.PSIHB_ISRN_REG set to 0x00030003FFFF0000
+ PSIHB_ISRN_REG_t reg;
+
+ PIR_t pir(0);
+ pir.nodeId = node;
+ 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,"PSIHB_ISRN_REG: 0x%016lx",reg.d64);
+
+ err = deviceWrite
+ ( i_target,
+ &reg,
+ scom_len,
+ DEVICE_SCOM_ADDRESS(PSIHB_ISRN_REG_t::PSIHB_ISRN_REG));
+
+ if(err)
+ {
+ // add callout
+ err->addHwCallout(i_target,
+ HWAS::SRCI_PRIORITY_HIGH,
+ HWAS::DECONFIG,
+ HWAS::GARD_NULL);
+ }
+ else
+ {
+ iv_chipList.push_back(i_target);
+ }
+ }
+
+ return err;
+}
-errlHndl_t IntrRp::registerInterrupt(msg_q_t i_msgQ,
+errlHndl_t IntrRp::initXIVR(enum ISNvalue_t i_isn, bool i_enable)
+{
+ errlHndl_t err = NULL;
+ size_t scom_len = sizeof(uint64_t);
+ uint64_t scom_addr = 0;
+
+ //Don't do any of this for ISN_INTERPROC
+ if(ISN_INTERPROC != i_isn)
+ {
+ //Setup the XIVR register
+ PsiHbXivr xivr;
+ PIR_t pir = intrDestCpuId();
+ xivr.pir = pir.word;
+ xivr.source = i_isn;
+
+ switch(i_isn)
+ {
+ 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;
+ break;
+
+ case ISN_HOST:
+ xivr.priority = PsiHbXivr::HOST_PRIO;
+ scom_addr = PsiHbXivr::HOST_XIVR_ADRR;
+ break;
+
+ default: //Unsupported ISN
+ TRACFCOMP(g_trac_intr,"Unsupported ISN: 0x%02x",i_isn);
+ /*@ errorlog tag
+ * @errortype ERRL_SEV_INFORMATIONAL
+ * @moduleid INTR::MOD_INTR_INIT_XIVR
+ * @reasoncode INTR::RC_BAD_ISN
+ * @userdata1 Interrupt type to register
+ * @userdata2 0
+ *
+ * @defdesc Unsupported ISN Requested
+ *
+ */
+ 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
+ );
+ }
+
+ // 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);
+ }
+ }
+
+ 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));
+
+ 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;
- Registry_t::iterator r = iv_registry.find(i_intr_type);
+ //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)
+ {
+ uint8_t chip = 0;
+ uint8_t node = 0;
+ (*target_itr)->tryGetAttr<ATTR_FABRIC_NODE_ID>(node);
+ (*target_itr)->tryGetAttr<ATTR_FABRIC_CHIP_ID>(chip);
+
+ PIR_t pir(0);
+ pir.nodeId = node;
+ pir.chipId = chip;
+ uint32_t l_irsn = makeXISR(pir, i_intr_type);
+
+ err = registerInterruptXISR(i_msgQ, i_msg_type, l_irsn);
+ if(err)
+ {
+ break;
+ }
+ }
+ }
+ 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_intr_type);
- iv_registry[i_intr_type] = intr_response_t(i_msgQ,i_msg_type);
+ TRACFCOMP(g_trac_intr,"INTR::register intr type 0x%x", i_xisr);
+ iv_registry[i_xisr] = intr_response_t(i_msgQ,i_msg_type);
}
else
{
if(r->second.msgQ != i_msgQ)
{
- /*@ errorlog tag
- * @errortype ERRL_SEV_INFORMATIONAL
- * @moduleid INTR::MOD_INTRRP_REGISTERINTERRUPT
- * @reasoncode INTR::RC_ALREADY_REGISTERED
- * @userdata1 Interrupt type
- * @userdata2 0
- *
- * @defdesc Interrupt type already registered
- *
- */
+ /*@ errorlog tag
+ * @errortype ERRL_SEV_INFORMATIONAL
+ * @moduleid INTR::MOD_INTRRP_REGISTERINTERRUPT
+ * @reasoncode INTR::RC_ALREADY_REGISTERED
+ * @userdata1 XISR
+ * @userdata2 0
+ *
+ * @defdesc Interrupt type already registered
+ *
+ */
err = new ERRORLOG::ErrlEntry
- (
- ERRORLOG::ERRL_SEV_INFORMATIONAL, // severity
- INTR::MOD_INTRRP_REGISTERINTERRUPT, // moduleid
- INTR::RC_ALREADY_REGISTERED, // reason code
- i_intr_type,
- 0
- );
+ (
+ ERRORLOG::ERRL_SEV_INFORMATIONAL, // severity
+ INTR::MOD_INTRRP_REGISTERINTERRUPT, // moduleid
+ INTR::RC_ALREADY_REGISTERED, // reason code
+ i_xisr,
+ 0
+ );
}
-
}
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;
+ (*target_itr)->tryGetAttr<ATTR_FABRIC_NODE_ID>(node);
+ (*target_itr)->tryGetAttr<ATTR_FABRIC_CHIP_ID>(chip);
+
+ PIR_t pir(0);
+ pir.nodeId = 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;
+
+ Registry_t::iterator r = iv_registry.find(i_xisr);
+ if(r != iv_registry.end())
+ {
+ msgQ = r->second.msgQ;
+ iv_registry.erase(r);
+ }
+
+ return msgQ;
+}
+
void IntrRp::initInterruptPresenter(const PIR_t i_pir) const
{
uint64_t baseAddr = iv_baseAddr + cpuOffsetAddr(i_pir);
@@ -621,6 +897,7 @@ errlHndl_t IntrRp::checkAddress(uint64_t i_addr)
void IntrRp::shutDown()
{
+ errlHndl_t err = NULL;
msg_t * rmsg = msg_allocate();
// Call everyone and say shutting down!
@@ -647,7 +924,49 @@ void IntrRp::shutDown()
msg_free(rmsg);
- // Reset the hardware regiseters
+ // 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;
+ }
+ }
+
+ // TODO secure boot - how do we know a processor chip has been added?
+ 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;
+ }
+ }
+
+
+ // Reset the IP hardware regiseters
iv_cpuList.push_back(iv_masterCpu);
@@ -839,8 +1158,43 @@ errlHndl_t INTR::disableExternalInterrupts()
return err;
}
-uint32_t INTR::intrDestCpuId(uint32_t i_xisr)
+errlHndl_t INTR::enablePsiIntr(TARGETING::Target * i_target)
{
- return Singleton<IntrRp>::instance().intrDestCpuId(i_xisr);
+ 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);
+
+ msg_sendrecv(intr_msgQ, msg);
+
+ err = reinterpret_cast<errlHndl_t>(msg->data[1]);
+ msg_free(msg);
+ }
+ else
+ {
+ /*@ 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
+ *
+ * @defdesc 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;
}
+
OpenPOWER on IntegriCloud