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/x86/kernel/rtc.c | |
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/x86/kernel/rtc.c')
-rw-r--r-- | arch/x86/kernel/rtc.c | 96 |
1 files changed, 63 insertions, 33 deletions
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(); |