aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjohn stultz <johnstul@us.ibm.com>2006-06-26 03:25:12 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-26 12:58:21 -0400
commit5d0cf410e94b1f1ff852c3f210d22cc6c5a27ffa (patch)
treea30cd6d201295945f401fd1f2731493f68db9ee9
parent61743fe445213b87fb55a389c8d073785323ca3e (diff)
[PATCH] Time: i386 Clocksource Drivers
Implement the time sources for i386 (acpi_pm, cyclone, hpet, pit, and tsc). With this patch, the conversion of the i386 arch to the generic timekeeping code should be complete. The patch should be fairly straight forward, only adding the new clocksources. [hirofumi@mail.parknet.co.jp: acpi_pm cleanup] Signed-off-by: John Stultz <johnstul@us.ibm.com> Signed-off-by: Adrian Bunk <bunk@stusta.de> Signed-off-by: Paul Mundt <lethal@linux-sh.org> Signed-off-by: John Stultz <johnstul@us.ibm.com> Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--Documentation/kernel-parameters.txt5
-rw-r--r--arch/i386/kernel/Makefile1
-rw-r--r--arch/i386/kernel/hpet.c67
-rw-r--r--arch/i386/kernel/i8253.c53
-rw-r--r--arch/i386/kernel/time.c3
-rw-r--r--arch/i386/kernel/tsc.c161
-rw-r--r--drivers/Makefile1
-rw-r--r--drivers/clocksource/Makefile2
-rw-r--r--drivers/clocksource/acpi_pm.c177
-rw-r--r--drivers/clocksource/cyclone.c119
-rw-r--r--kernel/time/clocksource.c11
11 files changed, 594 insertions, 6 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 968631678d4a..2e352a605fcf 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -180,6 +180,11 @@ running once the system is up.
180 override platform specific driver. 180 override platform specific driver.
181 See also Documentation/acpi-hotkey.txt. 181 See also Documentation/acpi-hotkey.txt.
182 182
183 acpi_pm_good [IA-32,X86-64]
184 Override the pmtimer bug detection: force the kernel
185 to assume that this machine's pmtimer latches its value
186 and always returns good values.
187
183 enable_timer_pin_1 [i386,x86-64] 188 enable_timer_pin_1 [i386,x86-64]
184 Enable PIN 1 of APIC timer 189 Enable PIN 1 of APIC timer
185 Can be useful to work around chipset bugs 190 Can be useful to work around chipset bugs
diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile
index f238cb6274eb..0fac85df64f1 100644
--- a/arch/i386/kernel/Makefile
+++ b/arch/i386/kernel/Makefile
@@ -36,6 +36,7 @@ obj-$(CONFIG_EFI) += efi.o efi_stub.o
36obj-$(CONFIG_DOUBLEFAULT) += doublefault.o 36obj-$(CONFIG_DOUBLEFAULT) += doublefault.o
37obj-$(CONFIG_VM86) += vm86.o 37obj-$(CONFIG_VM86) += vm86.o
38obj-$(CONFIG_EARLY_PRINTK) += early_printk.o 38obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
39obj-$(CONFIG_HPET_TIMER) += hpet.o
39 40
40EXTRA_AFLAGS := -traditional 41EXTRA_AFLAGS := -traditional
41 42
diff --git a/arch/i386/kernel/hpet.c b/arch/i386/kernel/hpet.c
new file mode 100644
index 000000000000..91a5bdd9f604
--- /dev/null
+++ b/arch/i386/kernel/hpet.c
@@ -0,0 +1,67 @@
1#include <linux/clocksource.h>
2#include <linux/errno.h>
3#include <linux/hpet.h>
4#include <linux/init.h>
5
6#include <asm/hpet.h>
7#include <asm/io.h>
8
9#define HPET_MASK 0xFFFFFFFF
10#define HPET_SHIFT 22
11
12/* FSEC = 10^-15 NSEC = 10^-9 */
13#define FSEC_PER_NSEC 1000000
14
15static void *hpet_ptr;
16
17static cycle_t read_hpet(void)
18{
19 return (cycle_t)readl(hpet_ptr);
20}
21
22static struct clocksource clocksource_hpet = {
23 .name = "hpet",
24 .rating = 250,
25 .read = read_hpet,
26 .mask = (cycle_t)HPET_MASK,
27 .mult = 0, /* set below */
28 .shift = HPET_SHIFT,
29 .is_continuous = 1,
30};
31
32static int __init init_hpet_clocksource(void)
33{
34 unsigned long hpet_period;
35 void __iomem* hpet_base;
36 u64 tmp;
37
38 if (!hpet_address)
39 return -ENODEV;
40
41 /* calculate the hpet address: */
42 hpet_base =
43 (void __iomem*)ioremap_nocache(hpet_address, HPET_MMAP_SIZE);
44 hpet_ptr = hpet_base + HPET_COUNTER;
45
46 /* calculate the frequency: */
47 hpet_period = readl(hpet_base + HPET_PERIOD);
48
49 /*
50 * hpet period is in femto seconds per cycle
51 * so we need to convert this to ns/cyc units
52 * aproximated by mult/2^shift
53 *
54 * fsec/cyc * 1nsec/1000000fsec = nsec/cyc = mult/2^shift
55 * fsec/cyc * 1ns/1000000fsec * 2^shift = mult
56 * fsec/cyc * 2^shift * 1nsec/1000000fsec = mult
57 * (fsec/cyc << shift)/1000000 = mult
58 * (hpet_period << shift)/FSEC_PER_NSEC = mult
59 */
60 tmp = (u64)hpet_period << HPET_SHIFT;
61 do_div(tmp, FSEC_PER_NSEC);
62 clocksource_hpet.mult = (u32)tmp;
63
64 return register_clocksource(&clocksource_hpet);
65}
66
67module_init(init_hpet_clocksource);
diff --git a/arch/i386/kernel/i8253.c b/arch/i386/kernel/i8253.c
index 29cb2eb34363..a276bceade68 100644
--- a/arch/i386/kernel/i8253.c
+++ b/arch/i386/kernel/i8253.c
@@ -2,6 +2,7 @@
2 * i8253.c 8253/PIT functions 2 * i8253.c 8253/PIT functions
3 * 3 *
4 */ 4 */
5#include <linux/clocksource.h>
5#include <linux/spinlock.h> 6#include <linux/spinlock.h>
6#include <linux/jiffies.h> 7#include <linux/jiffies.h>
7#include <linux/sysdev.h> 8#include <linux/sysdev.h>
@@ -30,3 +31,55 @@ void setup_pit_timer(void)
30 outb(LATCH >> 8 , PIT_CH0); /* MSB */ 31 outb(LATCH >> 8 , PIT_CH0); /* MSB */
31 spin_unlock_irqrestore(&i8253_lock, flags); 32 spin_unlock_irqrestore(&i8253_lock, flags);
32} 33}
34
35/*
36 * Since the PIT overflows every tick, its not very useful
37 * to just read by itself. So use jiffies to emulate a free
38 * running counter:
39 */
40static cycle_t pit_read(void)
41{
42 unsigned long flags;
43 int count;
44 u64 jifs;
45
46 spin_lock_irqsave(&i8253_lock, flags);
47 outb_p(0x00, PIT_MODE); /* latch the count ASAP */
48 count = inb_p(PIT_CH0); /* read the latched count */
49 count |= inb_p(PIT_CH0) << 8;
50
51 /* VIA686a test code... reset the latch if count > max + 1 */
52 if (count > LATCH) {
53 outb_p(0x34, PIT_MODE);
54 outb_p(LATCH & 0xff, PIT_CH0);
55 outb(LATCH >> 8, PIT_CH0);
56 count = LATCH - 1;
57 }
58 spin_unlock_irqrestore(&i8253_lock, flags);
59
60 jifs = jiffies_64;
61
62 jifs -= INITIAL_JIFFIES;
63 count = (LATCH-1) - count;
64
65 return (cycle_t)(jifs * LATCH) + count;
66}
67
68static struct clocksource clocksource_pit = {
69 .name = "pit",
70 .rating = 110,
71 .read = pit_read,
72 .mask = (cycle_t)-1,
73 .mult = 0,
74 .shift = 20,
75};
76
77static int __init init_pit_clocksource(void)
78{
79 if (num_possible_cpus() > 4) /* PIT does not scale! */
80 return 0;
81
82 clocksource_pit.mult = clocksource_hz2mult(CLOCK_TICK_RATE, 20);
83 return register_clocksource(&clocksource_pit);
84}
85module_init(init_pit_clocksource);
diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c
index 2a6ab86ffc15..5f43d0410122 100644
--- a/arch/i386/kernel/time.c
+++ b/arch/i386/kernel/time.c
@@ -82,9 +82,6 @@ extern unsigned long wall_jiffies;
82DEFINE_SPINLOCK(rtc_lock); 82DEFINE_SPINLOCK(rtc_lock);
83EXPORT_SYMBOL(rtc_lock); 83EXPORT_SYMBOL(rtc_lock);
84 84
85/* XXX - necessary to keep things compiling. to be removed later */
86u32 pmtmr_ioport;
87
88/* 85/*
89 * This is a special lock that is owned by the CPU and holds the index 86 * This is a special lock that is owned by the CPU and holds the index
90 * register we are working with. It is required for NMI access to the 87 * register we are working with. It is required for NMI access to the
diff --git a/arch/i386/kernel/tsc.c b/arch/i386/kernel/tsc.c
index 96b307495e5f..7713f86389af 100644
--- a/arch/i386/kernel/tsc.c
+++ b/arch/i386/kernel/tsc.c
@@ -4,11 +4,14 @@
4 * See comments there for proper credits. 4 * See comments there for proper credits.
5 */ 5 */
6 6
7#include <linux/clocksource.h>
7#include <linux/workqueue.h> 8#include <linux/workqueue.h>
8#include <linux/cpufreq.h> 9#include <linux/cpufreq.h>
9#include <linux/jiffies.h> 10#include <linux/jiffies.h>
10#include <linux/init.h> 11#include <linux/init.h>
12#include <linux/dmi.h>
11 13
14#include <asm/delay.h>
12#include <asm/tsc.h> 15#include <asm/tsc.h>
13#include <asm/delay.h> 16#include <asm/delay.h>
14#include <asm/io.h> 17#include <asm/io.h>
@@ -315,3 +318,161 @@ static int __init cpufreq_tsc(void)
315core_initcall(cpufreq_tsc); 318core_initcall(cpufreq_tsc);
316 319
317#endif 320#endif
321
322/* clock source code */
323
324static unsigned long current_tsc_khz = 0;
325static int tsc_update_callback(void);
326
327static cycle_t read_tsc(void)
328{
329 cycle_t ret;
330
331 rdtscll(ret);
332
333 return ret;
334}
335
336static struct clocksource clocksource_tsc = {
337 .name = "tsc",
338 .rating = 300,
339 .read = read_tsc,
340 .mask = (cycle_t)-1,
341 .mult = 0, /* to be set */
342 .shift = 22,
343 .update_callback = tsc_update_callback,
344 .is_continuous = 1,
345};
346
347static int tsc_update_callback(void)
348{
349 int change = 0;
350
351 /* check to see if we should switch to the safe clocksource: */
352 if (clocksource_tsc.rating != 50 && check_tsc_unstable()) {
353 clocksource_tsc.rating = 50;
354 reselect_clocksource();
355 change = 1;
356 }
357
358 /* only update if tsc_khz has changed: */
359 if (current_tsc_khz != tsc_khz) {
360 current_tsc_khz = tsc_khz;
361 clocksource_tsc.mult = clocksource_khz2mult(current_tsc_khz,
362 clocksource_tsc.shift);
363 change = 1;
364 }
365
366 return change;
367}
368
369static int __init dmi_mark_tsc_unstable(struct dmi_system_id *d)
370{
371 printk(KERN_NOTICE "%s detected: marking TSC unstable.\n",
372 d->ident);
373 mark_tsc_unstable();
374 return 0;
375}
376
377/* List of systems that have known TSC problems */
378static struct dmi_system_id __initdata bad_tsc_dmi_table[] = {
379 {
380 .callback = dmi_mark_tsc_unstable,
381 .ident = "IBM Thinkpad 380XD",
382 .matches = {
383 DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
384 DMI_MATCH(DMI_BOARD_NAME, "2635FA0"),
385 },
386 },
387 {}
388};
389
390#define TSC_FREQ_CHECK_INTERVAL (10*MSEC_PER_SEC) /* 10sec in MS */
391static struct timer_list verify_tsc_freq_timer;
392
393/* XXX - Probably should add locking */
394static void verify_tsc_freq(unsigned long unused)
395{
396 static u64 last_tsc;
397 static unsigned long last_jiffies;
398
399 u64 now_tsc, interval_tsc;
400 unsigned long now_jiffies, interval_jiffies;
401
402
403 if (check_tsc_unstable())
404 return;
405
406 rdtscll(now_tsc);
407 now_jiffies = jiffies;
408
409 if (!last_jiffies) {
410 goto out;
411 }
412
413 interval_jiffies = now_jiffies - last_jiffies;
414 interval_tsc = now_tsc - last_tsc;
415 interval_tsc *= HZ;
416 do_div(interval_tsc, cpu_khz*1000);
417
418 if (interval_tsc < (interval_jiffies * 3 / 4)) {
419 printk("TSC appears to be running slowly. "
420 "Marking it as unstable\n");
421 mark_tsc_unstable();
422 return;
423 }
424
425out:
426 last_tsc = now_tsc;
427 last_jiffies = now_jiffies;
428 /* set us up to go off on the next interval: */
429 mod_timer(&verify_tsc_freq_timer,
430 jiffies + msecs_to_jiffies(TSC_FREQ_CHECK_INTERVAL));
431}
432
433/*
434 * Make an educated guess if the TSC is trustworthy and synchronized
435 * over all CPUs.
436 */
437static __init int unsynchronized_tsc(void)
438{
439 /*
440 * Intel systems are normally all synchronized.
441 * Exceptions must mark TSC as unstable:
442 */
443 if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)
444 return 0;
445
446 /* assume multi socket systems are not synchronized: */
447 return num_possible_cpus() > 1;
448}
449
450static int __init init_tsc_clocksource(void)
451{
452
453 if (cpu_has_tsc && tsc_khz && !tsc_disable) {
454 /* check blacklist */
455 dmi_check_system(bad_tsc_dmi_table);
456
457 if (unsynchronized_tsc()) /* mark unstable if unsynced */
458 mark_tsc_unstable();
459 current_tsc_khz = tsc_khz;
460 clocksource_tsc.mult = clocksource_khz2mult(current_tsc_khz,
461 clocksource_tsc.shift);
462 /* lower the rating if we already know its unstable: */
463 if (check_tsc_unstable())
464 clocksource_tsc.rating = 50;
465
466 init_timer(&verify_tsc_freq_timer);
467 verify_tsc_freq_timer.function = verify_tsc_freq;
468 verify_tsc_freq_timer.expires =
469 jiffies + msecs_to_jiffies(TSC_FREQ_CHECK_INTERVAL);
470 add_timer(&verify_tsc_freq_timer);
471
472 return register_clocksource(&clocksource_tsc);
473 }
474
475 return 0;
476}
477
478module_init(init_tsc_clocksource);
diff --git a/drivers/Makefile b/drivers/Makefile
index 3c5170310bd0..fc2d744a4e4a 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -74,4 +74,5 @@ obj-$(CONFIG_SGI_SN) += sn/
74obj-y += firmware/ 74obj-y += firmware/
75obj-$(CONFIG_CRYPTO) += crypto/ 75obj-$(CONFIG_CRYPTO) += crypto/
76obj-$(CONFIG_SUPERH) += sh/ 76obj-$(CONFIG_SUPERH) += sh/
77obj-$(CONFIG_GENERIC_TIME) += clocksource/
77obj-$(CONFIG_DMA_ENGINE) += dma/ 78obj-$(CONFIG_DMA_ENGINE) += dma/
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
new file mode 100644
index 000000000000..be3511a308c0
--- /dev/null
+++ b/drivers/clocksource/Makefile
@@ -0,0 +1,2 @@
1obj-$(CONFIG_X86_CYCLONE_TIMER) += cyclone.o
2obj-$(CONFIG_X86_PM_TIMER) += acpi_pm.o
diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c
new file mode 100644
index 000000000000..a0e5cde2fa71
--- /dev/null
+++ b/drivers/clocksource/acpi_pm.c
@@ -0,0 +1,177 @@
1/*
2 * linux/drivers/clocksource/acpi_pm.c
3 *
4 * This file contains the ACPI PM based clocksource.
5 *
6 * This code was largely moved from the i386 timer_pm.c file
7 * which was (C) Dominik Brodowski <linux@brodo.de> 2003
8 * and contained the following comments:
9 *
10 * Driver to use the Power Management Timer (PMTMR) available in some
11 * southbridges as primary timing source for the Linux kernel.
12 *
13 * Based on parts of linux/drivers/acpi/hardware/hwtimer.c, timer_pit.c,
14 * timer_hpet.c, and on Arjan van de Ven's implementation for 2.4.
15 *
16 * This file is licensed under the GPL v2.
17 */
18
19#include <linux/clocksource.h>
20#include <linux/errno.h>
21#include <linux/init.h>
22#include <linux/pci.h>
23#include <asm/io.h>
24
25/* Number of PMTMR ticks expected during calibration run */
26#define PMTMR_TICKS_PER_SEC 3579545
27
28/*
29 * The I/O port the PMTMR resides at.
30 * The location is detected during setup_arch(),
31 * in arch/i386/acpi/boot.c
32 */
33u32 pmtmr_ioport;
34
35#define ACPI_PM_MASK 0xFFFFFF /* limit it to 24 bits */
36
37static inline u32 read_pmtmr(void)
38{
39 /* mask the output to 24 bits */
40 return inl(pmtmr_ioport) & ACPI_PM_MASK;
41}
42
43static cycle_t acpi_pm_read_verified(void)
44{
45 u32 v1 = 0, v2 = 0, v3 = 0;
46
47 /*
48 * It has been reported that because of various broken
49 * chipsets (ICH4, PIIX4 and PIIX4E) where the ACPI PM clock
50 * source is not latched, so you must read it multiple
51 * times to ensure a safe value is read:
52 */
53 do {
54 v1 = read_pmtmr();
55 v2 = read_pmtmr();
56 v3 = read_pmtmr();
57 } while ((v1 > v2 && v1 < v3) || (v2 > v3 && v2 < v1)
58 || (v3 > v1 && v3 < v2));
59
60 return (cycle_t)v2;
61}
62
63static cycle_t acpi_pm_read(void)
64{
65 return (cycle_t)read_pmtmr();
66}
67
68static struct clocksource clocksource_acpi_pm = {
69 .name = "acpi_pm",
70 .rating = 200,
71 .read = acpi_pm_read,
72 .mask = (cycle_t)ACPI_PM_MASK,
73 .mult = 0, /*to be caluclated*/
74 .shift = 22,
75 .is_continuous = 1,
76};
77
78
79#ifdef CONFIG_PCI
80static int acpi_pm_good;
81static int __init acpi_pm_good_setup(char *__str)
82{
83 acpi_pm_good = 1;
84 return 1;
85}
86__setup("acpi_pm_good", acpi_pm_good_setup);
87
88static inline void acpi_pm_need_workaround(void)
89{
90 clocksource_acpi_pm.read = acpi_pm_read_verified;
91 clocksource_acpi_pm.rating = 110;
92}
93
94/*
95 * PIIX4 Errata:
96 *
97 * The power management timer may return improper results when read.
98 * Although the timer value settles properly after incrementing,
99 * while incrementing there is a 3 ns window every 69.8 ns where the
100 * timer value is indeterminate (a 4.2% chance that the data will be
101 * incorrect when read). As a result, the ACPI free running count up
102 * timer specification is violated due to erroneous reads.
103 */
104static void __devinit acpi_pm_check_blacklist(struct pci_dev *dev)
105{
106 u8 rev;
107
108 if (acpi_pm_good)
109 return;
110
111 pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
112 /* the bug has been fixed in PIIX4M */
113 if (rev < 3) {
114 printk(KERN_WARNING "* Found PM-Timer Bug on the chipset."
115 " Due to workarounds for a bug,\n"
116 "* this clock source is slow. Consider trying"
117 " other clock sources\n");
118
119 acpi_pm_need_workaround();
120 }
121}
122DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3,
123 acpi_pm_check_blacklist);
124
125static void __devinit acpi_pm_check_graylist(struct pci_dev *dev)
126{
127 if (acpi_pm_good)
128 return;
129
130 printk(KERN_WARNING "* The chipset may have PM-Timer Bug. Due to"
131 " workarounds for a bug,\n"
132 "* this clock source is slow. If you are sure your timer"
133 " does not have\n"
134 "* this bug, please use \"acpi_pm_good\" to disable the"
135 " workaround\n");
136
137 acpi_pm_need_workaround();
138}
139DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0,
140 acpi_pm_check_graylist);
141#endif
142
143
144static int __init init_acpi_pm_clocksource(void)
145{
146 u32 value1, value2;
147 unsigned int i;
148
149 if (!pmtmr_ioport)
150 return -ENODEV;
151
152 clocksource_acpi_pm.mult = clocksource_hz2mult(PMTMR_TICKS_PER_SEC,
153 clocksource_acpi_pm.shift);
154
155 /* "verify" this timing source: */
156 value1 = read_pmtmr();
157 for (i = 0; i < 10000; i++) {
158 value2 = read_pmtmr();
159 if (value2 == value1)
160 continue;
161 if (value2 > value1)
162 goto pm_good;
163 if ((value2 < value1) && ((value2) < 0xFFF))
164 goto pm_good;
165 printk(KERN_INFO "PM-Timer had inconsistent results:"
166 " 0x%#x, 0x%#x - aborting.\n", value1, value2);
167 return -EINVAL;
168 }
169 printk(KERN_INFO "PM-Timer had no reasonable result:"
170 " 0x%#x - aborting.\n", value1);
171 return -ENODEV;
172
173pm_good:
174 return register_clocksource(&clocksource_acpi_pm);
175}
176
177module_init(init_acpi_pm_clocksource);
diff --git a/drivers/clocksource/cyclone.c b/drivers/clocksource/cyclone.c
new file mode 100644
index 000000000000..444eb11b9b4f
--- /dev/null
+++ b/drivers/clocksource/cyclone.c
@@ -0,0 +1,119 @@
1#include <linux/clocksource.h>
2#include <linux/string.h>
3#include <linux/errno.h>
4#include <linux/timex.h>
5#include <linux/init.h>
6
7#include <asm/pgtable.h>
8#include <asm/io.h>
9
10#include "mach_timer.h"
11
12#define CYCLONE_CBAR_ADDR 0xFEB00CD0 /* base address ptr */
13#define CYCLONE_PMCC_OFFSET 0x51A0 /* offset to control register */
14#define CYCLONE_MPCS_OFFSET 0x51A8 /* offset to select register */
15#define CYCLONE_MPMC_OFFSET 0x51D0 /* offset to count register */
16#define CYCLONE_TIMER_FREQ 99780000 /* 100Mhz, but not really */
17#define CYCLONE_TIMER_MASK 0xFFFFFFFF /* 32 bit mask */
18
19int use_cyclone = 0;
20static void __iomem *cyclone_ptr;
21
22static cycle_t read_cyclone(void)
23{
24 return (cycle_t)readl(cyclone_ptr);
25}
26
27static struct clocksource clocksource_cyclone = {
28 .name = "cyclone",
29 .rating = 250,
30 .read = read_cyclone,
31 .mask = (cycle_t)CYCLONE_TIMER_MASK,
32 .mult = 10,
33 .shift = 0,
34 .is_continuous = 1,
35};
36
37static int __init init_cyclone_clocksource(void)
38{
39 unsigned long base; /* saved value from CBAR */
40 unsigned long offset;
41 u32 __iomem* volatile cyclone_timer; /* Cyclone MPMC0 register */
42 u32 __iomem* reg;
43 int i;
44
45 /* make sure we're on a summit box: */
46 if (!use_cyclone)
47 return -ENODEV;
48
49 printk(KERN_INFO "Summit chipset: Starting Cyclone Counter.\n");
50
51 /* find base address: */
52 offset = CYCLONE_CBAR_ADDR;
53 reg = ioremap_nocache(offset, sizeof(reg));
54 if (!reg) {
55 printk(KERN_ERR "Summit chipset: Could not find valid CBAR register.\n");
56 return -ENODEV;
57 }
58 /* even on 64bit systems, this is only 32bits: */
59 base = readl(reg);
60 if (!base) {
61 printk(KERN_ERR "Summit chipset: Could not find valid CBAR value.\n");
62 return -ENODEV;
63 }
64 iounmap(reg);
65
66 /* setup PMCC: */
67 offset = base + CYCLONE_PMCC_OFFSET;
68 reg = ioremap_nocache(offset, sizeof(reg));
69 if (!reg) {
70 printk(KERN_ERR "Summit chipset: Could not find valid PMCC register.\n");
71 return -ENODEV;
72 }
73 writel(0x00000001,reg);
74 iounmap(reg);
75
76 /* setup MPCS: */
77 offset = base + CYCLONE_MPCS_OFFSET;
78 reg = ioremap_nocache(offset, sizeof(reg));
79 if (!reg) {
80 printk(KERN_ERR "Summit chipset: Could not find valid MPCS register.\n");
81 return -ENODEV;
82 }
83 writel(0x00000001,reg);
84 iounmap(reg);
85
86 /* map in cyclone_timer: */
87 offset = base + CYCLONE_MPMC_OFFSET;
88 cyclone_timer = ioremap_nocache(offset, sizeof(u64));
89 if (!cyclone_timer) {
90 printk(KERN_ERR "Summit chipset: Could not find valid MPMC register.\n");
91 return -ENODEV;
92 }
93
94 /* quick test to make sure its ticking: */
95 for (i = 0; i < 3; i++){
96 u32 old = readl(cyclone_timer);
97 int stall = 100;
98
99 while (stall--)
100 barrier();
101
102 if (readl(cyclone_timer) == old) {
103 printk(KERN_ERR "Summit chipset: Counter not counting! DISABLED\n");
104 iounmap(cyclone_timer);
105 cyclone_timer = NULL;
106 return -ENODEV;
107 }
108 }
109 cyclone_ptr = cyclone_timer;
110
111 /* sort out mult/shift values: */
112 clocksource_cyclone.shift = 22;
113 clocksource_cyclone.mult = clocksource_hz2mult(CYCLONE_TIMER_FREQ,
114 clocksource_cyclone.shift);
115
116 return register_clocksource(&clocksource_cyclone);
117}
118
119module_init(init_cyclone_clocksource);
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c
index 4288bfa12c3f..a9f387ea83b0 100644
--- a/kernel/time/clocksource.c
+++ b/kernel/time/clocksource.c
@@ -174,7 +174,7 @@ EXPORT_SYMBOL(register_clocksource);
174 * reselect_clocksource - Rescan list for next clocksource 174 * reselect_clocksource - Rescan list for next clocksource
175 * 175 *
176 * A quick helper function to be used if a clocksource changes its 176 * A quick helper function to be used if a clocksource changes its
177 * rating. Forces the clocksource list to be re-scaned for the best 177 * rating. Forces the clocksource list to be re-scanned for the best
178 * clocksource. 178 * clocksource.
179 */ 179 */
180void reselect_clocksource(void) 180void reselect_clocksource(void)
@@ -336,8 +336,13 @@ __setup("clocksource=", boot_override_clocksource);
336 */ 336 */
337static int __init boot_override_clock(char* str) 337static int __init boot_override_clock(char* str)
338{ 338{
339 printk("Warning! clock= boot option is deprecated.\n"); 339 if (!strcmp(str, "pmtmr")) {
340 340 printk("Warning: clock=pmtmr is deprecated. "
341 "Use clocksource=acpi_pm.\n");
342 return boot_override_clocksource("acpi_pm");
343 }
344 printk("Warning! clock= boot option is deprecated. "
345 "Use clocksource=xyz\n");
341 return boot_override_clocksource(str); 346 return boot_override_clocksource(str);
342} 347}
343 348