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/kernel | |
| parent | daf95f9b2b66313079186c2d8669ffa75155056f (diff) | |
| download | blackbird-hostboot-b42194c6063f64d59fe1c360fa4ae4edd85ad2f3.tar.gz blackbird-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/kernel')
| -rw-r--r-- | src/kernel/cpumgr.C | 18 | ||||
| -rw-r--r-- | src/kernel/doorbell.C | 48 | ||||
| -rw-r--r-- | src/kernel/intmsghandler.C | 28 | ||||
| -rw-r--r-- | src/kernel/ipc.C | 7 | ||||
| -rw-r--r-- | src/kernel/makefile | 1 | ||||
| -rw-r--r-- | src/kernel/misc.C | 10 | ||||
| -rw-r--r-- | src/kernel/syscall.C | 15 | ||||
| -rw-r--r-- | src/kernel/workitem.C | 50 |
8 files changed, 152 insertions, 25 deletions
diff --git a/src/kernel/cpumgr.C b/src/kernel/cpumgr.C index 1aef65650..c1733bb7c 100644 --- a/src/kernel/cpumgr.C +++ b/src/kernel/cpumgr.C @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2010,2015 */ +/* Contributors Listed Below - COPYRIGHT 2010,2016 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -45,6 +45,7 @@ #include <kernel/hbterminatetypes.H> #include <kernel/kernel_reasoncodes.H> #include <kernel/cpuid.H> +#include <kernel/doorbell.H> cpu_t** CpuManager::cv_cpus[KERNEL_MAX_SUPPORTED_NODES]; bool CpuManager::cv_shutdown_requested = false; @@ -193,7 +194,7 @@ void CpuManager::startCPU(ssize_t i) // Initialize CPU structure. if (NULL == cv_cpus[nodeId][cpuId]) { - printk("Starting CPU %ld...", i); + printk("Starting CPU with pir %ld...", i); cpu_t* cpu = cv_cpus[nodeId][cpuId] = new cpu_t(); // Initialize CPU. @@ -434,8 +435,21 @@ void CpuManager::startCore(uint64_t pir,uint64_t i_threads) } __sync_synchronize(); + //Send a message to userspace that a core with this base pir is being added + // userspace will know which threads on the core to expect already InterruptMsgHdlr::addCpuCore(pir); + for(size_t i = 0; i < threads; i++) + { + // Only wakeup the threads we were told to wakeup + if( i_threads & (0x8000000000000000 >> i) ) + { + printk("Dbell wkup pir %ld\n", pir + i); + //Initiate the Doorbell for this core/pir + send_doorbell_wakeup(pir + i); + } + } + return; }; diff --git a/src/kernel/doorbell.C b/src/kernel/doorbell.C index 33b782bf7..4b99e7aee 100644 --- a/src/kernel/doorbell.C +++ b/src/kernel/doorbell.C @@ -24,11 +24,16 @@ /* IBM_PROLOG_END_TAG */ #include <stdint.h> #include <arch/ppc.H> +#include <kernel/task.H> +#include <kernel/taskmgr.H> +#include <kernel/cpu.H> +#include <kernel/doorbell.H> +#include <kernel/console.H> #include <kernel/cpumgr.H> void doorbell_clear() { - register uint64_t msgtype = 0x0000000028000000; /// Comes from the ISA. + register uint64_t msgtype = _DOORBELL_MSG_TYPE; asm volatile("msgclr %0" :: "r" (msgtype)); return; @@ -36,9 +41,10 @@ void doorbell_clear() void doorbell_broadcast() { + /*TODO RTC 152189 size_t threadCount = CpuManager::getThreadCount(); - uint64_t msgtype = 0x0000000028000000; /// Comes from the ISA. + uint64_t msgtype = _DOORBELL_MSG_TYPE; uint64_t thread = getPIR() & (threadCount - 1); for (size_t i = 0; i < threadCount; ++i) { @@ -48,4 +54,42 @@ void doorbell_broadcast() asm volatile("msgsnd %0" :: "r" (msg)); } } + **/ } + +void doorbell_send(uint64_t i_pir) +{ + uint64_t msgtype = _DOORBELL_MSG_TYPE; + register uint64_t msg = msgtype | i_pir; + asm volatile("msgsnd %0" :: "r" (msg)); + + return; +} + +void send_doorbell_wakeup(uint64_t i_pir) +{ + cpu_t *l_cpu = CpuManager::getCpu(i_pir); + + printkd("send_doorbell_wakeup to pir: %lx\n", i_pir); + //Create WorkItem and put on the stack to be executed during doorbell + // execution + KernelWorkItem* l_work = new CpuWakeupDoorbellWorkItem(); + l_cpu->doorbell_actions.push(l_work); + //Send doorbell to wakeup core/thread + doorbell_send(i_pir); +} + +/* +TODO RTC 150861 +void send_doorbell_ipc(uint64_t i_pir) +{ + cpu_t *l_cpu = getCpu(i_pir) + + printk("send_doorbell_ipc to pir: %lx\n", i_pir); + //Create WorkItem and put on the stack to be executed during doorbell + // execution (if needed, otherwise can likely delete and just send doorbell) + KernelWorkItem* l_work = new IpcDoorbellWorkItem(); + l_cpu->doorbell_actions.push(l_work); + doorbell_send(i_pir) +} +**/ diff --git a/src/kernel/intmsghandler.C b/src/kernel/intmsghandler.C index 10c1dcfd8..301be0f05 100644 --- a/src/kernel/intmsghandler.C +++ b/src/kernel/intmsghandler.C @@ -113,7 +113,7 @@ void InterruptMsgHdlr::handleInterrupt() } else { - printk("InterrurptMsgHdlr got called before IPC was setup\n"); + printk("InterruptMsgHdlr got called before IPC was setup\n"); // The INTR mmio base address is not yet available via the attributes. // If we get here during an MPIPL then the BAR value could be read // from the ICP BAR SCOM register, however, since this value will @@ -165,28 +165,30 @@ void InterruptMsgHdlr::addCpuCore(uint64_t i_pir) { // To avoid conflict with interrupts on thread i_pir, change the key // for the message to be an invalid PIR. - uint64_t pir_key = i_pir | 0x8000000000000000ul; + uint64_t pir_key = i_pir | 0x4000000000000000ul; cv_instance->iv_lock.lock(); cv_instance->sendMessage(MSG_INTR_ADD_CPU, (void*)pir_key,(void *)i_pir,t); cv_instance->iv_lock.unlock(); + printkd("InterruptMsgHdlr::addCpuCore MSG_INTR_ADD_CPU message " + "sent for pir: %lx\n", i_pir); } } -void InterruptMsgHdlr::sendIPI(uint64_t i_pir, uint8_t i_favor) +void InterruptMsgHdlr::sendThreadWakeupMsg(uint64_t i_pir) { - uint64_t mfrrAddress = cv_ipc_base_address; - mfrrAddress += mmio_offset(i_pir); - mfrrAddress += MFRR_ADDR_OFFSET; - - mfrrAddress |= 0x8000000000000000ul; - - register uint8_t data = i_favor; + if(cv_instance) + { + // To avoid conflict with interrupts on thread i_pir, change the key + // for the message to be an invalid PIR. + uint64_t pir_key = i_pir | 0x8000000000000000ul; - eieio(); sync(); - MAGIC_INSTRUCTION(MAGIC_SIMICS_CORESTATESAVE); - asm volatile("stbcix %0,0,%1" :: "r" (data) , "r" (mfrrAddress)); + cv_instance->iv_lock.lock(); + cv_instance->sendMessage(MSG_INTR_CPU_WAKEUP, + (void*)pir_key,(void *)i_pir,NULL); + cv_instance->iv_lock.unlock(); + } } MessageHandler::HandleResult InterruptMsgHdlr::handleResponse diff --git a/src/kernel/ipc.C b/src/kernel/ipc.C index 9f0eaa908..e7a9ead9a 100644 --- a/src/kernel/ipc.C +++ b/src/kernel/ipc.C @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2013,2015 */ +/* Contributors Listed Below - COPYRIGHT 2013,2016 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -87,8 +87,11 @@ int KernelIpc::send(uint64_t i_q, msg_t * i_msg) printkd("IPC send from PIR %lx to PIR %x\n",getPIR(),p_dest->pir); + /* TODO RTC 150861 // send IPI - use this_node + 10 as favor level of interrupt - InterruptMsgHdlr::sendIPI(p_dest->pir,this_node + 0x10); + //P8 Call: InterruptMsgHdlr::sendIPI(p_dest->pir,this_node + 0x10); + //P9 Call (likely): send_doorbell_ipc(p_dest->pir); + **/ // The message allocation is freed here to make msg_send for IPC // messages behave the same as non-IPC msg_send; that is, the message diff --git a/src/kernel/makefile b/src/kernel/makefile index ea9666b44..cf5a69aa7 100644 --- a/src/kernel/makefile +++ b/src/kernel/makefile @@ -65,6 +65,7 @@ OBJS += ipc.o OBJS += machchk.o OBJS += doorbell.o +OBJS += workitem.o include ${ROOTPATH}/config.mk diff --git a/src/kernel/misc.C b/src/kernel/misc.C index 080c0adf3..3b25ae705 100644 --- a/src/kernel/misc.C +++ b/src/kernel/misc.C @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2011,2015 */ +/* Contributors Listed Below - COPYRIGHT 2011,2016 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -41,7 +41,7 @@ #include <kernel/ipc.H> #include <kernel/timemgr.H> #include <util/singleton.H> - +#include <kernel/doorbell.H> extern "C" void kernel_shutdown(size_t, uint64_t, uint64_t, uint64_t, @@ -340,8 +340,10 @@ namespace KernelMisc //Issue sbe master workaround InterruptMsgHdlr::issueSbeMboxWA(); + // NOTE: The cpu_t structures for theads 1:3 were created // during init (CpuManager::init). + // #ifdef HOSTBOOT_REAL_WINKLE // @todo- RTC 141924 Start the other threads 1:3 in a new manner @@ -349,6 +351,7 @@ namespace KernelMisc // Maybe something like: sendIPI(..) or addCpuCore(..) // Need interrupt code in place for this. + #else // get other 3 threads going in SIMICs for now MAGIC_INSTRUCTION(MAGIC_WAKE_OTHER_THREADS); @@ -371,6 +374,7 @@ namespace KernelMisc // get new core going in SIMICS MAGIC_INSTRUCTION(MAGIC_WAKE_FUSED_THREADS); #endif + } // end if fused core mode } @@ -440,7 +444,7 @@ namespace KernelMisc { if (slave->winkled) { - InterruptMsgHdlr::sendIPI(i); + InterruptMsgHdlr::sendThreadWakeupMsg(i); } } } diff --git a/src/kernel/syscall.C b/src/kernel/syscall.C index d7e729d80..6f087f021 100644 --- a/src/kernel/syscall.C +++ b/src/kernel/syscall.C @@ -55,6 +55,17 @@ extern "C" void kernel_execute_hype_doorbell() { task_t* t = TaskManager::getCurrentTask(); + doorbell_clear(); + + //Execute all work items on doorbell_actions stack + KernelWorkItem *l_work = t->cpu->doorbell_actions.pop(); + while(l_work != NULL) + { + //Execute Work Item and then delete it + (*l_work)(); + delete l_work; + l_work = t->cpu->doorbell_actions.pop(); + } if (t->cpu->idle_task == t) { @@ -63,8 +74,6 @@ void kernel_execute_hype_doorbell() } DeferredQueue::execute(); - - doorbell_clear(); } extern "C" @@ -401,7 +410,7 @@ namespace Systemcalls if (m->type >= MSG_FIRST_SYS_TYPE) { - printkd("Invalid message type for msg_sendrecv, type=%d.\n", + printk("Invalid message type for msg_sendrecv, type=%d.\n", m->type); TASK_SETRTN(t, -EINVAL); return; diff --git a/src/kernel/workitem.C b/src/kernel/workitem.C new file mode 100644 index 000000000..a883cdb8f --- /dev/null +++ b/src/kernel/workitem.C @@ -0,0 +1,50 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/kernel/workitem.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ + +#include <arch/ppc.H> +#include <kernel/workitem.H> +#include <kernel/console.H> +#include <kernel/intmsghandler.H> + +//Define the desired behavior for a CPU core/thread +// wakeup scenario +void CpuWakeupDoorbellWorkItem::operator() (void) +{ + size_t pir = getPIR(); + printk("Wkup pir %ld done\n", pir); + //Send message to the intrrp in userspace indicating this pir has woken up + // There is a task associated with the intrrp that monitors that the proper + // cores/threads have woken up + InterruptMsgHdlr::sendThreadWakeupMsg(pir); + return; +} + +/*TODO RTC 150861 +void IpcDoorbellWorkItem::operator() (void) +{ + //Decide what needs to be done when the Ipc Doorbell is received + // (if anything) +} +**/ |

