From 321ce4299b31ad8f54172079b32d20ead5d24a30 Mon Sep 17 00:00:00 2001 From: Patrick Williams Date: Mon, 1 Apr 2013 10:29:05 -0500 Subject: Allow winkle of all threads for multi-drawer add. RTC: 63124 Change-Id: I1ad1d6bdf6a2848b686b25504fabddddb701d440 Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/3813 Tested-by: Jenkins Server Reviewed-by: Douglas R. Gilbert Reviewed-by: Daniel M. Crowell Reviewed-by: Michael Baiocchi Reviewed-by: A. Patrick Williams III --- src/kernel/intmsghandler.C | 17 ++++++++- src/kernel/misc.C | 95 +++++++++++++++++++++++++++++++++++++++++++++- src/kernel/syscall.C | 15 ++++++-- 3 files changed, 121 insertions(+), 6 deletions(-) (limited to 'src/kernel') 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 #include // INITIAL_MEM_SIZE #include +#include 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(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); -- cgit v1.2.1