>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
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
