summaryrefslogtreecommitdiffstats
path: root/src/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel')
-rw-r--r--src/kernel/intmsghandler.C17
-rw-r--r--src/kernel/misc.C95
-rw-r--r--src/kernel/syscall.C15
3 files changed, 121 insertions, 6 deletions
diff --git a/src/kernel/intmsghandler.C b/src/kernel/intmsghandler.C
index a2f2fb096..538d322ae 100644
--- a/src/kernel/intmsghandler.C
+++ b/src/kernel/intmsghandler.C
@@ -5,7 +5,7 @@
/* */
/* IBM CONFIDENTIAL */
/* */
-/* COPYRIGHT International Business Machines Corp. 2011,2012 */
+/* COPYRIGHT International Business Machines Corp. 2011,2013 */
/* */
/* p1 */
/* */
@@ -76,7 +76,7 @@ void InterruptMsgHdlr::handleInterrupt()
if( cv_ipc_base_address != 0 )
{
- uint64_t xirrAddress = cv_ipc_base_address;
+ uint64_t xirrAddress = cv_ipc_base_address;
xirrAddress += mmio_offset(pir); // Add offset for this cpu
xirrAddress += XIRR_ADDR_OFFSET; // Add offset for XIRR register
@@ -144,6 +144,19 @@ void InterruptMsgHdlr::addCpuCore(uint64_t i_pir)
}
}
+void InterruptMsgHdlr::sendIPI(uint64_t i_pir)
+{
+ uint64_t mfrrAddress = cv_ipc_base_address;
+ mfrrAddress += mmio_offset(i_pir);
+ mfrrAddress += MFRR_ADDR_OFFSET;
+
+ register uint8_t data = 0;
+
+ eieio(); sync();
+ MAGIC_INSTRUCTION(MAGIC_SIMICS_CORESTATESAVE);
+ asm volatile("stbcix %0,0,%1" :: "r" (data) , "r" (mfrrAddress));
+}
+
MessageHandler::HandleResult InterruptMsgHdlr::handleResponse
(
msg_sys_types_t i_type,
diff --git a/src/kernel/misc.C b/src/kernel/misc.C
index f73bf2947..9fd511c33 100644
--- a/src/kernel/misc.C
+++ b/src/kernel/misc.C
@@ -34,6 +34,7 @@
#include <kernel/pagemgr.H>
#include <kernel/vmmmgr.H> // INITIAL_MEM_SIZE
#include <kernel/memstate.H>
+#include <kernel/intmsghandler.H>
extern "C"
void kernel_shutdown(size_t, uint64_t, uint64_t, uint64_t) NO_RETURN;
@@ -66,7 +67,7 @@ namespace KernelMisc
status);
}
- // Call to set the Core Scratch Reg 0 with the status
+ // Call to set the Core Scratch Reg 0 with the status
updateScratchReg(MMIO_SCRATCH_PROGRESS_CODE, status);
}
@@ -223,6 +224,98 @@ namespace KernelMisc
kassert(false);
}
+ void WinkleAll::masterPreWork()
+ {
+ printk("Winkle all - ");
+
+ // Save away the current timebase. All threads are in this object
+ // now so they're not going to be using the time for anything else.
+ iv_timebase = getTB();
+ }
+
+ void WinkleAll::activeMainWork()
+ {
+ cpu_t* cpu = CpuManager::getCurrentCPU();
+
+ // Return current task to run-queue so it isn't lost.
+ cpu->scheduler->returnRunnable();
+ TaskManager::setCurrentTask(cpu->idle_task);
+
+ // Clear LPCR values that wakes up from winkle. LPCR[49, 50, 51]
+ // Otherwise, there may be an interrupt pending or something that
+ // prevents us from fully entering winkle.
+ setLPCR(getLPCR() & (~0x0000000000007000));
+
+ // Deactivate CPU from kernel.
+ cpu->winkled = true;
+ CpuManager::deactivateCPU(cpu);
+
+ // Create kernel save area and store ptr in bottom of kernel stack.
+ task_t* saveArea = new task_t;
+ memset(saveArea, '\0', sizeof(task_t));
+ saveArea->context.msr_mask = 0xD030; // EE, ME, PR, IR, DR.
+ *(reinterpret_cast<task_t**>(cpu->kernel_stack_bottom)) = saveArea;
+
+ // Execute winkle.
+ kernel_execute_winkle(saveArea);
+
+ // Re-activate CPU in kernel and re-init VMM SPRs.
+ delete saveArea;
+ cpu->winkled = false;
+ CpuManager::activateCPU(cpu);
+ VmmManager::init_slb();
+
+ // Wake up all the other threads.
+ if(__sync_bool_compare_and_swap(&iv_firstThread, 0, 1))
+ {
+ for(uint64_t i = 0; i < KERNEL_MAX_SUPPORTED_CPUS_PER_NODE *
+ KERNEL_MAX_SUPPORTED_NODES; i++)
+ {
+ cpu_t* slave = CpuManager::getCpu(i);
+
+ if ((NULL != slave) && (slave != cpu))
+ {
+ if (slave->winkled)
+ {
+ InterruptMsgHdlr::sendIPI(i);
+ }
+ }
+ }
+ };
+
+ // Sync timebase.
+ if (getTB() < iv_timebase)
+ {
+ setTB(iv_timebase);
+ }
+
+ // Select a new task if not the master CPU. Master CPU will resume
+ // the code that called cpu_master_winkle().
+ if (!cpu->master)
+ {
+ cpu->scheduler->setNextRunnable();
+ }
+
+ }
+
+ void WinkleAll::masterPostWork()
+ {
+ printk("Awake!\n");
+
+ // Restore caller of cpu_all_winkle().
+ iv_caller->state = TASK_STATE_RUNNING;
+ TaskManager::setCurrentTask(iv_caller);
+ }
+
+ void WinkleAll::nonactiveMainWork()
+ {
+ // Race condition that should not occur...
+ //
+ // Attempted to winkle the threads and another thread came online in
+ // the process.
+ kassert(false);
+ }
+
int expand_full_cache()
{
static bool executed = false;
diff --git a/src/kernel/syscall.C b/src/kernel/syscall.C
index 71bd1a995..985d9c0ab 100644
--- a/src/kernel/syscall.C
+++ b/src/kernel/syscall.C
@@ -700,12 +700,13 @@ namespace Systemcalls
}
};
- /** Winkle all the threads so that the runtime SLW image can be loaded. */
+ /** Winkle all the threads. */
void CpuWinkle(task_t *t)
{
cpu_t* cpu = CpuManager::getCurrentCPU();
- if ((CpuManager::getCpuCount() > CpuManager::getThreadCount()) ||
+ if ((WINKLE_SCOPE_MASTER == TASK_GETARG0(t) &&
+ (CpuManager::getCpuCount() > CpuManager::getThreadCount())) ||
(!cpu->master))
{
TASK_SETRTN(t, -EDEADLK);
@@ -713,7 +714,15 @@ namespace Systemcalls
else
{
TASK_SETRTN(t, 0);
- KernelMisc::WinkleCore* deferred = new KernelMisc::WinkleCore(t);
+ DeferredWork* deferred = NULL;
+ if (WINKLE_SCOPE_MASTER == TASK_GETARG0(t))
+ {
+ deferred = new KernelMisc::WinkleCore(t);
+ }
+ else
+ {
+ deferred = new KernelMisc::WinkleAll(t);
+ }
t->state = TASK_STATE_BLOCK_USRSPACE;
t->state_info = deferred;
DeferredQueue::insert(deferred);
OpenPOWER on IntegriCloud