Commit e8990100 authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://linux-dj.bkbits.net/cpufreq

into ppc970.osdl.org:/home/torvalds/v2.6/linux
parents 8a6d2688 885d5a1d
......@@ -336,9 +336,10 @@ config ZBOOT_ROM_BSS
while the decompressor is running. Unless you have special requirements,
you should not change this value.
if (ARCH_SA1100 || ARCH_INTEGRATOR)
config CPU_FREQ
bool "Support CPU clock change (EXPERIMENTAL)"
depends on (ARCH_SA1100 || ARCH_INTEGRATOR) && EXPERIMENTAL
bool "Support CPU clock change"
help
CPU clock scaling allows you to change the clock speed of the
running CPU on the fly. This is a nice method to save battery power,
......@@ -348,20 +349,17 @@ config CPU_FREQ
written) to implement the policy. If you don't understand what this
is all about, it's safe to say 'N'.
# CPUfreq on SA11x0 is special -- it _needs_ the userspace governor
source "drivers/cpufreq/Kconfig"
config CPU_FREQ_SA1100
bool
depends on CPU_FREQ && SA1100_LART
default y
select CPU_FREQ_24_API if SYSCTL
config CPU_FREQ_SA1110
bool
depends on CPU_FREQ && (SA1100_ASSABET || SA1100_CERF || SA1100_PT_SYSTEM3)
default y
select CPU_FREQ_24_API if SYSCTL
config CPU_FREQ_INTEGRATOR
tristate "CPUfreq driver for ARM Integrator CPUs"
......@@ -374,10 +372,6 @@ config CPU_FREQ_INTEGRATOR
If in doubt, say Y.
if (CPU_FREQ_INTEGRATOR) || (CPU_FREQ_SA1110) || (CPU_FREQ_SA1100)
source "drivers/cpufreq/Kconfig"
endif
source "drivers/pci/Kconfig"
......
......@@ -42,16 +42,6 @@ config X86_ACPI_CPUFREQ
If in doubt, say N.
config X86_ACPI_CPUFREQ_PROC_INTF
bool "/proc/acpi/processor/../performance interface (deprecated)"
depends on X86_ACPI_CPUFREQ && PROC_FS
help
This enables the deprecated /proc/acpi/processor/../performance
interface. While it is helpful for debugging, the generic,
cross-architecture cpufreq interfaces should be used.
If in doubt, say N.
config ELAN_CPUFREQ
tristate "AMD Elan"
depends on CPU_FREQ_TABLE && X86_ELAN
......@@ -95,7 +85,7 @@ config X86_POWERNOW_K7_ACPI
config X86_POWERNOW_K8
tristate "AMD Opteron/Athlon64 PowerNow!"
depends on CPU_FREQ && EXPERIMENTAL
depends on CPU_FREQ_TABLE && EXPERIMENTAL
help
This adds the CPUFreq driver for mobile AMD Opteron/Athlon64 processors.
......@@ -122,29 +112,40 @@ config X86_GX_SUSPMOD
config X86_SPEEDSTEP_CENTRINO
tristate "Intel Enhanced SpeedStep"
depends on CPU_FREQ_TABLE
select X86_SPEEDSTEP_CENTRINO_TABLE if (!X86_SPEEDSTEP_CENTRINO_ACPI)
help
This adds the CPUFreq driver for Enhanced SpeedStep enabled
mobile CPUs. This means Intel Pentium M (Centrino) CPUs.
mobile CPUs. This means Intel Pentium M (Centrino) CPUs. However,
you also need to say Y to "Use ACPI tables to decode..." below
[which might imply enabling ACPI] if you want to use this driver
on non-Banias CPUs.
For details, take a look at <file:Documentation/cpu-freq/>.
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
bool "Use ACPI tables to decode valid frequency/voltage pairs"
depends on X86_SPEEDSTEP_CENTRINO
depends on ((X86_SPEEDSTEP_CENTRINO = "m" && ACPI_PROCESSOR) || (X86_SPEEDSTEP_CENTRINO = "y" && ACPI_PROCESSOR = "y"))
default y
help
Use primarily the information provided in the BIOS ACPI tables
to determine valid CPU frequency and voltage pairings.
to determine valid CPU frequency and voltage pairings. It is
required for the driver to work on non-Banias CPUs.
If in doubt, say Y.
config X86_SPEEDSTEP_CENTRINO_TABLE
bool "Built-in tables for Banias CPUs"
depends on X86_SPEEDSTEP_CENTRINO
default y
help
Use built-in tables for Banias CPUs if ACPI encoding
is not available.
If in doubt, say N.
config X86_SPEEDSTEP_ICH
tristate "Intel Speedstep on ICH-M chipsets (ioport interface)"
depends on CPU_FREQ_TABLE
......@@ -181,21 +182,6 @@ config X86_P4_CLOCKMOD
If in doubt, say N.
config X86_SPEEDSTEP_LIB
tristate
depends on (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
tristate "Transmeta LongRun"
depends on CPU_FREQ
......@@ -219,4 +205,34 @@ config X86_LONGHAUL
If in doubt, say N.
comment "shared options"
depends on CPU_FREQ
config X86_ACPI_CPUFREQ_PROC_INTF
bool "/proc/acpi/processor/../performance interface (deprecated)"
depends on PROC_FS
depends on X86_ACPI_CPUFREQ || X86_SPEEDSTEP_CENTRINO_ACPI || X86_POWERNOW_K7_ACPI || X86_POWERNOW_K8_ACPI
help
This enables the deprecated /proc/acpi/processor/../performance
interface. While it is helpful for debugging, the generic,
cross-architecture cpufreq interfaces should be used.
If in doubt, say N.
config X86_SPEEDSTEP_LIB
tristate
depends on (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 lets the probing code bypass some of those checks if the
parameter "relaxed_check=1" is passed to the module.
endmenu
......@@ -110,7 +110,7 @@ static int cpufreq_p4_target(struct cpufreq_policy *policy,
{
unsigned int newstate = DC_RESV;
struct cpufreq_freqs freqs;
cpumask_t cpus_allowed, affected_cpu_map;
cpumask_t cpus_allowed;
int i;
if (cpufreq_frequency_table_target(policy, &p4clockmod_table[0], target_freq, relation, &newstate))
......@@ -122,18 +122,8 @@ static int cpufreq_p4_target(struct cpufreq_policy *policy,
if (freqs.new == freqs.old)
return 0;
/* switch to physical CPU where state is to be changed*/
cpus_allowed = current->cpus_allowed;
/* only run on CPU to be set, or on its sibling */
#ifdef CONFIG_SMP
affected_cpu_map = cpu_sibling_map[policy->cpu];
#else
affected_cpu_map = cpumask_of_cpu(policy->cpu);
#endif
/* notifiers */
for_each_cpu_mask(i, affected_cpu_map) {
for_each_cpu_mask(i, policy->cpus) {
freqs.cpu = i;
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
}
......@@ -141,7 +131,9 @@ static int cpufreq_p4_target(struct cpufreq_policy *policy,
/* run on each logical CPU, see section 13.15.3 of IA32 Intel Architecture Software
* Developer's Manual, Volume 3
*/
for_each_cpu_mask(i, affected_cpu_map) {
cpus_allowed = current->cpus_allowed;
for_each_cpu_mask(i, policy->cpus) {
cpumask_t this_cpu = cpumask_of_cpu(i);
set_cpus_allowed(current, this_cpu);
......@@ -152,7 +144,7 @@ static int cpufreq_p4_target(struct cpufreq_policy *policy,
set_cpus_allowed(current, cpus_allowed);
/* notifiers */
for_each_cpu_mask(i, affected_cpu_map) {
for_each_cpu_mask(i, policy->cpus) {
freqs.cpu = i;
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
}
......@@ -219,6 +211,10 @@ static int cpufreq_p4_cpu_init(struct cpufreq_policy *policy)
int cpuid = 0;
unsigned int i;
#ifdef CONFIG_SMP
policy->cpus = cpu_sibling_map[policy->cpu];
#endif
/* Errata workaround */
cpuid = (c->x86 << 8) | (c->x86_model << 4) | c->x86_mask;
switch (cpuid) {
......@@ -260,14 +256,13 @@ static int cpufreq_p4_cpu_exit(struct cpufreq_policy *policy)
static unsigned int cpufreq_p4_get(unsigned int cpu)
{
cpumask_t cpus_allowed, affected_cpu_map;
cpumask_t cpus_allowed;
u32 l, h;
cpus_allowed = current->cpus_allowed;
affected_cpu_map = cpumask_of_cpu(cpu);
set_cpus_allowed(current, affected_cpu_map);
BUG_ON(!cpu_isset(smp_processor_id(), affected_cpu_map));
set_cpus_allowed(current, cpumask_of_cpu(cpu));
BUG_ON(smp_processor_id() != cpu);
rdmsr(MSR_IA32_THERM_CONTROL, l, h);
......@@ -335,4 +330,3 @@ MODULE_LICENSE ("GPL");
late_initcall(cpufreq_p4_init);
module_exit(cpufreq_p4_exit);
......@@ -39,7 +39,7 @@
#define PFX "powernow-k8: "
#define BFX PFX "BIOS error: "
#define VERSION "version 1.00.09b"
#define VERSION "version 1.00.09e"
#include "powernow-k8.h"
/* serialize freq changes */
......@@ -596,6 +596,8 @@ static int find_psb_table(struct powernow_k8_data *data)
unsigned int i;
u32 mvs;
u8 maxvid;
u32 cpst = 0;
u32 thiscpuid;
for (i = 0xc0000; i < 0xffff0; i += 0x10) {
/* Scan BIOS looking for the signature. */
......@@ -634,7 +636,14 @@ static int find_psb_table(struct powernow_k8_data *data)
dprintk(KERN_INFO PFX "maximum voltage step: %d - 0x%x\n", mvs, data->vidmvs);
dprintk(KERN_DEBUG PFX "numpst: 0x%x\n", psb->numpst);
if (psb->numpst != 1) {
cpst = psb->numpst;
if ((psb->cpuid == 0x00000fc0) || (psb->cpuid == 0x00000fe0) ){
thiscpuid = cpuid_eax(CPUID_PROCESSOR_SIGNATURE);
if ((thiscpuid == 0x00000fc0) || (thiscpuid == 0x00000fe0) ) {
cpst = 1;
}
}
if (cpst != 1) {
printk(KERN_ERR BFX "numpst must be 1\n");
return -ENODEV;
}
......
......@@ -77,7 +77,7 @@ static int centrino_verify_cpu_id(const struct cpuinfo_x86 *c, const struct cpu_
/* Operating points for current CPU */
static struct cpu_model *centrino_model;
static int centrino_cpu;
static const struct cpu_id *centrino_cpu;
#ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE
......@@ -289,7 +289,9 @@ static unsigned extract_clock(unsigned msr)
* for centrino, as some DSDTs are buggy.
* Ideally, this can be done using the acpi_data structure.
*/
if (centrino_cpu) {
if ((centrino_cpu == &cpu_ids[CPU_BANIAS]) ||
(centrino_cpu == &cpu_ids[CPU_DOTHAN_A1]) ||
(centrino_cpu == &cpu_ids[CPU_DOTHAN_B0])) {
msr = (msr >> 8) & 0xff;
return msr * 100000;
}
......@@ -457,7 +459,7 @@ static int centrino_cpu_init(struct cpufreq_policy *policy)
break;
if (i != N_IDS)
centrino_cpu = 1;
centrino_cpu = &cpu_ids[i];
if (centrino_cpu_init_acpi(policy)) {
if (policy->cpu != 0)
......@@ -567,7 +569,7 @@ static int centrino_target (struct cpufreq_policy *policy,
* Make sure we are running on the CPU that wants to change frequency
*/
saved_mask = current->cpus_allowed;
set_cpus_allowed(current, cpumask_of_cpu(policy->cpu));
set_cpus_allowed(current, policy->cpus);
if (smp_processor_id() != policy->cpu) {
return(-EAGAIN);
}
......
......@@ -223,24 +223,23 @@ static unsigned int speedstep_detect_chipset (void)
return 0;
}
static unsigned int speedstep_get(unsigned int cpu)
static unsigned int _speedstep_get(cpumask_t cpus)
{
unsigned int speed;
cpumask_t cpus_allowed,affected_cpu_map;
cpumask_t cpus_allowed;
/* only run on CPU to be set, or on its sibling */
cpus_allowed = current->cpus_allowed;
#ifdef CONFIG_SMP
affected_cpu_map = cpu_sibling_map[cpu];
#else
affected_cpu_map = cpumask_of_cpu(cpu);
#endif
set_cpus_allowed(current, affected_cpu_map);
speed=speedstep_get_processor_frequency(speedstep_processor);
set_cpus_allowed(current, cpus);
speed = speedstep_get_processor_frequency(speedstep_processor);
set_cpus_allowed(current, cpus_allowed);
return speed;
}
static unsigned int speedstep_get(unsigned int cpu)
{
return _speedstep_get(cpumask_of_cpu(cpu));
}
/**
* speedstep_target - set a new CPUFreq policy
* @policy: new policy
......@@ -255,13 +254,13 @@ static int speedstep_target (struct cpufreq_policy *policy,
{
unsigned int newstate = 0;
struct cpufreq_freqs freqs;
cpumask_t cpus_allowed, affected_cpu_map;
cpumask_t cpus_allowed;
int i;
if (cpufreq_frequency_table_target(policy, &speedstep_freqs[0], target_freq, relation, &newstate))
return -EINVAL;
freqs.old = speedstep_get(policy->cpu);
freqs.old = _speedstep_get(policy->cpus);
freqs.new = speedstep_freqs[newstate].frequency;
freqs.cpu = policy->cpu;
......@@ -271,27 +270,20 @@ static int speedstep_target (struct cpufreq_policy *policy,
cpus_allowed = current->cpus_allowed;
/* only run on CPU to be set, or on its sibling */
#ifdef CONFIG_SMP
affected_cpu_map = cpu_sibling_map[policy->cpu];
#else
affected_cpu_map = cpumask_of_cpu(policy->cpu);
#endif
for_each_cpu_mask(i, affected_cpu_map) {
for_each_cpu_mask(i, policy->cpus) {
freqs.cpu = i;
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
}
/* switch to physical CPU where state is to be changed */
set_cpus_allowed(current, affected_cpu_map);
set_cpus_allowed(current, policy->cpus);
speedstep_set_state(newstate);
/* allow to be run on all CPUs */
set_cpus_allowed(current, cpus_allowed);
for_each_cpu_mask(i, affected_cpu_map) {
for_each_cpu_mask(i, policy->cpus) {
freqs.cpu = i;
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
}
......@@ -317,21 +309,15 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
{
int result = 0;
unsigned int speed;
cpumask_t cpus_allowed,affected_cpu_map;
/* capability check */
if (policy->cpu != 0) /* FIXME: better support for SMT in cpufreq core. Up until then, it's better to register only one CPU */
return -ENODEV;
cpumask_t cpus_allowed;
/* only run on CPU to be set, or on its sibling */
cpus_allowed = current->cpus_allowed;
#ifdef CONFIG_SMP
affected_cpu_map = cpu_sibling_map[policy->cpu];
#else
affected_cpu_map = cpumask_of_cpu(policy->cpu);
policy->cpus = cpu_sibling_map[policy->cpu];
#endif
set_cpus_allowed(current, affected_cpu_map);
cpus_allowed = current->cpus_allowed;
set_cpus_allowed(current, policy->cpus);
/* detect low and high frequency */
result = speedstep_get_freqs(speedstep_processor,
......@@ -343,7 +329,7 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
return result;
/* get current speed setting */
speed = speedstep_get(policy->cpu);
speed = _speedstep_get(policy->cpus);
if (!speed)
return -EIO;
......
......@@ -260,12 +260,6 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
if (result) {
/* fall back to speedstep_lib.c dection mechanism: try both states out */
dprintk(KERN_INFO PFX "could not detect low and high frequencies by SMI call.\n");
if (!speedstep_processor)
speedstep_processor = speedstep_detect_processor();
if (!speedstep_processor)
return -ENODEV;
result = speedstep_get_freqs(speedstep_processor,
&speedstep_freqs[SPEEDSTEP_LOW].frequency,
&speedstep_freqs[SPEEDSTEP_HIGH].frequency,
......@@ -310,10 +304,6 @@ static unsigned int speedstep_get(unsigned int cpu)
{
if (cpu)
return -ENODEV;
if (!speedstep_processor)
speedstep_processor = speedstep_detect_processor();
if (!speedstep_processor)
return 0;
return speedstep_get_processor_frequency(speedstep_processor);
}
......@@ -354,10 +344,19 @@ static struct cpufreq_driver speedstep_driver = {
*/
static int __init speedstep_init(void)
{
struct cpuinfo_x86 *c = cpu_data;
speedstep_processor = speedstep_detect_processor();
switch (speedstep_processor) {
case SPEEDSTEP_PROCESSOR_PIII_T:
case SPEEDSTEP_PROCESSOR_PIII_C:
case SPEEDSTEP_PROCESSOR_PIII_C_EARLY:
break;
default:
speedstep_processor = 0;
}
if (c->x86_vendor != X86_VENDOR_INTEL) {
printk (KERN_INFO PFX "No Intel CPU detected.\n");
if (!speedstep_processor) {
dprintk (KERN_INFO PFX "No supported Intel CPU detected.\n");
return -ENODEV;
}
......
......@@ -48,7 +48,7 @@ config X86_POWERNOW_K8_ACPI
config X86_SPEEDSTEP_CENTRINO
tristate "Intel Enhanced SpeedStep"
depends on CPU_FREQ_TABLE
depends on CPU_FREQ_TABLE && ACPI_PROCESSOR
help
This adds the CPUFreq driver for Enhanced SpeedStep enabled
mobile CPUs. This means Intel Pentium M (Centrino) CPUs
......@@ -58,21 +58,11 @@ config X86_SPEEDSTEP_CENTRINO
If in doubt, say N.
config X86_SPEEDSTEP_CENTRINO_TABLE
config X86_SPEEDSTEP_CENTRINO_ACPI
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_ACPI_CPUFREQ
tristate "ACPI Processor P-States driver"
depends on CPU_FREQ_TABLE && ACPI_PROCESSOR
......@@ -84,9 +74,13 @@ config X86_ACPI_CPUFREQ
If in doubt, say N.
comment "shared options"
depends on CPU_FREQ
config X86_ACPI_CPUFREQ_PROC_INTF
bool "/proc/acpi/processor/../performance interface (deprecated)"
depends on X86_ACPI_CPUFREQ && PROC_FS
depends on PROC_FS
depends on X86_ACPI_CPUFREQ || X86_SPEEDSTEP_CENTRINO_ACPI || X86_POWERNOW_K8_ACPI
help
This enables the deprecated /proc/acpi/processor/../performance
interface. While it is helpful for debugging, the generic,
......
......@@ -33,7 +33,7 @@ config CPU_FREQ_DEFAULT_GOV_USERSPACE
help
Use the CPUFreq governor 'userspace' as default. This allows
you to set the CPU frequency manually or when an userspace
programm shall be able to set the CPU dynamically without having
program shall be able to set the CPU dynamically without having
to enable the userspace governor manually.
endchoice
......@@ -42,7 +42,7 @@ config CPU_FREQ_GOV_PERFORMANCE
tristate "'performance' governor"
depends on CPU_FREQ
help
This cpufreq governors set the frequency statically to the
This cpufreq governor sets the frequency statically to the
highest available CPU frequency.
If in doubt, say Y.
......@@ -51,7 +51,7 @@ config CPU_FREQ_GOV_POWERSAVE
tristate "'powersave' governor"
depends on CPU_FREQ
help
Theis cpufreq governors set the frequency statically to the
This cpufreq governor sets the frequency statically to the
lowest available CPU frequency.
If in doubt, say Y.
......@@ -61,14 +61,29 @@ config CPU_FREQ_GOV_USERSPACE
depends on CPU_FREQ
help
Enable this cpufreq governor when you either want to set the
CPU frequency manually or when an userspace programm shall
be able to set the CPU dynamically, like on LART
CPU frequency manually or when an userspace program shall
be able to set the CPU dynamically, like on LART
<http://www.lart.tudelft.nl/>
For details, take a look at <file:Documentation/cpu-freq/>.
If in doubt, say Y.
config CPU_FREQ_24_API
bool "/proc/sys/cpu/ interface (2.4. / OLD)"
depends on CPU_FREQ_GOV_USERSPACE
depends on SYSCTL
help
This enables the /proc/sys/cpu/ sysctl interface for controlling
the CPUFreq,"userspace" governor. This is the same interface
as known from the 2.4.-kernel patches for CPUFreq, and offers
the same functionality as long as "userspace" is the
selected governor for the specified CPU.
For details, take a look at <file:Documentation/cpu-freq/>.
If in doubt, say N.
config CPU_FREQ_GOV_ONDEMAND
tristate "'ondemand' cpufreq policy governor"
depends on CPU_FREQ
......@@ -83,17 +98,3 @@ config CPU_FREQ_GOV_ONDEMAND
For details, take a look at linux/Documentation/cpu-freq.
If in doubt, say N.
config CPU_FREQ_24_API
bool "/proc/sys/cpu/ interface (2.4. / OLD)"
depends on CPU_FREQ && SYSCTL && CPU_FREQ_GOV_USERSPACE
help
This enables the /proc/sys/cpu/ sysctl interface for controlling
the CPUFreq,"userspace" governor. This is the same interface
as known from the 2.4.-kernel patches for CPUFreq, and offers
the same functionality as long as "userspace" is the
selected governor for the specified CPU.
For details, take a look at <file:Documentation/cpu-freq/>.
If in doubt, say N.
......@@ -33,6 +33,14 @@ static struct cpufreq_driver *cpufreq_driver;
static struct cpufreq_policy *cpufreq_cpu_data[NR_CPUS];
static spinlock_t cpufreq_driver_lock = SPIN_LOCK_UNLOCKED;
/* we keep a copy of all ->add'ed CPU's struct sys_device here;
* as it is only accessed in ->add and ->remove, no lock or reference
* count is necessary.
*/
static struct sys_device *cpu_sys_devices[NR_CPUS];
/* internal prototypes */
static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event);
static void handle_update(void *data);
......@@ -154,6 +162,7 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
*/
if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) {
if ((likely(cpufreq_cpu_data[freqs->cpu])) &&
(likely(cpufreq_cpu_data[freqs->cpu]->cpu == freqs->cpu)) &&
(likely(cpufreq_cpu_data[freqs->cpu]->cur)) &&
(unlikely(freqs->old != cpufreq_cpu_data[freqs->cpu]->cur)))
{
......@@ -168,7 +177,8 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
case CPUFREQ_POSTCHANGE:
adjust_jiffies(CPUFREQ_POSTCHANGE, freqs);
notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_POSTCHANGE, freqs);
if (likely(cpufreq_cpu_data[freqs->cpu]))
if ((likely(cpufreq_cpu_data[freqs->cpu])) &&
(likely(cpufreq_cpu_data[freqs->cpu]->cpu == freqs->cpu)))
cpufreq_cpu_data[freqs->cpu]->cur = freqs->new;
break;
}
......@@ -456,6 +466,18 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
struct cpufreq_policy *policy;
struct freq_attr **drv_attr;
unsigned long flags;
unsigned int j;
#ifdef CONFIG_SMP
/* check whether a different CPU already registered this
* CPU because it is in the same boat. */
policy = cpufreq_cpu_get(cpu);
if (unlikely(policy)) {
cpu_sys_devices[cpu] = sys_dev;
sysfs_create_link(&sys_dev->kobj, &policy->kobj, "cpufreq");
return 0;
}
#endif
if (!try_module_get(cpufreq_driver->owner))
return -EINVAL;
......@@ -468,6 +490,8 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
memset(policy, 0, sizeof(struct cpufreq_policy));
policy->cpu = cpu;
policy->cpus = cpumask_of_cpu(cpu);
init_MUTEX_LOCKED(&policy->lock);
init_completion(&policy->kobj_unregister);
INIT_WORK(&policy->update, handle_update, (void *)(long)cpu);
......@@ -502,7 +526,8 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
sysfs_create_file(&policy->kobj, &scaling_cur_freq.attr);
spin_lock_irqsave(&cpufreq_driver_lock, flags);
cpufreq_cpu_data[cpu] = policy;
for_each_cpu_mask(j, policy->cpus)
cpufreq_cpu_data[j] = policy;
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
policy->governor = NULL; /* to assure that the starting sequence is
* run in cpufreq_set_policy */
......@@ -515,12 +540,14 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
goto err_out_unregister;
module_put(cpufreq_driver->owner);
cpu_sys_devices[cpu] = sys_dev;
return 0;
err_out_unregister:
spin_lock_irqsave(&cpufreq_driver_lock, flags);
cpufreq_cpu_data[cpu] = NULL;
for_each_cpu_mask(j, policy->cpus)
cpufreq_cpu_data[j] = NULL;
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
kobject_unregister(&policy->kobj);
......@@ -545,19 +572,69 @@ static int cpufreq_remove_dev (struct sys_device * sys_dev)
unsigned int cpu = sys_dev->id;
unsigned long flags;
struct cpufreq_policy *data;
#ifdef CONFIG_SMP
unsigned int j;
#endif
spin_lock_irqsave(&cpufreq_driver_lock, flags);
data = cpufreq_cpu_data[cpu];
if (!data) {
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
cpu_sys_devices[cpu] = NULL;
return -EINVAL;
}
cpufreq_cpu_data[cpu] = NULL;
#ifdef CONFIG_SMP
/* if this isn't the CPU which is the parent of the kobj, we
* only need to unlink, put and exit
*/
if (unlikely(cpu != data->cpu)) {
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
sysfs_remove_link(&sys_dev->kobj, "cpufreq");
cpu_sys_devices[cpu] = NULL;
cpufreq_cpu_put(data);
return 0;
}
#endif
cpu_sys_devices[cpu] = NULL;
if (!kobject_get(&data->kobj)) {
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
return -EFAULT;
}
#ifdef CONFIG_SMP
/* if we have other CPUs still registered, we need to unlink them,
* or else wait_for_completion below will lock up. Clean the
* cpufreq_cpu_data[] while holding the lock, and remove the sysfs
* links afterwards.
*/
if (unlikely(cpus_weight(data->cpus) > 1)) {
for_each_cpu_mask(j, data->cpus) {
if (j == cpu)
continue;
cpufreq_cpu_data[j] = NULL;
}
}
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
if (!kobject_get(&data->kobj))
return -EFAULT;
if (unlikely(cpus_weight(data->cpus) > 1)) {
for_each_cpu_mask(j, data->cpus) {
if (j == cpu)
continue;
sysfs_remove_link(&cpu_sys_devices[j]->kobj, "cpufreq");
cpufreq_cpu_put(data);
}
}
#else
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
#endif
if (cpufreq_driver->target)
__cpufreq_governor(data, CPUFREQ_GOV_STOP);
......@@ -676,6 +753,12 @@ static int cpufreq_resume(struct sys_device * sysdev)
if (!cpu_policy)
return -EINVAL;
/* only handle each CPU group once */
if (unlikely(cpu_policy->cpu != cpu)) {
cpufreq_cpu_put(cpu_policy);
return 0;
}
if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) {
unsigned int cur_freq = 0;
......
......@@ -515,7 +515,7 @@ static int cpufreq_governor_userspace(struct cpufreq_policy *policy,
unsigned int cpu = policy->cpu;
switch (event) {
case CPUFREQ_GOV_START:
if ((!cpu_online(cpu)) || (!try_module_get(THIS_MODULE)))
if (!cpu_online(cpu))
return -EINVAL;
BUG_ON(!policy->cur);
down(&userspace_sem);
......@@ -534,7 +534,6 @@ static int cpufreq_governor_userspace(struct cpufreq_policy *policy,
cpu_max_freq[cpu] = 0;
sysfs_remove_file (&policy->kobj, &freq_attr_scaling_setspeed.attr);
up(&userspace_sem);
module_put(THIS_MODULE);
break;
case CPUFREQ_GOV_LIMITS:
down(&userspace_sem);
......
......@@ -22,6 +22,7 @@
#include <linux/sysfs.h>
#include <linux/completion.h>
#include <linux/workqueue.h>
#include <linux/cpumask.h>
#define CPUFREQ_NAME_LEN 16
......@@ -69,7 +70,8 @@ struct cpufreq_real_policy {
};
struct cpufreq_policy {
unsigned int cpu; /* cpu nr */
cpumask_t cpus; /* affected CPUs */
unsigned int cpu; /* cpu nr of registered CPU */
struct cpufreq_cpuinfo cpuinfo;/* see above */
unsigned int min; /* in kHz */
......
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