diff options
Diffstat (limited to 'arch/arm/mvp/mvpkm/cpufreq_kernel.c')
-rw-r--r-- | arch/arm/mvp/mvpkm/cpufreq_kernel.c | 308 |
1 files changed, 0 insertions, 308 deletions
diff --git a/arch/arm/mvp/mvpkm/cpufreq_kernel.c b/arch/arm/mvp/mvpkm/cpufreq_kernel.c deleted file mode 100644 index 4ba71f2..0000000 --- a/arch/arm/mvp/mvpkm/cpufreq_kernel.c +++ /dev/null @@ -1,308 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief MVP host kernel cpufreq related - * - * Track CPU frequency changes. - */ - -#include <linux/module.h> -#include <linux/notifier.h> -#include <linux/cpu.h> -#include <linux/cpufreq.h> -#include <linux/rwsem.h> -#include <linux/smp.h> - -#include "mvp.h" -#include "cpufreq_kernel.h" -#include "mvp_timer.h" - -DEFINE_PER_CPU(struct TscToRate64Cb, tscToRate64); - - -/** - * @brief Return current CPU frequency - * @param cpu CPU number - * @return CPU frequency in Hz - * - * When CPU_FREQ is not available, it uses hardcoded frequencies. - */ -static uint32 -GetCpuFrequency(unsigned int cpu) -{ - unsigned int counterKHZ; - -#ifdef CONFIG_CPU_FREQ - counterKHZ = cpufreq_quick_get(cpu); - if (counterKHZ == 0) { - counterKHZ = cpufreq_get(cpu); - FATAL_IF(counterKHZ == 0); - } -#elif defined(MVP_HOST_BOARD_ve) - /** - * @knownjira{MVP-143} - * We're only using this under the simulator, and it's almost non perceptible to - * provide a fixed TSC frequency as the instructions / second executed widely - * varies depending over time. While we resolve this issue we can use the - * BogoMIPS reported at boot for now. - */ - KNOWN_BUG(MVP-143); - counterKHZ = 125e3; - printk(KERN_INFO "mvpkm: CPU_FREQ not available, forcing TSC to %d KHz\n", counterKHZ); -#elif defined(MVP_HOST_BOARD_panda) - counterKHZ = 1e6; -#else - /* - * If the kernel can't tell us and we have no further host knowledge, - * time to die. - */ -#error "host TSC frequency unknown." -#endif - - return counterKHZ * 1000; -} - -/** - * @brief Compute TSC to RATE64 ratio - * @param cpuFreq TSC frequency in Hz - * @param[out] ttr tscToRate64 pointer - */ -static void -TscToRate64(uint32 cpuFreq, struct TscToRate64Cb *ttr) -{ - uint32 shift; - uint64 mult; - - /* - * A little bit of math ! - * - * We need here to convert the TSC value to our RATE64 timebase. - * - * In other words: - * - * tsc * MVP_TIMER_RATE64 - * rate64 = ---------------------- - * cpuFreq - * - * But we are limited by CPU performance (does not divide easily), CPU - * instruction set, and CPU register file width. To fit performance - * requirement, the math becomes: - * - * rate64 = (cpuFreq * mult) >> shift - * - * To respect instruction set, both cpuFreq and mult must be 32-bit - * numbers. Thus (cpuFreq * mult) will be a 64-bit number. - * - * - * Log2 rate64 = Log2 cpuFreq + Log2 mult - shift - * - * shift = Log2 mult + Log2 cpuFreq - Log2 rate64 - * - * && Log2 mult < 32 - * - * => shift < 32 + Log2 cpuFreq - Log2 rate64 - * - * rate64 << shift - * => mult = --------------- - * cpuFreq - * - * (rate64 << shift) must be a 64-bit number: - * - * Log2 rate64 + shift < 64 - * - * => shift < 64 - Log2 rate64 - * - * While cpuFreq is lower than 2^32 Hz, we have: - * - * shift < 32 + Log2 cpuFreq - Log2 rate64 < 64 - Log2 rate64 - * - * As (31 - CLZ32 x) <= Log2 x < (32 - CLZ32 x): - * - * 31 - CLZ32 cpuFreq <= Log2 cpuFreq && - * - * CLZ32 rate64 - 32 < - Log2 rate64 - * - * 31 + CLZ32 rate64 - CLZ32 cpuFreq < 32 + Log2 cpuFreq - Log2 rate64 - * - * As we want shift to be as great as possible: - * - * => shift = 31 + CLZ32 rate64 - CLZ32 cpuFreq - * - * rate64 << shift - * && mult = --------------- - * cpuFreq - * - * - */ - - /* CLZ(MVP_TIMER_RATE64) is optimized by compiler in a constant */ - shift = 31 + CLZ(MVP_TIMER_RATE64) - CLZ(cpuFreq); - mult = MVP_TIMER_RATE64; - mult <<= shift; - do_div(mult, cpuFreq); - - /* verify Log2 mult < 32 */ - ASSERT(mult < (1ULL<<32)); - - /* update global variables */ - ttr->mult = mult; - ttr->shift = shift; -} - -/** - * @brief Compute TSC to RATE64 ratio for the current cpu - * @param info TSC frequency in Hz - * @sideeffect Update local cpu tscToRate64 - */ -static void -TscToRate64IPI(void *info) -{ - uint32 cpuFreq = (uint32)info; - - TscToRate64(cpuFreq, &__get_cpu_var(tscToRate64)); -} - -/** - * @brief Handle cpufreq transition notifications. - * @param nb Notifier block - * @param val Notified event - * @param data Linux cpufreq_freqs info - * @return NOTIFY_OK - * - * @note A frequency change can fail in which case PRECHANGE and POSTCHANGE - * will not be paired and you get any number of PRECHANGE and maybe never a - * POSTCHANGE (i.e. there is not enough battery voltage available to support a - * high frequency). - * @note This is called once per cpu core that is changing but not always on - * the core that is changing. - */ -static int -CpuFreqNotifier(struct notifier_block *nb, - unsigned long val, - void *data) -{ - struct cpufreq_freqs *freq = data; - bool updateRequired; - - /* ASSUMPTION: Only freq. increases can fail and that it is ok to tell the - * guest a higher frequency than it really is but not the other way around - * as that just leads to time "jumping" forward in the guest not backwards. - */ - updateRequired = (val == CPUFREQ_PRECHANGE && freq->new > freq->old) || - (val == CPUFREQ_POSTCHANGE && freq->new < freq->old); - - /* Call TscToRate64() on the correct CPU core so that locking is not - * required. This also has the side-effect of forcing any currently running - * vCPU's to worldswitch back to the host and correctly update the world - * switch page. - */ - if (updateRequired) { - uint32 hz = freq->new * 1000; - smp_call_function_single(freq->cpu, TscToRate64IPI, (void *)hz, false); - } - - return NOTIFY_OK; -} - -/** - * @brief Notifier block for cpufreq transitions - */ -static struct notifier_block cpuFreqNotifierBlock = { - .notifier_call = CpuFreqNotifier -}; - -/** - * @brief Handle cpuUp notifications. - * @param nb Notifier block - * @param action Notified action, e.g., CPU_ONLINE - * @param hcpu cpu no - * @return NOTIFY_OK - */ -static int -CpuUpNotifier(struct notifier_block *nb, - unsigned long action, - void *hcpu) -{ - long cpu = (long)hcpu; - - switch (action) { - case CPU_ONLINE: - /* The new CPU core is not yet executing normal tasks, so it is safe - * to update it's scaling factors from a different core. */ - TscToRate64(GetCpuFrequency(cpu), &per_cpu(tscToRate64, cpu)); - break; - default: - /* - * Ignore all other action notifications, - * such as CPU_UP_PREPARE, CPU_UP_CANCELED, - * CPU_DOWN_PREPARE, CPU_DOWN_FAILED, - * CPU_DYING, CPU_DEAD, CPU_POST_DEAD, etc. - * as they are irrelevant here. - */ - break; - } - - return NOTIFY_OK; -} - -/** - * @brief Notifier block for cpus going online - */ -static struct notifier_block cpuUpNotifierBlock = { - .notifier_call = CpuUpNotifier -}; - -/** - * @brief Initialize TSC ratio and register cpufreq transitions. - */ -void -CpuFreq_Init(void) -{ - int ret; - int cpu; - - /* register callback on frequency change */ - ret = cpufreq_register_notifier(&cpuFreqNotifierBlock, - CPUFREQ_TRANSITION_NOTIFIER); - FATAL_IF(ret < 0); - - /* register callback on cpu core online */ - ret = register_cpu_notifier(&cpuUpNotifierBlock); - FATAL_IF(ret < 0); - - /* Make sure that things are correctly initialized. */ - for_each_online_cpu(cpu) { - TscToRate64(GetCpuFrequency(cpu), &per_cpu(tscToRate64, cpu)); - } -} - -/** - * @brief Exit cpufreq, unregister cpufreq transitions - */ -void -CpuFreq_Exit(void) -{ - cpufreq_unregister_notifier(&cpuFreqNotifierBlock, - CPUFREQ_TRANSITION_NOTIFIER); - unregister_cpu_notifier(&cpuUpNotifierBlock); -} |