diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2008-01-30 07:30:26 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-01-30 07:30:26 -0500 |
commit | fe599f9fbc5d470ec5b55d08f2bbb991ddecbbc8 (patch) | |
tree | be07dcd4062fbcb801ae833678b3818d2fd47ceb /arch | |
parent | 6ce60b07e670e800c4c5cfe984ed5188e7a64135 (diff) |
x86: isolate the rtc code for sharing
The mach-default/mach_time.h code inline is moved to arch/x86/kernel/rtc.c
and the header files are adjusted.
Shrink the 3 dozen includes to the ones we really need.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/kernel/Makefile_32 | 2 | ||||
-rw-r--r-- | arch/x86/kernel/rtc.c | 166 | ||||
-rw-r--r-- | arch/x86/kernel/time_32.c | 105 |
3 files changed, 171 insertions, 102 deletions
diff --git a/arch/x86/kernel/Makefile_32 b/arch/x86/kernel/Makefile_32 index 31ff982bc26b..eb2da53578d7 100644 --- a/arch/x86/kernel/Makefile_32 +++ b/arch/x86/kernel/Makefile_32 | |||
@@ -8,7 +8,7 @@ CPPFLAGS_vmlinux.lds += -Ui386 | |||
8 | obj-y := process_32.o signal_32.o entry_32.o traps_32.o irq_32.o \ | 8 | obj-y := process_32.o signal_32.o entry_32.o traps_32.o irq_32.o \ |
9 | ptrace_32.o time_32.o ioport_32.o ldt.o setup_32.o i8259_32.o sys_i386_32.o \ | 9 | ptrace_32.o time_32.o ioport_32.o ldt.o setup_32.o i8259_32.o sys_i386_32.o \ |
10 | pci-dma_32.o i386_ksyms_32.o i387_32.o bootflag.o e820_32.o\ | 10 | pci-dma_32.o i386_ksyms_32.o i387_32.o bootflag.o e820_32.o\ |
11 | quirks.o i8237.o topology.o alternative.o i8253.o tsc_32.o io_delay.o | 11 | quirks.o i8237.o topology.o alternative.o i8253.o tsc_32.o io_delay.o rtc.o |
12 | 12 | ||
13 | obj-$(CONFIG_STACKTRACE) += stacktrace.o | 13 | obj-$(CONFIG_STACKTRACE) += stacktrace.o |
14 | obj-y += cpu/ | 14 | obj-y += cpu/ |
diff --git a/arch/x86/kernel/rtc.c b/arch/x86/kernel/rtc.c new file mode 100644 index 000000000000..45bf54d9f4c5 --- /dev/null +++ b/arch/x86/kernel/rtc.c | |||
@@ -0,0 +1,166 @@ | |||
1 | /* | ||
2 | * RTC related functions | ||
3 | */ | ||
4 | #include <linux/bcd.h> | ||
5 | #include <linux/mc146818rtc.h> | ||
6 | |||
7 | #include <asm/time.h> | ||
8 | |||
9 | /* | ||
10 | * In order to set the CMOS clock precisely, set_rtc_mmss has to be | ||
11 | * called 500 ms after the second nowtime has started, because when | ||
12 | * nowtime is written into the registers of the CMOS clock, it will | ||
13 | * jump to the next second precisely 500 ms later. Check the Motorola | ||
14 | * MC146818A or Dallas DS12887 data sheet for details. | ||
15 | * | ||
16 | * BUG: This routine does not handle hour overflow properly; it just | ||
17 | * sets the minutes. Usually you'll only notice that after reboot! | ||
18 | */ | ||
19 | int mach_set_rtc_mmss(unsigned long nowtime) | ||
20 | { | ||
21 | int retval = 0; | ||
22 | int real_seconds, real_minutes, cmos_minutes; | ||
23 | unsigned char save_control, save_freq_select; | ||
24 | |||
25 | save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */ | ||
26 | CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); | ||
27 | |||
28 | save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */ | ||
29 | CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); | ||
30 | |||
31 | cmos_minutes = CMOS_READ(RTC_MINUTES); | ||
32 | if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) | ||
33 | BCD_TO_BIN(cmos_minutes); | ||
34 | |||
35 | /* | ||
36 | * since we're only adjusting minutes and seconds, | ||
37 | * don't interfere with hour overflow. This avoids | ||
38 | * messing with unknown time zones but requires your | ||
39 | * RTC not to be off by more than 15 minutes | ||
40 | */ | ||
41 | real_seconds = nowtime % 60; | ||
42 | real_minutes = nowtime / 60; | ||
43 | if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) | ||
44 | real_minutes += 30; /* correct for half hour time zone */ | ||
45 | real_minutes %= 60; | ||
46 | |||
47 | if (abs(real_minutes - cmos_minutes) < 30) { | ||
48 | if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { | ||
49 | BIN_TO_BCD(real_seconds); | ||
50 | BIN_TO_BCD(real_minutes); | ||
51 | } | ||
52 | CMOS_WRITE(real_seconds,RTC_SECONDS); | ||
53 | CMOS_WRITE(real_minutes,RTC_MINUTES); | ||
54 | } else { | ||
55 | printk(KERN_WARNING | ||
56 | "set_rtc_mmss: can't update from %d to %d\n", | ||
57 | cmos_minutes, real_minutes); | ||
58 | retval = -1; | ||
59 | } | ||
60 | |||
61 | /* The following flags have to be released exactly in this order, | ||
62 | * otherwise the DS12887 (popular MC146818A clone with integrated | ||
63 | * battery and quartz) will not reset the oscillator and will not | ||
64 | * update precisely 500 ms later. You won't find this mentioned in | ||
65 | * the Dallas Semiconductor data sheets, but who believes data | ||
66 | * sheets anyway ... -- Markus Kuhn | ||
67 | */ | ||
68 | CMOS_WRITE(save_control, RTC_CONTROL); | ||
69 | CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); | ||
70 | |||
71 | return retval; | ||
72 | } | ||
73 | |||
74 | unsigned long mach_get_cmos_time(void) | ||
75 | { | ||
76 | unsigned int year, mon, day, hour, min, sec; | ||
77 | |||
78 | do { | ||
79 | sec = CMOS_READ(RTC_SECONDS); | ||
80 | min = CMOS_READ(RTC_MINUTES); | ||
81 | hour = CMOS_READ(RTC_HOURS); | ||
82 | day = CMOS_READ(RTC_DAY_OF_MONTH); | ||
83 | mon = CMOS_READ(RTC_MONTH); | ||
84 | year = CMOS_READ(RTC_YEAR); | ||
85 | } while (sec != CMOS_READ(RTC_SECONDS)); | ||
86 | |||
87 | if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { | ||
88 | BCD_TO_BIN(sec); | ||
89 | BCD_TO_BIN(min); | ||
90 | BCD_TO_BIN(hour); | ||
91 | BCD_TO_BIN(day); | ||
92 | BCD_TO_BIN(mon); | ||
93 | BCD_TO_BIN(year); | ||
94 | } | ||
95 | |||
96 | year += 1900; | ||
97 | if (year < 1970) | ||
98 | year += 100; | ||
99 | |||
100 | return mktime(year, mon, day, hour, min, sec); | ||
101 | } | ||
102 | |||
103 | DEFINE_SPINLOCK(rtc_lock); | ||
104 | EXPORT_SYMBOL(rtc_lock); | ||
105 | |||
106 | /* | ||
107 | * This is a special lock that is owned by the CPU and holds the index | ||
108 | * register we are working with. It is required for NMI access to the | ||
109 | * CMOS/RTC registers. See include/asm-i386/mc146818rtc.h for details. | ||
110 | */ | ||
111 | volatile unsigned long cmos_lock = 0; | ||
112 | EXPORT_SYMBOL(cmos_lock); | ||
113 | |||
114 | /* Routines for accessing the CMOS RAM/RTC. */ | ||
115 | unsigned char rtc_cmos_read(unsigned char addr) | ||
116 | { | ||
117 | unsigned char val; | ||
118 | |||
119 | lock_cmos_prefix(addr); | ||
120 | outb_p(addr, RTC_PORT(0)); | ||
121 | val = inb_p(RTC_PORT(1)); | ||
122 | lock_cmos_suffix(addr); | ||
123 | return val; | ||
124 | } | ||
125 | EXPORT_SYMBOL(rtc_cmos_read); | ||
126 | |||
127 | void rtc_cmos_write(unsigned char val, unsigned char addr) | ||
128 | { | ||
129 | lock_cmos_prefix(addr); | ||
130 | outb_p(addr, RTC_PORT(0)); | ||
131 | outb_p(val, RTC_PORT(1)); | ||
132 | lock_cmos_suffix(addr); | ||
133 | } | ||
134 | EXPORT_SYMBOL(rtc_cmos_write); | ||
135 | |||
136 | static int set_rtc_mmss(unsigned long nowtime) | ||
137 | { | ||
138 | int retval; | ||
139 | unsigned long flags; | ||
140 | |||
141 | /* gets recalled with irq locally disabled */ | ||
142 | /* XXX - does irqsave resolve this? -johnstul */ | ||
143 | spin_lock_irqsave(&rtc_lock, flags); | ||
144 | retval = set_wallclock(nowtime); | ||
145 | spin_unlock_irqrestore(&rtc_lock, flags); | ||
146 | |||
147 | return retval; | ||
148 | } | ||
149 | |||
150 | /* not static: needed by APM */ | ||
151 | unsigned long read_persistent_clock(void) | ||
152 | { | ||
153 | unsigned long retval; | ||
154 | unsigned long flags; | ||
155 | |||
156 | spin_lock_irqsave(&rtc_lock, flags); | ||
157 | retval = get_wallclock(); | ||
158 | spin_unlock_irqrestore(&rtc_lock, flags); | ||
159 | |||
160 | return retval; | ||
161 | } | ||
162 | |||
163 | int update_persistent_clock(struct timespec now) | ||
164 | { | ||
165 | return set_rtc_mmss(now.tv_sec); | ||
166 | } | ||
diff --git a/arch/x86/kernel/time_32.c b/arch/x86/kernel/time_32.c index 8a322c96bc23..e9ead762abe8 100644 --- a/arch/x86/kernel/time_32.c +++ b/arch/x86/kernel/time_32.c | |||
@@ -28,98 +28,21 @@ | |||
28 | * serialize accesses to xtime/lost_ticks). | 28 | * serialize accesses to xtime/lost_ticks). |
29 | */ | 29 | */ |
30 | 30 | ||
31 | #include <linux/errno.h> | 31 | #include <linux/init.h> |
32 | #include <linux/sched.h> | ||
33 | #include <linux/kernel.h> | ||
34 | #include <linux/param.h> | ||
35 | #include <linux/string.h> | ||
36 | #include <linux/mm.h> | ||
37 | #include <linux/interrupt.h> | 32 | #include <linux/interrupt.h> |
38 | #include <linux/time.h> | 33 | #include <linux/time.h> |
39 | #include <linux/delay.h> | ||
40 | #include <linux/init.h> | ||
41 | #include <linux/smp.h> | ||
42 | #include <linux/module.h> | ||
43 | #include <linux/sysdev.h> | ||
44 | #include <linux/bcd.h> | ||
45 | #include <linux/efi.h> | ||
46 | #include <linux/mca.h> | 34 | #include <linux/mca.h> |
47 | 35 | ||
48 | #include <asm/io.h> | ||
49 | #include <asm/smp.h> | ||
50 | #include <asm/irq.h> | ||
51 | #include <asm/msr.h> | ||
52 | #include <asm/delay.h> | ||
53 | #include <asm/mpspec.h> | ||
54 | #include <asm/uaccess.h> | ||
55 | #include <asm/processor.h> | ||
56 | #include <asm/timer.h> | ||
57 | #include <asm/time.h> | ||
58 | |||
59 | #include "mach_time.h" | ||
60 | |||
61 | #include <linux/timex.h> | ||
62 | |||
63 | #include <asm/hpet.h> | ||
64 | |||
65 | #include <asm/arch_hooks.h> | 36 | #include <asm/arch_hooks.h> |
37 | #include <asm/hpet.h> | ||
38 | #include <asm/time.h> | ||
66 | 39 | ||
67 | #include "io_ports.h" | 40 | #include "io_ports.h" |
68 | |||
69 | #include <asm/i8259.h> | ||
70 | |||
71 | #include "do_timer.h" | 41 | #include "do_timer.h" |
72 | 42 | ||
73 | unsigned int cpu_khz; /* Detected as we calibrate the TSC */ | 43 | unsigned int cpu_khz; /* Detected as we calibrate the TSC */ |
74 | EXPORT_SYMBOL(cpu_khz); | 44 | EXPORT_SYMBOL(cpu_khz); |
75 | 45 | ||
76 | DEFINE_SPINLOCK(rtc_lock); | ||
77 | EXPORT_SYMBOL(rtc_lock); | ||
78 | |||
79 | /* | ||
80 | * This is a special lock that is owned by the CPU and holds the index | ||
81 | * register we are working with. It is required for NMI access to the | ||
82 | * CMOS/RTC registers. See include/asm-i386/mc146818rtc.h for details. | ||
83 | */ | ||
84 | volatile unsigned long cmos_lock = 0; | ||
85 | EXPORT_SYMBOL(cmos_lock); | ||
86 | |||
87 | /* Routines for accessing the CMOS RAM/RTC. */ | ||
88 | unsigned char rtc_cmos_read(unsigned char addr) | ||
89 | { | ||
90 | unsigned char val; | ||
91 | lock_cmos_prefix(addr); | ||
92 | outb_p(addr, RTC_PORT(0)); | ||
93 | val = inb_p(RTC_PORT(1)); | ||
94 | lock_cmos_suffix(addr); | ||
95 | return val; | ||
96 | } | ||
97 | EXPORT_SYMBOL(rtc_cmos_read); | ||
98 | |||
99 | void rtc_cmos_write(unsigned char val, unsigned char addr) | ||
100 | { | ||
101 | lock_cmos_prefix(addr); | ||
102 | outb_p(addr, RTC_PORT(0)); | ||
103 | outb_p(val, RTC_PORT(1)); | ||
104 | lock_cmos_suffix(addr); | ||
105 | } | ||
106 | EXPORT_SYMBOL(rtc_cmos_write); | ||
107 | |||
108 | static int set_rtc_mmss(unsigned long nowtime) | ||
109 | { | ||
110 | int retval; | ||
111 | unsigned long flags; | ||
112 | |||
113 | /* gets recalled with irq locally disabled */ | ||
114 | /* XXX - does irqsave resolve this? -johnstul */ | ||
115 | spin_lock_irqsave(&rtc_lock, flags); | ||
116 | retval = set_wallclock(nowtime); | ||
117 | spin_unlock_irqrestore(&rtc_lock, flags); | ||
118 | |||
119 | return retval; | ||
120 | } | ||
121 | |||
122 | |||
123 | int timer_ack; | 46 | int timer_ack; |
124 | 47 | ||
125 | unsigned long profile_pc(struct pt_regs *regs) | 48 | unsigned long profile_pc(struct pt_regs *regs) |
@@ -137,7 +60,7 @@ unsigned long profile_pc(struct pt_regs *regs) | |||
137 | /* Return address is either directly at stack pointer | 60 | /* Return address is either directly at stack pointer |
138 | or above a saved eflags. Eflags has bits 22-31 zero, | 61 | or above a saved eflags. Eflags has bits 22-31 zero, |
139 | kernel addresses don't. */ | 62 | kernel addresses don't. */ |
140 | if (sp[0] >> 22) | 63 | if (sp[0] >> 22) |
141 | return sp[0]; | 64 | return sp[0]; |
142 | if (sp[1] >> 22) | 65 | if (sp[1] >> 22) |
143 | return sp[1]; | 66 | return sp[1]; |
@@ -193,26 +116,6 @@ irqreturn_t timer_interrupt(int irq, void *dev_id) | |||
193 | return IRQ_HANDLED; | 116 | return IRQ_HANDLED; |
194 | } | 117 | } |
195 | 118 | ||
196 | /* not static: needed by APM */ | ||
197 | unsigned long read_persistent_clock(void) | ||
198 | { | ||
199 | unsigned long retval; | ||
200 | unsigned long flags; | ||
201 | |||
202 | spin_lock_irqsave(&rtc_lock, flags); | ||
203 | |||
204 | retval = get_wallclock(); | ||
205 | |||
206 | spin_unlock_irqrestore(&rtc_lock, flags); | ||
207 | |||
208 | return retval; | ||
209 | } | ||
210 | |||
211 | int update_persistent_clock(struct timespec now) | ||
212 | { | ||
213 | return set_rtc_mmss(now.tv_sec); | ||
214 | } | ||
215 | |||
216 | extern void (*late_time_init)(void); | 119 | extern void (*late_time_init)(void); |
217 | /* Duplicate of time_init() below, with hpet_enable part added */ | 120 | /* Duplicate of time_init() below, with hpet_enable part added */ |
218 | void __init hpet_time_init(void) | 121 | void __init hpet_time_init(void) |