diff --git a/src/include/kernel/cpu.H b/src/include/kernel/cpu.H index f218e3e4526..e6dc4a1fa5b 100644 --- a/src/include/kernel/cpu.H +++ b/src/include/kernel/cpu.H @@ -104,6 +104,9 @@ struct cpu_t /** Sequence ID of CPU initialization. */ uint64_t cpu_start_seqid; + /** Timebase Restore Value (used during core wakeup) */ + uint64_t cpu_restore_tb; + /** Stack of WorkItems to be executed during doorbell wakeup */ Util::Lockfree::Stack doorbell_actions; }; diff --git a/src/include/kernel/doorbell.H b/src/include/kernel/doorbell.H index 1d01ce119da..d9a6136720a 100644 --- a/src/include/kernel/doorbell.H +++ b/src/include/kernel/doorbell.H @@ -56,6 +56,13 @@ void send_doorbell_wakeup(uint64_t i_pir); */ void send_doorbell_ipc(uint64_t i_pir); +/** Send a doorbell and also restore the thread's timebase + * + * @param i_pir - PIR to send doorbell to wakeup + * @param i_tb - Timebase value to restore during wakeup + */ +void send_doorbell_restore_tb(uint64_t i_pir, uint64_t i_tb); + enum { _DOORBELL_MSG_TYPE = 0x0000000028000000, /// Comes from the ISA. diff --git a/src/include/kernel/workitem.H b/src/include/kernel/workitem.H index 856f5b36501..027f3626fdd 100644 --- a/src/include/kernel/workitem.H +++ b/src/include/kernel/workitem.H @@ -53,6 +53,18 @@ class CpuWakeupDoorbellWorkItem : public KernelWorkItem ~CpuWakeupDoorbellWorkItem() = default; }; +//A work item to be created/executed during a Master CPU +// wakeup scenario, it will also restore the timebase +// on the threads being woken up +class CpuTbRestoreDoorbellWorkItem : public KernelWorkItem +{ + public: + //Implement operator() function + void operator() (void); + + //No data to clean up, use default destructor + ~CpuTbRestoreDoorbellWorkItem() = default; +}; #endif diff --git a/src/kernel/cpumgr.C b/src/kernel/cpumgr.C index 5f92f0869f3..450fc818de8 100644 --- a/src/kernel/cpumgr.C +++ b/src/kernel/cpumgr.C @@ -253,6 +253,7 @@ void CpuManager::startCPU(ssize_t i) cpu->idle_task = TaskManager::createIdleTask(); cpu->idle_task->cpu = cpu; cpu->periodic_count = 0; + cpu->cpu_restore_tb = 0; // Call TimeManager setup for a CPU. TimeManager::init_cpu(cpu); diff --git a/src/kernel/doorbell.C b/src/kernel/doorbell.C index 3ff13c201ad..0a50aa3027d 100644 --- a/src/kernel/doorbell.C +++ b/src/kernel/doorbell.C @@ -83,6 +83,20 @@ void send_doorbell_wakeup(uint64_t i_pir) doorbell_send(i_pir); } +void send_doorbell_restore_tb(uint64_t i_pir, uint64_t i_tb) +{ + cpu_t *l_cpu = CpuManager::getCpu(i_pir); + l_cpu->cpu_restore_tb = i_tb; + + printkd("send_doorbell_restore_tb to pir: %lx\n", i_pir); + //Create WorkItem and put on the stack to be executed during doorbell + // execution + KernelWorkItem* l_work = new CpuTbRestoreDoorbellWorkItem(); + l_cpu->doorbell_actions.push(l_work); + //Send doorbell to wakeup core/thread + doorbell_send(i_pir); +} + void send_doorbell_ipc(uint64_t i_pir) { printk("send_doorbell_ipc to pir: %lx\n", i_pir); diff --git a/src/kernel/misc.C b/src/kernel/misc.C index 5eabaddd109..f59fbe82e36 100644 --- a/src/kernel/misc.C +++ b/src/kernel/misc.C @@ -347,7 +347,7 @@ namespace KernelMisc // NOTE: The deferred work container verifies master core // threads 1-3 wake up so a direct doorbell can be sent. For // threads on other cores send_doorbell_wakeup() is used. - doorbell_send(l_pir + i); + send_doorbell_restore_tb(l_pir + i, iv_timebase); } } @@ -357,7 +357,6 @@ namespace KernelMisc { cpu->scheduler->setNextRunnable(); } - } void WinkleCore::masterPostWork() @@ -464,7 +463,6 @@ namespace KernelMisc { cpu->scheduler->setNextRunnable(); } - } void WinkleAll::masterPostWork() diff --git a/src/kernel/workitem.C b/src/kernel/workitem.C index 0edf83083a2..53f91cb3b97 100644 --- a/src/kernel/workitem.C +++ b/src/kernel/workitem.C @@ -27,6 +27,7 @@ #include #include #include +#include //Define the desired behavior for a CPU core/thread // wakeup scenario @@ -40,3 +41,17 @@ void CpuWakeupDoorbellWorkItem::operator() (void) InterruptMsgHdlr::sendThreadWakeupMsg(pir); return; } + +void CpuTbRestoreDoorbellWorkItem::operator() (void) +{ + size_t pir = getPIR(); + cpu_t *l_cpu = CpuManager::getCpu(pir); + + uint64_t l_restore_tb = l_cpu->cpu_restore_tb; + printkd("pir:%ld tb:0x%0x\n", pir, l_restore_tb); + if (l_restore_tb > getTB()) + { + setTB(l_restore_tb); + } + return; +}