>From a65b889a9ad15034a4aed5c7cf6656117359dbae Mon Sep 17 00:00:00 2001
From: Illyas Mansoor <[email protected]>
Date: Wed, 3 Nov 2010 02:43:45 +0530
Subject: [PATCH 2/2] p-state driver based on sfi idle

This is a p-state driver based on the sfi idle. Most of the
code has been taken from the acpi p-state driver.

Signed-off-by: Vishwesh M Rudramuni <[email protected]>
Acked-by: Illyas Mansoor <[email protected]>
---
 arch/x86/kernel/cpu/cpufreq/Kconfig       |    1 -
 arch/x86/kernel/cpu/cpufreq/sfi-cpufreq.c |  221 ++++++++++++++++++++++++++++-
 2 files changed, 218 insertions(+), 4 deletions(-)

diff --git a/arch/x86/kernel/cpu/cpufreq/Kconfig 
b/arch/x86/kernel/cpu/cpufreq/Kconfig
index 0250139..ffabf2c 100644
--- a/arch/x86/kernel/cpu/cpufreq/Kconfig
+++ b/arch/x86/kernel/cpu/cpufreq/Kconfig
@@ -12,7 +12,6 @@ comment "CPUFreq processor drivers"
 
 config X86_SFI_CPUFREQ
        tristate "SFI Processor P-States driver"
-       depends on SFI_PROCESSOR_PM
        select CPU_FREQ_TABLE
        help
          This driver adds a CPUFreq driver which utilizes the SFI
diff --git a/arch/x86/kernel/cpu/cpufreq/sfi-cpufreq.c 
b/arch/x86/kernel/cpu/cpufreq/sfi-cpufreq.c
index 8cf1975..11d1438 100644
--- a/arch/x86/kernel/cpu/cpufreq/sfi-cpufreq.c
+++ b/arch/x86/kernel/cpu/cpufreq/sfi-cpufreq.c
@@ -55,9 +55,30 @@
 MODULE_AUTHOR("Vishwesh Rudramuni");
 MODULE_DESCRIPTION("SFI Processor P-States Driver");
 MODULE_LICENSE("GPL");
+
+DEFINE_PER_CPU(struct sfi_processor *, sfi_processors);
+
+static DEFINE_MUTEX(performance_mutex);
+int sfi_cpufreq_num;
+static u32 sfi_cpu_num;
+
+#define                SFI_FREQ_MAX            32
 #define                SYSTEM_INTEL_MSR_CAPABLE                0x1
 #define                INTEL_MSR_RANGE                         (0xffff)
 #define                CPUID_6_ECX_APERFMPERF_CAPABILITY       (0x1)
+#define                SFI_PROCESSOR_COMPONENT 0x01000000
+#define                SFI_PROCESSOR_CLASS             "processor"
+#define                SFI_PROCESSOR_FILE_PERFORMANCE  "performance"
+#define                _COMPONENT              SFI_PROCESSOR_COMPONENT
+#define                MSR_IA32_CLOCK_CR_GEYSIII_VCC_3 0xcf
+#define                GRD_RATIO_900   9
+#define                GRD_RATIO_1100  0xb
+#define                CTRL_VAL_900    0x90c
+#define                CTRL_VAL_1100   0xb14
+#define                GRD_VID_MASK           0x3F
+#define                GRD_BUS_RATIO_MASK     0xF
+#define                SFI_CPU_MAX        8
+
 
 struct sfi_cpufreq_data {
        struct sfi_processor_performance *sfi_data;
@@ -69,6 +90,8 @@ struct sfi_cpufreq_data {
 
 static DEFINE_PER_CPU(struct sfi_cpufreq_data *, drv_data);
 static DEFINE_PER_CPU(struct aperfmperf, old_perf);
+struct sfi_freq_table_entry sfi_cpufreq_array[SFI_FREQ_MAX];
+static struct sfi_cpu_table_entry sfi_cpu_array[SFI_CPU_MAX];
 
 /* sfi_perf_data is a pointer to percpu data. */
 static struct sfi_processor_performance *sfi_perf_data;
@@ -77,6 +100,144 @@ static struct cpufreq_driver sfi_cpufreq_driver;
 
 static unsigned int sfi_pstate_strict;
 
+static int __init parse_freq(struct sfi_table_header *table)
+{
+       struct sfi_table_simple *sb;
+       struct sfi_freq_table_entry *pentry;
+       int totallen;
+
+       sb = (struct sfi_table_simple *)table;
+       if (!sb) {
+               printk(KERN_WARNING "SFI: Unable to map FREQ\n");
+               return -ENODEV;
+       }
+
+       if (!sfi_cpufreq_num) {
+               sfi_cpufreq_num = SFI_GET_NUM_ENTRIES(sb,
+                        struct sfi_freq_table_entry);
+               pentry = (struct sfi_freq_table_entry *)sb->pentry;
+               totallen = sfi_cpufreq_num * sizeof(*pentry);
+               memcpy(sfi_cpufreq_array, pentry, totallen);
+       }
+
+       return 0;
+}
+
+static int sfi_processor_get_performance_states(struct sfi_processor *pr)
+{
+       int result = 0;
+       int i;
+
+       pr->performance->state_count = sfi_cpufreq_num;
+       pr->performance->states =
+           kmalloc(sizeof(struct sfi_processor_px) * sfi_cpufreq_num,
+                   GFP_KERNEL);
+       if (!pr->performance->states)
+               result = -ENOMEM;
+
+       printk(KERN_INFO "Num p-states %d\n", sfi_cpufreq_num);
+
+       /* Populate the P-states info from the SFI table here */
+       for (i = 0; i < sfi_cpufreq_num; i++) {
+               pr->performance->states[i].core_frequency = \
+                       sfi_cpufreq_array[i].freq_mhz;
+               pr->performance->states[i].transition_latency = \
+                       sfi_cpufreq_array[i].latency;
+               pr->performance->states[i].control = \
+                       sfi_cpufreq_array[i].ctrl_val;
+               printk(KERN_INFO "State [%d]: core_frequency[%d] \
+                       transition_latency[%d] \
+                       control[0x%x] status[0x%x]\n", i,
+                       (u32) pr->performance->states[i].core_frequency,
+                       (u32) pr->performance->states[i].transition_latency,
+                       (u32) pr->performance->states[i].control,
+                       (u32) pr->performance->states[i].status);
+       }
+
+       return result;
+}
+
+void set_cpu_to_gfm(void)
+{
+       unsigned int l, h;
+       unsigned int grd_vid, grd_ratio;
+
+       /* program the GFM when the cpu's are initialized */
+       rdmsr(MSR_IA32_CLOCK_CR_GEYSIII_VCC_3, l, h);
+       grd_vid = (l >> 12) & GRD_VID_MASK;
+       grd_ratio = (l >> 7) & GRD_BUS_RATIO_MASK;
+
+       /* program the control values for GFM */
+       if (grd_ratio == GRD_RATIO_900)
+               l = CTRL_VAL_900;
+       else if (grd_ratio == GRD_RATIO_1100)
+               l = CTRL_VAL_1100;
+
+       h = 0;
+
+       /* write the value to change the freq to GFM */
+       wrmsr(MSR_IA32_PERF_CTL, l, h);
+}
+
+int
+sfi_processor_register_performance(struct sfi_processor_performance
+                                   *performance, unsigned int cpu)
+{
+       struct sfi_processor *pr;
+
+       mutex_lock(&performance_mutex);
+
+       pr = per_cpu(sfi_processors, cpu);
+       if (!pr) {
+               mutex_unlock(&performance_mutex);
+               return -ENODEV;
+       }
+
+       if (pr->performance) {
+               mutex_unlock(&performance_mutex);
+               return -EBUSY;
+       }
+
+       WARN_ON(!performance);
+
+       pr->performance = performance;
+
+       /* parse the freq table from sfi */
+       sfi_cpufreq_num = 0;
+       sfi_table_parse(SFI_SIG_FREQ, NULL, NULL, parse_freq);
+
+       sfi_processor_get_performance_states(pr);
+
+       /* ensure that the frequency is set to GFM after initialization */
+       set_cpu_to_gfm();
+
+       mutex_unlock(&performance_mutex);
+       return 0;
+}
+
+void sfi_processor_unregister_performance(struct sfi_processor_performance
+                                     *performance, unsigned int cpu)
+{
+       struct sfi_processor *pr;
+
+
+       mutex_lock(&performance_mutex);
+
+       pr = per_cpu(sfi_processors, cpu);
+       if (!pr) {
+               mutex_unlock(&performance_mutex);
+               return;
+       }
+
+       if (pr->performance)
+               kfree(pr->performance->states);
+       pr->performance = NULL;
+
+       mutex_unlock(&performance_mutex);
+
+       return;
+}
+
 static int check_est_cpu(unsigned int cpuid)
 {
        struct cpuinfo_x86 *cpu = &cpu_data(cpuid);
@@ -292,9 +453,6 @@ static int sfi_cpufreq_target(struct cpufreq_policy *policy,
                }
        }
 
-       trace_power_frequency(POWER_PSTATE,
-                               data->freq_table[next_state].frequency);
-
        cmd.type = SYSTEM_INTEL_MSR_CAPABLE;
        cmd.msr.reg = MSR_IA32_PERF_CTL;
        cmd.val = (u32) perf->states[next_perf_state].control;
@@ -572,12 +730,62 @@ static struct cpufreq_driver sfi_cpufreq_driver = {
        .attr = sfi_cpufreq_attr,
 };
 
+static int __init parse_cpus(struct sfi_table_header *table)
+{
+       struct sfi_table_simple *sb;
+       struct sfi_cpu_table_entry *pentry;
+       int i;
+
+       sb = (struct sfi_table_simple *)table;
+
+       sfi_cpu_num = SFI_GET_NUM_ENTRIES(sb, u64);
+
+       pentry = (struct sfi_cpu_table_entry *) sb->pentry;
+       for (i = 0; i < sfi_cpu_num; i++) {
+               sfi_cpu_array[i].apic_id = pentry->apic_id;
+               printk(KERN_INFO "APIC ID: %d\n", pentry->apic_id);
+               pentry++;
+       }
+
+       return 0;
+
+}
+
+static int __init init_sfi_processor_list(void)
+{
+       struct sfi_processor *pr;
+       int i;
+       int result;
+
+       /* parse the cpus from the sfi table */
+       result = sfi_table_parse(SFI_SIG_CPUS, NULL, NULL, parse_cpus);
+
+       if (result < 0)
+               return result;
+
+       pr = kzalloc(sfi_cpu_num * sizeof(struct sfi_processor), GFP_KERNEL);
+       if (!pr)
+               return -ENOMEM;
+
+       for (i = 0; i < sfi_cpu_num; i++) {
+               pr->id = sfi_cpu_array[i].apic_id;
+               per_cpu(sfi_processors, pr->id) = pr;
+               pr++;
+       }
+
+       return 0;
+}
+
 static int __init sfi_cpufreq_init(void)
 {
        int ret;
 
        dprintk("sfi_cpufreq_init\n");
 
+       ret = init_sfi_processor_list();
+       if (ret)
+               return ret;
+
        ret = sfi_cpufreq_early_init();
        if (ret)
                return ret;
@@ -587,8 +795,14 @@ static int __init sfi_cpufreq_init(void)
 
 static void __exit sfi_cpufreq_exit(void)
 {
+
+       struct sfi_processor *pr;
+
        dprintk("sfi_cpufreq_exit\n");
 
+       pr = per_cpu(sfi_processors, 0);
+       kfree(pr);
+
        cpufreq_unregister_driver(&sfi_cpufreq_driver);
 
        free_percpu(sfi_perf_data);
@@ -605,3 +819,4 @@ late_initcall(sfi_cpufreq_init);
 module_exit(sfi_cpufreq_exit);
 
 MODULE_ALIAS("sfi");
+
-- 
1.7.2.3

Attachment: 0002-p-state-driver-based-on-sfi-idle.patch
Description: 0002-p-state-driver-based-on-sfi-idle.patch

_______________________________________________
MeeGo-kernel mailing list
[email protected]
http://lists.meego.com/listinfo/meego-kernel

Reply via email to