From bb9e50d71e1cac38c09b77d15983e0b731a2949c Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Tue, 13 Mar 2012 20:43:38 -0400 Subject: [PATCH] Revert "Merge branch 'stable/cpufreq-xen.v6.rebased' into uek2-merge" This reverts commit 2fa5344c95525da55cd6896af85541fc23c1bdc0, reversing changes made to d696e467d97b748cab14eb1b9910bf45f2044033. As the upstream version has changed course.. and also remove xen/processor-passthru.c which the git commit: 696e467d97b748cab14eb1b9910bf45f2044033 should have done. Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/Kconfig | 25 +- drivers/xen/Makefile | 2 +- drivers/xen/cpufreq_xen.c | 445 ---------------------------- drivers/xen/processor-passthru.c | 492 ------------------------------- 4 files changed, 13 insertions(+), 951 deletions(-) delete mode 100644 drivers/xen/cpufreq_xen.c delete mode 100644 drivers/xen/processor-passthru.c diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig index e2a7d748187a..73dced010765 100644 --- a/drivers/xen/Kconfig +++ b/drivers/xen/Kconfig @@ -151,21 +151,20 @@ config XEN_MCE_LOG Allow kernel fetching mce log from xen platform and converting it into linux mcelog format for mcelog tools -config CPU_FREQ_GOV_XEN - tristate "'xen' governor for hypervisor scaling" - depends on XEN && X86 && ACPI_PROCESSOR && CPU_FREQ - default m - help - This cpufreq governor leaves the frequency decision to the Xen hypervisor. - - To do that the driver parses the Power Management data and uploads said - information to the Xen hypervisor. Then the Xen hypervisor can select the - proper Cx and Pxx states. - To compile this driver as a module, choose M here: the - module will be called cpufreq_xen. If you do not know what to choose, - select M here. +config XEN_PROCESSOR_PASSTHRU + tristate "Processor passthrough driver for Xen" + depends on XEN + depends on ACPI_PROCESSOR + depends on X86 + depends on CPU_FREQ + help + This driver parses the processor structure and passes the information + to the Xen hypervisor. It is used to allow the Xen hypervisor to have the + full power management data and be able to select proper Cx and Pxx states. + The driver should be loaded after acpi processor and cpufreq drivers have + been loaded. If you do not know what to choose, select M here. config XEN_PRIVCMD diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile index 9b25bcc05945..2f3ba85a3c84 100644 --- a/drivers/xen/Makefile +++ b/drivers/xen/Makefile @@ -19,7 +19,7 @@ obj-$(CONFIG_XEN_TMEM) += tmem.o obj-$(CONFIG_SWIOTLB_XEN) += swiotlb-xen.o obj-$(CONFIG_XEN_DOM0) += pci.o acpi.o obj-$(CONFIG_XEN_PRIVCMD) += xen-privcmd.o -obj-$(CONFIG_CPU_FREQ_GOV_XEN) += cpufreq_xen.o +obj-$(CONFIG_XEN_PROCESSOR_PASSTHRU) += processor-passthru.o obj-$(CONFIG_XEN_PCIDEV_BACKEND) += xen-pciback/ xen-evtchn-y := evtchn.o xen-gntdev-y := gntdev.o diff --git a/drivers/xen/cpufreq_xen.c b/drivers/xen/cpufreq_xen.c deleted file mode 100644 index 1b709bfceb55..000000000000 --- a/drivers/xen/cpufreq_xen.c +++ /dev/null @@ -1,445 +0,0 @@ -/* - * Copyright 2012 by Oracle Inc - * Author: Konrad Rzeszutek Wilk - * - * This code borrows ideas from https://lkml.org/lkml/2011/11/30/249 - * so many thanks go to Kevin Tian - * and Yu Ke . - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define DRV_NAME "cpufreq-xen" - -static int no_hypercall; -MODULE_PARM_DESC(off, "Inhibit the hypercall."); -module_param_named(off, no_hypercall, int, 0400); - -/* - * Mutex to protect the acpi_ids_done. - */ -static DEFINE_MUTEX(acpi_ids_mutex); -/* - * Don't think convert this to cpumask_var_t or use cpumask_bit - as those - * shrink to nr_cpu_bits (which is dependent on possible_cpu), which can be - * less than what we want to put in. - */ -#define NR_ACPI_CPUS NR_CPUS -#define MAX_ACPI_BITS (BITS_TO_LONGS(NR_ACPI_CPUS)) -static unsigned long *acpi_ids_done; -/* - * Again, don't convert to cpumask - as we are reading the raw ACPI CPU ids - * which can go beyond what we presently see. - */ -static unsigned long *acpi_id_present; - -/* - * Pertient data for the timer to be launched to check if the # of - * ACPI CPU ids is different from the one we have processed. - */ -#define DELAY_TIMER msecs_to_jiffies(5000 /* 5 sec */) -static struct acpi_processor *pr_backup; -static struct delayed_work work; - -static int push_cxx_to_hypervisor(struct acpi_processor *_pr) -{ - struct xen_platform_op op = { - .cmd = XENPF_set_processor_pminfo, - .interface_version = XENPF_INTERFACE_VERSION, - .u.set_pminfo.id = _pr->acpi_id, - .u.set_pminfo.type = XEN_PM_CX, - }; - struct xen_processor_cx *dst_cx, *dst_cx_states = NULL; - struct acpi_processor_cx *cx; - int i, ok, ret = 0; - - dst_cx_states = kcalloc(_pr->power.count, - sizeof(struct xen_processor_cx), GFP_KERNEL); - if (!dst_cx_states) - return -ENOMEM; - - for (ok = 0, i = 1; i <= _pr->power.count; i++) { - cx = &_pr->power.states[i]; - if (!cx->valid) - continue; - - dst_cx = &(dst_cx_states[ok++]); - - dst_cx->reg.space_id = ACPI_ADR_SPACE_SYSTEM_IO; - if (cx->entry_method == ACPI_CSTATE_SYSTEMIO) { - dst_cx->reg.bit_width = 8; - dst_cx->reg.bit_offset = 0; - dst_cx->reg.access_size = 1; - } else { - dst_cx->reg.space_id = ACPI_ADR_SPACE_FIXED_HARDWARE; - if (cx->entry_method == ACPI_CSTATE_FFH) { - /* NATIVE_CSTATE_BEYOND_HALT */ - dst_cx->reg.bit_offset = 2; - dst_cx->reg.bit_width = 1; /* VENDOR_INTEL */ - } - dst_cx->reg.access_size = 0; - } - dst_cx->reg.address = cx->address; - - dst_cx->type = cx->type; - dst_cx->latency = cx->latency; - dst_cx->power = cx->power; - - dst_cx->dpcnt = 0; - set_xen_guest_handle(dst_cx->dp, NULL); -#ifdef DEBUG - pr_debug(DRV_NAME ": CX: ID:%d [C%d:%s] entry:%d\n", - _pr->acpi_id, cx->type, cx->desc, cx->entry_method); -#endif - } - if (!ok) { - pr_err(DRV_NAME ": No _Cx for CPU %d\n", _pr->acpi_id); - kfree(dst_cx_states); - return -EINVAL; - } - op.u.set_pminfo.power.count = ok; - op.u.set_pminfo.power.flags.bm_control = _pr->flags.bm_control; - op.u.set_pminfo.power.flags.bm_check = _pr->flags.bm_check; - op.u.set_pminfo.power.flags.has_cst = _pr->flags.has_cst; - op.u.set_pminfo.power.flags.power_setup_done = - _pr->flags.power_setup_done; - - set_xen_guest_handle(op.u.set_pminfo.power.states, dst_cx_states); - - if (!no_hypercall) - ret = HYPERVISOR_dom0_op(&op); - - if (ret) - pr_err(DRV_NAME "(CX): Hypervisor error (%d) for ACPI ID: %d\n", - ret, _pr->acpi_id); - - kfree(dst_cx_states); - - return ret; -} -static struct xen_processor_px * -xen_copy_pss_data(struct acpi_processor *_pr, - struct xen_processor_performance *dst_perf) -{ - struct xen_processor_px *dst_states = NULL; - int i; - - BUILD_BUG_ON(sizeof(struct xen_processor_px) != - sizeof(struct acpi_processor_px)); - - dst_states = kcalloc(_pr->performance->state_count, - sizeof(struct xen_processor_px), GFP_KERNEL); - if (!dst_states) - return ERR_PTR(-ENOMEM); - - dst_perf->state_count = _pr->performance->state_count; - for (i = 0; i < _pr->performance->state_count; i++) { - /* Fortunatly for us, they are both the same size */ - memcpy(&(dst_states[i]), &(_pr->performance->states[i]), - sizeof(struct acpi_processor_px)); - } - return dst_states; -} -static int xen_copy_psd_data(struct acpi_processor *_pr, - struct xen_processor_performance *dst) -{ - BUILD_BUG_ON(sizeof(struct xen_psd_package) != - sizeof(struct acpi_psd_package)); - - if (_pr->performance->shared_type != CPUFREQ_SHARED_TYPE_NONE) { - dst->shared_type = _pr->performance->shared_type; - - memcpy(&(dst->domain_info), &(_pr->performance->domain_info), - sizeof(struct acpi_psd_package)); - } else { - if ((&cpu_data(0))->x86_vendor != X86_VENDOR_AMD) - return -EINVAL; - - /* On AMD, the powernow-k8 is loaded before acpi_cpufreq - * meaning that acpi_processor_preregister_performance never - * gets called which would parse the _PSD. The only relevant - * information from _PSD we need is whether it is HW_ALL or any - * other type. AMD K8 >= are SW_ALL or SW_ANY, AMD K7<= HW_ANY. - * This driver checks at the start whether it is K8 so it - * if we get here it can only be K8. - */ - dst->shared_type = CPUFREQ_SHARED_TYPE_ANY; - dst->domain_info.coord_type = DOMAIN_COORD_TYPE_SW_ANY; - dst->domain_info.num_processors = num_online_cpus(); - } - return 0; -} -static int xen_copy_pct_data(struct acpi_pct_register *pct, - struct xen_pct_register *dst_pct) -{ - /* It would be nice if you could just do 'memcpy(pct, dst_pct') but - * sadly the Xen structure did not have the proper padding so the - * descriptor field takes two (dst_pct) bytes instead of one (pct). - */ - dst_pct->descriptor = pct->descriptor; - dst_pct->length = pct->length; - dst_pct->space_id = pct->space_id; - dst_pct->bit_width = pct->bit_width; - dst_pct->bit_offset = pct->bit_offset; - dst_pct->reserved = pct->reserved; - dst_pct->address = pct->address; - return 0; -} -static int push_pxx_to_hypervisor(struct acpi_processor *_pr) -{ - int ret = 0; - struct xen_platform_op op = { - .cmd = XENPF_set_processor_pminfo, - .interface_version = XENPF_INTERFACE_VERSION, - .u.set_pminfo.id = _pr->acpi_id, - .u.set_pminfo.type = XEN_PM_PX, - }; - struct xen_processor_performance *dst_perf; - struct xen_processor_px *dst_states = NULL; - - dst_perf = &op.u.set_pminfo.perf; - - dst_perf->platform_limit = _pr->performance_platform_limit; - dst_perf->flags |= XEN_PX_PPC; - xen_copy_pct_data(&(_pr->performance->control_register), - &dst_perf->control_register); - xen_copy_pct_data(&(_pr->performance->status_register), - &dst_perf->status_register); - dst_perf->flags |= XEN_PX_PCT; - dst_states = xen_copy_pss_data(_pr, dst_perf); - if (!IS_ERR_OR_NULL(dst_states)) { - set_xen_guest_handle(dst_perf->states, dst_states); - dst_perf->flags |= XEN_PX_PSS; - } - if (!xen_copy_psd_data(_pr, dst_perf)) - dst_perf->flags |= XEN_PX_PSD; - - if (!no_hypercall) - ret = HYPERVISOR_dom0_op(&op); - - if (ret) - pr_err(DRV_NAME "(_PXX): Hypervisor error (%d) for ACPI ID %d\n", - ret, _pr->acpi_id); - - if (!IS_ERR_OR_NULL(dst_states)) - kfree(dst_states); - - return ret; -} -static int upload_pm_data(struct acpi_processor *_pr) -{ - int err = 0; - - if (__test_and_set_bit(_pr->acpi_id, acpi_ids_done)) - return -EBUSY; - - if (_pr->flags.power) - err = push_cxx_to_hypervisor(_pr); - - if (_pr->performance && _pr->performance->states) - err |= push_pxx_to_hypervisor(_pr); - - return err; -} -static acpi_status -read_acpi_id(acpi_handle handle, u32 lvl, void *context, void **rv) -{ - u32 acpi_id; - acpi_status status; - acpi_object_type acpi_type; - unsigned long long tmp; - union acpi_object object = { 0 }; - struct acpi_buffer buffer = { sizeof(union acpi_object), &object }; - - status = acpi_get_type(handle, &acpi_type); - if (ACPI_FAILURE(status)) - return AE_OK; - - switch (acpi_type) { - case ACPI_TYPE_PROCESSOR: - status = acpi_evaluate_object(handle, NULL, NULL, &buffer); - if (ACPI_FAILURE(status)) - return AE_OK; - acpi_id = object.processor.proc_id; - break; - case ACPI_TYPE_DEVICE: - status = acpi_evaluate_integer(handle, "_UID", NULL, &tmp); - if (ACPI_FAILURE(status)) - return AE_OK; - acpi_id = tmp; - break; - default: - return AE_OK; - } - if (acpi_id > NR_ACPI_CPUS) { - WARN_ONCE(1, "There are %d ACPI processors, but kernel can only do %d!\n", - acpi_id, NR_ACPI_CPUS); - return AE_OK; - } - __set_bit(acpi_id, acpi_id_present); - - return AE_OK; -} -static unsigned int more_acpi_ids(void) -{ - unsigned int n = 0; - - acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, - read_acpi_id, NULL, NULL, NULL); - acpi_get_devices("ACPI0007", read_acpi_id, NULL, NULL); - - mutex_lock(&acpi_ids_mutex); - if (!bitmap_equal(acpi_id_present, acpi_ids_done, MAX_ACPI_BITS)) - n = bitmap_weight(acpi_id_present, MAX_ACPI_BITS); - mutex_unlock(&acpi_ids_mutex); - - return n; -} -static void do_check_acpi_id_timer(struct work_struct *_work) -{ - /* All online CPUs have been processed at this stage. Now verify - * whether in fact "online CPUs" == physical CPUs. - */ - acpi_id_present = kcalloc(MAX_ACPI_BITS, sizeof(unsigned long), GFP_KERNEL); - if (!acpi_id_present) - return; - memset(acpi_id_present, 0, MAX_ACPI_BITS * sizeof(unsigned long)); - - if (more_acpi_ids()) { - int cpu; - if (!pr_backup) { - schedule_delayed_work(&work, DELAY_TIMER); - return; - } - for_each_set_bit(cpu, acpi_id_present, MAX_ACPI_BITS) { - pr_backup->acpi_id = cpu; - mutex_lock(&acpi_ids_mutex); - (void)upload_pm_data(pr_backup); - mutex_unlock(&acpi_ids_mutex); - } - } - kfree(acpi_id_present); - acpi_id_present = NULL; -} - -static int cpufreq_governor_xen(struct cpufreq_policy *policy, - unsigned int event) -{ - struct acpi_processor *_pr; - - switch (event) { - case CPUFREQ_GOV_START: - case CPUFREQ_GOV_LIMITS: - /* Set it to max and let the hypervisor take over */ - __cpufreq_driver_target(policy, policy->max, CPUFREQ_RELATION_H); - - _pr = per_cpu(processors, policy->cpu /* APIC ID */); - if (!_pr) - break; - - mutex_lock(&acpi_ids_mutex); - if (!pr_backup) { - pr_backup = kzalloc(sizeof(struct acpi_processor), GFP_KERNEL); - memcpy(pr_backup, _pr, sizeof(struct acpi_processor)); - - INIT_DELAYED_WORK_DEFERRABLE(&work, do_check_acpi_id_timer); - schedule_delayed_work(&work, DELAY_TIMER); - } - (void)upload_pm_data(_pr); - mutex_unlock(&acpi_ids_mutex); - break; - default: - break; - } - return 0; -} -static struct cpufreq_governor cpufreq_gov_xen = { - .name = "xen", - .governor = cpufreq_governor_xen, - .owner = THIS_MODULE, -}; -static int __init check_prereq(void) -{ - struct cpuinfo_x86 *c = &cpu_data(0); - - if (!xen_initial_domain()) - return -ENODEV; - - if (!acpi_gbl_FADT.smi_command) - return -ENODEV; - - if (c->x86_vendor == X86_VENDOR_INTEL) { - if (!cpu_has(c, X86_FEATURE_EST)) - return -ENODEV; - - return 0; - } - if (c->x86_vendor == X86_VENDOR_AMD) { - u32 hi = 0, lo = 0; - /* Copied from powernow-k8.h, can't include ../cpufreq/powernow - * as we get compile warnings for the static functions. - */ -#define MSR_PSTATE_CUR_LIMIT 0xc0010061 /* pstate current limit MSR */ - rdmsr(MSR_PSTATE_CUR_LIMIT, lo, hi); - - /* If the MSR cannot provide the data, the powernow-k8 - * won't process the data properly either. - */ - if (hi || lo) - return 0; - } - return -ENODEV; -} - -static int __init xen_processor_passthru_init(void) -{ - int rc = check_prereq(); - - if (rc) - return rc; - - acpi_ids_done = kcalloc(MAX_ACPI_BITS, sizeof(unsigned long), GFP_KERNEL); - if (!acpi_ids_done) - return -ENOMEM; - memset(acpi_ids_done, 0, MAX_ACPI_BITS * sizeof(unsigned long)); - - return cpufreq_register_governor(&cpufreq_gov_xen); -} -static void __exit xen_processor_passthru_exit(void) -{ - cpufreq_unregister_governor(&cpufreq_gov_xen); - cancel_delayed_work_sync(&work); - kfree(acpi_ids_done); - kfree(pr_backup); -} - -MODULE_AUTHOR("Konrad Rzeszutek Wilk "); -MODULE_DESCRIPTION("CPUfreq policy governor 'xen' which uploads PM data to Xen hypervisor"); -MODULE_LICENSE("GPL"); - -late_initcall(xen_processor_passthru_init); -module_exit(xen_processor_passthru_exit); diff --git a/drivers/xen/processor-passthru.c b/drivers/xen/processor-passthru.c deleted file mode 100644 index e4dff423f557..000000000000 --- a/drivers/xen/processor-passthru.c +++ /dev/null @@ -1,492 +0,0 @@ -/* - * Copyright 2012 by Oracle Inc - * Author: Konrad Rzeszutek Wilk - * - * This code borrows ideas from https://lkml.org/lkml/2011/11/30/249 - * so many thanks go to Kevin Tian - * and Yu Ke . - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define DRV_NAME "xen-processor-thru" -MODULE_AUTHOR("Konrad Rzeszutek Wilk "); -MODULE_DESCRIPTION("ACPI Power Management driver to pass Cx and Pxx data to Xen hypervisor"); -MODULE_LICENSE("GPL"); - - -static int no_hypercall; -MODULE_PARM_DESC(off, "Inhibit the hypercall."); -module_param_named(off, no_hypercall, int, 0400); - -/* - * Mutex to protect the acpi_ids_done. - */ -static DEFINE_MUTEX(acpi_ids_mutex); -/* - * Don't think convert this to cpumask_var_t or use cpumask_bit - as those - * shrink to nr_cpu_bits (which is dependent on possible_cpu), which can be - * less than what we want to put in. - */ -#define NR_ACPI_CPUS NR_CPUS -#define MAX_ACPI_BITS (BITS_TO_LONGS(NR_ACPI_CPUS)) -static unsigned long *acpi_ids_done; -/* - * Again, don't convert to cpumask - as we are reading the raw ACPI CPU ids - * which can go beyond what we presently see. - */ -static unsigned long *acpi_id_present; - - -#define POLL_TIMER msecs_to_jiffies(5000 /* 5 sec */) -static struct task_struct *xen_processor_thread; - -static int xen_push_cxx_to_hypervisor(struct acpi_processor *_pr) -{ - struct xen_platform_op op = { - .cmd = XENPF_set_processor_pminfo, - .interface_version = XENPF_INTERFACE_VERSION, - .u.set_pminfo.id = _pr->acpi_id, - .u.set_pminfo.type = XEN_PM_CX, - }; - struct xen_processor_cx *xen_cx, *xen_cx_states = NULL; - struct acpi_processor_cx *cx; - int i, ok, ret = 0; - - xen_cx_states = kcalloc(_pr->power.count, - sizeof(struct xen_processor_cx), GFP_KERNEL); - if (!xen_cx_states) - return -ENOMEM; - - for (ok = 0, i = 1; i <= _pr->power.count; i++) { - cx = &_pr->power.states[i]; - if (!cx->valid) - continue; - - xen_cx = &(xen_cx_states[ok++]); - - xen_cx->reg.space_id = ACPI_ADR_SPACE_SYSTEM_IO; - if (cx->entry_method == ACPI_CSTATE_SYSTEMIO) { - xen_cx->reg.bit_width = 8; - xen_cx->reg.bit_offset = 0; - xen_cx->reg.access_size = 1; - } else { - xen_cx->reg.space_id = ACPI_ADR_SPACE_FIXED_HARDWARE; - if (cx->entry_method == ACPI_CSTATE_FFH) { - /* NATIVE_CSTATE_BEYOND_HALT */ - xen_cx->reg.bit_offset = 2; - xen_cx->reg.bit_width = 1; /* VENDOR_INTEL */ - } - xen_cx->reg.access_size = 0; - } - xen_cx->reg.address = cx->address; - - xen_cx->type = cx->type; - xen_cx->latency = cx->latency; - xen_cx->power = cx->power; - - xen_cx->dpcnt = 0; - set_xen_guest_handle(xen_cx->dp, NULL); -#ifdef DEBUG - pr_debug(DRV_NAME ": CX: ID:%d [C%d:%s] entry:%d\n", _pr->acpi_id, - cx->type, cx->desc, cx->entry_method); -#endif - } - if (!ok) { - pr_err(DRV_NAME ": No available Cx info for cpu %d\n", _pr->acpi_id); - kfree(xen_cx_states); - return -EINVAL; - } - op.u.set_pminfo.power.count = ok; - op.u.set_pminfo.power.flags.bm_control = _pr->flags.bm_control; - op.u.set_pminfo.power.flags.bm_check = _pr->flags.bm_check; - op.u.set_pminfo.power.flags.has_cst = _pr->flags.has_cst; - op.u.set_pminfo.power.flags.power_setup_done = - _pr->flags.power_setup_done; - - set_xen_guest_handle(op.u.set_pminfo.power.states, xen_cx_states); - - if (!no_hypercall) - ret = HYPERVISOR_dom0_op(&op); - - if (ret) - pr_err(DRV_NAME "(CX): Hypervisor returned (%d) for ACPI ID: %d\n", - ret, _pr->acpi_id); - - kfree(xen_cx_states); - - return ret; -} -static struct xen_processor_px *xen_copy_pss_data(struct acpi_processor *_pr, - struct xen_processor_performance *xen_perf) -{ - struct xen_processor_px *xen_states = NULL; - int i; - - BUILD_BUG_ON(sizeof(struct xen_processor_px) != - sizeof(struct acpi_processor_px)); - - xen_states = kcalloc(_pr->performance->state_count, - sizeof(struct xen_processor_px), GFP_KERNEL); - if (!xen_states) - return ERR_PTR(-ENOMEM); - - xen_perf->state_count = _pr->performance->state_count; - for (i = 0; i < _pr->performance->state_count; i++) { - /* Fortunatly for us, they are both the same size */ - memcpy(&(xen_states[i]), &(_pr->performance->states[i]), - sizeof(struct acpi_processor_px)); - } - return xen_states; -} -static int xen_copy_psd_data(struct acpi_processor *_pr, - struct xen_processor_performance *xen_perf) -{ - BUILD_BUG_ON(sizeof(struct xen_psd_package) != - sizeof(struct acpi_psd_package)); - - if (_pr->performance->shared_type != CPUFREQ_SHARED_TYPE_NONE) { - xen_perf->shared_type = _pr->performance->shared_type; - - memcpy(&(xen_perf->domain_info), &(_pr->performance->domain_info), - sizeof(struct acpi_psd_package)); - } else { - if ((&cpu_data(0))->x86_vendor != X86_VENDOR_AMD) - return -EINVAL; - - /* On AMD, the powernow-k8 is loaded before acpi_cpufreq - * meaning that acpi_processor_preregister_performance never - * gets called which would parse the _PSD. The only relevant - * information from _PSD we need is whether it is HW_ALL or any - * other type. AMD K8 >= are SW_ALL or SW_ANY, AMD K7<= HW_ANY. - * This driver checks at the start whether it is K8 so it - * if we get here it can only be K8. - */ - xen_perf->shared_type = CPUFREQ_SHARED_TYPE_ANY; - xen_perf->domain_info.coord_type = DOMAIN_COORD_TYPE_SW_ANY; - xen_perf->domain_info.num_processors = num_online_cpus(); - } - return 0; -} -static int xen_copy_pct_data(struct acpi_pct_register *pct, - struct xen_pct_register *_pct) -{ - /* It would be nice if you could just do 'memcpy(pct, _pct') but - * sadly the Xen structure did not have the proper padding - * so the descriptor field takes two (_pct) bytes instead of one (pct). - */ - _pct->descriptor = pct->descriptor; - _pct->length = pct->length; - _pct->space_id = pct->space_id; - _pct->bit_width = pct->bit_width; - _pct->bit_offset = pct->bit_offset; - _pct->reserved = pct->reserved; - _pct->address = pct->address; - return 0; -} -static int xen_push_pxx_to_hypervisor(struct acpi_processor *_pr) -{ - int ret = 0; - struct xen_platform_op op = { - .cmd = XENPF_set_processor_pminfo, - .interface_version = XENPF_INTERFACE_VERSION, - .u.set_pminfo.id = _pr->acpi_id, - .u.set_pminfo.type = XEN_PM_PX, - }; - struct xen_processor_performance *xen_perf; - struct xen_processor_px *xen_states = NULL; - - xen_perf = &op.u.set_pminfo.perf; - - xen_perf->platform_limit = _pr->performance_platform_limit; - xen_perf->flags |= XEN_PX_PPC; - xen_copy_pct_data(&(_pr->performance->control_register), - &xen_perf->control_register); - xen_copy_pct_data(&(_pr->performance->status_register), - &xen_perf->status_register); - xen_perf->flags |= XEN_PX_PCT; - xen_states = xen_copy_pss_data(_pr, xen_perf); - if (!IS_ERR_OR_NULL(xen_states)) { - set_xen_guest_handle(xen_perf->states, xen_states); - xen_perf->flags |= XEN_PX_PSS; - } - if (!xen_copy_psd_data(_pr, xen_perf)) - xen_perf->flags |= XEN_PX_PSD; - - if (!no_hypercall) - ret = HYPERVISOR_dom0_op(&op); - - if (ret) - pr_err(DRV_NAME "(_PXX): Hypervisor returned (%d) for ACPI ID %d\n", - ret, _pr->acpi_id); - - if (!IS_ERR_OR_NULL(xen_states)) - kfree(xen_states); - - return ret; -} -/* - * We read out the struct acpi_processor, and serialize access - * so that there is only one caller. This is so that we won't - * race with the CPU hotplug code (xen_cpu_soft_notify). - */ -static int xen_process_data(struct acpi_processor *_pr) -{ - int err = 0; - - mutex_lock(&acpi_ids_mutex); - if (__test_and_set_bit(_pr->acpi_id, acpi_ids_done)) { - mutex_unlock(&acpi_ids_mutex); - return -EBUSY; - } - if (_pr->flags.power) - err = xen_push_cxx_to_hypervisor(_pr); - - if (_pr->performance && _pr->performance->states) - err |= xen_push_pxx_to_hypervisor(_pr); - - mutex_unlock(&acpi_ids_mutex); - return err; -} -static acpi_status -xen_read_acpi_id(acpi_handle handle, u32 lvl, void *context, void **rv) -{ - u32 acpi_id; - acpi_status status; - acpi_object_type acpi_type; - unsigned long long tmp; - union acpi_object object = { 0 }; - struct acpi_buffer buffer = { sizeof(union acpi_object), &object }; - - status = acpi_get_type(handle, &acpi_type); - if (ACPI_FAILURE(status)) - return AE_OK; - - switch (acpi_type) { - case ACPI_TYPE_PROCESSOR: - status = acpi_evaluate_object(handle, NULL, NULL, &buffer); - if (ACPI_FAILURE(status)) - return AE_OK; - acpi_id = object.processor.proc_id; - break; - case ACPI_TYPE_DEVICE: - status = acpi_evaluate_integer(handle, "_UID", NULL, &tmp); - if (ACPI_FAILURE(status)) - return AE_OK; - acpi_id = tmp; - break; - default: - return AE_OK; - } - if (acpi_id > NR_ACPI_CPUS) { - WARN_ONCE(1, "There are %d ACPI processors, but kernel can only do %d!\n", - acpi_id, NR_ACPI_CPUS); - return AE_OK; - } - __set_bit(acpi_id, acpi_id_present); - - return AE_OK; -} -static unsigned int xen_acpi_ids_more(void) -{ - unsigned int n = 0; - - acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, - xen_read_acpi_id, NULL, NULL, NULL); - acpi_get_devices("ACPI0007", xen_read_acpi_id, NULL, NULL); - - mutex_lock(&acpi_ids_mutex); - if (!bitmap_equal(acpi_id_present, acpi_ids_done, MAX_ACPI_BITS)) - n = bitmap_weight(acpi_id_present, MAX_ACPI_BITS); - mutex_unlock(&acpi_ids_mutex); - - return n; -} - -static int xen_processor_check(void) -{ - struct cpufreq_policy *policy; - struct acpi_processor *pr_backup = NULL; - int cpu, err = 0; - - cpu = get_cpu(); - put_cpu(); - policy = cpufreq_cpu_get(cpu); - if (!policy) - return -EBUSY; - - get_online_cpus(); - for_each_online_cpu(cpu) { - struct acpi_processor *_pr; - - _pr = per_cpu(processors, cpu /* APIC ID */); - if (!_pr) - continue; - - if (!pr_backup) { - pr_backup = kzalloc(sizeof(struct acpi_processor), GFP_KERNEL); - memcpy(pr_backup, _pr, sizeof(struct acpi_processor)); - } - (void)xen_process_data(_pr); - } - put_online_cpus(); - - cpufreq_cpu_put(policy); - - /* All online CPUs have been processed at this stage. Now verify - * whether in fact "online CPUs" == physical CPUs. - */ - acpi_id_present = kcalloc(MAX_ACPI_BITS, sizeof(unsigned long), GFP_KERNEL); - if (!acpi_id_present) { - err = -ENOMEM; - goto err_out; - } - memset(acpi_id_present, 0, MAX_ACPI_BITS * sizeof(unsigned long)); - - if (xen_acpi_ids_more() && pr_backup) { - for_each_set_bit(cpu, acpi_id_present, MAX_ACPI_BITS) { - pr_backup->acpi_id = cpu; - /* We will get -EBUSY if it has been programmed already. */ - (void)xen_process_data(pr_backup); - } - } - kfree(acpi_id_present); - acpi_id_present = NULL; -err_out: - kfree(pr_backup); - pr_backup = NULL; - return err; -} -/* - * The purpose of this timer/thread is to wait for the ACPI processor - * and CPUfreq drivers to load up and parse the Pxx and Cxx information - * before we attempt to read it. - */ -static void xen_processor_timeout(unsigned long arg) -{ - wake_up_process((struct task_struct *)arg); -} -static int xen_processor_thread_func(void *dummy) -{ - struct timer_list timer; - int err = 0; - - setup_deferrable_timer_on_stack(&timer, xen_processor_timeout, - (unsigned long)current); - do { - __set_current_state(TASK_INTERRUPTIBLE); - mod_timer(&timer, jiffies + POLL_TIMER); - schedule(); - err = xen_processor_check(); - if (err != -EBUSY) - break; - } while (!kthread_should_stop()); - - if (err) - pr_err(DRV_NAME ": Failed to upload data (%d)!\n", err); - del_timer_sync(&timer); - destroy_timer_on_stack(&timer); - return 0; -} - -static int xen_cpu_soft_notify(struct notifier_block *nfb, - unsigned long action, void *hcpu) -{ - unsigned int cpu = (unsigned long)hcpu; - struct acpi_processor *_pr = per_cpu(processors, cpu); - - if (action == CPU_ONLINE && _pr) - (void)xen_process_data(_pr); - - return NOTIFY_OK; -} - -static struct notifier_block xen_cpu_notifier = { - .notifier_call = xen_cpu_soft_notify, - .priority = -1, /* Be the last one */ -}; - -static int __init check_prereq(void) -{ - struct cpuinfo_x86 *c = &cpu_data(0); - - if (!xen_initial_domain()) - return -ENODEV; - - if (!acpi_gbl_FADT.smi_command) - return -ENODEV; - - if (c->x86_vendor == X86_VENDOR_INTEL) { - if (!cpu_has(c, X86_FEATURE_EST)) - return -ENODEV; - - return 0; - } - if (c->x86_vendor == X86_VENDOR_AMD) { - u32 hi = 0, lo = 0; - /* Copied from powernow-k8.h, can't include ../cpufreq/powernow - * as we get compile warnings for the static functions. - */ -#define MSR_PSTATE_CUR_LIMIT 0xc0010061 /* pstate current limit MSR */ - rdmsr(MSR_PSTATE_CUR_LIMIT, lo, hi); - - /* If the MSR cannot provide the data, the powernow-k8 - * won't process the data properly either. - */ - if (hi || lo) - return 0; - } - return -ENODEV; -} - -static int __init xen_processor_passthru_init(void) -{ - int rc = check_prereq(); - - if (rc) - return rc; - - acpi_ids_done = kcalloc(MAX_ACPI_BITS, sizeof(unsigned long), GFP_KERNEL); - if (!acpi_ids_done) - return -ENOMEM; - memset(acpi_ids_done, 0, MAX_ACPI_BITS * sizeof(unsigned long)); - xen_processor_thread = kthread_run(xen_processor_thread_func, NULL, DRV_NAME); - if (IS_ERR(xen_processor_thread)) { - pr_err(DRV_NAME ": Failed to create thread. Aborting.\n"); - return -ENOMEM; - } - register_hotcpu_notifier(&xen_cpu_notifier); - return 0; -} -static void __exit xen_processor_passthru_exit(void) -{ - unregister_hotcpu_notifier(&xen_cpu_notifier); - if (xen_processor_thread) - kthread_stop(xen_processor_thread); - kfree(acpi_ids_done); -} -late_initcall(xen_processor_passthru_init); -module_exit(xen_processor_passthru_exit); -- 2.50.1