summaryrefslogtreecommitdiffstats
path: root/src/usr
diff options
context:
space:
mode:
authorBill Hoffa <wghoffa@us.ibm.com>2016-01-13 14:06:31 -0600
committerDaniel M. Crowell <dcrowell@us.ibm.com>2016-05-06 11:03:22 -0400
commitb42194c6063f64d59fe1c360fa4ae4edd85ad2f3 (patch)
treeb055e27081164600409203f31c3eac93f32397cb /src/usr
parentdaf95f9b2b66313079186c2d8669ffa75155056f (diff)
downloadtalos-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.C200
-rw-r--r--src/usr/intr/intrrp.H6
-rw-r--r--src/usr/isteps/istep16/call_host_activate_master.C3
-rw-r--r--src/usr/isteps/istep16/call_host_activate_slave_cores.C17
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)
OpenPOWER on IntegriCloud