[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] x86: Setup cpufreq infrasturcture, driver and tools



# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1210769711 -3600
# Node ID 50fb7620d05ad869f354619e9fdf72e316c0d2b5
# Parent  66ddfc4d69631a069d8914bff12bd54fe97a4e9f
x86: Setup cpufreq infrasturcture, driver and tools

Initializing basic Px data structure, setup cpufreq infrastructure:
* cpufreq data structure initializing, including freq table and policy;
* basic driver and tools, to measure freq or drive to Px target;
* setup _PSD domain to coordinately work;

Signed-off-by: Liu Jinsong <jinsong.liu@xxxxxxxxx>
---
 xen/arch/x86/acpi/cpufreq/Makefile           |    2 
 xen/arch/x86/acpi/cpufreq/cpufreq.c          |  557 ++++++++++++++++++++++++++-
 xen/arch/x86/acpi/cpufreq/cpufreq_ondemand.c |    6 
 xen/arch/x86/acpi/cpufreq/utility.c          |  167 ++++++++
 xen/include/acpi/cpufreq/cpufreq.h           |  129 ++++++
 5 files changed, 858 insertions(+), 3 deletions(-)

diff -r 66ddfc4d6963 -r 50fb7620d05a xen/arch/x86/acpi/cpufreq/Makefile
--- a/xen/arch/x86/acpi/cpufreq/Makefile        Wed May 14 13:50:46 2008 +0100
+++ b/xen/arch/x86/acpi/cpufreq/Makefile        Wed May 14 13:55:11 2008 +0100
@@ -1,1 +1,3 @@ obj-y += cpufreq.o
 obj-y += cpufreq.o
+obj-y += utility.o
+obj-y += cpufreq_ondemand.o
diff -r 66ddfc4d6963 -r 50fb7620d05a xen/arch/x86/acpi/cpufreq/cpufreq.c
--- a/xen/arch/x86/acpi/cpufreq/cpufreq.c       Wed May 14 13:50:46 2008 +0100
+++ b/xen/arch/x86/acpi/cpufreq/cpufreq.c       Wed May 14 13:55:11 2008 +0100
@@ -42,11 +42,562 @@
 #include <asm/percpu.h>
 #include <asm/cpufeature.h>
 #include <acpi/acpi.h>
-#include <acpi/cpufreq/processor_perf.h>
+#include <acpi/cpufreq/cpufreq.h>
 
 struct processor_pminfo processor_pminfo[NR_CPUS];
+struct cpufreq_policy xen_px_policy[NR_CPUS];
+
+enum {
+    UNDEFINED_CAPABLE = 0,
+    SYSTEM_INTEL_MSR_CAPABLE,
+    SYSTEM_IO_CAPABLE,
+};
+
+#define INTEL_MSR_RANGE         (0xffff)
+#define CPUID_6_ECX_APERFMPERF_CAPABILITY       (0x1)
+
+struct acpi_cpufreq_data {
+    struct processor_performance *acpi_data;
+    struct cpufreq_frequency_table *freq_table;
+    unsigned int max_freq;
+    unsigned int resume;
+    unsigned int cpu_feature;
+};
+
+static struct acpi_cpufreq_data *drv_data[NR_CPUS];
+
+static struct cpufreq_driver acpi_cpufreq_driver;
+
+static int check_est_cpu(unsigned int cpuid)
+{
+    struct cpuinfo_x86 *cpu = &cpu_data[cpuid];
+
+    if (cpu->x86_vendor != X86_VENDOR_INTEL ||
+        !cpu_has(cpu, X86_FEATURE_EST))
+        return 0;
+
+    return 1;
+}
+
+static unsigned extract_io(u32 value, struct acpi_cpufreq_data *data)
+{
+    struct processor_performance *perf;
+    int i;
+
+    perf = data->acpi_data;
+
+    for (i=0; i<perf->state_count; i++) {
+        if (value == perf->states[i].status)
+            return data->freq_table[i].frequency;
+    }
+    return 0;
+}
+
+static unsigned extract_msr(u32 msr, struct acpi_cpufreq_data *data)
+{
+    int i;
+    struct processor_performance *perf;
+
+    msr &= INTEL_MSR_RANGE;
+    perf = data->acpi_data;
+
+    for (i=0; data->freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
+        if (msr == perf->states[data->freq_table[i].index].status)
+            return data->freq_table[i].frequency;
+    }
+    return data->freq_table[0].frequency;
+}
+
+static unsigned extract_freq(u32 val, struct acpi_cpufreq_data *data)
+{
+    switch (data->cpu_feature) {
+    case SYSTEM_INTEL_MSR_CAPABLE:
+        return extract_msr(val, data);
+    case SYSTEM_IO_CAPABLE:
+        return extract_io(val, data);
+    default:
+        return 0;
+    }
+}
+
+struct msr_addr {
+    u32 reg;
+};
+
+struct io_addr {
+    u16 port;
+    u8 bit_width;
+};
+
+typedef union {
+    struct msr_addr msr;
+    struct io_addr io;
+} drv_addr_union;
+
+struct drv_cmd {
+    unsigned int type;
+    cpumask_t mask;
+    drv_addr_union addr;
+    u32 val;
+};
+
+static void do_drv_read(struct drv_cmd *cmd)
+{
+    u32 h;
+
+    switch (cmd->type) {
+    case SYSTEM_INTEL_MSR_CAPABLE:
+        rdmsr(cmd->addr.msr.reg, cmd->val, h);
+        break;
+    case SYSTEM_IO_CAPABLE:
+        acpi_os_read_port((acpi_io_address)cmd->addr.io.port,
+            &cmd->val, (u32)cmd->addr.io.bit_width);
+        break;
+    default:
+        break;
+    }
+}
+
+static void do_drv_write(void *drvcmd)
+{
+    struct drv_cmd *cmd;
+    u32 lo, hi;
+
+    cmd = (struct drv_cmd *)drvcmd;
+
+    switch (cmd->type) {
+    case SYSTEM_INTEL_MSR_CAPABLE:
+        rdmsr(cmd->addr.msr.reg, lo, hi);
+        lo = (lo & ~INTEL_MSR_RANGE) | (cmd->val & INTEL_MSR_RANGE);
+        wrmsr(cmd->addr.msr.reg, lo, hi);
+        break;
+    case SYSTEM_IO_CAPABLE:
+        acpi_os_write_port((acpi_io_address)cmd->addr.io.port,
+            cmd->val, (u32)cmd->addr.io.bit_width);
+        break;
+    default:
+        break;
+    }
+}
+
+static void drv_read(struct drv_cmd *cmd)
+{
+    cmd->val = 0;
+
+    do_drv_read(cmd);
+}
+
+static void drv_write(struct drv_cmd *cmd)
+{
+    on_selected_cpus( cmd->mask, do_drv_write, (void *)cmd, 0, 0);
+}
+
+static u32 get_cur_val(cpumask_t mask)
+{
+    struct processor_performance *perf;
+    struct drv_cmd cmd;
+
+    if (unlikely(cpus_empty(mask)))
+        return 0;
+
+    switch (drv_data[first_cpu(mask)]->cpu_feature) {
+    case SYSTEM_INTEL_MSR_CAPABLE:
+        cmd.type = SYSTEM_INTEL_MSR_CAPABLE;
+        cmd.addr.msr.reg = MSR_IA32_PERF_STATUS;
+        break;
+    case SYSTEM_IO_CAPABLE:
+        cmd.type = SYSTEM_IO_CAPABLE;
+        perf = drv_data[first_cpu(mask)]->acpi_data;
+        cmd.addr.io.port = perf->control_register.address;
+        cmd.addr.io.bit_width = perf->control_register.bit_width;
+        break;
+    default:
+        return 0;
+    }
+
+    cmd.mask = mask;
+
+    drv_read(&cmd);
+    return cmd.val;
+}
+
+/*
+ * Return the measured active (C0) frequency on this CPU since last call
+ * to this function.
+ * Input: cpu number
+ * Return: Average CPU frequency in terms of max frequency (zero on error)
+ *
+ * We use IA32_MPERF and IA32_APERF MSRs to get the measured performance
+ * over a period of time, while CPU is in C0 state.
+ * IA32_MPERF counts at the rate of max advertised frequency
+ * IA32_APERF counts at the rate of actual CPU frequency
+ * Only IA32_APERF/IA32_MPERF ratio is architecturally defined and
+ * no meaning should be associated with absolute values of these MSRs.
+ */
+/* FIXME: handle query on non-current cpu later */
+static unsigned int get_measured_perf(unsigned int cpu)
+{
+    union {
+        struct {
+            uint32_t lo;
+            uint32_t hi;
+        } split;
+        uint64_t whole;
+    } aperf_cur, mperf_cur;
+
+    unsigned int perf_percent;
+    unsigned int retval;
+
+    rdmsr(MSR_IA32_APERF, aperf_cur.split.lo, aperf_cur.split.hi);
+    rdmsr(MSR_IA32_MPERF, mperf_cur.split.lo, mperf_cur.split.hi);
+
+    wrmsr(MSR_IA32_APERF, 0,0);
+    wrmsr(MSR_IA32_MPERF, 0,0);
+
+    if (unlikely(((unsigned long)(-1) / 100) < aperf_cur.whole)) {
+        int shift_count = 7;
+        aperf_cur.whole >>= shift_count;
+        mperf_cur.whole >>= shift_count;
+    }
+
+    if (aperf_cur.whole && mperf_cur.whole)
+        perf_percent = (aperf_cur.whole * 100) / mperf_cur.whole;
+    else
+        perf_percent = 0;
+
+
+    retval = drv_data[cpu]->max_freq * perf_percent / 100;
+    return retval;
+}
+
+static unsigned int get_cur_freq_on_cpu(unsigned int cpu)
+{
+    struct acpi_cpufreq_data *data = drv_data[cpu];
+    unsigned int freq;
+
+    if (unlikely(data == NULL ||
+        data->acpi_data == NULL || data->freq_table == NULL)) {
+        return 0;
+    }
+
+    freq = extract_freq(get_cur_val(cpumask_of_cpu(cpu)), data);
+    return freq;
+}
+
+static unsigned int check_freqs(cpumask_t mask, unsigned int freq,
+                                struct acpi_cpufreq_data *data)
+{
+    unsigned int cur_freq;
+    unsigned int i;
+
+    for (i=0; i<100; i++) {
+        cur_freq = extract_freq(get_cur_val(mask), data);
+        if (cur_freq == freq)
+            return 1;
+        udelay(10);
+    }
+    return 0;
+}
+
+static int acpi_cpufreq_target(struct cpufreq_policy *policy,
+                               unsigned int target_freq, unsigned int relation)
+{
+    struct acpi_cpufreq_data *data = drv_data[policy->cpu];
+    struct processor_performance *perf;
+    struct cpufreq_freqs freqs;
+    cpumask_t online_policy_cpus;
+    struct drv_cmd cmd;
+    unsigned int next_state = 0; /* Index into freq_table */
+    unsigned int next_perf_state = 0; /* Index into perf table */
+    int result = 0;
+
+    if (unlikely(data == NULL ||
+        data->acpi_data == NULL || data->freq_table == NULL)) {
+        return -ENODEV;
+    }
+
+    perf = data->acpi_data;
+    result = cpufreq_frequency_table_target(policy,
+                                            data->freq_table,
+                                            target_freq,
+                                            relation, &next_state);
+    if (unlikely(result))
+        return -ENODEV;
+
+    online_policy_cpus = policy->cpus;
+
+    next_perf_state = data->freq_table[next_state].index;
+    if (perf->state == next_perf_state) {
+        if (unlikely(data->resume)) {
+            printk("xen_pminfo: @acpi_cpufreq_target, "
+                "Called after resume, resetting to P%d\n", 
+                next_perf_state);
+            data->resume = 0;
+        }
+        else
+            return 0;
+    }
+
+    switch (data->cpu_feature) {
+    case SYSTEM_INTEL_MSR_CAPABLE:
+        cmd.type = SYSTEM_INTEL_MSR_CAPABLE;
+        cmd.addr.msr.reg = MSR_IA32_PERF_CTL;
+        cmd.val = (u32) perf->states[next_perf_state].control;
+        break;
+    case SYSTEM_IO_CAPABLE:
+        cmd.type = SYSTEM_IO_CAPABLE;
+        cmd.addr.io.port = perf->control_register.address;
+        cmd.addr.io.bit_width = perf->control_register.bit_width;
+        cmd.val = (u32) perf->states[next_perf_state].control;
+        break;
+    default:
+        return -ENODEV;
+    }
+
+    cpus_clear(cmd.mask);
+
+    if (policy->shared_type != CPUFREQ_SHARED_TYPE_ANY)
+        cmd.mask = online_policy_cpus;
+    else
+        cpu_set(policy->cpu, cmd.mask);
+
+    freqs.old = perf->states[perf->state].core_frequency * 1000;
+    freqs.new = data->freq_table[next_state].frequency;
+
+    drv_write(&cmd);
+
+    if (!check_freqs(cmd.mask, freqs.new, data))
+        return -EAGAIN;
+
+    perf->state = next_perf_state;
+    policy->cur = freqs.new;
+
+    return result;
+}
+
+static unsigned long
+acpi_cpufreq_guess_freq(struct acpi_cpufreq_data *data, unsigned int cpu)
+{
+    struct processor_performance *perf = data->acpi_data;
+
+    if (cpu_khz) {
+        /* search the closest match to cpu_khz */
+        unsigned int i;
+        unsigned long freq;
+        unsigned long freqn = perf->states[0].core_frequency * 1000;
+
+        for (i=0; i<(perf->state_count-1); i++) {
+            freq = freqn;
+            freqn = perf->states[i+1].core_frequency * 1000;
+            if ((2 * cpu_khz) > (freqn + freq)) {
+                perf->state = i;
+                return freq;
+            }
+        }
+        perf->state = perf->state_count-1;
+        return freqn;
+    } else {
+        /* assume CPU is at P0... */
+        perf->state = 0;
+        return perf->states[0].core_frequency * 1000;
+    }
+}
+
+static int 
+acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
+{
+    unsigned int i;
+    unsigned int valid_states = 0;
+    unsigned int cpu = policy->cpu;
+    struct acpi_cpufreq_data *data;
+    unsigned int result = 0;
+    struct cpuinfo_x86 *c = &cpu_data[policy->cpu];
+    struct processor_performance *perf;
+
+    data = xmalloc(struct acpi_cpufreq_data);
+    if (!data)
+        return -ENOMEM;
+    memset(data, 0, sizeof(struct acpi_cpufreq_data));
+
+    drv_data[cpu] = data;
+
+    data->acpi_data = &processor_pminfo[cpu].perf;
+
+    perf = data->acpi_data;
+    policy->shared_type = perf->shared_type;
+
+    /*
+     * Will let policy->cpus know about dependency only when software
+     * coordination is required.
+     */
+    if (policy->shared_type == CPUFREQ_SHARED_TYPE_ALL ||
+        policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) {
+        policy->cpus = perf->shared_cpu_map;
+    } else {
+        policy->cpus = cpumask_of_cpu(cpu);    
+    }
+
+    /* capability check */
+    if (perf->state_count <= 1) {
+        printk("No P-States\n");
+        result = -ENODEV;
+        goto err_unreg;
+    }
+
+    if (perf->control_register.space_id != perf->status_register.space_id) {
+        result = -ENODEV;
+        goto err_unreg;
+    }
+
+    switch (perf->control_register.space_id) {
+    case ACPI_ADR_SPACE_SYSTEM_IO:
+        printk("xen_pminfo: @acpi_cpufreq_cpu_init,"
+            "SYSTEM IO addr space\n");
+        data->cpu_feature = SYSTEM_IO_CAPABLE;
+        break;
+    case ACPI_ADR_SPACE_FIXED_HARDWARE:
+        printk("xen_pminfo: @acpi_cpufreq_cpu_init," 
+            "HARDWARE addr space\n");
+        if (!check_est_cpu(cpu)) {
+            result = -ENODEV;
+            goto err_unreg;
+        }
+        data->cpu_feature = SYSTEM_INTEL_MSR_CAPABLE;
+        break;
+    default:
+        result = -ENODEV;
+        goto err_unreg;
+    }
+
+    data->freq_table = xmalloc_array(struct cpufreq_frequency_table, 
+                                    (perf->state_count+1));
+    if (!data->freq_table) {
+        result = -ENOMEM;
+        goto err_unreg;
+    }
+
+    /* detect transition latency */
+    policy->cpuinfo.transition_latency = 0;
+    for (i=0; i<perf->state_count; i++) {
+        if ((perf->states[i].transition_latency * 1000) >
+            policy->cpuinfo.transition_latency)
+            policy->cpuinfo.transition_latency =
+                perf->states[i].transition_latency * 1000;
+    }
+
+    data->max_freq = perf->states[0].core_frequency * 1000;
+    /* table init */
+    for (i=0; i<perf->state_count; i++) {
+        if (i>0 && perf->states[i].core_frequency >=
+            data->freq_table[valid_states-1].frequency / 1000)
+            continue;
+
+        data->freq_table[valid_states].index = i;
+        data->freq_table[valid_states].frequency =
+            perf->states[i].core_frequency * 1000;
+        valid_states++;
+    }
+    data->freq_table[valid_states].frequency = CPUFREQ_TABLE_END;
+    perf->state = 0;
+
+    result = cpufreq_frequency_table_cpuinfo(policy, data->freq_table);
+    if (result)
+        goto err_freqfree;
+
+    switch (perf->control_register.space_id) {
+    case ACPI_ADR_SPACE_SYSTEM_IO:
+        /* Current speed is unknown and not detectable by IO port */
+        policy->cur = acpi_cpufreq_guess_freq(data, policy->cpu);
+        break;
+    case ACPI_ADR_SPACE_FIXED_HARDWARE:
+        acpi_cpufreq_driver.get = get_cur_freq_on_cpu;
+        policy->cur = get_cur_freq_on_cpu(cpu);
+        break;
+    default:
+        break;
+    }
+
+    /* Check for APERF/MPERF support in hardware */
+    if (c->x86_vendor == X86_VENDOR_INTEL && c->cpuid_level >= 6) {
+        unsigned int ecx;
+        ecx = cpuid_ecx(6);
+        if (ecx & CPUID_6_ECX_APERFMPERF_CAPABILITY)
+            acpi_cpufreq_driver.getavg = get_measured_perf;
+    }
+
+    /*
+     * the first call to ->target() should result in us actually
+     * writing something to the appropriate registers.
+     */
+    data->resume = 1;
+
+    return result;
+
+err_freqfree:
+    xfree(data->freq_table);
+err_unreg:
+    xfree(data);
+    drv_data[cpu] = NULL;
+
+    return result;
+}
+
+static struct cpufreq_driver acpi_cpufreq_driver = {
+    .target = acpi_cpufreq_target,
+    .init   = acpi_cpufreq_cpu_init,
+};
 
 int acpi_cpufreq_init(void)
 {
-    return 0;
-}
+    unsigned int i, ret = 0;
+    unsigned int dom, max_dom = 0;
+    cpumask_t *pt, dom_mask;
+
+    cpus_clear(dom_mask);
+
+    for_each_online_cpu(i) {
+        cpu_set(processor_pminfo[i].perf.domain_info.domain, dom_mask);
+        if (max_dom < processor_pminfo[i].perf.domain_info.domain)
+            max_dom = processor_pminfo[i].perf.domain_info.domain;
+    }
+    max_dom++;
+
+    pt = xmalloc_array(cpumask_t, max_dom);
+    if (!pt)
+        return -ENOMEM;
+    memset(pt, 0, max_dom * sizeof(cpumask_t));
+
+    /* get cpumask of each psd domain */
+    for_each_online_cpu(i)
+        cpu_set(i, pt[processor_pminfo[i].perf.domain_info.domain]);
+
+    for_each_online_cpu(i)
+        processor_pminfo[i].perf.shared_cpu_map = 
+            pt[processor_pminfo[i].perf.domain_info.domain];
+
+    cpufreq_driver = &acpi_cpufreq_driver;
+
+    /* setup cpufreq infrastructure */
+    for_each_online_cpu(i) {
+        xen_px_policy[i].cpu = i;
+
+        ret = acpi_cpufreq_cpu_init(&xen_px_policy[i]);
+        if (ret)
+            goto cpufreq_init_out;
+    }
+
+    /* setup ondemand cpufreq */
+    for (dom=0; dom<max_dom; dom++) {
+        if (!cpu_isset(dom, dom_mask))
+            continue;
+        i = first_cpu(pt[dom]);
+        ret = cpufreq_governor_dbs(&xen_px_policy[i], CPUFREQ_GOV_START);
+        if (ret)
+            goto cpufreq_init_out;
+    }
+
+cpufreq_init_out:
+    xfree(pt);
+   
+    return ret;
+}
diff -r 66ddfc4d6963 -r 50fb7620d05a 
xen/arch/x86/acpi/cpufreq/cpufreq_ondemand.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/arch/x86/acpi/cpufreq/cpufreq_ondemand.c      Wed May 14 13:55:11 
2008 +0100
@@ -0,0 +1,6 @@
+#include <acpi/cpufreq/cpufreq.h>
+
+int cpufreq_governor_dbs(struct cpufreq_policy *policy, unsigned int event)
+{
+    return 0;
+}
diff -r 66ddfc4d6963 -r 50fb7620d05a xen/arch/x86/acpi/cpufreq/utility.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/arch/x86/acpi/cpufreq/utility.c       Wed May 14 13:55:11 2008 +0100
@@ -0,0 +1,167 @@
+/*
+ *  utility.c - misc functions for cpufreq driver and Px statistic
+ *
+ *  Copyright (C) 2001 Russell King
+ *            (C) 2002 - 2003 Dominik Brodowski <linux@xxxxxxxx>
+ *
+ *  Oct 2005 - Ashok Raj <ashok.raj@xxxxxxxxx>
+ *    Added handling for CPU hotplug
+ *  Feb 2006 - Jacob Shin <jacob.shin@xxxxxxx>
+ *    Fix handling for CPU hotplug -- affected CPUs
+ *  Feb 2008 - Liu Jinsong <jinsong.liu@xxxxxxxxx>
+ *    1. Merge cpufreq.c and freq_table.c of linux 2.6.23
+ *    And poring to Xen hypervisor
+ *    2. some Px statistic interface funcdtions
+ *
+ * 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.
+ *
+ */
+
+#include <xen/errno.h>
+#include <xen/cpumask.h>
+#include <xen/types.h>
+#include <xen/spinlock.h>
+#include <xen/percpu.h>
+#include <xen/types.h>
+#include <xen/sched.h>
+#include <xen/timer.h>
+#include <asm/config.h>
+#include <acpi/cpufreq/cpufreq.h>
+#include <public/sysctl.h>
+
+struct cpufreq_driver *cpufreq_driver;
+
+/*********************************************************************
+ *                   FREQUENCY TABLE HELPERS                         *
+ *********************************************************************/
+
+int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
+                                    struct cpufreq_frequency_table *table)
+{
+    unsigned int min_freq = ~0;
+    unsigned int max_freq = 0;
+    unsigned int i;
+
+    for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
+        unsigned int freq = table[i].frequency;
+        if (freq == CPUFREQ_ENTRY_INVALID)
+            continue;
+        if (freq < min_freq)
+            min_freq = freq;
+        if (freq > max_freq)
+            max_freq = freq;
+    }
+
+    policy->min = policy->cpuinfo.min_freq = min_freq;
+    policy->max = policy->cpuinfo.max_freq = max_freq;
+
+    if (policy->min == ~0)
+        return -EINVAL;
+    else
+        return 0;
+}
+
+int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
+                                   struct cpufreq_frequency_table *table,
+                                   unsigned int target_freq,
+                                   unsigned int relation,
+                                   unsigned int *index)
+{
+    struct cpufreq_frequency_table optimal = {
+        .index = ~0,
+        .frequency = 0,
+    };
+    struct cpufreq_frequency_table suboptimal = {
+        .index = ~0,
+        .frequency = 0,
+    };
+    unsigned int i;
+
+    switch (relation) {
+    case CPUFREQ_RELATION_H:
+        suboptimal.frequency = ~0;
+        break;
+    case CPUFREQ_RELATION_L:
+        optimal.frequency = ~0;
+        break;
+    }
+
+    if (!cpu_online(policy->cpu))
+        return -EINVAL;
+
+    for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
+        unsigned int freq = table[i].frequency;
+        if (freq == CPUFREQ_ENTRY_INVALID)
+            continue;
+        if ((freq < policy->min) || (freq > policy->max))
+            continue;
+        switch(relation) {
+        case CPUFREQ_RELATION_H:
+            if (freq <= target_freq) {
+                if (freq >= optimal.frequency) {
+                    optimal.frequency = freq;
+                    optimal.index = i;
+                }
+            } else {
+                if (freq <= suboptimal.frequency) {
+                    suboptimal.frequency = freq;
+                    suboptimal.index = i;
+                }
+            }
+            break;
+        case CPUFREQ_RELATION_L:
+            if (freq >= target_freq) {
+                if (freq <= optimal.frequency) {
+                    optimal.frequency = freq;
+                    optimal.index = i;
+                }
+            } else {
+                if (freq >= suboptimal.frequency) {
+                    suboptimal.frequency = freq;
+                    suboptimal.index = i;
+                }
+            }
+            break;
+        }
+    }
+    if (optimal.index > i) {
+        if (suboptimal.index > i)
+            return -EINVAL;
+        *index = suboptimal.index;
+    } else
+        *index = optimal.index;
+
+    return 0;
+}
+
+
+/*********************************************************************
+ *               GOVERNORS                                           *
+ *********************************************************************/
+
+int __cpufreq_driver_target(struct cpufreq_policy *policy,
+                            unsigned int target_freq,
+                            unsigned int relation)
+{
+    int retval = -EINVAL;
+
+    if (cpu_online(policy->cpu) && cpufreq_driver->target)
+        retval = cpufreq_driver->target(policy, target_freq, relation);
+
+    return retval;
+}
+
+int __cpufreq_driver_getavg(struct cpufreq_policy *policy)
+{
+    int ret = 0;
+
+    if (!policy)
+        return -EINVAL;
+
+    if (cpu_online(policy->cpu) && cpufreq_driver->getavg)
+        ret = cpufreq_driver->getavg(policy->cpu);
+
+    return ret;
+}
diff -r 66ddfc4d6963 -r 50fb7620d05a xen/include/acpi/cpufreq/cpufreq.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/include/acpi/cpufreq/cpufreq.h        Wed May 14 13:55:11 2008 +0100
@@ -0,0 +1,129 @@
+/*
+ *  xen/include/acpi/cpufreq/cpufreq.h
+ *
+ *  Copyright (C) 2001 Russell King
+ *            (C) 2002 - 2003 Dominik Brodowski <linux@xxxxxxxx>
+ *
+ * $Id: cpufreq.h,v 1.36 2003/01/20 17:31:48 db Exp $
+ *
+ * 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.
+ */
+
+#include <xen/types.h>
+#include <xen/list.h>
+#include <xen/cpumask.h>
+
+#include "processor_perf.h"
+
+#define CPUFREQ_NAME_LEN 16
+
+struct cpufreq_cpuinfo {
+    unsigned int        max_freq;
+    unsigned int        min_freq;
+    unsigned int        transition_latency; /* in 10^(-9) s = nanoseconds */
+};
+
+struct cpufreq_policy {
+    cpumask_t           cpus;          /* affected CPUs */
+    unsigned int        shared_type;   /* ANY or ALL affected CPUs
+                                          should set cpufreq */
+    unsigned int        cpu;           /* cpu nr of registered CPU */
+    struct cpufreq_cpuinfo    cpuinfo; /* see above */
+
+    unsigned int        min;    /* in kHz */
+    unsigned int        max;    /* in kHz */
+    unsigned int        cur;    /* in kHz, only needed if cpufreq
+                                 * governors are used */
+};
+
+#define CPUFREQ_SHARED_TYPE_NONE (0) /* None */
+#define CPUFREQ_SHARED_TYPE_HW   (1) /* HW does needed coordination */
+#define CPUFREQ_SHARED_TYPE_ALL  (2) /* All dependent CPUs should set freq */
+#define CPUFREQ_SHARED_TYPE_ANY  (3) /* Freq can be set from any dependent 
CPU*/
+
+/******************** cpufreq transition notifiers *******************/
+
+struct cpufreq_freqs {
+    unsigned int cpu;    /* cpu nr */
+    unsigned int old;
+    unsigned int new;
+    u8 flags;            /* flags of cpufreq_driver, see below. */
+};
+
+
+/*********************************************************************
+ *                          CPUFREQ GOVERNORS                        *
+ *********************************************************************/
+
+#define CPUFREQ_GOV_START  1
+#define CPUFREQ_GOV_STOP   2
+#define CPUFREQ_GOV_LIMITS 3
+
+/* pass a target to the cpufreq driver */
+extern int __cpufreq_driver_target(struct cpufreq_policy *policy,
+                                   unsigned int target_freq,
+                                   unsigned int relation);
+extern int __cpufreq_driver_getavg(struct cpufreq_policy *policy);
+
+
+/*********************************************************************
+ *                      CPUFREQ DRIVER INTERFACE                     *
+ *********************************************************************/
+
+#define CPUFREQ_RELATION_L 0  /* lowest frequency at or above target */
+#define CPUFREQ_RELATION_H 1  /* highest frequency below or at target */
+
+struct cpufreq_driver {
+    int    (*init)(struct cpufreq_policy *policy);
+    int    (*verify)(struct cpufreq_policy *policy);
+    int    (*target)(struct cpufreq_policy *policy,
+                     unsigned int target_freq,
+                     unsigned int relation);
+    unsigned int    (*get)(unsigned int cpu);
+    unsigned int    (*getavg)(unsigned int cpu);
+    int    (*exit)(struct cpufreq_policy *policy);
+};
+
+extern struct cpufreq_driver *cpufreq_driver;
+
+void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int 
state);
+
+/*********************************************************************
+ *                     FREQUENCY TABLE HELPERS                       *
+ *********************************************************************/
+
+#define CPUFREQ_ENTRY_INVALID ~0
+#define CPUFREQ_TABLE_END     ~1
+
+struct cpufreq_frequency_table {
+    unsigned int    index;     /* any */
+    unsigned int    frequency; /* kHz - doesn't need to be in ascending
+                                * order */
+};
+
+int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
+                   struct cpufreq_frequency_table *table);
+
+int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
+                   struct cpufreq_frequency_table *table,
+                   unsigned int target_freq,
+                   unsigned int relation,
+                   unsigned int *index);
+
+
+/*********************************************************************
+ *                     UNIFIED DEBUG HELPERS                         *
+ *********************************************************************/
+
+struct cpu_dbs_info_s {
+    uint64_t prev_cpu_idle;
+    uint64_t prev_cpu_wall;
+    struct cpufreq_policy *cur_policy;
+    struct cpufreq_frequency_table *freq_table;
+    int cpu;
+    unsigned int enable:1;
+};
+
+int cpufreq_governor_dbs(struct cpufreq_policy *policy, unsigned int event);

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.