Commit 5958cbab authored by Andrew Morton's avatar Andrew Morton Committed by Dave Jones

[PATCH] x86 clock override boot option

From: john stultz <johnstul@us.ibm.com>

This patch allows one to manually specify the i386 gettimeofday time-source
by passing clock=[pit|tsc|cyclone|...] as a boot argument.  The argument will
override the default probled selection, and in case the selected time-source
not be avalible the code defaults to using the PIT (printing a warning saying
so).
parent 3a2631da
...@@ -207,6 +207,12 @@ running once the system is up. ...@@ -207,6 +207,12 @@ running once the system is up.
chandev= [HW,NET] Generic channel device initialisation chandev= [HW,NET] Generic channel device initialisation
clock= [BUGS=IA-32, HW] gettimeofday timesource override.
Forces specified timesource (if avaliable) to be used
when calculating gettimeofday(). If specicified timesource
is not avalible, it defaults to PIT.
Format: { pit | tsc | cyclone | ... }
cm206= [HW,CD] cm206= [HW,CD]
Format: { auto | [<io>,][<irq>] } Format: { auto | [<io>,][<irq>] }
......
...@@ -422,7 +422,7 @@ void __init smp_callin(void) ...@@ -422,7 +422,7 @@ void __init smp_callin(void)
/* /*
* Synchronize the TSC with the BP * Synchronize the TSC with the BP
*/ */
if (cpu_has_tsc) if (cpu_has_tsc && cpu_khz)
synchronize_tsc_ap(); synchronize_tsc_ap();
} }
...@@ -1114,7 +1114,7 @@ static void __init smp_boot_cpus(unsigned int max_cpus) ...@@ -1114,7 +1114,7 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
/* /*
* Synchronize the TSC with the AP * Synchronize the TSC with the AP
*/ */
if (cpu_has_tsc && cpucount) if (cpu_has_tsc && cpucount && cpu_khz)
synchronize_tsc_bp(); synchronize_tsc_bp();
} }
......
#include <linux/init.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/string.h>
#include <asm/timer.h> #include <asm/timer.h>
/* list of externed timers */ /* list of externed timers */
...@@ -17,6 +19,17 @@ static struct timer_opts* timers[] = { ...@@ -17,6 +19,17 @@ static struct timer_opts* timers[] = {
NULL, NULL,
}; };
static char clock_override[10] __initdata;
static int __init clock_setup(char* str)
{
if (str) {
strncpy(clock_override, str,10);
clock_override[9] = '\0';
}
return 1;
}
__setup("clock=", clock_setup);
/* iterates through the list of timers, returning the first /* iterates through the list of timers, returning the first
* one that initializes successfully. * one that initializes successfully.
...@@ -28,7 +41,7 @@ struct timer_opts* select_timer(void) ...@@ -28,7 +41,7 @@ struct timer_opts* select_timer(void)
/* find most preferred working timer */ /* find most preferred working timer */
while (timers[i]) { while (timers[i]) {
if (timers[i]->init) if (timers[i]->init)
if (timers[i]->init() == 0) if (timers[i]->init(clock_override) == 0)
return timers[i]; return timers[i];
++i; ++i;
} }
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/timex.h> #include <linux/timex.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/string.h>
#include <asm/timer.h> #include <asm/timer.h>
#include <asm/io.h> #include <asm/io.h>
...@@ -73,7 +74,7 @@ static unsigned long get_offset_cyclone(void) ...@@ -73,7 +74,7 @@ static unsigned long get_offset_cyclone(void)
return delay_at_last_interrupt + offset; return delay_at_last_interrupt + offset;
} }
static int init_cyclone(void) static int __init init_cyclone(char* override)
{ {
u32* reg; u32* reg;
u32 base; /* saved cyclone base address */ u32 base; /* saved cyclone base address */
...@@ -81,8 +82,11 @@ static int init_cyclone(void) ...@@ -81,8 +82,11 @@ static int init_cyclone(void)
u32 offset; /* offset from pageaddr to cyclone_timer register */ u32 offset; /* offset from pageaddr to cyclone_timer register */
int i; int i;
/* check clock override */
if (override[0] && strncmp(override,"cyclone",7))
return -ENODEV;
/*make sure we're on a summit box*/ /*make sure we're on a summit box*/
/*XXX need to use proper summit hooks! such as xapic -john*/
if(!use_cyclone) return -ENODEV; if(!use_cyclone) return -ENODEV;
printk(KERN_INFO "Summit chipset: Starting Cyclone Counter.\n"); printk(KERN_INFO "Summit chipset: Starting Cyclone Counter.\n");
......
#include <linux/init.h>
#include <asm/timer.h> #include <asm/timer.h>
static int init_none(void) static int __init init_none(char* override)
{ {
return 0; return 0;
} }
......
...@@ -17,8 +17,12 @@ extern spinlock_t i8259A_lock; ...@@ -17,8 +17,12 @@ extern spinlock_t i8259A_lock;
extern spinlock_t i8253_lock; extern spinlock_t i8253_lock;
#include "do_timer.h" #include "do_timer.h"
static int init_pit(void) static int __init init_pit(char* override)
{ {
/* check clock override */
if (override[0] && strncmp(override,"pit",3))
printk(KERN_ERR "Warning: clock= override failed. Defaulting to PIT\n");
return 0; return 0;
} }
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <linux/timex.h> #include <linux/timex.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/cpufreq.h> #include <linux/cpufreq.h>
#include <linux/string.h>
#include <asm/timer.h> #include <asm/timer.h>
#include <asm/io.h> #include <asm/io.h>
...@@ -244,8 +245,13 @@ static struct notifier_block time_cpufreq_notifier_block = { ...@@ -244,8 +245,13 @@ static struct notifier_block time_cpufreq_notifier_block = {
#endif #endif
static int init_tsc(void) static int __init init_tsc(char* override)
{ {
/* check clock override */
if (override[0] && strncmp(override,"tsc",3))
return -ENODEV;
/* /*
* If we have APM enabled or the CPU clock speed is variable * If we have APM enabled or the CPU clock speed is variable
* (CPU stops clock on HLT or slows clock to save power) * (CPU stops clock on HLT or slows clock to save power)
......
...@@ -4,14 +4,14 @@ ...@@ -4,14 +4,14 @@
/** /**
* struct timer_ops - used to define a timer source * struct timer_ops - used to define a timer source
* *
* @init: Probes and initializes the timer. Returns 0 on success, anything * @init: Probes and initializes the timer. Takes clock= override
* else on failure. * string as an argument. Returns 0 on success, anything else on failure.
* @mark_offset: called by the timer interrupt * @mark_offset: called by the timer interrupt
* @get_offset: called by gettimeofday(). Returns the number of ms since the * @get_offset: called by gettimeofday(). Returns the number of ms since the
* last timer intruupt. * last timer intruupt.
*/ */
struct timer_opts{ struct timer_opts{
int (*init)(void); int (*init)(char *override);
void (*mark_offset)(void); void (*mark_offset)(void);
unsigned long (*get_offset)(void); unsigned long (*get_offset)(void);
void (*delay)(unsigned long); void (*delay)(unsigned long);
......
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