Commit 945a3d28 authored by Dave Jones's avatar Dave Jones

Merge delerium.codemonkey.org.uk:/mnt/nfs/sepia/bar/src/kernel/2.6/trees/bk-linus

into delerium.codemonkey.org.uk:/mnt/nfs/sepia/bar/src/kernel/2.6/trees/cpufreq
parents 96531b37 1197daff
...@@ -120,6 +120,21 @@ config X86_SPEEDSTEP_CENTRINO ...@@ -120,6 +120,21 @@ config X86_SPEEDSTEP_CENTRINO
If in doubt, say N. If in doubt, say N.
config X86_SPEEDSTEP_CENTRINO_TABLE
bool
depends on X86_SPEEDSTEP_CENTRINO
default y
config X86_SPEEDSTEP_CENTRINO_ACPI
bool "Use ACPI tables to decode valid frequency/voltage pairs (EXPERIMENTAL)"
depends on EXPERIMENTAL
depends on ((X86_SPEEDSTEP_CENTRINO = "m" && ACPI_PROCESSOR) || (X86_SPEEDSTEP_CENTRINO = "y" && ACPI_PROCESSOR = "y"))
help
Use primarily the information provided in the BIOS ACPI tables
to determine valid CPU frequency and voltage pairings.
If in doubt, say Y.
config X86_SPEEDSTEP_ICH config X86_SPEEDSTEP_ICH
tristate "Intel Speedstep on ICH-M chipsets (ioport interface)" tristate "Intel Speedstep on ICH-M chipsets (ioport interface)"
depends on CPU_FREQ_TABLE depends on CPU_FREQ_TABLE
...@@ -161,6 +176,16 @@ config X86_SPEEDSTEP_LIB ...@@ -161,6 +176,16 @@ config X86_SPEEDSTEP_LIB
depends on (X86_SPEEDSTEP_ICH || X86_SPEEDSTEP_SMI || X86_P4_CLOCKMOD) depends on (X86_SPEEDSTEP_ICH || X86_SPEEDSTEP_SMI || X86_P4_CLOCKMOD)
default (X86_SPEEDSTEP_ICH || X86_SPEEDSTEP_SMI || X86_P4_CLOCKMOD) default (X86_SPEEDSTEP_ICH || X86_SPEEDSTEP_SMI || X86_P4_CLOCKMOD)
config X86_SPEEDSTEP_RELAXED_CAP_CHECK
bool "Relaxed speedstep capability checks"
depends on (X86_SPEEDSTEP_SMI || X86_SPEEDSTEP_ICH)
help
Don't perform all checks for a speedstep capable system which would
normally be done. Some ancient or strange systems, though speedstep
capable, don't always indicate that they are speedstep capable. This
option let's the probing code bypass some of those checks if the
parameter "relaxed_check=1" is passed to the module.
config X86_LONGRUN config X86_LONGRUN
tristate "Transmeta LongRun" tristate "Transmeta LongRun"
depends on CPU_FREQ depends on CPU_FREQ
......
...@@ -458,7 +458,7 @@ static int __init longhaul_cpu_init (struct cpufreq_policy *policy) ...@@ -458,7 +458,7 @@ static int __init longhaul_cpu_init (struct cpufreq_policy *policy)
return 0; return 0;
} }
static int longhaul_cpu_exit(struct cpufreq_policy *policy) static int __exit longhaul_cpu_exit(struct cpufreq_policy *policy)
{ {
cpufreq_frequency_table_put_attr(policy->cpu); cpufreq_frequency_table_put_attr(policy->cpu);
return 0; return 0;
......
...@@ -33,7 +33,7 @@ static unsigned int longrun_low_freq, longrun_high_freq; ...@@ -33,7 +33,7 @@ static unsigned int longrun_low_freq, longrun_high_freq;
* Reads the current LongRun policy by access to MSR_TMTA_LONGRUN_FLAGS * Reads the current LongRun policy by access to MSR_TMTA_LONGRUN_FLAGS
* and MSR_TMTA_LONGRUN_CTRL * and MSR_TMTA_LONGRUN_CTRL
*/ */
static void longrun_get_policy(struct cpufreq_policy *policy) static void __init longrun_get_policy(struct cpufreq_policy *policy)
{ {
u32 msr_lo, msr_hi; u32 msr_lo, msr_hi;
......
...@@ -181,21 +181,24 @@ static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c) ...@@ -181,21 +181,24 @@ static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c)
{ {
if ((c->x86 == 0x06) && (c->x86_model == 0x09)) { if ((c->x86 == 0x06) && (c->x86_model == 0x09)) {
/* Pentium M */ /* Pentium M */
printk(KERN_DEBUG PFX "Warning: Pentium M detected. The speedstep_centrino module\n"); printk(KERN_WARNING PFX "Warning: Pentium M detected. "
printk(KERN_DEBUG PFX "offers voltage scaling in addition of frequency scaling. You\n"); "The speedstep_centrino module offers voltage scaling"
printk(KERN_DEBUG PFX "should use that instead of p4-clockmod, if possible.\n"); " in addition of frequency scaling. You should use "
"that instead of p4-clockmod, if possible.\n");
return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_PM); return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_PM);
} }
if (c->x86 != 0xF) { if (c->x86 != 0xF) {
printk(KERN_DEBUG PFX "Unknown p4-clockmod-capable CPU. Please send an e-mail to <linux@brodo.de>\n"); printk(KERN_WARNING PFX "Unknown p4-clockmod-capable CPU. Please send an e-mail to <linux@brodo.de>\n");
return 0; return 0;
} }
if (speedstep_detect_processor() == SPEEDSTEP_PROCESSOR_P4M) { if (speedstep_detect_processor() == SPEEDSTEP_PROCESSOR_P4M) {
printk(KERN_DEBUG PFX "Warning: Pentium 4-M detected. The speedstep-ich or acpi cpufreq \n"); printk(KERN_WARNING PFX "Warning: Pentium 4-M detected. "
printk(KERN_DEBUG PFX "modules offers voltage scaling in addition of frequency scaling. You\n"); "The speedstep-ich or acpi cpufreq modules offers "
printk(KERN_DEBUG PFX "should use either one instead of p4-clockmod, if possible.\n"); "voltage scaling in addition of frequency scaling. "
"You should use either one instead of p4-clockmod, "
"if possible.\n");
return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_P4M); return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_P4M);
} }
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/cpufreq.h> #include <linux/cpufreq.h>
#include <linux/config.h>
#include <asm/msr.h> #include <asm/msr.h>
#include <asm/processor.h> #include <asm/processor.h>
...@@ -46,7 +47,9 @@ struct cpu_model ...@@ -46,7 +47,9 @@ struct cpu_model
}; };
/* Operating points for current CPU */ /* Operating points for current CPU */
static const struct cpu_model *centrino_model; static struct cpu_model *centrino_model;
#ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE
/* Computes the correct form for IA32_PERF_CTL MSR for a particular /* Computes the correct form for IA32_PERF_CTL MSR for a particular
frequency/voltage operating point; frequency in MHz, volts in mV. frequency/voltage operating point; frequency in MHz, volts in mV.
...@@ -172,7 +175,7 @@ static struct cpufreq_frequency_table op_1700[] = ...@@ -172,7 +175,7 @@ static struct cpufreq_frequency_table op_1700[] =
/* CPU models, their operating frequency range, and freq/voltage /* CPU models, their operating frequency range, and freq/voltage
operating points */ operating points */
static const struct cpu_model models[] = static struct cpu_model models[] =
{ {
_CPU( 900, " 900"), _CPU( 900, " 900"),
CPU(1000), CPU(1000),
...@@ -187,6 +190,48 @@ static const struct cpu_model models[] = ...@@ -187,6 +190,48 @@ static const struct cpu_model models[] =
}; };
#undef CPU #undef CPU
static int centrino_cpu_init_table(struct cpufreq_policy *policy)
{
struct cpuinfo_x86 *cpu = &cpu_data[policy->cpu];
struct cpu_model *model;
if (!cpu_has(cpu, X86_FEATURE_EST))
return -ENODEV;
/* Only Intel Pentium M stepping 5 for now - add new CPUs as
they appear after making sure they use PERF_CTL in the same
way. */
if (cpu->x86_vendor != X86_VENDOR_INTEL ||
cpu->x86 != 6 ||
cpu->x86_model != 9 ||
cpu->x86_mask != 5) {
printk(KERN_INFO PFX "found unsupported CPU with Enhanced SpeedStep: "
"send /proc/cpuinfo to " MAINTAINER "\n");
return -ENODEV;
}
for(model = models; model->model_name != NULL; model++)
if (strcmp(cpu->x86_model_id, model->model_name) == 0)
break;
if (model->model_name == NULL) {
printk(KERN_INFO PFX "no support for CPU model \"%s\": "
"send /proc/cpuinfo to " MAINTAINER "\n",
cpu->x86_model_id);
return -ENOENT;
}
centrino_model = model;
printk(KERN_INFO PFX "found \"%s\": max frequency: %dkHz\n",
model->model_name, model->max_freq);
return 0;
}
#else
static inline int centrino_cpu_init_table(struct cpufreq_policy *policy) { return -ENODEV; }
#endif /* CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE */
/* Extract clock in kHz from PERF_CTL value */ /* Extract clock in kHz from PERF_CTL value */
static unsigned extract_clock(unsigned msr) static unsigned extract_clock(unsigned msr)
{ {
...@@ -203,13 +248,148 @@ static unsigned get_cur_freq(void) ...@@ -203,13 +248,148 @@ static unsigned get_cur_freq(void)
return extract_clock(l); return extract_clock(l);
} }
#ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI
static struct acpi_processor_performance p;
#include <linux/acpi.h>
#include <acpi/processor.h>
#define ACPI_PDC_CAPABILITY_ENHANCED_SPEEDSTEP 0x1
/*
* centrino_cpu_init_acpi - register with ACPI P-States library
*
* Register with the ACPI P-States library (part of drivers/acpi/processor.c)
* in order to determine correct frequency and voltage pairings by reading
* the _PSS of the ACPI DSDT or SSDT tables.
*/
static int centrino_cpu_init_acpi(struct cpufreq_policy *policy)
{
union acpi_object arg0 = {ACPI_TYPE_BUFFER};
u32 arg0_buf[3];
struct acpi_object_list arg_list = {1, &arg0};
unsigned long cur_freq;
int result = 0, i;
/* _PDC settings */
arg0.buffer.length = 12;
arg0.buffer.pointer = (u8 *) arg0_buf;
arg0_buf[0] = ACPI_PDC_REVISION_ID;
arg0_buf[1] = 1;
arg0_buf[2] = ACPI_PDC_CAPABILITY_ENHANCED_SPEEDSTEP;
p.pdc = &arg_list;
/* register with ACPI core */
if (acpi_processor_register_performance(&p, 0))
return -EIO;
/* verify the acpi_data */
if (p.state_count <= 1) {
printk(KERN_DEBUG "No P-States\n");
result = -ENODEV;
goto err_unreg;
}
if ((p.control_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) ||
(p.status_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE)) {
printk(KERN_DEBUG "Invalid control/status registers\n");
result = -EIO;
goto err_unreg;
}
for (i=0; i<p.state_count; i++) {
if (p.states[i].control != p.states[i].status) {
printk(KERN_DEBUG "Different control and status values\n");
result = -EINVAL;
goto err_unreg;
}
if (!p.states[i].core_frequency) {
printk(KERN_DEBUG "Zero core frequency\n");
result = -EINVAL;
goto err_unreg;
}
if (extract_clock(p.states[i].control) !=
(p.states[i].core_frequency * 1000)) {
printk(KERN_DEBUG "Invalid encoded frequency\n");
result = -EINVAL;
goto err_unreg;
}
}
centrino_model = kmalloc(sizeof(struct cpu_model), GFP_KERNEL);
if (!centrino_model) {
result = -ENOMEM;
goto err_unreg;
}
memset(centrino_model, 0, sizeof(struct cpu_model));
centrino_model->model_name=NULL;
centrino_model->max_freq = p.states[0].core_frequency * 1000;
centrino_model->op_points = kmalloc(sizeof(struct cpufreq_frequency_table) *
(p.state_count + 1), GFP_KERNEL);
if (!centrino_model->op_points) {
result = -ENOMEM;
goto err_kfree;
}
cur_freq = get_cur_freq();
for (i=0; i<p.state_count; i++) {
centrino_model->op_points[i].index = p.states[i].control;
centrino_model->op_points[i].frequency = p.states[i].core_frequency * 1000;
if (cur_freq == centrino_model->op_points[i].frequency)
p.state = i;
}
centrino_model->op_points[p.state_count].frequency = CPUFREQ_TABLE_END;
return 0;
err_kfree:
kfree(centrino_model);
err_unreg:
acpi_processor_unregister_performance(&p, 0);
return (result);
}
#else
static inline int centrino_cpu_init_acpi(struct cpufreq_policy *policy) { return -ENODEV; }
#endif
static int centrino_cpu_init(struct cpufreq_policy *policy) static int centrino_cpu_init(struct cpufreq_policy *policy)
{ {
unsigned freq; unsigned freq;
unsigned l, h;
int ret;
if (policy->cpu != 0 || centrino_model == NULL) if (policy->cpu != 0)
return -ENODEV; return -ENODEV;
if (centrino_cpu_init_acpi(policy)) {
if (centrino_cpu_init_table(policy)) {
return -ENODEV;
}
}
/* Check to see if Enhanced SpeedStep is enabled, and try to
enable it if not. */
rdmsr(MSR_IA32_MISC_ENABLE, l, h);
if (!(l & (1<<16))) {
l |= (1<<16);
wrmsr(MSR_IA32_MISC_ENABLE, l, h);
/* check to see if it stuck */
rdmsr(MSR_IA32_MISC_ENABLE, l, h);
if (!(l & (1<<16))) {
printk(KERN_INFO PFX "couldn't enable Enhanced SpeedStep\n");
return -ENODEV;
}
}
freq = get_cur_freq(); freq = get_cur_freq();
policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
...@@ -219,7 +399,33 @@ static int centrino_cpu_init(struct cpufreq_policy *policy) ...@@ -219,7 +399,33 @@ static int centrino_cpu_init(struct cpufreq_policy *policy)
dprintk(KERN_INFO PFX "centrino_cpu_init: policy=%d cur=%dkHz\n", dprintk(KERN_INFO PFX "centrino_cpu_init: policy=%d cur=%dkHz\n",
policy->policy, policy->cur); policy->policy, policy->cur);
return cpufreq_frequency_table_cpuinfo(policy, centrino_model->op_points); ret = cpufreq_frequency_table_cpuinfo(policy, centrino_model->op_points);
if (ret)
return (ret);
cpufreq_frequency_table_get_attr(centrino_model->op_points, policy->cpu);
return 0;
}
static int centrino_cpu_exit(struct cpufreq_policy *policy)
{
if (!centrino_model)
return -ENODEV;
cpufreq_frequency_table_put_attr(policy->cpu);
#ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI
if (!centrino_model->model_name) {
acpi_processor_unregister_performance(&p, 0);
kfree(centrino_model->op_points);
kfree(centrino_model);
}
#endif
centrino_model = NULL;
return 0;
} }
/** /**
...@@ -295,12 +501,19 @@ static int centrino_target (struct cpufreq_policy *policy, ...@@ -295,12 +501,19 @@ static int centrino_target (struct cpufreq_policy *policy,
return 0; return 0;
} }
static struct freq_attr* centrino_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs,
NULL,
};
static struct cpufreq_driver centrino_driver = { static struct cpufreq_driver centrino_driver = {
.name = "centrino", /* should be speedstep-centrino, .name = "centrino", /* should be speedstep-centrino,
but there's a 16 char limit */ but there's a 16 char limit */
.init = centrino_cpu_init, .init = centrino_cpu_init,
.exit = centrino_cpu_exit,
.verify = centrino_verify, .verify = centrino_verify,
.target = centrino_target, .target = centrino_target,
.attr = centrino_attr,
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
...@@ -322,55 +535,10 @@ static struct cpufreq_driver centrino_driver = { ...@@ -322,55 +535,10 @@ static struct cpufreq_driver centrino_driver = {
static int __init centrino_init(void) static int __init centrino_init(void)
{ {
struct cpuinfo_x86 *cpu = cpu_data; struct cpuinfo_x86 *cpu = cpu_data;
const struct cpu_model *model;
unsigned l, h;
if (!cpu_has(cpu, X86_FEATURE_EST)) if (!cpu_has(cpu, X86_FEATURE_EST))
return -ENODEV; return -ENODEV;
/* Only Intel Pentium M stepping 5 for now - add new CPUs as
they appear after making sure they use PERF_CTL in the same
way. */
if (cpu->x86_vendor != X86_VENDOR_INTEL ||
cpu->x86 != 6 ||
cpu->x86_model != 9 ||
cpu->x86_mask != 5) {
printk(KERN_INFO PFX "found unsupported CPU with Enhanced SpeedStep: "
"send /proc/cpuinfo to " MAINTAINER "\n");
return -ENODEV;
}
/* Check to see if Enhanced SpeedStep is enabled, and try to
enable it if not. */
rdmsr(MSR_IA32_MISC_ENABLE, l, h);
if (!(l & (1<<16))) {
l |= (1<<16);
wrmsr(MSR_IA32_MISC_ENABLE, l, h);
/* check to see if it stuck */
rdmsr(MSR_IA32_MISC_ENABLE, l, h);
if (!(l & (1<<16))) {
printk(KERN_INFO PFX "couldn't enable Enhanced SpeedStep\n");
return -ENODEV;
}
}
for(model = models; model->model_name != NULL; model++)
if (strcmp(cpu->x86_model_id, model->model_name) == 0)
break;
if (model->model_name == NULL) {
printk(KERN_INFO PFX "no support for CPU model \"%s\": "
"send /proc/cpuinfo to " MAINTAINER "\n",
cpu->x86_model_id);
return -ENOENT;
}
centrino_model = model;
printk(KERN_INFO PFX "found \"%s\": max frequency: %dkHz\n",
model->model_name, model->max_freq);
return cpufreq_register_driver(&centrino_driver); return cpufreq_register_driver(&centrino_driver);
} }
...@@ -383,5 +551,5 @@ MODULE_AUTHOR ("Jeremy Fitzhardinge <jeremy@goop.org>"); ...@@ -383,5 +551,5 @@ MODULE_AUTHOR ("Jeremy Fitzhardinge <jeremy@goop.org>");
MODULE_DESCRIPTION ("Enhanced SpeedStep driver for Intel Pentium M processors."); MODULE_DESCRIPTION ("Enhanced SpeedStep driver for Intel Pentium M processors.");
MODULE_LICENSE ("GPL"); MODULE_LICENSE ("GPL");
module_init(centrino_init); late_initcall(centrino_init);
module_exit(centrino_exit); module_exit(centrino_exit);
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/cpufreq.h> #include <linux/cpufreq.h>
#include <linux/pci.h> #include <linux/pci.h>
...@@ -30,6 +31,12 @@ ...@@ -30,6 +31,12 @@
#define dprintk(msg...) do { } while(0) #define dprintk(msg...) do { } while(0)
#endif #endif
#ifdef CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK
static int relaxed_check = 0;
#else
#define relaxed_check 0
#endif
/********************************************************************* /*********************************************************************
* GET PROCESSOR CORE SPEED IN KHZ * * GET PROCESSOR CORE SPEED IN KHZ *
*********************************************************************/ *********************************************************************/
...@@ -120,7 +127,7 @@ static unsigned int pentiumM_get_frequency(void) ...@@ -120,7 +127,7 @@ static unsigned int pentiumM_get_frequency(void)
msr_tmp = (msr_lo >> 22) & 0x1f; msr_tmp = (msr_lo >> 22) & 0x1f;
dprintk(KERN_DEBUG "speedstep-lib: bits 22-26 are 0x%x\n", msr_tmp); dprintk(KERN_DEBUG "speedstep-lib: bits 22-26 are 0x%x\n", msr_tmp);
return (msr_tmp * 100 * 10000); return (msr_tmp * 100 * 1000);
} }
...@@ -265,6 +272,7 @@ unsigned int speedstep_detect_processor (void) ...@@ -265,6 +272,7 @@ unsigned int speedstep_detect_processor (void)
ebx = cpuid_ebx(0x00000001); ebx = cpuid_ebx(0x00000001);
ebx &= 0x000000FF; ebx &= 0x000000FF;
if (ebx != 0x06) if (ebx != 0x06)
return 0; return 0;
...@@ -292,7 +300,7 @@ unsigned int speedstep_detect_processor (void) ...@@ -292,7 +300,7 @@ unsigned int speedstep_detect_processor (void)
*/ */
rdmsr(MSR_IA32_PLATFORM_ID, msr_lo, msr_hi); rdmsr(MSR_IA32_PLATFORM_ID, msr_lo, msr_hi);
dprintk(KERN_DEBUG "cpufreq: Coppermine: MSR_IA32_PLATFORM ID is 0x%x, 0x%x\n", msr_lo, msr_hi); dprintk(KERN_DEBUG "cpufreq: Coppermine: MSR_IA32_PLATFORM ID is 0x%x, 0x%x\n", msr_lo, msr_hi);
if ((msr_hi & (1<<18)) && (msr_hi & (3<<24))) { if ((msr_hi & (1<<18)) && (relaxed_check ? 1 : (msr_hi & (3<<24)))) {
if (c->x86_mask == 0x01) if (c->x86_mask == 0x01)
return SPEEDSTEP_PROCESSOR_PIII_C_EARLY; return SPEEDSTEP_PROCESSOR_PIII_C_EARLY;
else else
...@@ -362,6 +370,11 @@ unsigned int speedstep_get_freqs(unsigned int processor, ...@@ -362,6 +370,11 @@ unsigned int speedstep_get_freqs(unsigned int processor,
} }
EXPORT_SYMBOL_GPL(speedstep_get_freqs); EXPORT_SYMBOL_GPL(speedstep_get_freqs);
#ifdef CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK
module_param(relaxed_check, int, 0444);
MODULE_PARM_DESC(relaxed_check, "Don't do all checks for speedstep capability.");
#endif
MODULE_AUTHOR ("Dominik Brodowski <linux@brodo.de>"); MODULE_AUTHOR ("Dominik Brodowski <linux@brodo.de>");
MODULE_DESCRIPTION ("Library for Intel SpeedStep 1 or 2 cpufreq drivers."); MODULE_DESCRIPTION ("Library for Intel SpeedStep 1 or 2 cpufreq drivers.");
MODULE_LICENSE ("GPL"); MODULE_LICENSE ("GPL");
...@@ -963,6 +963,7 @@ EXPORT_SYMBOL_GPL(cpufreq_notify_transition); ...@@ -963,6 +963,7 @@ EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
int cpufreq_register_driver(struct cpufreq_driver *driver_data) int cpufreq_register_driver(struct cpufreq_driver *driver_data)
{ {
unsigned long flags; unsigned long flags;
int ret;
if (!driver_data || !driver_data->verify || !driver_data->init || if (!driver_data || !driver_data->verify || !driver_data->init ||
((!driver_data->setpolicy) && (!driver_data->target))) ((!driver_data->setpolicy) && (!driver_data->target)))
...@@ -976,7 +977,28 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data) ...@@ -976,7 +977,28 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
cpufreq_driver = driver_data; cpufreq_driver = driver_data;
spin_unlock_irqrestore(&cpufreq_driver_lock, flags); spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
return sysdev_driver_register(&cpu_sysdev_class,&cpufreq_sysdev_driver); ret = sysdev_driver_register(&cpu_sysdev_class,&cpufreq_sysdev_driver);
if ((!ret) && !(cpufreq_driver->flags & CPUFREQ_STICKY)) {
int i;
ret = -ENODEV;
/* check for at least one working CPU */
for (i=0; i<NR_CPUS; i++)
if (cpufreq_cpu_data[i])
ret = 0;
/* if all ->init() calls failed, unregister */
if (ret) {
sysdev_driver_unregister(&cpu_sysdev_class, &cpufreq_sysdev_driver);
spin_lock_irqsave(&cpufreq_driver_lock, flags);
cpufreq_driver = NULL;
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
}
}
return (ret);
} }
EXPORT_SYMBOL_GPL(cpufreq_register_driver); EXPORT_SYMBOL_GPL(cpufreq_register_driver);
......
...@@ -175,6 +175,7 @@ struct freq_attr; ...@@ -175,6 +175,7 @@ struct freq_attr;
struct cpufreq_driver { struct cpufreq_driver {
struct module *owner; struct module *owner;
char name[CPUFREQ_NAME_LEN]; char name[CPUFREQ_NAME_LEN];
u8 flags;
/* needed by all drivers */ /* needed by all drivers */
int (*init) (struct cpufreq_policy *policy); int (*init) (struct cpufreq_policy *policy);
...@@ -192,6 +193,11 @@ struct cpufreq_driver { ...@@ -192,6 +193,11 @@ struct cpufreq_driver {
struct freq_attr **attr; struct freq_attr **attr;
}; };
/* flags */
#define CPUFREQ_STICKY 0x01 /* the driver isn't removed even if
all ->init() calls failed */
int cpufreq_register_driver(struct cpufreq_driver *driver_data); int cpufreq_register_driver(struct cpufreq_driver *driver_data);
int cpufreq_unregister_driver(struct cpufreq_driver *driver_data); int cpufreq_unregister_driver(struct cpufreq_driver *driver_data);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment