diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2008-01-30 07:30:27 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-01-30 07:30:27 -0500 |
commit | 1122b134bcd6e77c5a4117952b8cbc55c8d018bc (patch) | |
tree | e4b0df9c7fb4686357a33c00d037898725ab5b82 /arch | |
parent | fe599f9fbc5d470ec5b55d08f2bbb991ddecbbc8 (diff) |
x86: share rtc code
Remove the rtc code from time_64.c and add the extra bits to the
i386 path. The ACPI century check is probably valid for i386 as
well, but this is material for a separate patch.
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_64 | 2 | ||||
-rw-r--r-- | arch/x86/kernel/rtc.c | 96 | ||||
-rw-r--r-- | arch/x86/kernel/time_64.c | 157 |
3 files changed, 64 insertions, 191 deletions
diff --git a/arch/x86/kernel/Makefile_64 b/arch/x86/kernel/Makefile_64 index 9cb3df27c413..ae95d21ea885 100644 --- a/arch/x86/kernel/Makefile_64 +++ b/arch/x86/kernel/Makefile_64 | |||
@@ -11,7 +11,7 @@ obj-y := process_64.o signal_64.o entry_64.o traps_64.o irq_64.o \ | |||
11 | x8664_ksyms_64.o i387_64.o syscall_64.o vsyscall_64.o \ | 11 | x8664_ksyms_64.o i387_64.o syscall_64.o vsyscall_64.o \ |
12 | setup64.o bootflag.o e820_64.o reboot_64.o quirks.o i8237.o \ | 12 | setup64.o bootflag.o e820_64.o reboot_64.o quirks.o i8237.o \ |
13 | pci-dma_64.o pci-nommu_64.o alternative.o hpet.o tsc_64.o bugs_64.o \ | 13 | pci-dma_64.o pci-nommu_64.o alternative.o hpet.o tsc_64.o bugs_64.o \ |
14 | i8253.o io_delay.o | 14 | i8253.o io_delay.o rtc.o |
15 | 15 | ||
16 | obj-$(CONFIG_STACKTRACE) += stacktrace.o | 16 | obj-$(CONFIG_STACKTRACE) += stacktrace.o |
17 | obj-y += cpu/ | 17 | obj-y += cpu/ |
diff --git a/arch/x86/kernel/rtc.c b/arch/x86/kernel/rtc.c index 45bf54d9f4c5..d040840ff1b6 100644 --- a/arch/x86/kernel/rtc.c +++ b/arch/x86/kernel/rtc.c | |||
@@ -1,11 +1,32 @@ | |||
1 | /* | 1 | /* |
2 | * RTC related functions | 2 | * RTC related functions |
3 | */ | 3 | */ |
4 | #include <linux/acpi.h> | ||
4 | #include <linux/bcd.h> | 5 | #include <linux/bcd.h> |
5 | #include <linux/mc146818rtc.h> | 6 | #include <linux/mc146818rtc.h> |
6 | 7 | ||
7 | #include <asm/time.h> | 8 | #include <asm/time.h> |
8 | 9 | ||
10 | #ifdef CONFIG_X86_32 | ||
11 | # define CMOS_YEARS_OFFS 1900 | ||
12 | /* | ||
13 | * This is a special lock that is owned by the CPU and holds the index | ||
14 | * register we are working with. It is required for NMI access to the | ||
15 | * CMOS/RTC registers. See include/asm-i386/mc146818rtc.h for details. | ||
16 | */ | ||
17 | volatile unsigned long cmos_lock = 0; | ||
18 | EXPORT_SYMBOL(cmos_lock); | ||
19 | #else | ||
20 | /* | ||
21 | * x86-64 systems only exists since 2002. | ||
22 | * This will work up to Dec 31, 2100 | ||
23 | */ | ||
24 | # define CMOS_YEARS_OFFS 2000 | ||
25 | #endif | ||
26 | |||
27 | DEFINE_SPINLOCK(rtc_lock); | ||
28 | EXPORT_SYMBOL(rtc_lock); | ||
29 | |||
9 | /* | 30 | /* |
10 | * In order to set the CMOS clock precisely, set_rtc_mmss has to be | 31 | * 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 | 32 | * called 500 ms after the second nowtime has started, because when |
@@ -22,10 +43,12 @@ int mach_set_rtc_mmss(unsigned long nowtime) | |||
22 | int real_seconds, real_minutes, cmos_minutes; | 43 | int real_seconds, real_minutes, cmos_minutes; |
23 | unsigned char save_control, save_freq_select; | 44 | unsigned char save_control, save_freq_select; |
24 | 45 | ||
25 | save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */ | 46 | /* tell the clock it's being set */ |
47 | save_control = CMOS_READ(RTC_CONTROL); | ||
26 | CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); | 48 | CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); |
27 | 49 | ||
28 | save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */ | 50 | /* stop and reset prescaler */ |
51 | save_freq_select = CMOS_READ(RTC_FREQ_SELECT); | ||
29 | CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); | 52 | CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); |
30 | 53 | ||
31 | cmos_minutes = CMOS_READ(RTC_MINUTES); | 54 | cmos_minutes = CMOS_READ(RTC_MINUTES); |
@@ -40,8 +63,9 @@ int mach_set_rtc_mmss(unsigned long nowtime) | |||
40 | */ | 63 | */ |
41 | real_seconds = nowtime % 60; | 64 | real_seconds = nowtime % 60; |
42 | real_minutes = nowtime / 60; | 65 | real_minutes = nowtime / 60; |
66 | /* correct for half hour time zone */ | ||
43 | if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) | 67 | if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) |
44 | real_minutes += 30; /* correct for half hour time zone */ | 68 | real_minutes += 30; |
45 | real_minutes %= 60; | 69 | real_minutes %= 60; |
46 | 70 | ||
47 | if (abs(real_minutes - cmos_minutes) < 30) { | 71 | if (abs(real_minutes - cmos_minutes) < 30) { |
@@ -73,18 +97,32 @@ int mach_set_rtc_mmss(unsigned long nowtime) | |||
73 | 97 | ||
74 | unsigned long mach_get_cmos_time(void) | 98 | unsigned long mach_get_cmos_time(void) |
75 | { | 99 | { |
76 | unsigned int year, mon, day, hour, min, sec; | 100 | unsigned int year, mon, day, hour, min, sec, century = 0; |
77 | 101 | ||
78 | do { | 102 | /* |
79 | sec = CMOS_READ(RTC_SECONDS); | 103 | * If UIP is clear, then we have >= 244 microseconds before |
80 | min = CMOS_READ(RTC_MINUTES); | 104 | * RTC registers will be updated. Spec sheet says that this |
81 | hour = CMOS_READ(RTC_HOURS); | 105 | * is the reliable way to read RTC - registers. If UIP is set |
82 | day = CMOS_READ(RTC_DAY_OF_MONTH); | 106 | * then the register access might be invalid. |
83 | mon = CMOS_READ(RTC_MONTH); | 107 | */ |
84 | year = CMOS_READ(RTC_YEAR); | 108 | while ((CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)) |
85 | } while (sec != CMOS_READ(RTC_SECONDS)); | 109 | cpu_relax(); |
86 | 110 | ||
87 | if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { | 111 | sec = CMOS_READ(RTC_SECONDS); |
112 | min = CMOS_READ(RTC_MINUTES); | ||
113 | hour = CMOS_READ(RTC_HOURS); | ||
114 | day = CMOS_READ(RTC_DAY_OF_MONTH); | ||
115 | mon = CMOS_READ(RTC_MONTH); | ||
116 | year = CMOS_READ(RTC_YEAR); | ||
117 | |||
118 | #if defined(CONFIG_ACPI) && defined(CONFIG_X86_64) | ||
119 | /* CHECKME: Is this really 64bit only ??? */ | ||
120 | if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID && | ||
121 | acpi_gbl_FADT.century) | ||
122 | century = CMOS_READ(acpi_gbl_FADT.century); | ||
123 | #endif | ||
124 | |||
125 | if (RTC_ALWAYS_BCD || !(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY)) { | ||
88 | BCD_TO_BIN(sec); | 126 | BCD_TO_BIN(sec); |
89 | BCD_TO_BIN(min); | 127 | BCD_TO_BIN(min); |
90 | BCD_TO_BIN(hour); | 128 | BCD_TO_BIN(hour); |
@@ -93,24 +131,19 @@ unsigned long mach_get_cmos_time(void) | |||
93 | BCD_TO_BIN(year); | 131 | BCD_TO_BIN(year); |
94 | } | 132 | } |
95 | 133 | ||
96 | year += 1900; | 134 | if (century) { |
97 | if (year < 1970) | 135 | BCD_TO_BIN(century); |
98 | year += 100; | 136 | year += century * 100; |
137 | printk(KERN_INFO "Extended CMOS year: %d\n", century * 100); | ||
138 | } else { | ||
139 | year += CMOS_YEARS_OFFS; | ||
140 | if (year < 1970) | ||
141 | year += 100; | ||
142 | } | ||
99 | 143 | ||
100 | return mktime(year, mon, day, hour, min, sec); | 144 | return mktime(year, mon, day, hour, min, sec); |
101 | } | 145 | } |
102 | 146 | ||
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. */ | 147 | /* Routines for accessing the CMOS RAM/RTC. */ |
115 | unsigned char rtc_cmos_read(unsigned char addr) | 148 | unsigned char rtc_cmos_read(unsigned char addr) |
116 | { | 149 | { |
@@ -138,8 +171,6 @@ static int set_rtc_mmss(unsigned long nowtime) | |||
138 | int retval; | 171 | int retval; |
139 | unsigned long flags; | 172 | unsigned long flags; |
140 | 173 | ||
141 | /* gets recalled with irq locally disabled */ | ||
142 | /* XXX - does irqsave resolve this? -johnstul */ | ||
143 | spin_lock_irqsave(&rtc_lock, flags); | 174 | spin_lock_irqsave(&rtc_lock, flags); |
144 | retval = set_wallclock(nowtime); | 175 | retval = set_wallclock(nowtime); |
145 | spin_unlock_irqrestore(&rtc_lock, flags); | 176 | spin_unlock_irqrestore(&rtc_lock, flags); |
@@ -150,8 +181,7 @@ static int set_rtc_mmss(unsigned long nowtime) | |||
150 | /* not static: needed by APM */ | 181 | /* not static: needed by APM */ |
151 | unsigned long read_persistent_clock(void) | 182 | unsigned long read_persistent_clock(void) |
152 | { | 183 | { |
153 | unsigned long retval; | 184 | unsigned long retval, flags; |
154 | unsigned long flags; | ||
155 | 185 | ||
156 | spin_lock_irqsave(&rtc_lock, flags); | 186 | spin_lock_irqsave(&rtc_lock, flags); |
157 | retval = get_wallclock(); | 187 | retval = get_wallclock(); |
diff --git a/arch/x86/kernel/time_64.c b/arch/x86/kernel/time_64.c index 0a01504586a5..64cd03ed9bfc 100644 --- a/arch/x86/kernel/time_64.c +++ b/arch/x86/kernel/time_64.c | |||
@@ -46,9 +46,6 @@ | |||
46 | #include <asm/nmi.h> | 46 | #include <asm/nmi.h> |
47 | #include <asm/vgtod.h> | 47 | #include <asm/vgtod.h> |
48 | 48 | ||
49 | DEFINE_SPINLOCK(rtc_lock); | ||
50 | EXPORT_SYMBOL(rtc_lock); | ||
51 | |||
52 | volatile unsigned long __jiffies __section_jiffies = INITIAL_JIFFIES; | 49 | volatile unsigned long __jiffies __section_jiffies = INITIAL_JIFFIES; |
53 | 50 | ||
54 | unsigned long profile_pc(struct pt_regs *regs) | 51 | unsigned long profile_pc(struct pt_regs *regs) |
@@ -69,103 +66,6 @@ unsigned long profile_pc(struct pt_regs *regs) | |||
69 | } | 66 | } |
70 | EXPORT_SYMBOL(profile_pc); | 67 | EXPORT_SYMBOL(profile_pc); |
71 | 68 | ||
72 | /* Routines for accessing the CMOS RAM/RTC. */ | ||
73 | unsigned char rtc_cmos_read(unsigned char addr) | ||
74 | { | ||
75 | unsigned char val; | ||
76 | lock_cmos_prefix(addr); | ||
77 | outb_p(addr, RTC_PORT(0)); | ||
78 | val = inb_p(RTC_PORT(1)); | ||
79 | lock_cmos_suffix(addr); | ||
80 | return val; | ||
81 | } | ||
82 | EXPORT_SYMBOL(rtc_cmos_read); | ||
83 | |||
84 | void rtc_cmos_write(unsigned char val, unsigned char addr) | ||
85 | { | ||
86 | lock_cmos_prefix(addr); | ||
87 | outb_p(addr, RTC_PORT(0)); | ||
88 | outb_p(val, RTC_PORT(1)); | ||
89 | lock_cmos_suffix(addr); | ||
90 | } | ||
91 | EXPORT_SYMBOL(rtc_cmos_write); | ||
92 | |||
93 | /* | ||
94 | * In order to set the CMOS clock precisely, set_rtc_mmss has to be called 500 | ||
95 | * ms after the second nowtime has started, because when nowtime is written | ||
96 | * into the registers of the CMOS clock, it will jump to the next second | ||
97 | * precisely 500 ms later. Check the Motorola MC146818A or Dallas DS12887 data | ||
98 | * sheet for details. | ||
99 | */ | ||
100 | |||
101 | static int set_rtc_mmss(unsigned long nowtime) | ||
102 | { | ||
103 | int retval = 0; | ||
104 | int real_seconds, real_minutes, cmos_minutes; | ||
105 | unsigned char control, freq_select; | ||
106 | unsigned long flags; | ||
107 | |||
108 | /* | ||
109 | * set_rtc_mmss is called when irqs are enabled, so disable irqs here | ||
110 | */ | ||
111 | spin_lock_irqsave(&rtc_lock, flags); | ||
112 | /* | ||
113 | * Tell the clock it's being set and stop it. | ||
114 | */ | ||
115 | control = CMOS_READ(RTC_CONTROL); | ||
116 | CMOS_WRITE(control | RTC_SET, RTC_CONTROL); | ||
117 | |||
118 | freq_select = CMOS_READ(RTC_FREQ_SELECT); | ||
119 | CMOS_WRITE(freq_select | RTC_DIV_RESET2, RTC_FREQ_SELECT); | ||
120 | |||
121 | cmos_minutes = CMOS_READ(RTC_MINUTES); | ||
122 | BCD_TO_BIN(cmos_minutes); | ||
123 | |||
124 | /* | ||
125 | * since we're only adjusting minutes and seconds, don't interfere with hour | ||
126 | * overflow. This avoids messing with unknown time zones but requires your RTC | ||
127 | * not to be off by more than 15 minutes. Since we're calling it only when | ||
128 | * our clock is externally synchronized using NTP, this shouldn't be a problem. | ||
129 | */ | ||
130 | |||
131 | real_seconds = nowtime % 60; | ||
132 | real_minutes = nowtime / 60; | ||
133 | if (((abs(real_minutes - cmos_minutes) + 15) / 30) & 1) | ||
134 | real_minutes += 30; /* correct for half hour time zone */ | ||
135 | real_minutes %= 60; | ||
136 | |||
137 | if (abs(real_minutes - cmos_minutes) >= 30) { | ||
138 | printk(KERN_WARNING "time.c: can't update CMOS clock " | ||
139 | "from %d to %d\n", cmos_minutes, real_minutes); | ||
140 | retval = -1; | ||
141 | } else { | ||
142 | BIN_TO_BCD(real_seconds); | ||
143 | BIN_TO_BCD(real_minutes); | ||
144 | CMOS_WRITE(real_seconds, RTC_SECONDS); | ||
145 | CMOS_WRITE(real_minutes, RTC_MINUTES); | ||
146 | } | ||
147 | |||
148 | /* | ||
149 | * The following flags have to be released exactly in this order, otherwise the | ||
150 | * DS12887 (popular MC146818A clone with integrated battery and quartz) will | ||
151 | * not reset the oscillator and will not update precisely 500 ms later. You | ||
152 | * won't find this mentioned in the Dallas Semiconductor data sheets, but who | ||
153 | * believes data sheets anyway ... -- Markus Kuhn | ||
154 | */ | ||
155 | |||
156 | CMOS_WRITE(control, RTC_CONTROL); | ||
157 | CMOS_WRITE(freq_select, RTC_FREQ_SELECT); | ||
158 | |||
159 | spin_unlock_irqrestore(&rtc_lock, flags); | ||
160 | |||
161 | return retval; | ||
162 | } | ||
163 | |||
164 | int update_persistent_clock(struct timespec now) | ||
165 | { | ||
166 | return set_rtc_mmss(now.tv_sec); | ||
167 | } | ||
168 | |||
169 | static irqreturn_t timer_event_interrupt(int irq, void *dev_id) | 69 | static irqreturn_t timer_event_interrupt(int irq, void *dev_id) |
170 | { | 70 | { |
171 | add_pda(irq0_irqs, 1); | 71 | add_pda(irq0_irqs, 1); |
@@ -175,63 +75,6 @@ static irqreturn_t timer_event_interrupt(int irq, void *dev_id) | |||
175 | return IRQ_HANDLED; | 75 | return IRQ_HANDLED; |
176 | } | 76 | } |
177 | 77 | ||
178 | unsigned long read_persistent_clock(void) | ||
179 | { | ||
180 | unsigned int year, mon, day, hour, min, sec; | ||
181 | unsigned long flags; | ||
182 | unsigned century = 0; | ||
183 | |||
184 | spin_lock_irqsave(&rtc_lock, flags); | ||
185 | /* | ||
186 | * if UIP is clear, then we have >= 244 microseconds before RTC | ||
187 | * registers will be updated. Spec sheet says that this is the | ||
188 | * reliable way to read RTC - registers invalid (off bus) during update | ||
189 | */ | ||
190 | while ((CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)) | ||
191 | cpu_relax(); | ||
192 | |||
193 | |||
194 | /* now read all RTC registers while stable with interrupts disabled */ | ||
195 | sec = CMOS_READ(RTC_SECONDS); | ||
196 | min = CMOS_READ(RTC_MINUTES); | ||
197 | hour = CMOS_READ(RTC_HOURS); | ||
198 | day = CMOS_READ(RTC_DAY_OF_MONTH); | ||
199 | mon = CMOS_READ(RTC_MONTH); | ||
200 | year = CMOS_READ(RTC_YEAR); | ||
201 | #ifdef CONFIG_ACPI | ||
202 | if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID && | ||
203 | acpi_gbl_FADT.century) | ||
204 | century = CMOS_READ(acpi_gbl_FADT.century); | ||
205 | #endif | ||
206 | spin_unlock_irqrestore(&rtc_lock, flags); | ||
207 | |||
208 | /* | ||
209 | * We know that x86-64 always uses BCD format, no need to check the | ||
210 | * config register. | ||
211 | */ | ||
212 | |||
213 | BCD_TO_BIN(sec); | ||
214 | BCD_TO_BIN(min); | ||
215 | BCD_TO_BIN(hour); | ||
216 | BCD_TO_BIN(day); | ||
217 | BCD_TO_BIN(mon); | ||
218 | BCD_TO_BIN(year); | ||
219 | |||
220 | if (century) { | ||
221 | BCD_TO_BIN(century); | ||
222 | year += century * 100; | ||
223 | printk(KERN_INFO "Extended CMOS year: %d\n", century * 100); | ||
224 | } else { | ||
225 | /* | ||
226 | * x86-64 systems only exists since 2002. | ||
227 | * This will work up to Dec 31, 2100 | ||
228 | */ | ||
229 | year += 2000; | ||
230 | } | ||
231 | |||
232 | return mktime(year, mon, day, hour, min, sec); | ||
233 | } | ||
234 | |||
235 | /* calibrate_cpu is used on systems with fixed rate TSCs to determine | 78 | /* calibrate_cpu is used on systems with fixed rate TSCs to determine |
236 | * processor frequency */ | 79 | * processor frequency */ |
237 | #define TICK_COUNT 100000000 | 80 | #define TICK_COUNT 100000000 |