diff options
author | Bill Hoffa <wghoffa@us.ibm.com> | 2016-01-13 14:06:31 -0600 |
---|---|---|
committer | Daniel M. Crowell <dcrowell@us.ibm.com> | 2016-05-06 11:03:22 -0400 |
commit | b42194c6063f64d59fe1c360fa4ae4edd85ad2f3 (patch) | |
tree | b055e27081164600409203f31c3eac93f32397cb /src/usr | |
parent | daf95f9b2b66313079186c2d8669ffa75155056f (diff) | |
download | talos-hostboot-b42194c6063f64d59fe1c360fa4ae4edd85ad2f3.tar.gz talos-hostboot-b42194c6063f64d59fe1c360fa4ae4edd85ad2f3.zip |
Doorbell Interrupt Base Support for Core/Thread Wakeup
This change includes:
- Implementation of a generic KernelWorkItem Class
- Kernel functionality for doorbell send to specific PIRs
- Kernel changes to send core/thread Wakeup doorbells using
doorbell_send() + placing KernelWorkItems on a cpu stack obj
to be executed during doorbell wakeup
- Kernel Interrupt Message handler changes to send wakeup msgs
- Interrupt Resource Provider (INTRRP) Changes to handle
wakeup msgs and monitor for timeouts
- Changes to the IPL flow to invoke proper Core/Thread Wakeup
- A basic outline (commented out) for how IPC messages can be
implemented in the future
Change-Id: I547fb8719bac657def561565ae11ab18cde72096
CMVC-Prereq: 992722
RTC:137564
Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/22815
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')
-rw-r--r-- | src/usr/intr/intrrp.C | 200 | ||||
-rw-r--r-- | src/usr/intr/intrrp.H | 6 | ||||
-rw-r--r-- | src/usr/isteps/istep16/call_host_activate_master.C | 3 | ||||
-rw-r--r-- | src/usr/isteps/istep16/call_host_activate_slave_cores.C | 17 |
4 files changed, 118 insertions, 108 deletions
diff --git a/src/usr/intr/intrrp.C b/src/usr/intr/intrrp.C index e4abde595..91bca3c11 100644 --- a/src/usr/intr/intrrp.C +++ b/src/usr/intr/intrrp.C @@ -180,7 +180,10 @@ errlHndl_t IntrRp::_init() // so unmask those interrupts l_err = unmaskInterruptSource(LSI_PSU); - + //Set value for enabled threads + uint64_t l_en_threads = get_enabled_threads(); + TRACDCOMP(g_trac_intr, "IntrRp::_init() Threads enabled:" + " %lx", l_en_threads); } while(0); return l_err; @@ -421,11 +424,7 @@ void IntrRp::msgHandler() uint64_t l_data0 = (l_xirr_pir & 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); - - TRACFCOMP(g_trac_intr, + TRACDCOMP(g_trac_intr, "External Interrupt received. XIRR=%x, PIR=%x", xirr,pir.word); //An external interrupt comes from two paths @@ -467,15 +466,6 @@ void IntrRp::msgHandler() (uint32_t) type, rc); } } - else if (type == INTERPROC_XISR) - { - // Ignore "spurious" IPIs (handled below). - - // Note that we could get an INTERPROC interrupt - // and handle it through the above registration list - // 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"); @@ -490,89 +480,78 @@ void IntrRp::msgHandler() "Ignoring it.", (uint32_t)type); } + } + break; - // Handle IPIs special since they're used for waking up - // cores and have special clearing requirements. - if (type == INTERPROC_XISR) - { - // Clear IPI request. - volatile uint8_t * mfrr = - reinterpret_cast<uint8_t*>(baseAddr + MFRR_OFFSET); + case MSG_INTR_CPU_WAKEUP: + { + uint64_t l_xirr_pir = msg->data[0]; + uint64_t l_data0 = (l_xirr_pir & 0xFFFFFFFF); + PIR_t l_pir = static_cast<PIR_t>(l_data0); + PIR_t l_core_pir = l_pir; + l_core_pir.threadId = 0; - TRACFCOMP( g_trac_intr,"mfrr = %x",*mfrr); + if (iv_ipisPending.count(l_core_pir)) + { + TRACFCOMP(g_trac_intr,INFO_MRK + "IntrRp::msgHandler Doorbell wakeup received" + " for %d", l_pir.word); - (*mfrr) = 0xff; - eieio(); // Force mfrr clear before xirr EIO. + IPI_Info_t& ipiInfo = iv_ipisPending[l_core_pir]; + ipiInfo.first &= + ~(0x8000000000000000 >> l_pir.threadId); - // Deal with pending IPIs. - PIR_t core_pir = pir; core_pir.threadId = 0; - if (iv_ipisPending.count(core_pir)) + if (0 == ipiInfo.first) { - TRACFCOMP(g_trac_intr,INFO_MRK - "IPI wakeup received for %d", pir.word); - - IPI_Info_t& ipiInfo = iv_ipisPending[core_pir]; - - ipiInfo.first &= - ~(0x8000000000000000 >> pir.threadId); - - if (0 == ipiInfo.first) - { - msg_t* ipiMsg = ipiInfo.second; - iv_ipisPending.erase(core_pir); - - ipiMsg->data[1] = 0; - msg_respond(iv_msgQ, ipiMsg); - } - else - { - TRACDCOMP(g_trac_intr,INFO_MRK - "IPI still pending for %x", - ipiInfo.first); - } + msg_t* ipiMsg = ipiInfo.second; + iv_ipisPending.erase(l_core_pir); + ipiMsg->data[1] = 0; + msg_respond(iv_msgQ, ipiMsg); } - - // Writing the XIRR with the same value read earlier - // to signal an EOI. - xirr |= CPPR_MASK; //set all CPPR bits - allow any INTR - *xirrAddress = xirr; - - TRACDCOMP(g_trac_intr, - "EOI issued. XIRR=%x, PIR=%x", - xirr,pir); - - // Now handle any IPC messages - // If something is registered for IPIs - // and msg is ready, then handle - if(r != iv_registry.end() && - (KernelIpc::ipc_data_area.msg_queue_id != - IPC_DATA_AREA_CLEAR) && - (KernelIpc::ipc_data_area.msg_queue_id != - IPC_DATA_AREA_LOCKED)) + else { - msg_q_t msgQ = r->second.msgQ; - - msg_t * rmsg = msg_allocate(); - rmsg->type = r->second.msgType; - rmsg->data[0] = type; // interrupt type - rmsg->data[1] = l_xirr_pir; - rmsg->extra_data = NULL; - - int rc = msg_sendrecv_noblk(msgQ, rmsg, iv_msgQ); - if(rc) - { - TRACFCOMP(g_trac_intr,ERR_MRK - "IPI Interrupt received, but could " - "not send message to the registered " - "handler. Ignoring it. rc = %d", - rc); - } + TRACFCOMP(g_trac_intr,INFO_MRK + "IPI still pending for %x", + ipiInfo.first); } + } } break; +/*TODO RTC 150861 -- I think a new IPC message type needs to be defined. + * And the code below should be executed when this new message + * type is received. The Kernel will send this message to + * here (this intrrp code) during doorbell wakeup. + + // Now handle any IPC messages + // If something is registered for IPIs + // and msg is ready, then handle + if(r != iv_registry.end() && + (KernelIpc::ipc_data_area.msg_queue_id != + IPC_DATA_AREA_CLEAR) && + (KernelIpc::ipc_data_area.msg_queue_id != + IPC_DATA_AREA_LOCKED)) + { + msg_q_t msgQ = r->second.msgQ; + msg_t * rmsg = msg_allocate(); + rmsg->type = r->second.msgType; + rmsg->data[0] = type; // interrupt type + rmsg->data[1] = l_xirr_pir; + rmsg->extra_data = NULL; + + int rc = msg_sendrecv_noblk(msgQ, rmsg, iv_msgQ); + if(rc) + { + TRACFCOMP(g_trac_intr,ERR_MRK + "IPI Interrupt received, but could " + "not send message to the registered " + "handler. Ignoring it. rc = %d", + rc); + } + } +**/ case MSG_INTR_EOI: { // Use standrard EOI (End of Interrupt) sequence @@ -662,13 +641,16 @@ void IntrRp::msgHandler() } 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: { + //Get the base PIR sent from the kernel PIR_t pir = msg->data[1]; + //No need to care about thread ID as that will be gathered + // below pir.threadId = 0; + //Push back base core PIR for later use iv_cpuList.push_back(pir); TRACFCOMP(g_trac_intr,"Add CPU group[%d], chip[%d]," @@ -676,40 +658,31 @@ void IntrRp::msgHandler() pir.groupId, pir.chipId, pir.coreId, pir.threadId); - size_t threads = cpu_thread_count(); + //Get threads to be enabled so they will be monitored uint64_t en_threads = get_enabled_threads(); - iv_ipisPending[pir] = IPI_Info_t(en_threads, msg); - for(size_t thread = 0; thread < threads; ++thread) - { - // Skip threads that we shouldn't be starting - if( !(en_threads & (0x8000000000000000>>thread)) ) - { - TRACDCOMP(g_trac_intr,"MSG_INTR_ADD_CPU: Skipping thread %d",thread); - continue; - } - pir.threadId = thread; - //wh_p9 initInterruptPresenter(pir); - sendIPI(pir); - } - - pir.threadId = 0; + //Create handleCpuTimeout task - this task will monitor + // for wakeup messages from each individual expected + // thread to be sent. task_create(handleCpuTimeout, reinterpret_cast<void*>(pir.word)); + TRACFCOMP(g_trac_intr, "handleCpuTimeout task started" + " responding to kernel message"); } break; -#endif case MSG_INTR_ADD_CPU_TIMEOUT: { PIR_t pir = msg->data[0]; + TRACDCOMP("IntrRp::msgHandler() CPU Timeout Message " + "received for: %x", pir.word); size_t count = msg->data[1]; if(iv_ipisPending.count(pir)) { if (count < CPU_WAKEUP_INTERVAL_COUNT) { - TRACDCOMP(g_trac_intr, + TRACFCOMP(g_trac_intr, INFO_MRK "Cpu wakeup pending on %x", pir.word); @@ -2768,6 +2741,8 @@ void* INTR::IntrRp::handleCpuTimeout(void* _pir) msg->data[0] = pir; msg_q_t intr_msgQ = msg_q_resolve(VFS_ROOT_MSG_INTR); + TRACFCOMP( g_trac_intr,"handleCpuTimeout for pir: %lx", pir); + do { // Sleep for the right amount. @@ -2838,3 +2813,20 @@ void INTR::drainQueue() } //else no queue, no need to do anything } + +uint64_t INTR::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 ) + { + //TODO RTC 151022 + //Read <SBE memory area> for enabled threads value + // and set attribute appropriately + en_threads = 0xF000000000000000; //Enable all the threads + sys->setAttr<TARGETING::ATTR_ENABLED_THREADS>(en_threads); + } + return en_threads; +} diff --git a/src/usr/intr/intrrp.H b/src/usr/intr/intrrp.H index a5ef9cddc..5141544b0 100644 --- a/src/usr/intr/intrrp.H +++ b/src/usr/intr/intrrp.H @@ -67,6 +67,12 @@ namespace INTR return r.u32; } + /** + * @brief Utility function to get the list of enabled threads + * @return Bitstring of enabled threads + */ + uint64_t get_enabled_threads( void ); + class IntrRp { public: diff --git a/src/usr/isteps/istep16/call_host_activate_master.C b/src/usr/isteps/istep16/call_host_activate_master.C index a90a97549..213f04596 100644 --- a/src/usr/isteps/istep16/call_host_activate_master.C +++ b/src/usr/isteps/istep16/call_host_activate_master.C @@ -107,6 +107,9 @@ void* call_host_activate_master (void *io_pArgs) TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "startDeadManLoop SUCCESS" ); } + //Need to indicate to PHYP to save HRMOR and other SPR Data to be + // applied during wakeup + MAGIC_INSTRUCTION(MAGIC_SIMICS_CORESTATESAVE); //Because of a bug in how the SBE injects the IPI used to wake //up the master core, need to ensure no mailbox traffic diff --git a/src/usr/isteps/istep16/call_host_activate_slave_cores.C b/src/usr/isteps/istep16/call_host_activate_slave_cores.C index 6e4977524..1d521213e 100644 --- a/src/usr/isteps/istep16/call_host_activate_slave_cores.C +++ b/src/usr/isteps/istep16/call_host_activate_slave_cores.C @@ -65,16 +65,22 @@ void* call_host_activate_slave_cores (void *io_pArgs) // @@@@@ CUSTOM BLOCK: @@@@@ - uint64_t l_masterCoreID = task_getcpuid() & ~7; + uint64_t l_masterCoreID = PIR_t::coreFromPir(task_getcpuid()); TargetHandleList l_cores; getAllChiplets(l_cores, TYPE_CORE); + uint32_t l_numCores = 0; for(TargetHandleList::const_iterator l_core = l_cores.begin(); l_core != l_cores.end(); ++l_core) { + TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, + "Iterating all cores in system - " + "This is core: %d", l_numCores); + l_numCores += 1; + ConstTargetHandle_t l_processor = getParentChip(*l_core); CHIP_UNIT_ATTR l_coreId = @@ -86,20 +92,23 @@ void* call_host_activate_slave_cores (void *io_pArgs) TARGETING::Target* sys = NULL; TARGETING::targetService().getTopLevelTarget(sys); assert( sys != NULL ); - uint64_t en_threads = sys->getAttr<ATTR_ENABLED_THREADS>(); const fapi2::Target<fapi2::TARGET_TYPE_CORE> l_fapi2_coreTarget( const_cast<TARGETING::Target*> (*l_core)); + //Determine PIR and threads to enable for this core uint64_t pir = PIR_t(l_logicalGroupId, l_chipId, l_coreId).word; + uint64_t en_threads = sys->getAttr<ATTR_ENABLED_THREADS>(); + TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, + "pir for this core is: %lx", pir); if (pir != l_masterCoreID) { TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, - "call_host_activate_slave_cores: Waking %x", + "call_host_activate_slave_cores: Waking %x.", pir ); - int rc = cpu_start_core(pir,en_threads); + int rc = cpu_start_core(pir, en_threads); // Handle time out error if (-ETIME == rc) |