Commit 33dc3a9b authored by David S. Miller's avatar David S. Miller

[SPARC64]: cpufreq cleanup, move notifier into common area.

parent ed8695bd
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <asm/system.h> #include <asm/system.h>
#include <asm/smp.h> #include <asm/smp.h>
#include <asm/spitfire.h> #include <asm/spitfire.h>
#include <asm/timer.h>
/* Used to synchronize acceses to NatSemi SUPER I/O chip configure /* Used to synchronize acceses to NatSemi SUPER I/O chip configure
* operations in asm/ns87303.h * operations in asm/ns87303.h
...@@ -88,7 +89,6 @@ void __init device_scan(void) ...@@ -88,7 +89,6 @@ void __init device_scan(void)
#ifndef CONFIG_SMP #ifndef CONFIG_SMP
{ {
extern unsigned long up_clock_tick;
up_clock_tick = prom_getintdefault(prom_node_cpu, up_clock_tick = prom_getintdefault(prom_node_cpu,
"clock-frequency", "clock-frequency",
0); 0);
......
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
#include <asm/starfire.h> #include <asm/starfire.h>
#include <asm/hardirq.h> #include <asm/hardirq.h>
#include <asm/mmu_context.h> #include <asm/mmu_context.h>
#include <asm/timer.h>
#ifdef CONFIG_IP_PNP #ifdef CONFIG_IP_PNP
#include <net/ipconfig.h> #include <net/ipconfig.h>
......
...@@ -55,6 +55,7 @@ ...@@ -55,6 +55,7 @@
#endif #endif
#include <asm/a.out.h> #include <asm/a.out.h>
#include <asm/ns87303.h> #include <asm/ns87303.h>
#include <asm/timer.h>
struct poll { struct poll {
int fd; int fd;
...@@ -159,11 +160,7 @@ EXPORT_SYMBOL(_do_write_unlock); ...@@ -159,11 +160,7 @@ EXPORT_SYMBOL(_do_write_unlock);
EXPORT_SYMBOL(smp_call_function); EXPORT_SYMBOL(smp_call_function);
#endif /* CONFIG_SMP */ #endif /* CONFIG_SMP */
/* Uniprocessor clock frequency */ EXPORT_SYMBOL(sparc64_get_clock_tick);
#ifndef CONFIG_SMP
extern unsigned long up_clock_tick;
EXPORT_SYMBOL(up_clock_tick);
#endif
/* semaphores */ /* semaphores */
EXPORT_SYMBOL(down); EXPORT_SYMBOL(down);
......
...@@ -26,6 +26,8 @@ ...@@ -26,6 +26,8 @@
#include <linux/profile.h> #include <linux/profile.h>
#include <linux/bcd.h> #include <linux/bcd.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/cpufreq.h>
#include <linux/percpu.h>
#include <asm/oplib.h> #include <asm/oplib.h>
#include <asm/mostek.h> #include <asm/mostek.h>
...@@ -988,6 +990,73 @@ static unsigned long sparc64_init_timers(void (*cfunc)(int, void *, struct pt_re ...@@ -988,6 +990,73 @@ static unsigned long sparc64_init_timers(void (*cfunc)(int, void *, struct pt_re
return clock; return clock;
} }
struct freq_table {
unsigned long udelay_val_ref;
unsigned long clock_tick_ref;
unsigned int ref_freq;
};
static DEFINE_PER_CPU(struct freq_table, sparc64_freq_table) = { 0, 0, 0 };
unsigned long sparc64_get_clock_tick(unsigned int cpu)
{
struct freq_table *ft = &per_cpu(sparc64_freq_table, cpu);
if (ft->clock_tick_ref)
return ft->clock_tick_ref;
#ifdef CONFIG_SMP
return cpu_data[cpu].clock_tick;
#else
return up_clock_tick;
#endif
}
#ifdef CONFIG_CPU_FREQ
static int sparc64_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
void *data)
{
struct cpufreq_freqs *freq = data;
unsigned int cpu = freq->cpu;
struct freq_table *ft = &per_cpu(sparc64_freq_table, cpu);
#ifdef CONFIG_SMP
if (!ft->ref_freq) {
ft->ref_freq = freq->old;
ft->udelay_val_ref = cpu_data[cpu].udelay_val;
ft->clock_tick_ref = cpu_data[cpu].clock_tick;
}
if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) ||
(val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) {
cpu_data[cpu].udelay_val =
cpufreq_scale(ft->udelay_val_ref,
ft->ref_freq,
freq->new);
cpu_data[cpu].clock_tick =
cpufreq_scale(ft->clock_tick_ref,
ft->ref_freq,
freq->new);
}
#else
/* In the non-SMP case, kernel/cpufreq.c takes care of adjusting
* loops_per_jiffy.
*/
if (!ft->ref_freq) {
ft->ref_freq = freq->old;
ft->clock_tick_ref = up_clock_tick;
}
if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) ||
(val == CPUFREQ_POSTCHANGE && freq->old > freq->new))
up_clock_tick = cpufreq_scale(ft->clock_tick_ref, ft->ref_freq, freq->new);
#endif
return 0;
}
static struct notifier_block sparc64_cpufreq_notifier_block = {
.notifier_call = sparc64_cpufreq_notifier
};
#endif
/* The quotient formula is taken from the IA64 port. */ /* The quotient formula is taken from the IA64 port. */
void __init time_init(void) void __init time_init(void)
{ {
...@@ -996,6 +1065,11 @@ void __init time_init(void) ...@@ -996,6 +1065,11 @@ void __init time_init(void)
timer_ticks_per_usec_quotient = timer_ticks_per_usec_quotient =
(((1000000UL << 30) + (((1000000UL << 30) +
(clock / 2)) / clock); (clock / 2)) / clock);
#ifdef CONFIG_CPU_FREQ
cpufreq_register_notifier(&sparc64_cpufreq_notifier_block,
CPUFREQ_TRANSITION_NOTIFIER);
#endif
} }
static __inline__ unsigned long do_gettimeoffset(void) static __inline__ unsigned long do_gettimeoffset(void)
......
...@@ -16,14 +16,12 @@ ...@@ -16,14 +16,12 @@
#include <linux/init.h> #include <linux/init.h>
#include <asm/head.h> #include <asm/head.h>
#include <asm/timer.h>
static struct cpufreq_driver *cpufreq_us3_driver; static struct cpufreq_driver *cpufreq_us3_driver;
struct us3_freq_percpu_info { struct us3_freq_percpu_info {
struct cpufreq_frequency_table table[4]; struct cpufreq_frequency_table table[4];
unsigned long udelay_val_ref;
unsigned long clock_tick_ref;
unsigned int ref_freq;
}; };
/* Indexed by cpu number. */ /* Indexed by cpu number. */
...@@ -56,71 +54,9 @@ static void write_safari_cfg(unsigned long val) ...@@ -56,71 +54,9 @@ static void write_safari_cfg(unsigned long val)
: "memory"); : "memory");
} }
#ifndef CONFIG_SMP
extern unsigned long up_clock_tick;
unsigned long clock_tick_ref;
unsigned int ref_freq;
#endif
static __inline__ unsigned long get_clock_tick(unsigned int cpu)
{
#ifdef CONFIG_SMP
if (us3_freq_table[cpu].clock_tick_ref)
return us3_freq_table[cpu].clock_tick_ref;
return cpu_data[cpu].clock_tick;
#else
if (clock_tick_ref)
return clock_tick_ref;
return up_clock_tick;
#endif
}
static int us3_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
void *data)
{
struct cpufreq_freqs *freq = data;
#ifdef CONFIG_SMP
unsigned int cpu = freq->cpu;
if (!us3_freq_table[cpu].ref_freq) {
us3_freq_table[cpu].ref_freq = freq->old;
us3_freq_table[cpu].udelay_val_ref = cpu_data[cpu].udelay_val;
us3_freq_table[cpu].clock_tick_ref = cpu_data[cpu].clock_tick;
}
if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) ||
(val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) {
cpu_data[cpu].udelay_val =
cpufreq_scale(us3_freq_table[cpu].udelay_val_ref,
us3_freq_table[cpu].ref_freq,
freq->new);
cpu_data[cpu].clock_tick =
cpufreq_scale(us3_freq_table[cpu].clock_tick_ref,
us3_freq_table[cpu].ref_freq,
freq->new);
}
#else
/* In the non-SMP case, kernel/cpufreq.c takes care of adjusting
* loops_per_jiffy.
*/
if (!ref_freq) {
ref_freq = freq->old;
clock_tick_ref = up_clock_tick;
}
if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) ||
(val == CPUFREQ_POSTCHANGE && freq->old > freq->new))
up_clock_tick = cpufreq_scale(clock_tick_ref, ref_freq, freq->new);
#endif
return 0;
}
static struct notifier_block us3_cpufreq_notifier_block = {
.notifier_call = us3_cpufreq_notifier
};
static unsigned long get_current_freq(unsigned int cpu, unsigned long safari_cfg) static unsigned long get_current_freq(unsigned int cpu, unsigned long safari_cfg)
{ {
unsigned long clock_tick = get_clock_tick(cpu); unsigned long clock_tick = sparc64_get_clock_tick(cpu);
unsigned long ret; unsigned long ret;
switch (safari_cfg & SAFARI_CFG_DIV_MASK) { switch (safari_cfg & SAFARI_CFG_DIV_MASK) {
...@@ -151,7 +87,7 @@ static void us3_set_cpu_divider_index(unsigned int cpu, unsigned int index) ...@@ -151,7 +87,7 @@ static void us3_set_cpu_divider_index(unsigned int cpu, unsigned int index)
cpus_allowed = current->cpus_allowed; cpus_allowed = current->cpus_allowed;
set_cpus_allowed(current, (1UL << cpu)); set_cpus_allowed(current, (1UL << cpu));
new_freq = get_clock_tick(cpu); new_freq = sparc64_get_clock_tick(cpu);
switch (index) { switch (index) {
case 0: case 0:
new_bits = SAFARI_CFG_DIV_1; new_bits = SAFARI_CFG_DIV_1;
...@@ -186,17 +122,17 @@ static void us3_set_cpu_divider_index(unsigned int cpu, unsigned int index) ...@@ -186,17 +122,17 @@ static void us3_set_cpu_divider_index(unsigned int cpu, unsigned int index)
set_cpus_allowed(current, cpus_allowed); set_cpus_allowed(current, cpus_allowed);
} }
static int us3freq_target(struct cpufreq_policy *policy, static int us3_freq_target(struct cpufreq_policy *policy,
unsigned int target_freq, unsigned int target_freq,
unsigned int relation) unsigned int relation)
{ {
unsigned int new_index = 0; unsigned int new_index = 0;
if (cpufreq_frequency_table_target(policy, if (cpufreq_frequency_table_target(policy,
&us3_freq_table[policy->cpu].table[0], &us3_freq_table[policy->cpu].table[0],
target_freq, target_freq,
relation, relation,
&new_index)) &new_index))
return -EINVAL; return -EINVAL;
us3_set_cpu_divider_index(policy->cpu, new_index); us3_set_cpu_divider_index(policy->cpu, new_index);
...@@ -204,16 +140,16 @@ static int us3freq_target(struct cpufreq_policy *policy, ...@@ -204,16 +140,16 @@ static int us3freq_target(struct cpufreq_policy *policy,
return 0; return 0;
} }
static int us3freq_verify(struct cpufreq_policy *policy) static int us3_freq_verify(struct cpufreq_policy *policy)
{ {
return cpufreq_frequency_table_verify(policy, return cpufreq_frequency_table_verify(policy,
&us3_freq_table[policy->cpu].table[0]); &us3_freq_table[policy->cpu].table[0]);
} }
static int __init us3freq_cpu_init(struct cpufreq_policy *policy) static int __init us3_freq_cpu_init(struct cpufreq_policy *policy)
{ {
unsigned int cpu = policy->cpu; unsigned int cpu = policy->cpu;
unsigned long clock_tick = get_clock_tick(cpu); unsigned long clock_tick = sparc64_get_clock_tick(cpu);
struct cpufreq_frequency_table *table = struct cpufreq_frequency_table *table =
&us3_freq_table[cpu].table[0]; &us3_freq_table[cpu].table[0];
...@@ -233,7 +169,7 @@ static int __init us3freq_cpu_init(struct cpufreq_policy *policy) ...@@ -233,7 +169,7 @@ static int __init us3freq_cpu_init(struct cpufreq_policy *policy)
return cpufreq_frequency_table_cpuinfo(policy, table); return cpufreq_frequency_table_cpuinfo(policy, table);
} }
static int __exit us3freq_cpu_exit(struct cpufreq_policy *policy) static int __exit us3_freq_cpu_exit(struct cpufreq_policy *policy)
{ {
if (cpufreq_us3_driver) if (cpufreq_us3_driver)
us3_set_cpu_divider_index(policy->cpu, 0); us3_set_cpu_divider_index(policy->cpu, 0);
...@@ -241,7 +177,7 @@ static int __exit us3freq_cpu_exit(struct cpufreq_policy *policy) ...@@ -241,7 +177,7 @@ static int __exit us3freq_cpu_exit(struct cpufreq_policy *policy)
return 0; return 0;
} }
static int __init us3freq_init(void) static int __init us3_freq_init(void)
{ {
unsigned long manuf, impl, ver; unsigned long manuf, impl, ver;
int ret; int ret;
...@@ -254,9 +190,6 @@ static int __init us3freq_init(void) ...@@ -254,9 +190,6 @@ static int __init us3freq_init(void)
(impl == CHEETAH_IMPL || impl == CHEETAH_PLUS_IMPL)) { (impl == CHEETAH_IMPL || impl == CHEETAH_PLUS_IMPL)) {
struct cpufreq_driver *driver; struct cpufreq_driver *driver;
cpufreq_register_notifier(&us3_cpufreq_notifier_block,
CPUFREQ_TRANSITION_NOTIFIER);
ret = -ENOMEM; ret = -ENOMEM;
driver = kmalloc(sizeof(struct cpufreq_driver), GFP_KERNEL); driver = kmalloc(sizeof(struct cpufreq_driver), GFP_KERNEL);
if (!driver) if (!driver)
...@@ -272,10 +205,10 @@ static int __init us3freq_init(void) ...@@ -272,10 +205,10 @@ static int __init us3freq_init(void)
memset(us3_freq_table, 0, memset(us3_freq_table, 0,
(NR_CPUS * sizeof(struct us3_freq_percpu_info))); (NR_CPUS * sizeof(struct us3_freq_percpu_info)));
driver->verify = us3freq_verify; driver->verify = us3_freq_verify;
driver->target = us3freq_target; driver->target = us3_freq_target;
driver->init = us3freq_cpu_init; driver->init = us3_freq_cpu_init;
driver->exit = us3freq_cpu_exit; driver->exit = us3_freq_cpu_exit;
driver->owner = THIS_MODULE, driver->owner = THIS_MODULE,
strcpy(driver->name, "UltraSPARC-III"); strcpy(driver->name, "UltraSPARC-III");
...@@ -295,20 +228,16 @@ static int __init us3freq_init(void) ...@@ -295,20 +228,16 @@ static int __init us3freq_init(void)
kfree(us3_freq_table); kfree(us3_freq_table);
us3_freq_table = NULL; us3_freq_table = NULL;
} }
cpufreq_unregister_notifier(&us3_cpufreq_notifier_block,
CPUFREQ_TRANSITION_NOTIFIER);
return ret; return ret;
} }
return -ENODEV; return -ENODEV;
} }
static void __exit us3freq_exit(void) static void __exit us3_freq_exit(void)
{ {
if (cpufreq_us3_driver) { if (cpufreq_us3_driver) {
cpufreq_unregister_driver(cpufreq_us3_driver); cpufreq_unregister_driver(cpufreq_us3_driver);
cpufreq_unregister_notifier(&us3_cpufreq_notifier_block,
CPUFREQ_TRANSITION_NOTIFIER);
kfree(cpufreq_us3_driver); kfree(cpufreq_us3_driver);
cpufreq_us3_driver = NULL; cpufreq_us3_driver = NULL;
...@@ -321,5 +250,5 @@ MODULE_AUTHOR("David S. Miller <davem@redhat.com>"); ...@@ -321,5 +250,5 @@ MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
MODULE_DESCRIPTION("cpufreq driver for UltraSPARC-III"); MODULE_DESCRIPTION("cpufreq driver for UltraSPARC-III");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
module_init(us3freq_init); module_init(us3_freq_init);
module_exit(us3freq_exit); module_exit(us3_freq_exit);
...@@ -66,4 +66,10 @@ extern unsigned long timer_tick_offset; ...@@ -66,4 +66,10 @@ extern unsigned long timer_tick_offset;
extern void timer_tick_interrupt(struct pt_regs *); extern void timer_tick_interrupt(struct pt_regs *);
#endif #endif
#ifndef CONFIG_SMP
extern unsigned long up_clock_tick;
#endif
extern unsigned long sparc64_get_clock_tick(unsigned int cpu);
#endif /* _SPARC64_TIMER_H */ #endif /* _SPARC64_TIMER_H */
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