Commit 021989622810b02aab4b24f91e1f5ada2b654579
Committed by
H. Peter Anvin
1 parent
1cf180c94e
Exists in
master
and in
7 other branches
x86, hpet: Fix bogus error check in hpet_assign_irq()
create_irq() returns -1 if the interrupt allocation failed, but the code checks for irq == 0. Use create_irq_nr() instead. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Cc: Venkatesh Pallipadi <venki@google.com> LKML-Reference: <alpine.LFD.2.00.1009282310360.2416@localhost6.localdomain6> Cc: stable@kernel.org Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Showing 1 changed file with 1 additions and 1 deletions Inline Diff
arch/x86/kernel/hpet.c
1 | #include <linux/clocksource.h> | 1 | #include <linux/clocksource.h> |
2 | #include <linux/clockchips.h> | 2 | #include <linux/clockchips.h> |
3 | #include <linux/interrupt.h> | 3 | #include <linux/interrupt.h> |
4 | #include <linux/sysdev.h> | 4 | #include <linux/sysdev.h> |
5 | #include <linux/delay.h> | 5 | #include <linux/delay.h> |
6 | #include <linux/errno.h> | 6 | #include <linux/errno.h> |
7 | #include <linux/slab.h> | 7 | #include <linux/slab.h> |
8 | #include <linux/hpet.h> | 8 | #include <linux/hpet.h> |
9 | #include <linux/init.h> | 9 | #include <linux/init.h> |
10 | #include <linux/cpu.h> | 10 | #include <linux/cpu.h> |
11 | #include <linux/pm.h> | 11 | #include <linux/pm.h> |
12 | #include <linux/io.h> | 12 | #include <linux/io.h> |
13 | 13 | ||
14 | #include <asm/fixmap.h> | 14 | #include <asm/fixmap.h> |
15 | #include <asm/i8253.h> | 15 | #include <asm/i8253.h> |
16 | #include <asm/hpet.h> | 16 | #include <asm/hpet.h> |
17 | 17 | ||
18 | #define HPET_MASK CLOCKSOURCE_MASK(32) | 18 | #define HPET_MASK CLOCKSOURCE_MASK(32) |
19 | 19 | ||
20 | /* FSEC = 10^-15 | 20 | /* FSEC = 10^-15 |
21 | NSEC = 10^-9 */ | 21 | NSEC = 10^-9 */ |
22 | #define FSEC_PER_NSEC 1000000L | 22 | #define FSEC_PER_NSEC 1000000L |
23 | 23 | ||
24 | #define HPET_DEV_USED_BIT 2 | 24 | #define HPET_DEV_USED_BIT 2 |
25 | #define HPET_DEV_USED (1 << HPET_DEV_USED_BIT) | 25 | #define HPET_DEV_USED (1 << HPET_DEV_USED_BIT) |
26 | #define HPET_DEV_VALID 0x8 | 26 | #define HPET_DEV_VALID 0x8 |
27 | #define HPET_DEV_FSB_CAP 0x1000 | 27 | #define HPET_DEV_FSB_CAP 0x1000 |
28 | #define HPET_DEV_PERI_CAP 0x2000 | 28 | #define HPET_DEV_PERI_CAP 0x2000 |
29 | 29 | ||
30 | #define EVT_TO_HPET_DEV(evt) container_of(evt, struct hpet_dev, evt) | 30 | #define EVT_TO_HPET_DEV(evt) container_of(evt, struct hpet_dev, evt) |
31 | 31 | ||
32 | /* | 32 | /* |
33 | * HPET address is set in acpi/boot.c, when an ACPI entry exists | 33 | * HPET address is set in acpi/boot.c, when an ACPI entry exists |
34 | */ | 34 | */ |
35 | unsigned long hpet_address; | 35 | unsigned long hpet_address; |
36 | u8 hpet_blockid; /* OS timer block num */ | 36 | u8 hpet_blockid; /* OS timer block num */ |
37 | u8 hpet_msi_disable; | 37 | u8 hpet_msi_disable; |
38 | 38 | ||
39 | #ifdef CONFIG_PCI_MSI | 39 | #ifdef CONFIG_PCI_MSI |
40 | static unsigned long hpet_num_timers; | 40 | static unsigned long hpet_num_timers; |
41 | #endif | 41 | #endif |
42 | static void __iomem *hpet_virt_address; | 42 | static void __iomem *hpet_virt_address; |
43 | 43 | ||
44 | struct hpet_dev { | 44 | struct hpet_dev { |
45 | struct clock_event_device evt; | 45 | struct clock_event_device evt; |
46 | unsigned int num; | 46 | unsigned int num; |
47 | int cpu; | 47 | int cpu; |
48 | unsigned int irq; | 48 | unsigned int irq; |
49 | unsigned int flags; | 49 | unsigned int flags; |
50 | char name[10]; | 50 | char name[10]; |
51 | }; | 51 | }; |
52 | 52 | ||
53 | inline unsigned int hpet_readl(unsigned int a) | 53 | inline unsigned int hpet_readl(unsigned int a) |
54 | { | 54 | { |
55 | return readl(hpet_virt_address + a); | 55 | return readl(hpet_virt_address + a); |
56 | } | 56 | } |
57 | 57 | ||
58 | static inline void hpet_writel(unsigned int d, unsigned int a) | 58 | static inline void hpet_writel(unsigned int d, unsigned int a) |
59 | { | 59 | { |
60 | writel(d, hpet_virt_address + a); | 60 | writel(d, hpet_virt_address + a); |
61 | } | 61 | } |
62 | 62 | ||
63 | #ifdef CONFIG_X86_64 | 63 | #ifdef CONFIG_X86_64 |
64 | #include <asm/pgtable.h> | 64 | #include <asm/pgtable.h> |
65 | #endif | 65 | #endif |
66 | 66 | ||
67 | static inline void hpet_set_mapping(void) | 67 | static inline void hpet_set_mapping(void) |
68 | { | 68 | { |
69 | hpet_virt_address = ioremap_nocache(hpet_address, HPET_MMAP_SIZE); | 69 | hpet_virt_address = ioremap_nocache(hpet_address, HPET_MMAP_SIZE); |
70 | #ifdef CONFIG_X86_64 | 70 | #ifdef CONFIG_X86_64 |
71 | __set_fixmap(VSYSCALL_HPET, hpet_address, PAGE_KERNEL_VSYSCALL_NOCACHE); | 71 | __set_fixmap(VSYSCALL_HPET, hpet_address, PAGE_KERNEL_VSYSCALL_NOCACHE); |
72 | #endif | 72 | #endif |
73 | } | 73 | } |
74 | 74 | ||
75 | static inline void hpet_clear_mapping(void) | 75 | static inline void hpet_clear_mapping(void) |
76 | { | 76 | { |
77 | iounmap(hpet_virt_address); | 77 | iounmap(hpet_virt_address); |
78 | hpet_virt_address = NULL; | 78 | hpet_virt_address = NULL; |
79 | } | 79 | } |
80 | 80 | ||
81 | /* | 81 | /* |
82 | * HPET command line enable / disable | 82 | * HPET command line enable / disable |
83 | */ | 83 | */ |
84 | static int boot_hpet_disable; | 84 | static int boot_hpet_disable; |
85 | int hpet_force_user; | 85 | int hpet_force_user; |
86 | static int hpet_verbose; | 86 | static int hpet_verbose; |
87 | 87 | ||
88 | static int __init hpet_setup(char *str) | 88 | static int __init hpet_setup(char *str) |
89 | { | 89 | { |
90 | if (str) { | 90 | if (str) { |
91 | if (!strncmp("disable", str, 7)) | 91 | if (!strncmp("disable", str, 7)) |
92 | boot_hpet_disable = 1; | 92 | boot_hpet_disable = 1; |
93 | if (!strncmp("force", str, 5)) | 93 | if (!strncmp("force", str, 5)) |
94 | hpet_force_user = 1; | 94 | hpet_force_user = 1; |
95 | if (!strncmp("verbose", str, 7)) | 95 | if (!strncmp("verbose", str, 7)) |
96 | hpet_verbose = 1; | 96 | hpet_verbose = 1; |
97 | } | 97 | } |
98 | return 1; | 98 | return 1; |
99 | } | 99 | } |
100 | __setup("hpet=", hpet_setup); | 100 | __setup("hpet=", hpet_setup); |
101 | 101 | ||
102 | static int __init disable_hpet(char *str) | 102 | static int __init disable_hpet(char *str) |
103 | { | 103 | { |
104 | boot_hpet_disable = 1; | 104 | boot_hpet_disable = 1; |
105 | return 1; | 105 | return 1; |
106 | } | 106 | } |
107 | __setup("nohpet", disable_hpet); | 107 | __setup("nohpet", disable_hpet); |
108 | 108 | ||
109 | static inline int is_hpet_capable(void) | 109 | static inline int is_hpet_capable(void) |
110 | { | 110 | { |
111 | return !boot_hpet_disable && hpet_address; | 111 | return !boot_hpet_disable && hpet_address; |
112 | } | 112 | } |
113 | 113 | ||
114 | /* | 114 | /* |
115 | * HPET timer interrupt enable / disable | 115 | * HPET timer interrupt enable / disable |
116 | */ | 116 | */ |
117 | static int hpet_legacy_int_enabled; | 117 | static int hpet_legacy_int_enabled; |
118 | 118 | ||
119 | /** | 119 | /** |
120 | * is_hpet_enabled - check whether the hpet timer interrupt is enabled | 120 | * is_hpet_enabled - check whether the hpet timer interrupt is enabled |
121 | */ | 121 | */ |
122 | int is_hpet_enabled(void) | 122 | int is_hpet_enabled(void) |
123 | { | 123 | { |
124 | return is_hpet_capable() && hpet_legacy_int_enabled; | 124 | return is_hpet_capable() && hpet_legacy_int_enabled; |
125 | } | 125 | } |
126 | EXPORT_SYMBOL_GPL(is_hpet_enabled); | 126 | EXPORT_SYMBOL_GPL(is_hpet_enabled); |
127 | 127 | ||
128 | static void _hpet_print_config(const char *function, int line) | 128 | static void _hpet_print_config(const char *function, int line) |
129 | { | 129 | { |
130 | u32 i, timers, l, h; | 130 | u32 i, timers, l, h; |
131 | printk(KERN_INFO "hpet: %s(%d):\n", function, line); | 131 | printk(KERN_INFO "hpet: %s(%d):\n", function, line); |
132 | l = hpet_readl(HPET_ID); | 132 | l = hpet_readl(HPET_ID); |
133 | h = hpet_readl(HPET_PERIOD); | 133 | h = hpet_readl(HPET_PERIOD); |
134 | timers = ((l & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT) + 1; | 134 | timers = ((l & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT) + 1; |
135 | printk(KERN_INFO "hpet: ID: 0x%x, PERIOD: 0x%x\n", l, h); | 135 | printk(KERN_INFO "hpet: ID: 0x%x, PERIOD: 0x%x\n", l, h); |
136 | l = hpet_readl(HPET_CFG); | 136 | l = hpet_readl(HPET_CFG); |
137 | h = hpet_readl(HPET_STATUS); | 137 | h = hpet_readl(HPET_STATUS); |
138 | printk(KERN_INFO "hpet: CFG: 0x%x, STATUS: 0x%x\n", l, h); | 138 | printk(KERN_INFO "hpet: CFG: 0x%x, STATUS: 0x%x\n", l, h); |
139 | l = hpet_readl(HPET_COUNTER); | 139 | l = hpet_readl(HPET_COUNTER); |
140 | h = hpet_readl(HPET_COUNTER+4); | 140 | h = hpet_readl(HPET_COUNTER+4); |
141 | printk(KERN_INFO "hpet: COUNTER_l: 0x%x, COUNTER_h: 0x%x\n", l, h); | 141 | printk(KERN_INFO "hpet: COUNTER_l: 0x%x, COUNTER_h: 0x%x\n", l, h); |
142 | 142 | ||
143 | for (i = 0; i < timers; i++) { | 143 | for (i = 0; i < timers; i++) { |
144 | l = hpet_readl(HPET_Tn_CFG(i)); | 144 | l = hpet_readl(HPET_Tn_CFG(i)); |
145 | h = hpet_readl(HPET_Tn_CFG(i)+4); | 145 | h = hpet_readl(HPET_Tn_CFG(i)+4); |
146 | printk(KERN_INFO "hpet: T%d: CFG_l: 0x%x, CFG_h: 0x%x\n", | 146 | printk(KERN_INFO "hpet: T%d: CFG_l: 0x%x, CFG_h: 0x%x\n", |
147 | i, l, h); | 147 | i, l, h); |
148 | l = hpet_readl(HPET_Tn_CMP(i)); | 148 | l = hpet_readl(HPET_Tn_CMP(i)); |
149 | h = hpet_readl(HPET_Tn_CMP(i)+4); | 149 | h = hpet_readl(HPET_Tn_CMP(i)+4); |
150 | printk(KERN_INFO "hpet: T%d: CMP_l: 0x%x, CMP_h: 0x%x\n", | 150 | printk(KERN_INFO "hpet: T%d: CMP_l: 0x%x, CMP_h: 0x%x\n", |
151 | i, l, h); | 151 | i, l, h); |
152 | l = hpet_readl(HPET_Tn_ROUTE(i)); | 152 | l = hpet_readl(HPET_Tn_ROUTE(i)); |
153 | h = hpet_readl(HPET_Tn_ROUTE(i)+4); | 153 | h = hpet_readl(HPET_Tn_ROUTE(i)+4); |
154 | printk(KERN_INFO "hpet: T%d ROUTE_l: 0x%x, ROUTE_h: 0x%x\n", | 154 | printk(KERN_INFO "hpet: T%d ROUTE_l: 0x%x, ROUTE_h: 0x%x\n", |
155 | i, l, h); | 155 | i, l, h); |
156 | } | 156 | } |
157 | } | 157 | } |
158 | 158 | ||
159 | #define hpet_print_config() \ | 159 | #define hpet_print_config() \ |
160 | do { \ | 160 | do { \ |
161 | if (hpet_verbose) \ | 161 | if (hpet_verbose) \ |
162 | _hpet_print_config(__FUNCTION__, __LINE__); \ | 162 | _hpet_print_config(__FUNCTION__, __LINE__); \ |
163 | } while (0) | 163 | } while (0) |
164 | 164 | ||
165 | /* | 165 | /* |
166 | * When the hpet driver (/dev/hpet) is enabled, we need to reserve | 166 | * When the hpet driver (/dev/hpet) is enabled, we need to reserve |
167 | * timer 0 and timer 1 in case of RTC emulation. | 167 | * timer 0 and timer 1 in case of RTC emulation. |
168 | */ | 168 | */ |
169 | #ifdef CONFIG_HPET | 169 | #ifdef CONFIG_HPET |
170 | 170 | ||
171 | static void hpet_reserve_msi_timers(struct hpet_data *hd); | 171 | static void hpet_reserve_msi_timers(struct hpet_data *hd); |
172 | 172 | ||
173 | static void hpet_reserve_platform_timers(unsigned int id) | 173 | static void hpet_reserve_platform_timers(unsigned int id) |
174 | { | 174 | { |
175 | struct hpet __iomem *hpet = hpet_virt_address; | 175 | struct hpet __iomem *hpet = hpet_virt_address; |
176 | struct hpet_timer __iomem *timer = &hpet->hpet_timers[2]; | 176 | struct hpet_timer __iomem *timer = &hpet->hpet_timers[2]; |
177 | unsigned int nrtimers, i; | 177 | unsigned int nrtimers, i; |
178 | struct hpet_data hd; | 178 | struct hpet_data hd; |
179 | 179 | ||
180 | nrtimers = ((id & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT) + 1; | 180 | nrtimers = ((id & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT) + 1; |
181 | 181 | ||
182 | memset(&hd, 0, sizeof(hd)); | 182 | memset(&hd, 0, sizeof(hd)); |
183 | hd.hd_phys_address = hpet_address; | 183 | hd.hd_phys_address = hpet_address; |
184 | hd.hd_address = hpet; | 184 | hd.hd_address = hpet; |
185 | hd.hd_nirqs = nrtimers; | 185 | hd.hd_nirqs = nrtimers; |
186 | hpet_reserve_timer(&hd, 0); | 186 | hpet_reserve_timer(&hd, 0); |
187 | 187 | ||
188 | #ifdef CONFIG_HPET_EMULATE_RTC | 188 | #ifdef CONFIG_HPET_EMULATE_RTC |
189 | hpet_reserve_timer(&hd, 1); | 189 | hpet_reserve_timer(&hd, 1); |
190 | #endif | 190 | #endif |
191 | 191 | ||
192 | /* | 192 | /* |
193 | * NOTE that hd_irq[] reflects IOAPIC input pins (LEGACY_8254 | 193 | * NOTE that hd_irq[] reflects IOAPIC input pins (LEGACY_8254 |
194 | * is wrong for i8259!) not the output IRQ. Many BIOS writers | 194 | * is wrong for i8259!) not the output IRQ. Many BIOS writers |
195 | * don't bother configuring *any* comparator interrupts. | 195 | * don't bother configuring *any* comparator interrupts. |
196 | */ | 196 | */ |
197 | hd.hd_irq[0] = HPET_LEGACY_8254; | 197 | hd.hd_irq[0] = HPET_LEGACY_8254; |
198 | hd.hd_irq[1] = HPET_LEGACY_RTC; | 198 | hd.hd_irq[1] = HPET_LEGACY_RTC; |
199 | 199 | ||
200 | for (i = 2; i < nrtimers; timer++, i++) { | 200 | for (i = 2; i < nrtimers; timer++, i++) { |
201 | hd.hd_irq[i] = (readl(&timer->hpet_config) & | 201 | hd.hd_irq[i] = (readl(&timer->hpet_config) & |
202 | Tn_INT_ROUTE_CNF_MASK) >> Tn_INT_ROUTE_CNF_SHIFT; | 202 | Tn_INT_ROUTE_CNF_MASK) >> Tn_INT_ROUTE_CNF_SHIFT; |
203 | } | 203 | } |
204 | 204 | ||
205 | hpet_reserve_msi_timers(&hd); | 205 | hpet_reserve_msi_timers(&hd); |
206 | 206 | ||
207 | hpet_alloc(&hd); | 207 | hpet_alloc(&hd); |
208 | 208 | ||
209 | } | 209 | } |
210 | #else | 210 | #else |
211 | static void hpet_reserve_platform_timers(unsigned int id) { } | 211 | static void hpet_reserve_platform_timers(unsigned int id) { } |
212 | #endif | 212 | #endif |
213 | 213 | ||
214 | /* | 214 | /* |
215 | * Common hpet info | 215 | * Common hpet info |
216 | */ | 216 | */ |
217 | static unsigned long hpet_period; | 217 | static unsigned long hpet_period; |
218 | 218 | ||
219 | static void hpet_legacy_set_mode(enum clock_event_mode mode, | 219 | static void hpet_legacy_set_mode(enum clock_event_mode mode, |
220 | struct clock_event_device *evt); | 220 | struct clock_event_device *evt); |
221 | static int hpet_legacy_next_event(unsigned long delta, | 221 | static int hpet_legacy_next_event(unsigned long delta, |
222 | struct clock_event_device *evt); | 222 | struct clock_event_device *evt); |
223 | 223 | ||
224 | /* | 224 | /* |
225 | * The hpet clock event device | 225 | * The hpet clock event device |
226 | */ | 226 | */ |
227 | static struct clock_event_device hpet_clockevent = { | 227 | static struct clock_event_device hpet_clockevent = { |
228 | .name = "hpet", | 228 | .name = "hpet", |
229 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, | 229 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, |
230 | .set_mode = hpet_legacy_set_mode, | 230 | .set_mode = hpet_legacy_set_mode, |
231 | .set_next_event = hpet_legacy_next_event, | 231 | .set_next_event = hpet_legacy_next_event, |
232 | .shift = 32, | 232 | .shift = 32, |
233 | .irq = 0, | 233 | .irq = 0, |
234 | .rating = 50, | 234 | .rating = 50, |
235 | }; | 235 | }; |
236 | 236 | ||
237 | static void hpet_stop_counter(void) | 237 | static void hpet_stop_counter(void) |
238 | { | 238 | { |
239 | unsigned long cfg = hpet_readl(HPET_CFG); | 239 | unsigned long cfg = hpet_readl(HPET_CFG); |
240 | cfg &= ~HPET_CFG_ENABLE; | 240 | cfg &= ~HPET_CFG_ENABLE; |
241 | hpet_writel(cfg, HPET_CFG); | 241 | hpet_writel(cfg, HPET_CFG); |
242 | } | 242 | } |
243 | 243 | ||
244 | static void hpet_reset_counter(void) | 244 | static void hpet_reset_counter(void) |
245 | { | 245 | { |
246 | hpet_writel(0, HPET_COUNTER); | 246 | hpet_writel(0, HPET_COUNTER); |
247 | hpet_writel(0, HPET_COUNTER + 4); | 247 | hpet_writel(0, HPET_COUNTER + 4); |
248 | } | 248 | } |
249 | 249 | ||
250 | static void hpet_start_counter(void) | 250 | static void hpet_start_counter(void) |
251 | { | 251 | { |
252 | unsigned int cfg = hpet_readl(HPET_CFG); | 252 | unsigned int cfg = hpet_readl(HPET_CFG); |
253 | cfg |= HPET_CFG_ENABLE; | 253 | cfg |= HPET_CFG_ENABLE; |
254 | hpet_writel(cfg, HPET_CFG); | 254 | hpet_writel(cfg, HPET_CFG); |
255 | } | 255 | } |
256 | 256 | ||
257 | static void hpet_restart_counter(void) | 257 | static void hpet_restart_counter(void) |
258 | { | 258 | { |
259 | hpet_stop_counter(); | 259 | hpet_stop_counter(); |
260 | hpet_reset_counter(); | 260 | hpet_reset_counter(); |
261 | hpet_start_counter(); | 261 | hpet_start_counter(); |
262 | } | 262 | } |
263 | 263 | ||
264 | static void hpet_resume_device(void) | 264 | static void hpet_resume_device(void) |
265 | { | 265 | { |
266 | force_hpet_resume(); | 266 | force_hpet_resume(); |
267 | } | 267 | } |
268 | 268 | ||
269 | static void hpet_resume_counter(struct clocksource *cs) | 269 | static void hpet_resume_counter(struct clocksource *cs) |
270 | { | 270 | { |
271 | hpet_resume_device(); | 271 | hpet_resume_device(); |
272 | hpet_restart_counter(); | 272 | hpet_restart_counter(); |
273 | } | 273 | } |
274 | 274 | ||
275 | static void hpet_enable_legacy_int(void) | 275 | static void hpet_enable_legacy_int(void) |
276 | { | 276 | { |
277 | unsigned int cfg = hpet_readl(HPET_CFG); | 277 | unsigned int cfg = hpet_readl(HPET_CFG); |
278 | 278 | ||
279 | cfg |= HPET_CFG_LEGACY; | 279 | cfg |= HPET_CFG_LEGACY; |
280 | hpet_writel(cfg, HPET_CFG); | 280 | hpet_writel(cfg, HPET_CFG); |
281 | hpet_legacy_int_enabled = 1; | 281 | hpet_legacy_int_enabled = 1; |
282 | } | 282 | } |
283 | 283 | ||
284 | static void hpet_legacy_clockevent_register(void) | 284 | static void hpet_legacy_clockevent_register(void) |
285 | { | 285 | { |
286 | /* Start HPET legacy interrupts */ | 286 | /* Start HPET legacy interrupts */ |
287 | hpet_enable_legacy_int(); | 287 | hpet_enable_legacy_int(); |
288 | 288 | ||
289 | /* | 289 | /* |
290 | * The mult factor is defined as (include/linux/clockchips.h) | 290 | * The mult factor is defined as (include/linux/clockchips.h) |
291 | * mult/2^shift = cyc/ns (in contrast to ns/cyc in clocksource.h) | 291 | * mult/2^shift = cyc/ns (in contrast to ns/cyc in clocksource.h) |
292 | * hpet_period is in units of femtoseconds (per cycle), so | 292 | * hpet_period is in units of femtoseconds (per cycle), so |
293 | * mult/2^shift = cyc/ns = 10^6/hpet_period | 293 | * mult/2^shift = cyc/ns = 10^6/hpet_period |
294 | * mult = (10^6 * 2^shift)/hpet_period | 294 | * mult = (10^6 * 2^shift)/hpet_period |
295 | * mult = (FSEC_PER_NSEC << hpet_clockevent.shift)/hpet_period | 295 | * mult = (FSEC_PER_NSEC << hpet_clockevent.shift)/hpet_period |
296 | */ | 296 | */ |
297 | hpet_clockevent.mult = div_sc((unsigned long) FSEC_PER_NSEC, | 297 | hpet_clockevent.mult = div_sc((unsigned long) FSEC_PER_NSEC, |
298 | hpet_period, hpet_clockevent.shift); | 298 | hpet_period, hpet_clockevent.shift); |
299 | /* Calculate the min / max delta */ | 299 | /* Calculate the min / max delta */ |
300 | hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF, | 300 | hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF, |
301 | &hpet_clockevent); | 301 | &hpet_clockevent); |
302 | /* 5 usec minimum reprogramming delta. */ | 302 | /* 5 usec minimum reprogramming delta. */ |
303 | hpet_clockevent.min_delta_ns = 5000; | 303 | hpet_clockevent.min_delta_ns = 5000; |
304 | 304 | ||
305 | /* | 305 | /* |
306 | * Start hpet with the boot cpu mask and make it | 306 | * Start hpet with the boot cpu mask and make it |
307 | * global after the IO_APIC has been initialized. | 307 | * global after the IO_APIC has been initialized. |
308 | */ | 308 | */ |
309 | hpet_clockevent.cpumask = cpumask_of(smp_processor_id()); | 309 | hpet_clockevent.cpumask = cpumask_of(smp_processor_id()); |
310 | clockevents_register_device(&hpet_clockevent); | 310 | clockevents_register_device(&hpet_clockevent); |
311 | global_clock_event = &hpet_clockevent; | 311 | global_clock_event = &hpet_clockevent; |
312 | printk(KERN_DEBUG "hpet clockevent registered\n"); | 312 | printk(KERN_DEBUG "hpet clockevent registered\n"); |
313 | } | 313 | } |
314 | 314 | ||
315 | static int hpet_setup_msi_irq(unsigned int irq); | 315 | static int hpet_setup_msi_irq(unsigned int irq); |
316 | 316 | ||
317 | static void hpet_set_mode(enum clock_event_mode mode, | 317 | static void hpet_set_mode(enum clock_event_mode mode, |
318 | struct clock_event_device *evt, int timer) | 318 | struct clock_event_device *evt, int timer) |
319 | { | 319 | { |
320 | unsigned int cfg, cmp, now; | 320 | unsigned int cfg, cmp, now; |
321 | uint64_t delta; | 321 | uint64_t delta; |
322 | 322 | ||
323 | switch (mode) { | 323 | switch (mode) { |
324 | case CLOCK_EVT_MODE_PERIODIC: | 324 | case CLOCK_EVT_MODE_PERIODIC: |
325 | hpet_stop_counter(); | 325 | hpet_stop_counter(); |
326 | delta = ((uint64_t)(NSEC_PER_SEC/HZ)) * evt->mult; | 326 | delta = ((uint64_t)(NSEC_PER_SEC/HZ)) * evt->mult; |
327 | delta >>= evt->shift; | 327 | delta >>= evt->shift; |
328 | now = hpet_readl(HPET_COUNTER); | 328 | now = hpet_readl(HPET_COUNTER); |
329 | cmp = now + (unsigned int) delta; | 329 | cmp = now + (unsigned int) delta; |
330 | cfg = hpet_readl(HPET_Tn_CFG(timer)); | 330 | cfg = hpet_readl(HPET_Tn_CFG(timer)); |
331 | /* Make sure we use edge triggered interrupts */ | 331 | /* Make sure we use edge triggered interrupts */ |
332 | cfg &= ~HPET_TN_LEVEL; | 332 | cfg &= ~HPET_TN_LEVEL; |
333 | cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC | | 333 | cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC | |
334 | HPET_TN_SETVAL | HPET_TN_32BIT; | 334 | HPET_TN_SETVAL | HPET_TN_32BIT; |
335 | hpet_writel(cfg, HPET_Tn_CFG(timer)); | 335 | hpet_writel(cfg, HPET_Tn_CFG(timer)); |
336 | hpet_writel(cmp, HPET_Tn_CMP(timer)); | 336 | hpet_writel(cmp, HPET_Tn_CMP(timer)); |
337 | udelay(1); | 337 | udelay(1); |
338 | /* | 338 | /* |
339 | * HPET on AMD 81xx needs a second write (with HPET_TN_SETVAL | 339 | * HPET on AMD 81xx needs a second write (with HPET_TN_SETVAL |
340 | * cleared) to T0_CMP to set the period. The HPET_TN_SETVAL | 340 | * cleared) to T0_CMP to set the period. The HPET_TN_SETVAL |
341 | * bit is automatically cleared after the first write. | 341 | * bit is automatically cleared after the first write. |
342 | * (See AMD-8111 HyperTransport I/O Hub Data Sheet, | 342 | * (See AMD-8111 HyperTransport I/O Hub Data Sheet, |
343 | * Publication # 24674) | 343 | * Publication # 24674) |
344 | */ | 344 | */ |
345 | hpet_writel((unsigned int) delta, HPET_Tn_CMP(timer)); | 345 | hpet_writel((unsigned int) delta, HPET_Tn_CMP(timer)); |
346 | hpet_start_counter(); | 346 | hpet_start_counter(); |
347 | hpet_print_config(); | 347 | hpet_print_config(); |
348 | break; | 348 | break; |
349 | 349 | ||
350 | case CLOCK_EVT_MODE_ONESHOT: | 350 | case CLOCK_EVT_MODE_ONESHOT: |
351 | cfg = hpet_readl(HPET_Tn_CFG(timer)); | 351 | cfg = hpet_readl(HPET_Tn_CFG(timer)); |
352 | cfg &= ~HPET_TN_PERIODIC; | 352 | cfg &= ~HPET_TN_PERIODIC; |
353 | cfg |= HPET_TN_ENABLE | HPET_TN_32BIT; | 353 | cfg |= HPET_TN_ENABLE | HPET_TN_32BIT; |
354 | hpet_writel(cfg, HPET_Tn_CFG(timer)); | 354 | hpet_writel(cfg, HPET_Tn_CFG(timer)); |
355 | break; | 355 | break; |
356 | 356 | ||
357 | case CLOCK_EVT_MODE_UNUSED: | 357 | case CLOCK_EVT_MODE_UNUSED: |
358 | case CLOCK_EVT_MODE_SHUTDOWN: | 358 | case CLOCK_EVT_MODE_SHUTDOWN: |
359 | cfg = hpet_readl(HPET_Tn_CFG(timer)); | 359 | cfg = hpet_readl(HPET_Tn_CFG(timer)); |
360 | cfg &= ~HPET_TN_ENABLE; | 360 | cfg &= ~HPET_TN_ENABLE; |
361 | hpet_writel(cfg, HPET_Tn_CFG(timer)); | 361 | hpet_writel(cfg, HPET_Tn_CFG(timer)); |
362 | break; | 362 | break; |
363 | 363 | ||
364 | case CLOCK_EVT_MODE_RESUME: | 364 | case CLOCK_EVT_MODE_RESUME: |
365 | if (timer == 0) { | 365 | if (timer == 0) { |
366 | hpet_enable_legacy_int(); | 366 | hpet_enable_legacy_int(); |
367 | } else { | 367 | } else { |
368 | struct hpet_dev *hdev = EVT_TO_HPET_DEV(evt); | 368 | struct hpet_dev *hdev = EVT_TO_HPET_DEV(evt); |
369 | hpet_setup_msi_irq(hdev->irq); | 369 | hpet_setup_msi_irq(hdev->irq); |
370 | disable_irq(hdev->irq); | 370 | disable_irq(hdev->irq); |
371 | irq_set_affinity(hdev->irq, cpumask_of(hdev->cpu)); | 371 | irq_set_affinity(hdev->irq, cpumask_of(hdev->cpu)); |
372 | enable_irq(hdev->irq); | 372 | enable_irq(hdev->irq); |
373 | } | 373 | } |
374 | hpet_print_config(); | 374 | hpet_print_config(); |
375 | break; | 375 | break; |
376 | } | 376 | } |
377 | } | 377 | } |
378 | 378 | ||
379 | static int hpet_next_event(unsigned long delta, | 379 | static int hpet_next_event(unsigned long delta, |
380 | struct clock_event_device *evt, int timer) | 380 | struct clock_event_device *evt, int timer) |
381 | { | 381 | { |
382 | u32 cnt; | 382 | u32 cnt; |
383 | 383 | ||
384 | cnt = hpet_readl(HPET_COUNTER); | 384 | cnt = hpet_readl(HPET_COUNTER); |
385 | cnt += (u32) delta; | 385 | cnt += (u32) delta; |
386 | hpet_writel(cnt, HPET_Tn_CMP(timer)); | 386 | hpet_writel(cnt, HPET_Tn_CMP(timer)); |
387 | 387 | ||
388 | /* | 388 | /* |
389 | * We need to read back the CMP register on certain HPET | 389 | * We need to read back the CMP register on certain HPET |
390 | * implementations (ATI chipsets) which seem to delay the | 390 | * implementations (ATI chipsets) which seem to delay the |
391 | * transfer of the compare register into the internal compare | 391 | * transfer of the compare register into the internal compare |
392 | * logic. With small deltas this might actually be too late as | 392 | * logic. With small deltas this might actually be too late as |
393 | * the counter could already be higher than the compare value | 393 | * the counter could already be higher than the compare value |
394 | * at that point and we would wait for the next hpet interrupt | 394 | * at that point and we would wait for the next hpet interrupt |
395 | * forever. We found out that reading the CMP register back | 395 | * forever. We found out that reading the CMP register back |
396 | * forces the transfer so we can rely on the comparison with | 396 | * forces the transfer so we can rely on the comparison with |
397 | * the counter register below. If the read back from the | 397 | * the counter register below. If the read back from the |
398 | * compare register does not match the value we programmed | 398 | * compare register does not match the value we programmed |
399 | * then we might have a real hardware problem. We can not do | 399 | * then we might have a real hardware problem. We can not do |
400 | * much about it here, but at least alert the user/admin with | 400 | * much about it here, but at least alert the user/admin with |
401 | * a prominent warning. | 401 | * a prominent warning. |
402 | * | 402 | * |
403 | * An erratum on some chipsets (ICH9,..), results in | 403 | * An erratum on some chipsets (ICH9,..), results in |
404 | * comparator read immediately following a write returning old | 404 | * comparator read immediately following a write returning old |
405 | * value. Workaround for this is to read this value second | 405 | * value. Workaround for this is to read this value second |
406 | * time, when first read returns old value. | 406 | * time, when first read returns old value. |
407 | * | 407 | * |
408 | * In fact the write to the comparator register is delayed up | 408 | * In fact the write to the comparator register is delayed up |
409 | * to two HPET cycles so the workaround we tried to restrict | 409 | * to two HPET cycles so the workaround we tried to restrict |
410 | * the readback to those known to be borked ATI chipsets | 410 | * the readback to those known to be borked ATI chipsets |
411 | * failed miserably. So we give up on optimizations forever | 411 | * failed miserably. So we give up on optimizations forever |
412 | * and penalize all HPET incarnations unconditionally. | 412 | * and penalize all HPET incarnations unconditionally. |
413 | */ | 413 | */ |
414 | if (unlikely((u32)hpet_readl(HPET_Tn_CMP(timer)) != cnt)) { | 414 | if (unlikely((u32)hpet_readl(HPET_Tn_CMP(timer)) != cnt)) { |
415 | if (hpet_readl(HPET_Tn_CMP(timer)) != cnt) | 415 | if (hpet_readl(HPET_Tn_CMP(timer)) != cnt) |
416 | printk_once(KERN_WARNING | 416 | printk_once(KERN_WARNING |
417 | "hpet: compare register read back failed.\n"); | 417 | "hpet: compare register read back failed.\n"); |
418 | } | 418 | } |
419 | 419 | ||
420 | return (s32)(hpet_readl(HPET_COUNTER) - cnt) >= 0 ? -ETIME : 0; | 420 | return (s32)(hpet_readl(HPET_COUNTER) - cnt) >= 0 ? -ETIME : 0; |
421 | } | 421 | } |
422 | 422 | ||
423 | static void hpet_legacy_set_mode(enum clock_event_mode mode, | 423 | static void hpet_legacy_set_mode(enum clock_event_mode mode, |
424 | struct clock_event_device *evt) | 424 | struct clock_event_device *evt) |
425 | { | 425 | { |
426 | hpet_set_mode(mode, evt, 0); | 426 | hpet_set_mode(mode, evt, 0); |
427 | } | 427 | } |
428 | 428 | ||
429 | static int hpet_legacy_next_event(unsigned long delta, | 429 | static int hpet_legacy_next_event(unsigned long delta, |
430 | struct clock_event_device *evt) | 430 | struct clock_event_device *evt) |
431 | { | 431 | { |
432 | return hpet_next_event(delta, evt, 0); | 432 | return hpet_next_event(delta, evt, 0); |
433 | } | 433 | } |
434 | 434 | ||
435 | /* | 435 | /* |
436 | * HPET MSI Support | 436 | * HPET MSI Support |
437 | */ | 437 | */ |
438 | #ifdef CONFIG_PCI_MSI | 438 | #ifdef CONFIG_PCI_MSI |
439 | 439 | ||
440 | static DEFINE_PER_CPU(struct hpet_dev *, cpu_hpet_dev); | 440 | static DEFINE_PER_CPU(struct hpet_dev *, cpu_hpet_dev); |
441 | static struct hpet_dev *hpet_devs; | 441 | static struct hpet_dev *hpet_devs; |
442 | 442 | ||
443 | void hpet_msi_unmask(unsigned int irq) | 443 | void hpet_msi_unmask(unsigned int irq) |
444 | { | 444 | { |
445 | struct hpet_dev *hdev = get_irq_data(irq); | 445 | struct hpet_dev *hdev = get_irq_data(irq); |
446 | unsigned int cfg; | 446 | unsigned int cfg; |
447 | 447 | ||
448 | /* unmask it */ | 448 | /* unmask it */ |
449 | cfg = hpet_readl(HPET_Tn_CFG(hdev->num)); | 449 | cfg = hpet_readl(HPET_Tn_CFG(hdev->num)); |
450 | cfg |= HPET_TN_FSB; | 450 | cfg |= HPET_TN_FSB; |
451 | hpet_writel(cfg, HPET_Tn_CFG(hdev->num)); | 451 | hpet_writel(cfg, HPET_Tn_CFG(hdev->num)); |
452 | } | 452 | } |
453 | 453 | ||
454 | void hpet_msi_mask(unsigned int irq) | 454 | void hpet_msi_mask(unsigned int irq) |
455 | { | 455 | { |
456 | unsigned int cfg; | 456 | unsigned int cfg; |
457 | struct hpet_dev *hdev = get_irq_data(irq); | 457 | struct hpet_dev *hdev = get_irq_data(irq); |
458 | 458 | ||
459 | /* mask it */ | 459 | /* mask it */ |
460 | cfg = hpet_readl(HPET_Tn_CFG(hdev->num)); | 460 | cfg = hpet_readl(HPET_Tn_CFG(hdev->num)); |
461 | cfg &= ~HPET_TN_FSB; | 461 | cfg &= ~HPET_TN_FSB; |
462 | hpet_writel(cfg, HPET_Tn_CFG(hdev->num)); | 462 | hpet_writel(cfg, HPET_Tn_CFG(hdev->num)); |
463 | } | 463 | } |
464 | 464 | ||
465 | void hpet_msi_write(unsigned int irq, struct msi_msg *msg) | 465 | void hpet_msi_write(unsigned int irq, struct msi_msg *msg) |
466 | { | 466 | { |
467 | struct hpet_dev *hdev = get_irq_data(irq); | 467 | struct hpet_dev *hdev = get_irq_data(irq); |
468 | 468 | ||
469 | hpet_writel(msg->data, HPET_Tn_ROUTE(hdev->num)); | 469 | hpet_writel(msg->data, HPET_Tn_ROUTE(hdev->num)); |
470 | hpet_writel(msg->address_lo, HPET_Tn_ROUTE(hdev->num) + 4); | 470 | hpet_writel(msg->address_lo, HPET_Tn_ROUTE(hdev->num) + 4); |
471 | } | 471 | } |
472 | 472 | ||
473 | void hpet_msi_read(unsigned int irq, struct msi_msg *msg) | 473 | void hpet_msi_read(unsigned int irq, struct msi_msg *msg) |
474 | { | 474 | { |
475 | struct hpet_dev *hdev = get_irq_data(irq); | 475 | struct hpet_dev *hdev = get_irq_data(irq); |
476 | 476 | ||
477 | msg->data = hpet_readl(HPET_Tn_ROUTE(hdev->num)); | 477 | msg->data = hpet_readl(HPET_Tn_ROUTE(hdev->num)); |
478 | msg->address_lo = hpet_readl(HPET_Tn_ROUTE(hdev->num) + 4); | 478 | msg->address_lo = hpet_readl(HPET_Tn_ROUTE(hdev->num) + 4); |
479 | msg->address_hi = 0; | 479 | msg->address_hi = 0; |
480 | } | 480 | } |
481 | 481 | ||
482 | static void hpet_msi_set_mode(enum clock_event_mode mode, | 482 | static void hpet_msi_set_mode(enum clock_event_mode mode, |
483 | struct clock_event_device *evt) | 483 | struct clock_event_device *evt) |
484 | { | 484 | { |
485 | struct hpet_dev *hdev = EVT_TO_HPET_DEV(evt); | 485 | struct hpet_dev *hdev = EVT_TO_HPET_DEV(evt); |
486 | hpet_set_mode(mode, evt, hdev->num); | 486 | hpet_set_mode(mode, evt, hdev->num); |
487 | } | 487 | } |
488 | 488 | ||
489 | static int hpet_msi_next_event(unsigned long delta, | 489 | static int hpet_msi_next_event(unsigned long delta, |
490 | struct clock_event_device *evt) | 490 | struct clock_event_device *evt) |
491 | { | 491 | { |
492 | struct hpet_dev *hdev = EVT_TO_HPET_DEV(evt); | 492 | struct hpet_dev *hdev = EVT_TO_HPET_DEV(evt); |
493 | return hpet_next_event(delta, evt, hdev->num); | 493 | return hpet_next_event(delta, evt, hdev->num); |
494 | } | 494 | } |
495 | 495 | ||
496 | static int hpet_setup_msi_irq(unsigned int irq) | 496 | static int hpet_setup_msi_irq(unsigned int irq) |
497 | { | 497 | { |
498 | if (arch_setup_hpet_msi(irq, hpet_blockid)) { | 498 | if (arch_setup_hpet_msi(irq, hpet_blockid)) { |
499 | destroy_irq(irq); | 499 | destroy_irq(irq); |
500 | return -EINVAL; | 500 | return -EINVAL; |
501 | } | 501 | } |
502 | return 0; | 502 | return 0; |
503 | } | 503 | } |
504 | 504 | ||
505 | static int hpet_assign_irq(struct hpet_dev *dev) | 505 | static int hpet_assign_irq(struct hpet_dev *dev) |
506 | { | 506 | { |
507 | unsigned int irq; | 507 | unsigned int irq; |
508 | 508 | ||
509 | irq = create_irq(); | 509 | irq = create_irq_nr(0, -1); |
510 | if (!irq) | 510 | if (!irq) |
511 | return -EINVAL; | 511 | return -EINVAL; |
512 | 512 | ||
513 | set_irq_data(irq, dev); | 513 | set_irq_data(irq, dev); |
514 | 514 | ||
515 | if (hpet_setup_msi_irq(irq)) | 515 | if (hpet_setup_msi_irq(irq)) |
516 | return -EINVAL; | 516 | return -EINVAL; |
517 | 517 | ||
518 | dev->irq = irq; | 518 | dev->irq = irq; |
519 | return 0; | 519 | return 0; |
520 | } | 520 | } |
521 | 521 | ||
522 | static irqreturn_t hpet_interrupt_handler(int irq, void *data) | 522 | static irqreturn_t hpet_interrupt_handler(int irq, void *data) |
523 | { | 523 | { |
524 | struct hpet_dev *dev = (struct hpet_dev *)data; | 524 | struct hpet_dev *dev = (struct hpet_dev *)data; |
525 | struct clock_event_device *hevt = &dev->evt; | 525 | struct clock_event_device *hevt = &dev->evt; |
526 | 526 | ||
527 | if (!hevt->event_handler) { | 527 | if (!hevt->event_handler) { |
528 | printk(KERN_INFO "Spurious HPET timer interrupt on HPET timer %d\n", | 528 | printk(KERN_INFO "Spurious HPET timer interrupt on HPET timer %d\n", |
529 | dev->num); | 529 | dev->num); |
530 | return IRQ_HANDLED; | 530 | return IRQ_HANDLED; |
531 | } | 531 | } |
532 | 532 | ||
533 | hevt->event_handler(hevt); | 533 | hevt->event_handler(hevt); |
534 | return IRQ_HANDLED; | 534 | return IRQ_HANDLED; |
535 | } | 535 | } |
536 | 536 | ||
537 | static int hpet_setup_irq(struct hpet_dev *dev) | 537 | static int hpet_setup_irq(struct hpet_dev *dev) |
538 | { | 538 | { |
539 | 539 | ||
540 | if (request_irq(dev->irq, hpet_interrupt_handler, | 540 | if (request_irq(dev->irq, hpet_interrupt_handler, |
541 | IRQF_TIMER | IRQF_DISABLED | IRQF_NOBALANCING, | 541 | IRQF_TIMER | IRQF_DISABLED | IRQF_NOBALANCING, |
542 | dev->name, dev)) | 542 | dev->name, dev)) |
543 | return -1; | 543 | return -1; |
544 | 544 | ||
545 | disable_irq(dev->irq); | 545 | disable_irq(dev->irq); |
546 | irq_set_affinity(dev->irq, cpumask_of(dev->cpu)); | 546 | irq_set_affinity(dev->irq, cpumask_of(dev->cpu)); |
547 | enable_irq(dev->irq); | 547 | enable_irq(dev->irq); |
548 | 548 | ||
549 | printk(KERN_DEBUG "hpet: %s irq %d for MSI\n", | 549 | printk(KERN_DEBUG "hpet: %s irq %d for MSI\n", |
550 | dev->name, dev->irq); | 550 | dev->name, dev->irq); |
551 | 551 | ||
552 | return 0; | 552 | return 0; |
553 | } | 553 | } |
554 | 554 | ||
555 | /* This should be called in specific @cpu */ | 555 | /* This should be called in specific @cpu */ |
556 | static void init_one_hpet_msi_clockevent(struct hpet_dev *hdev, int cpu) | 556 | static void init_one_hpet_msi_clockevent(struct hpet_dev *hdev, int cpu) |
557 | { | 557 | { |
558 | struct clock_event_device *evt = &hdev->evt; | 558 | struct clock_event_device *evt = &hdev->evt; |
559 | uint64_t hpet_freq; | 559 | uint64_t hpet_freq; |
560 | 560 | ||
561 | WARN_ON(cpu != smp_processor_id()); | 561 | WARN_ON(cpu != smp_processor_id()); |
562 | if (!(hdev->flags & HPET_DEV_VALID)) | 562 | if (!(hdev->flags & HPET_DEV_VALID)) |
563 | return; | 563 | return; |
564 | 564 | ||
565 | if (hpet_setup_msi_irq(hdev->irq)) | 565 | if (hpet_setup_msi_irq(hdev->irq)) |
566 | return; | 566 | return; |
567 | 567 | ||
568 | hdev->cpu = cpu; | 568 | hdev->cpu = cpu; |
569 | per_cpu(cpu_hpet_dev, cpu) = hdev; | 569 | per_cpu(cpu_hpet_dev, cpu) = hdev; |
570 | evt->name = hdev->name; | 570 | evt->name = hdev->name; |
571 | hpet_setup_irq(hdev); | 571 | hpet_setup_irq(hdev); |
572 | evt->irq = hdev->irq; | 572 | evt->irq = hdev->irq; |
573 | 573 | ||
574 | evt->rating = 110; | 574 | evt->rating = 110; |
575 | evt->features = CLOCK_EVT_FEAT_ONESHOT; | 575 | evt->features = CLOCK_EVT_FEAT_ONESHOT; |
576 | if (hdev->flags & HPET_DEV_PERI_CAP) | 576 | if (hdev->flags & HPET_DEV_PERI_CAP) |
577 | evt->features |= CLOCK_EVT_FEAT_PERIODIC; | 577 | evt->features |= CLOCK_EVT_FEAT_PERIODIC; |
578 | 578 | ||
579 | evt->set_mode = hpet_msi_set_mode; | 579 | evt->set_mode = hpet_msi_set_mode; |
580 | evt->set_next_event = hpet_msi_next_event; | 580 | evt->set_next_event = hpet_msi_next_event; |
581 | evt->shift = 32; | 581 | evt->shift = 32; |
582 | 582 | ||
583 | /* | 583 | /* |
584 | * The period is a femto seconds value. We need to calculate the | 584 | * The period is a femto seconds value. We need to calculate the |
585 | * scaled math multiplication factor for nanosecond to hpet tick | 585 | * scaled math multiplication factor for nanosecond to hpet tick |
586 | * conversion. | 586 | * conversion. |
587 | */ | 587 | */ |
588 | hpet_freq = FSEC_PER_SEC; | 588 | hpet_freq = FSEC_PER_SEC; |
589 | do_div(hpet_freq, hpet_period); | 589 | do_div(hpet_freq, hpet_period); |
590 | evt->mult = div_sc((unsigned long) hpet_freq, | 590 | evt->mult = div_sc((unsigned long) hpet_freq, |
591 | NSEC_PER_SEC, evt->shift); | 591 | NSEC_PER_SEC, evt->shift); |
592 | /* Calculate the max delta */ | 592 | /* Calculate the max delta */ |
593 | evt->max_delta_ns = clockevent_delta2ns(0x7FFFFFFF, evt); | 593 | evt->max_delta_ns = clockevent_delta2ns(0x7FFFFFFF, evt); |
594 | /* 5 usec minimum reprogramming delta. */ | 594 | /* 5 usec minimum reprogramming delta. */ |
595 | evt->min_delta_ns = 5000; | 595 | evt->min_delta_ns = 5000; |
596 | 596 | ||
597 | evt->cpumask = cpumask_of(hdev->cpu); | 597 | evt->cpumask = cpumask_of(hdev->cpu); |
598 | clockevents_register_device(evt); | 598 | clockevents_register_device(evt); |
599 | } | 599 | } |
600 | 600 | ||
601 | #ifdef CONFIG_HPET | 601 | #ifdef CONFIG_HPET |
602 | /* Reserve at least one timer for userspace (/dev/hpet) */ | 602 | /* Reserve at least one timer for userspace (/dev/hpet) */ |
603 | #define RESERVE_TIMERS 1 | 603 | #define RESERVE_TIMERS 1 |
604 | #else | 604 | #else |
605 | #define RESERVE_TIMERS 0 | 605 | #define RESERVE_TIMERS 0 |
606 | #endif | 606 | #endif |
607 | 607 | ||
608 | static void hpet_msi_capability_lookup(unsigned int start_timer) | 608 | static void hpet_msi_capability_lookup(unsigned int start_timer) |
609 | { | 609 | { |
610 | unsigned int id; | 610 | unsigned int id; |
611 | unsigned int num_timers; | 611 | unsigned int num_timers; |
612 | unsigned int num_timers_used = 0; | 612 | unsigned int num_timers_used = 0; |
613 | int i; | 613 | int i; |
614 | 614 | ||
615 | if (hpet_msi_disable) | 615 | if (hpet_msi_disable) |
616 | return; | 616 | return; |
617 | 617 | ||
618 | if (boot_cpu_has(X86_FEATURE_ARAT)) | 618 | if (boot_cpu_has(X86_FEATURE_ARAT)) |
619 | return; | 619 | return; |
620 | id = hpet_readl(HPET_ID); | 620 | id = hpet_readl(HPET_ID); |
621 | 621 | ||
622 | num_timers = ((id & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT); | 622 | num_timers = ((id & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT); |
623 | num_timers++; /* Value read out starts from 0 */ | 623 | num_timers++; /* Value read out starts from 0 */ |
624 | hpet_print_config(); | 624 | hpet_print_config(); |
625 | 625 | ||
626 | hpet_devs = kzalloc(sizeof(struct hpet_dev) * num_timers, GFP_KERNEL); | 626 | hpet_devs = kzalloc(sizeof(struct hpet_dev) * num_timers, GFP_KERNEL); |
627 | if (!hpet_devs) | 627 | if (!hpet_devs) |
628 | return; | 628 | return; |
629 | 629 | ||
630 | hpet_num_timers = num_timers; | 630 | hpet_num_timers = num_timers; |
631 | 631 | ||
632 | for (i = start_timer; i < num_timers - RESERVE_TIMERS; i++) { | 632 | for (i = start_timer; i < num_timers - RESERVE_TIMERS; i++) { |
633 | struct hpet_dev *hdev = &hpet_devs[num_timers_used]; | 633 | struct hpet_dev *hdev = &hpet_devs[num_timers_used]; |
634 | unsigned int cfg = hpet_readl(HPET_Tn_CFG(i)); | 634 | unsigned int cfg = hpet_readl(HPET_Tn_CFG(i)); |
635 | 635 | ||
636 | /* Only consider HPET timer with MSI support */ | 636 | /* Only consider HPET timer with MSI support */ |
637 | if (!(cfg & HPET_TN_FSB_CAP)) | 637 | if (!(cfg & HPET_TN_FSB_CAP)) |
638 | continue; | 638 | continue; |
639 | 639 | ||
640 | hdev->flags = 0; | 640 | hdev->flags = 0; |
641 | if (cfg & HPET_TN_PERIODIC_CAP) | 641 | if (cfg & HPET_TN_PERIODIC_CAP) |
642 | hdev->flags |= HPET_DEV_PERI_CAP; | 642 | hdev->flags |= HPET_DEV_PERI_CAP; |
643 | hdev->num = i; | 643 | hdev->num = i; |
644 | 644 | ||
645 | sprintf(hdev->name, "hpet%d", i); | 645 | sprintf(hdev->name, "hpet%d", i); |
646 | if (hpet_assign_irq(hdev)) | 646 | if (hpet_assign_irq(hdev)) |
647 | continue; | 647 | continue; |
648 | 648 | ||
649 | hdev->flags |= HPET_DEV_FSB_CAP; | 649 | hdev->flags |= HPET_DEV_FSB_CAP; |
650 | hdev->flags |= HPET_DEV_VALID; | 650 | hdev->flags |= HPET_DEV_VALID; |
651 | num_timers_used++; | 651 | num_timers_used++; |
652 | if (num_timers_used == num_possible_cpus()) | 652 | if (num_timers_used == num_possible_cpus()) |
653 | break; | 653 | break; |
654 | } | 654 | } |
655 | 655 | ||
656 | printk(KERN_INFO "HPET: %d timers in total, %d timers will be used for per-cpu timer\n", | 656 | printk(KERN_INFO "HPET: %d timers in total, %d timers will be used for per-cpu timer\n", |
657 | num_timers, num_timers_used); | 657 | num_timers, num_timers_used); |
658 | } | 658 | } |
659 | 659 | ||
660 | #ifdef CONFIG_HPET | 660 | #ifdef CONFIG_HPET |
661 | static void hpet_reserve_msi_timers(struct hpet_data *hd) | 661 | static void hpet_reserve_msi_timers(struct hpet_data *hd) |
662 | { | 662 | { |
663 | int i; | 663 | int i; |
664 | 664 | ||
665 | if (!hpet_devs) | 665 | if (!hpet_devs) |
666 | return; | 666 | return; |
667 | 667 | ||
668 | for (i = 0; i < hpet_num_timers; i++) { | 668 | for (i = 0; i < hpet_num_timers; i++) { |
669 | struct hpet_dev *hdev = &hpet_devs[i]; | 669 | struct hpet_dev *hdev = &hpet_devs[i]; |
670 | 670 | ||
671 | if (!(hdev->flags & HPET_DEV_VALID)) | 671 | if (!(hdev->flags & HPET_DEV_VALID)) |
672 | continue; | 672 | continue; |
673 | 673 | ||
674 | hd->hd_irq[hdev->num] = hdev->irq; | 674 | hd->hd_irq[hdev->num] = hdev->irq; |
675 | hpet_reserve_timer(hd, hdev->num); | 675 | hpet_reserve_timer(hd, hdev->num); |
676 | } | 676 | } |
677 | } | 677 | } |
678 | #endif | 678 | #endif |
679 | 679 | ||
680 | static struct hpet_dev *hpet_get_unused_timer(void) | 680 | static struct hpet_dev *hpet_get_unused_timer(void) |
681 | { | 681 | { |
682 | int i; | 682 | int i; |
683 | 683 | ||
684 | if (!hpet_devs) | 684 | if (!hpet_devs) |
685 | return NULL; | 685 | return NULL; |
686 | 686 | ||
687 | for (i = 0; i < hpet_num_timers; i++) { | 687 | for (i = 0; i < hpet_num_timers; i++) { |
688 | struct hpet_dev *hdev = &hpet_devs[i]; | 688 | struct hpet_dev *hdev = &hpet_devs[i]; |
689 | 689 | ||
690 | if (!(hdev->flags & HPET_DEV_VALID)) | 690 | if (!(hdev->flags & HPET_DEV_VALID)) |
691 | continue; | 691 | continue; |
692 | if (test_and_set_bit(HPET_DEV_USED_BIT, | 692 | if (test_and_set_bit(HPET_DEV_USED_BIT, |
693 | (unsigned long *)&hdev->flags)) | 693 | (unsigned long *)&hdev->flags)) |
694 | continue; | 694 | continue; |
695 | return hdev; | 695 | return hdev; |
696 | } | 696 | } |
697 | return NULL; | 697 | return NULL; |
698 | } | 698 | } |
699 | 699 | ||
700 | struct hpet_work_struct { | 700 | struct hpet_work_struct { |
701 | struct delayed_work work; | 701 | struct delayed_work work; |
702 | struct completion complete; | 702 | struct completion complete; |
703 | }; | 703 | }; |
704 | 704 | ||
705 | static void hpet_work(struct work_struct *w) | 705 | static void hpet_work(struct work_struct *w) |
706 | { | 706 | { |
707 | struct hpet_dev *hdev; | 707 | struct hpet_dev *hdev; |
708 | int cpu = smp_processor_id(); | 708 | int cpu = smp_processor_id(); |
709 | struct hpet_work_struct *hpet_work; | 709 | struct hpet_work_struct *hpet_work; |
710 | 710 | ||
711 | hpet_work = container_of(w, struct hpet_work_struct, work.work); | 711 | hpet_work = container_of(w, struct hpet_work_struct, work.work); |
712 | 712 | ||
713 | hdev = hpet_get_unused_timer(); | 713 | hdev = hpet_get_unused_timer(); |
714 | if (hdev) | 714 | if (hdev) |
715 | init_one_hpet_msi_clockevent(hdev, cpu); | 715 | init_one_hpet_msi_clockevent(hdev, cpu); |
716 | 716 | ||
717 | complete(&hpet_work->complete); | 717 | complete(&hpet_work->complete); |
718 | } | 718 | } |
719 | 719 | ||
720 | static int hpet_cpuhp_notify(struct notifier_block *n, | 720 | static int hpet_cpuhp_notify(struct notifier_block *n, |
721 | unsigned long action, void *hcpu) | 721 | unsigned long action, void *hcpu) |
722 | { | 722 | { |
723 | unsigned long cpu = (unsigned long)hcpu; | 723 | unsigned long cpu = (unsigned long)hcpu; |
724 | struct hpet_work_struct work; | 724 | struct hpet_work_struct work; |
725 | struct hpet_dev *hdev = per_cpu(cpu_hpet_dev, cpu); | 725 | struct hpet_dev *hdev = per_cpu(cpu_hpet_dev, cpu); |
726 | 726 | ||
727 | switch (action & 0xf) { | 727 | switch (action & 0xf) { |
728 | case CPU_ONLINE: | 728 | case CPU_ONLINE: |
729 | INIT_DELAYED_WORK_ON_STACK(&work.work, hpet_work); | 729 | INIT_DELAYED_WORK_ON_STACK(&work.work, hpet_work); |
730 | init_completion(&work.complete); | 730 | init_completion(&work.complete); |
731 | /* FIXME: add schedule_work_on() */ | 731 | /* FIXME: add schedule_work_on() */ |
732 | schedule_delayed_work_on(cpu, &work.work, 0); | 732 | schedule_delayed_work_on(cpu, &work.work, 0); |
733 | wait_for_completion(&work.complete); | 733 | wait_for_completion(&work.complete); |
734 | destroy_timer_on_stack(&work.work.timer); | 734 | destroy_timer_on_stack(&work.work.timer); |
735 | break; | 735 | break; |
736 | case CPU_DEAD: | 736 | case CPU_DEAD: |
737 | if (hdev) { | 737 | if (hdev) { |
738 | free_irq(hdev->irq, hdev); | 738 | free_irq(hdev->irq, hdev); |
739 | hdev->flags &= ~HPET_DEV_USED; | 739 | hdev->flags &= ~HPET_DEV_USED; |
740 | per_cpu(cpu_hpet_dev, cpu) = NULL; | 740 | per_cpu(cpu_hpet_dev, cpu) = NULL; |
741 | } | 741 | } |
742 | break; | 742 | break; |
743 | } | 743 | } |
744 | return NOTIFY_OK; | 744 | return NOTIFY_OK; |
745 | } | 745 | } |
746 | #else | 746 | #else |
747 | 747 | ||
748 | static int hpet_setup_msi_irq(unsigned int irq) | 748 | static int hpet_setup_msi_irq(unsigned int irq) |
749 | { | 749 | { |
750 | return 0; | 750 | return 0; |
751 | } | 751 | } |
752 | static void hpet_msi_capability_lookup(unsigned int start_timer) | 752 | static void hpet_msi_capability_lookup(unsigned int start_timer) |
753 | { | 753 | { |
754 | return; | 754 | return; |
755 | } | 755 | } |
756 | 756 | ||
757 | #ifdef CONFIG_HPET | 757 | #ifdef CONFIG_HPET |
758 | static void hpet_reserve_msi_timers(struct hpet_data *hd) | 758 | static void hpet_reserve_msi_timers(struct hpet_data *hd) |
759 | { | 759 | { |
760 | return; | 760 | return; |
761 | } | 761 | } |
762 | #endif | 762 | #endif |
763 | 763 | ||
764 | static int hpet_cpuhp_notify(struct notifier_block *n, | 764 | static int hpet_cpuhp_notify(struct notifier_block *n, |
765 | unsigned long action, void *hcpu) | 765 | unsigned long action, void *hcpu) |
766 | { | 766 | { |
767 | return NOTIFY_OK; | 767 | return NOTIFY_OK; |
768 | } | 768 | } |
769 | 769 | ||
770 | #endif | 770 | #endif |
771 | 771 | ||
772 | /* | 772 | /* |
773 | * Clock source related code | 773 | * Clock source related code |
774 | */ | 774 | */ |
775 | static cycle_t read_hpet(struct clocksource *cs) | 775 | static cycle_t read_hpet(struct clocksource *cs) |
776 | { | 776 | { |
777 | return (cycle_t)hpet_readl(HPET_COUNTER); | 777 | return (cycle_t)hpet_readl(HPET_COUNTER); |
778 | } | 778 | } |
779 | 779 | ||
780 | #ifdef CONFIG_X86_64 | 780 | #ifdef CONFIG_X86_64 |
781 | static cycle_t __vsyscall_fn vread_hpet(void) | 781 | static cycle_t __vsyscall_fn vread_hpet(void) |
782 | { | 782 | { |
783 | return readl((const void __iomem *)fix_to_virt(VSYSCALL_HPET) + 0xf0); | 783 | return readl((const void __iomem *)fix_to_virt(VSYSCALL_HPET) + 0xf0); |
784 | } | 784 | } |
785 | #endif | 785 | #endif |
786 | 786 | ||
787 | static struct clocksource clocksource_hpet = { | 787 | static struct clocksource clocksource_hpet = { |
788 | .name = "hpet", | 788 | .name = "hpet", |
789 | .rating = 250, | 789 | .rating = 250, |
790 | .read = read_hpet, | 790 | .read = read_hpet, |
791 | .mask = HPET_MASK, | 791 | .mask = HPET_MASK, |
792 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | 792 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, |
793 | .resume = hpet_resume_counter, | 793 | .resume = hpet_resume_counter, |
794 | #ifdef CONFIG_X86_64 | 794 | #ifdef CONFIG_X86_64 |
795 | .vread = vread_hpet, | 795 | .vread = vread_hpet, |
796 | #endif | 796 | #endif |
797 | }; | 797 | }; |
798 | 798 | ||
799 | static int hpet_clocksource_register(void) | 799 | static int hpet_clocksource_register(void) |
800 | { | 800 | { |
801 | u64 start, now; | 801 | u64 start, now; |
802 | u64 hpet_freq; | 802 | u64 hpet_freq; |
803 | cycle_t t1; | 803 | cycle_t t1; |
804 | 804 | ||
805 | /* Start the counter */ | 805 | /* Start the counter */ |
806 | hpet_restart_counter(); | 806 | hpet_restart_counter(); |
807 | 807 | ||
808 | /* Verify whether hpet counter works */ | 808 | /* Verify whether hpet counter works */ |
809 | t1 = hpet_readl(HPET_COUNTER); | 809 | t1 = hpet_readl(HPET_COUNTER); |
810 | rdtscll(start); | 810 | rdtscll(start); |
811 | 811 | ||
812 | /* | 812 | /* |
813 | * We don't know the TSC frequency yet, but waiting for | 813 | * We don't know the TSC frequency yet, but waiting for |
814 | * 200000 TSC cycles is safe: | 814 | * 200000 TSC cycles is safe: |
815 | * 4 GHz == 50us | 815 | * 4 GHz == 50us |
816 | * 1 GHz == 200us | 816 | * 1 GHz == 200us |
817 | */ | 817 | */ |
818 | do { | 818 | do { |
819 | rep_nop(); | 819 | rep_nop(); |
820 | rdtscll(now); | 820 | rdtscll(now); |
821 | } while ((now - start) < 200000UL); | 821 | } while ((now - start) < 200000UL); |
822 | 822 | ||
823 | if (t1 == hpet_readl(HPET_COUNTER)) { | 823 | if (t1 == hpet_readl(HPET_COUNTER)) { |
824 | printk(KERN_WARNING | 824 | printk(KERN_WARNING |
825 | "HPET counter not counting. HPET disabled\n"); | 825 | "HPET counter not counting. HPET disabled\n"); |
826 | return -ENODEV; | 826 | return -ENODEV; |
827 | } | 827 | } |
828 | 828 | ||
829 | /* | 829 | /* |
830 | * The definition of mult is (include/linux/clocksource.h) | 830 | * The definition of mult is (include/linux/clocksource.h) |
831 | * mult/2^shift = ns/cyc and hpet_period is in units of fsec/cyc | 831 | * mult/2^shift = ns/cyc and hpet_period is in units of fsec/cyc |
832 | * so we first need to convert hpet_period to ns/cyc units: | 832 | * so we first need to convert hpet_period to ns/cyc units: |
833 | * mult/2^shift = ns/cyc = hpet_period/10^6 | 833 | * mult/2^shift = ns/cyc = hpet_period/10^6 |
834 | * mult = (hpet_period * 2^shift)/10^6 | 834 | * mult = (hpet_period * 2^shift)/10^6 |
835 | * mult = (hpet_period << shift)/FSEC_PER_NSEC | 835 | * mult = (hpet_period << shift)/FSEC_PER_NSEC |
836 | */ | 836 | */ |
837 | 837 | ||
838 | /* Need to convert hpet_period (fsec/cyc) to cyc/sec: | 838 | /* Need to convert hpet_period (fsec/cyc) to cyc/sec: |
839 | * | 839 | * |
840 | * cyc/sec = FSEC_PER_SEC/hpet_period(fsec/cyc) | 840 | * cyc/sec = FSEC_PER_SEC/hpet_period(fsec/cyc) |
841 | * cyc/sec = (FSEC_PER_NSEC * NSEC_PER_SEC)/hpet_period | 841 | * cyc/sec = (FSEC_PER_NSEC * NSEC_PER_SEC)/hpet_period |
842 | */ | 842 | */ |
843 | hpet_freq = FSEC_PER_SEC; | 843 | hpet_freq = FSEC_PER_SEC; |
844 | do_div(hpet_freq, hpet_period); | 844 | do_div(hpet_freq, hpet_period); |
845 | clocksource_register_hz(&clocksource_hpet, (u32)hpet_freq); | 845 | clocksource_register_hz(&clocksource_hpet, (u32)hpet_freq); |
846 | 846 | ||
847 | return 0; | 847 | return 0; |
848 | } | 848 | } |
849 | 849 | ||
850 | /** | 850 | /** |
851 | * hpet_enable - Try to setup the HPET timer. Returns 1 on success. | 851 | * hpet_enable - Try to setup the HPET timer. Returns 1 on success. |
852 | */ | 852 | */ |
853 | int __init hpet_enable(void) | 853 | int __init hpet_enable(void) |
854 | { | 854 | { |
855 | unsigned int id; | 855 | unsigned int id; |
856 | int i; | 856 | int i; |
857 | 857 | ||
858 | if (!is_hpet_capable()) | 858 | if (!is_hpet_capable()) |
859 | return 0; | 859 | return 0; |
860 | 860 | ||
861 | hpet_set_mapping(); | 861 | hpet_set_mapping(); |
862 | 862 | ||
863 | /* | 863 | /* |
864 | * Read the period and check for a sane value: | 864 | * Read the period and check for a sane value: |
865 | */ | 865 | */ |
866 | hpet_period = hpet_readl(HPET_PERIOD); | 866 | hpet_period = hpet_readl(HPET_PERIOD); |
867 | 867 | ||
868 | /* | 868 | /* |
869 | * AMD SB700 based systems with spread spectrum enabled use a | 869 | * AMD SB700 based systems with spread spectrum enabled use a |
870 | * SMM based HPET emulation to provide proper frequency | 870 | * SMM based HPET emulation to provide proper frequency |
871 | * setting. The SMM code is initialized with the first HPET | 871 | * setting. The SMM code is initialized with the first HPET |
872 | * register access and takes some time to complete. During | 872 | * register access and takes some time to complete. During |
873 | * this time the config register reads 0xffffffff. We check | 873 | * this time the config register reads 0xffffffff. We check |
874 | * for max. 1000 loops whether the config register reads a non | 874 | * for max. 1000 loops whether the config register reads a non |
875 | * 0xffffffff value to make sure that HPET is up and running | 875 | * 0xffffffff value to make sure that HPET is up and running |
876 | * before we go further. A counting loop is safe, as the HPET | 876 | * before we go further. A counting loop is safe, as the HPET |
877 | * access takes thousands of CPU cycles. On non SB700 based | 877 | * access takes thousands of CPU cycles. On non SB700 based |
878 | * machines this check is only done once and has no side | 878 | * machines this check is only done once and has no side |
879 | * effects. | 879 | * effects. |
880 | */ | 880 | */ |
881 | for (i = 0; hpet_readl(HPET_CFG) == 0xFFFFFFFF; i++) { | 881 | for (i = 0; hpet_readl(HPET_CFG) == 0xFFFFFFFF; i++) { |
882 | if (i == 1000) { | 882 | if (i == 1000) { |
883 | printk(KERN_WARNING | 883 | printk(KERN_WARNING |
884 | "HPET config register value = 0xFFFFFFFF. " | 884 | "HPET config register value = 0xFFFFFFFF. " |
885 | "Disabling HPET\n"); | 885 | "Disabling HPET\n"); |
886 | goto out_nohpet; | 886 | goto out_nohpet; |
887 | } | 887 | } |
888 | } | 888 | } |
889 | 889 | ||
890 | if (hpet_period < HPET_MIN_PERIOD || hpet_period > HPET_MAX_PERIOD) | 890 | if (hpet_period < HPET_MIN_PERIOD || hpet_period > HPET_MAX_PERIOD) |
891 | goto out_nohpet; | 891 | goto out_nohpet; |
892 | 892 | ||
893 | /* | 893 | /* |
894 | * Read the HPET ID register to retrieve the IRQ routing | 894 | * Read the HPET ID register to retrieve the IRQ routing |
895 | * information and the number of channels | 895 | * information and the number of channels |
896 | */ | 896 | */ |
897 | id = hpet_readl(HPET_ID); | 897 | id = hpet_readl(HPET_ID); |
898 | hpet_print_config(); | 898 | hpet_print_config(); |
899 | 899 | ||
900 | #ifdef CONFIG_HPET_EMULATE_RTC | 900 | #ifdef CONFIG_HPET_EMULATE_RTC |
901 | /* | 901 | /* |
902 | * The legacy routing mode needs at least two channels, tick timer | 902 | * The legacy routing mode needs at least two channels, tick timer |
903 | * and the rtc emulation channel. | 903 | * and the rtc emulation channel. |
904 | */ | 904 | */ |
905 | if (!(id & HPET_ID_NUMBER)) | 905 | if (!(id & HPET_ID_NUMBER)) |
906 | goto out_nohpet; | 906 | goto out_nohpet; |
907 | #endif | 907 | #endif |
908 | 908 | ||
909 | if (hpet_clocksource_register()) | 909 | if (hpet_clocksource_register()) |
910 | goto out_nohpet; | 910 | goto out_nohpet; |
911 | 911 | ||
912 | if (id & HPET_ID_LEGSUP) { | 912 | if (id & HPET_ID_LEGSUP) { |
913 | hpet_legacy_clockevent_register(); | 913 | hpet_legacy_clockevent_register(); |
914 | return 1; | 914 | return 1; |
915 | } | 915 | } |
916 | return 0; | 916 | return 0; |
917 | 917 | ||
918 | out_nohpet: | 918 | out_nohpet: |
919 | hpet_clear_mapping(); | 919 | hpet_clear_mapping(); |
920 | hpet_address = 0; | 920 | hpet_address = 0; |
921 | return 0; | 921 | return 0; |
922 | } | 922 | } |
923 | 923 | ||
924 | /* | 924 | /* |
925 | * Needs to be late, as the reserve_timer code calls kalloc ! | 925 | * Needs to be late, as the reserve_timer code calls kalloc ! |
926 | * | 926 | * |
927 | * Not a problem on i386 as hpet_enable is called from late_time_init, | 927 | * Not a problem on i386 as hpet_enable is called from late_time_init, |
928 | * but on x86_64 it is necessary ! | 928 | * but on x86_64 it is necessary ! |
929 | */ | 929 | */ |
930 | static __init int hpet_late_init(void) | 930 | static __init int hpet_late_init(void) |
931 | { | 931 | { |
932 | int cpu; | 932 | int cpu; |
933 | 933 | ||
934 | if (boot_hpet_disable) | 934 | if (boot_hpet_disable) |
935 | return -ENODEV; | 935 | return -ENODEV; |
936 | 936 | ||
937 | if (!hpet_address) { | 937 | if (!hpet_address) { |
938 | if (!force_hpet_address) | 938 | if (!force_hpet_address) |
939 | return -ENODEV; | 939 | return -ENODEV; |
940 | 940 | ||
941 | hpet_address = force_hpet_address; | 941 | hpet_address = force_hpet_address; |
942 | hpet_enable(); | 942 | hpet_enable(); |
943 | } | 943 | } |
944 | 944 | ||
945 | if (!hpet_virt_address) | 945 | if (!hpet_virt_address) |
946 | return -ENODEV; | 946 | return -ENODEV; |
947 | 947 | ||
948 | if (hpet_readl(HPET_ID) & HPET_ID_LEGSUP) | 948 | if (hpet_readl(HPET_ID) & HPET_ID_LEGSUP) |
949 | hpet_msi_capability_lookup(2); | 949 | hpet_msi_capability_lookup(2); |
950 | else | 950 | else |
951 | hpet_msi_capability_lookup(0); | 951 | hpet_msi_capability_lookup(0); |
952 | 952 | ||
953 | hpet_reserve_platform_timers(hpet_readl(HPET_ID)); | 953 | hpet_reserve_platform_timers(hpet_readl(HPET_ID)); |
954 | hpet_print_config(); | 954 | hpet_print_config(); |
955 | 955 | ||
956 | if (hpet_msi_disable) | 956 | if (hpet_msi_disable) |
957 | return 0; | 957 | return 0; |
958 | 958 | ||
959 | if (boot_cpu_has(X86_FEATURE_ARAT)) | 959 | if (boot_cpu_has(X86_FEATURE_ARAT)) |
960 | return 0; | 960 | return 0; |
961 | 961 | ||
962 | for_each_online_cpu(cpu) { | 962 | for_each_online_cpu(cpu) { |
963 | hpet_cpuhp_notify(NULL, CPU_ONLINE, (void *)(long)cpu); | 963 | hpet_cpuhp_notify(NULL, CPU_ONLINE, (void *)(long)cpu); |
964 | } | 964 | } |
965 | 965 | ||
966 | /* This notifier should be called after workqueue is ready */ | 966 | /* This notifier should be called after workqueue is ready */ |
967 | hotcpu_notifier(hpet_cpuhp_notify, -20); | 967 | hotcpu_notifier(hpet_cpuhp_notify, -20); |
968 | 968 | ||
969 | return 0; | 969 | return 0; |
970 | } | 970 | } |
971 | fs_initcall(hpet_late_init); | 971 | fs_initcall(hpet_late_init); |
972 | 972 | ||
973 | void hpet_disable(void) | 973 | void hpet_disable(void) |
974 | { | 974 | { |
975 | if (is_hpet_capable() && hpet_virt_address) { | 975 | if (is_hpet_capable() && hpet_virt_address) { |
976 | unsigned int cfg = hpet_readl(HPET_CFG); | 976 | unsigned int cfg = hpet_readl(HPET_CFG); |
977 | 977 | ||
978 | if (hpet_legacy_int_enabled) { | 978 | if (hpet_legacy_int_enabled) { |
979 | cfg &= ~HPET_CFG_LEGACY; | 979 | cfg &= ~HPET_CFG_LEGACY; |
980 | hpet_legacy_int_enabled = 0; | 980 | hpet_legacy_int_enabled = 0; |
981 | } | 981 | } |
982 | cfg &= ~HPET_CFG_ENABLE; | 982 | cfg &= ~HPET_CFG_ENABLE; |
983 | hpet_writel(cfg, HPET_CFG); | 983 | hpet_writel(cfg, HPET_CFG); |
984 | } | 984 | } |
985 | } | 985 | } |
986 | 986 | ||
987 | #ifdef CONFIG_HPET_EMULATE_RTC | 987 | #ifdef CONFIG_HPET_EMULATE_RTC |
988 | 988 | ||
989 | /* HPET in LegacyReplacement Mode eats up RTC interrupt line. When, HPET | 989 | /* HPET in LegacyReplacement Mode eats up RTC interrupt line. When, HPET |
990 | * is enabled, we support RTC interrupt functionality in software. | 990 | * is enabled, we support RTC interrupt functionality in software. |
991 | * RTC has 3 kinds of interrupts: | 991 | * RTC has 3 kinds of interrupts: |
992 | * 1) Update Interrupt - generate an interrupt, every sec, when RTC clock | 992 | * 1) Update Interrupt - generate an interrupt, every sec, when RTC clock |
993 | * is updated | 993 | * is updated |
994 | * 2) Alarm Interrupt - generate an interrupt at a specific time of day | 994 | * 2) Alarm Interrupt - generate an interrupt at a specific time of day |
995 | * 3) Periodic Interrupt - generate periodic interrupt, with frequencies | 995 | * 3) Periodic Interrupt - generate periodic interrupt, with frequencies |
996 | * 2Hz-8192Hz (2Hz-64Hz for non-root user) (all freqs in powers of 2) | 996 | * 2Hz-8192Hz (2Hz-64Hz for non-root user) (all freqs in powers of 2) |
997 | * (1) and (2) above are implemented using polling at a frequency of | 997 | * (1) and (2) above are implemented using polling at a frequency of |
998 | * 64 Hz. The exact frequency is a tradeoff between accuracy and interrupt | 998 | * 64 Hz. The exact frequency is a tradeoff between accuracy and interrupt |
999 | * overhead. (DEFAULT_RTC_INT_FREQ) | 999 | * overhead. (DEFAULT_RTC_INT_FREQ) |
1000 | * For (3), we use interrupts at 64Hz or user specified periodic | 1000 | * For (3), we use interrupts at 64Hz or user specified periodic |
1001 | * frequency, whichever is higher. | 1001 | * frequency, whichever is higher. |
1002 | */ | 1002 | */ |
1003 | #include <linux/mc146818rtc.h> | 1003 | #include <linux/mc146818rtc.h> |
1004 | #include <linux/rtc.h> | 1004 | #include <linux/rtc.h> |
1005 | #include <asm/rtc.h> | 1005 | #include <asm/rtc.h> |
1006 | 1006 | ||
1007 | #define DEFAULT_RTC_INT_FREQ 64 | 1007 | #define DEFAULT_RTC_INT_FREQ 64 |
1008 | #define DEFAULT_RTC_SHIFT 6 | 1008 | #define DEFAULT_RTC_SHIFT 6 |
1009 | #define RTC_NUM_INTS 1 | 1009 | #define RTC_NUM_INTS 1 |
1010 | 1010 | ||
1011 | static unsigned long hpet_rtc_flags; | 1011 | static unsigned long hpet_rtc_flags; |
1012 | static int hpet_prev_update_sec; | 1012 | static int hpet_prev_update_sec; |
1013 | static struct rtc_time hpet_alarm_time; | 1013 | static struct rtc_time hpet_alarm_time; |
1014 | static unsigned long hpet_pie_count; | 1014 | static unsigned long hpet_pie_count; |
1015 | static u32 hpet_t1_cmp; | 1015 | static u32 hpet_t1_cmp; |
1016 | static u32 hpet_default_delta; | 1016 | static u32 hpet_default_delta; |
1017 | static u32 hpet_pie_delta; | 1017 | static u32 hpet_pie_delta; |
1018 | static unsigned long hpet_pie_limit; | 1018 | static unsigned long hpet_pie_limit; |
1019 | 1019 | ||
1020 | static rtc_irq_handler irq_handler; | 1020 | static rtc_irq_handler irq_handler; |
1021 | 1021 | ||
1022 | /* | 1022 | /* |
1023 | * Check that the hpet counter c1 is ahead of the c2 | 1023 | * Check that the hpet counter c1 is ahead of the c2 |
1024 | */ | 1024 | */ |
1025 | static inline int hpet_cnt_ahead(u32 c1, u32 c2) | 1025 | static inline int hpet_cnt_ahead(u32 c1, u32 c2) |
1026 | { | 1026 | { |
1027 | return (s32)(c2 - c1) < 0; | 1027 | return (s32)(c2 - c1) < 0; |
1028 | } | 1028 | } |
1029 | 1029 | ||
1030 | /* | 1030 | /* |
1031 | * Registers a IRQ handler. | 1031 | * Registers a IRQ handler. |
1032 | */ | 1032 | */ |
1033 | int hpet_register_irq_handler(rtc_irq_handler handler) | 1033 | int hpet_register_irq_handler(rtc_irq_handler handler) |
1034 | { | 1034 | { |
1035 | if (!is_hpet_enabled()) | 1035 | if (!is_hpet_enabled()) |
1036 | return -ENODEV; | 1036 | return -ENODEV; |
1037 | if (irq_handler) | 1037 | if (irq_handler) |
1038 | return -EBUSY; | 1038 | return -EBUSY; |
1039 | 1039 | ||
1040 | irq_handler = handler; | 1040 | irq_handler = handler; |
1041 | 1041 | ||
1042 | return 0; | 1042 | return 0; |
1043 | } | 1043 | } |
1044 | EXPORT_SYMBOL_GPL(hpet_register_irq_handler); | 1044 | EXPORT_SYMBOL_GPL(hpet_register_irq_handler); |
1045 | 1045 | ||
1046 | /* | 1046 | /* |
1047 | * Deregisters the IRQ handler registered with hpet_register_irq_handler() | 1047 | * Deregisters the IRQ handler registered with hpet_register_irq_handler() |
1048 | * and does cleanup. | 1048 | * and does cleanup. |
1049 | */ | 1049 | */ |
1050 | void hpet_unregister_irq_handler(rtc_irq_handler handler) | 1050 | void hpet_unregister_irq_handler(rtc_irq_handler handler) |
1051 | { | 1051 | { |
1052 | if (!is_hpet_enabled()) | 1052 | if (!is_hpet_enabled()) |
1053 | return; | 1053 | return; |
1054 | 1054 | ||
1055 | irq_handler = NULL; | 1055 | irq_handler = NULL; |
1056 | hpet_rtc_flags = 0; | 1056 | hpet_rtc_flags = 0; |
1057 | } | 1057 | } |
1058 | EXPORT_SYMBOL_GPL(hpet_unregister_irq_handler); | 1058 | EXPORT_SYMBOL_GPL(hpet_unregister_irq_handler); |
1059 | 1059 | ||
1060 | /* | 1060 | /* |
1061 | * Timer 1 for RTC emulation. We use one shot mode, as periodic mode | 1061 | * Timer 1 for RTC emulation. We use one shot mode, as periodic mode |
1062 | * is not supported by all HPET implementations for timer 1. | 1062 | * is not supported by all HPET implementations for timer 1. |
1063 | * | 1063 | * |
1064 | * hpet_rtc_timer_init() is called when the rtc is initialized. | 1064 | * hpet_rtc_timer_init() is called when the rtc is initialized. |
1065 | */ | 1065 | */ |
1066 | int hpet_rtc_timer_init(void) | 1066 | int hpet_rtc_timer_init(void) |
1067 | { | 1067 | { |
1068 | unsigned int cfg, cnt, delta; | 1068 | unsigned int cfg, cnt, delta; |
1069 | unsigned long flags; | 1069 | unsigned long flags; |
1070 | 1070 | ||
1071 | if (!is_hpet_enabled()) | 1071 | if (!is_hpet_enabled()) |
1072 | return 0; | 1072 | return 0; |
1073 | 1073 | ||
1074 | if (!hpet_default_delta) { | 1074 | if (!hpet_default_delta) { |
1075 | uint64_t clc; | 1075 | uint64_t clc; |
1076 | 1076 | ||
1077 | clc = (uint64_t) hpet_clockevent.mult * NSEC_PER_SEC; | 1077 | clc = (uint64_t) hpet_clockevent.mult * NSEC_PER_SEC; |
1078 | clc >>= hpet_clockevent.shift + DEFAULT_RTC_SHIFT; | 1078 | clc >>= hpet_clockevent.shift + DEFAULT_RTC_SHIFT; |
1079 | hpet_default_delta = clc; | 1079 | hpet_default_delta = clc; |
1080 | } | 1080 | } |
1081 | 1081 | ||
1082 | if (!(hpet_rtc_flags & RTC_PIE) || hpet_pie_limit) | 1082 | if (!(hpet_rtc_flags & RTC_PIE) || hpet_pie_limit) |
1083 | delta = hpet_default_delta; | 1083 | delta = hpet_default_delta; |
1084 | else | 1084 | else |
1085 | delta = hpet_pie_delta; | 1085 | delta = hpet_pie_delta; |
1086 | 1086 | ||
1087 | local_irq_save(flags); | 1087 | local_irq_save(flags); |
1088 | 1088 | ||
1089 | cnt = delta + hpet_readl(HPET_COUNTER); | 1089 | cnt = delta + hpet_readl(HPET_COUNTER); |
1090 | hpet_writel(cnt, HPET_T1_CMP); | 1090 | hpet_writel(cnt, HPET_T1_CMP); |
1091 | hpet_t1_cmp = cnt; | 1091 | hpet_t1_cmp = cnt; |
1092 | 1092 | ||
1093 | cfg = hpet_readl(HPET_T1_CFG); | 1093 | cfg = hpet_readl(HPET_T1_CFG); |
1094 | cfg &= ~HPET_TN_PERIODIC; | 1094 | cfg &= ~HPET_TN_PERIODIC; |
1095 | cfg |= HPET_TN_ENABLE | HPET_TN_32BIT; | 1095 | cfg |= HPET_TN_ENABLE | HPET_TN_32BIT; |
1096 | hpet_writel(cfg, HPET_T1_CFG); | 1096 | hpet_writel(cfg, HPET_T1_CFG); |
1097 | 1097 | ||
1098 | local_irq_restore(flags); | 1098 | local_irq_restore(flags); |
1099 | 1099 | ||
1100 | return 1; | 1100 | return 1; |
1101 | } | 1101 | } |
1102 | EXPORT_SYMBOL_GPL(hpet_rtc_timer_init); | 1102 | EXPORT_SYMBOL_GPL(hpet_rtc_timer_init); |
1103 | 1103 | ||
1104 | /* | 1104 | /* |
1105 | * The functions below are called from rtc driver. | 1105 | * The functions below are called from rtc driver. |
1106 | * Return 0 if HPET is not being used. | 1106 | * Return 0 if HPET is not being used. |
1107 | * Otherwise do the necessary changes and return 1. | 1107 | * Otherwise do the necessary changes and return 1. |
1108 | */ | 1108 | */ |
1109 | int hpet_mask_rtc_irq_bit(unsigned long bit_mask) | 1109 | int hpet_mask_rtc_irq_bit(unsigned long bit_mask) |
1110 | { | 1110 | { |
1111 | if (!is_hpet_enabled()) | 1111 | if (!is_hpet_enabled()) |
1112 | return 0; | 1112 | return 0; |
1113 | 1113 | ||
1114 | hpet_rtc_flags &= ~bit_mask; | 1114 | hpet_rtc_flags &= ~bit_mask; |
1115 | return 1; | 1115 | return 1; |
1116 | } | 1116 | } |
1117 | EXPORT_SYMBOL_GPL(hpet_mask_rtc_irq_bit); | 1117 | EXPORT_SYMBOL_GPL(hpet_mask_rtc_irq_bit); |
1118 | 1118 | ||
1119 | int hpet_set_rtc_irq_bit(unsigned long bit_mask) | 1119 | int hpet_set_rtc_irq_bit(unsigned long bit_mask) |
1120 | { | 1120 | { |
1121 | unsigned long oldbits = hpet_rtc_flags; | 1121 | unsigned long oldbits = hpet_rtc_flags; |
1122 | 1122 | ||
1123 | if (!is_hpet_enabled()) | 1123 | if (!is_hpet_enabled()) |
1124 | return 0; | 1124 | return 0; |
1125 | 1125 | ||
1126 | hpet_rtc_flags |= bit_mask; | 1126 | hpet_rtc_flags |= bit_mask; |
1127 | 1127 | ||
1128 | if ((bit_mask & RTC_UIE) && !(oldbits & RTC_UIE)) | 1128 | if ((bit_mask & RTC_UIE) && !(oldbits & RTC_UIE)) |
1129 | hpet_prev_update_sec = -1; | 1129 | hpet_prev_update_sec = -1; |
1130 | 1130 | ||
1131 | if (!oldbits) | 1131 | if (!oldbits) |
1132 | hpet_rtc_timer_init(); | 1132 | hpet_rtc_timer_init(); |
1133 | 1133 | ||
1134 | return 1; | 1134 | return 1; |
1135 | } | 1135 | } |
1136 | EXPORT_SYMBOL_GPL(hpet_set_rtc_irq_bit); | 1136 | EXPORT_SYMBOL_GPL(hpet_set_rtc_irq_bit); |
1137 | 1137 | ||
1138 | int hpet_set_alarm_time(unsigned char hrs, unsigned char min, | 1138 | int hpet_set_alarm_time(unsigned char hrs, unsigned char min, |
1139 | unsigned char sec) | 1139 | unsigned char sec) |
1140 | { | 1140 | { |
1141 | if (!is_hpet_enabled()) | 1141 | if (!is_hpet_enabled()) |
1142 | return 0; | 1142 | return 0; |
1143 | 1143 | ||
1144 | hpet_alarm_time.tm_hour = hrs; | 1144 | hpet_alarm_time.tm_hour = hrs; |
1145 | hpet_alarm_time.tm_min = min; | 1145 | hpet_alarm_time.tm_min = min; |
1146 | hpet_alarm_time.tm_sec = sec; | 1146 | hpet_alarm_time.tm_sec = sec; |
1147 | 1147 | ||
1148 | return 1; | 1148 | return 1; |
1149 | } | 1149 | } |
1150 | EXPORT_SYMBOL_GPL(hpet_set_alarm_time); | 1150 | EXPORT_SYMBOL_GPL(hpet_set_alarm_time); |
1151 | 1151 | ||
1152 | int hpet_set_periodic_freq(unsigned long freq) | 1152 | int hpet_set_periodic_freq(unsigned long freq) |
1153 | { | 1153 | { |
1154 | uint64_t clc; | 1154 | uint64_t clc; |
1155 | 1155 | ||
1156 | if (!is_hpet_enabled()) | 1156 | if (!is_hpet_enabled()) |
1157 | return 0; | 1157 | return 0; |
1158 | 1158 | ||
1159 | if (freq <= DEFAULT_RTC_INT_FREQ) | 1159 | if (freq <= DEFAULT_RTC_INT_FREQ) |
1160 | hpet_pie_limit = DEFAULT_RTC_INT_FREQ / freq; | 1160 | hpet_pie_limit = DEFAULT_RTC_INT_FREQ / freq; |
1161 | else { | 1161 | else { |
1162 | clc = (uint64_t) hpet_clockevent.mult * NSEC_PER_SEC; | 1162 | clc = (uint64_t) hpet_clockevent.mult * NSEC_PER_SEC; |
1163 | do_div(clc, freq); | 1163 | do_div(clc, freq); |
1164 | clc >>= hpet_clockevent.shift; | 1164 | clc >>= hpet_clockevent.shift; |
1165 | hpet_pie_delta = clc; | 1165 | hpet_pie_delta = clc; |
1166 | hpet_pie_limit = 0; | 1166 | hpet_pie_limit = 0; |
1167 | } | 1167 | } |
1168 | return 1; | 1168 | return 1; |
1169 | } | 1169 | } |
1170 | EXPORT_SYMBOL_GPL(hpet_set_periodic_freq); | 1170 | EXPORT_SYMBOL_GPL(hpet_set_periodic_freq); |
1171 | 1171 | ||
1172 | int hpet_rtc_dropped_irq(void) | 1172 | int hpet_rtc_dropped_irq(void) |
1173 | { | 1173 | { |
1174 | return is_hpet_enabled(); | 1174 | return is_hpet_enabled(); |
1175 | } | 1175 | } |
1176 | EXPORT_SYMBOL_GPL(hpet_rtc_dropped_irq); | 1176 | EXPORT_SYMBOL_GPL(hpet_rtc_dropped_irq); |
1177 | 1177 | ||
1178 | static void hpet_rtc_timer_reinit(void) | 1178 | static void hpet_rtc_timer_reinit(void) |
1179 | { | 1179 | { |
1180 | unsigned int cfg, delta; | 1180 | unsigned int cfg, delta; |
1181 | int lost_ints = -1; | 1181 | int lost_ints = -1; |
1182 | 1182 | ||
1183 | if (unlikely(!hpet_rtc_flags)) { | 1183 | if (unlikely(!hpet_rtc_flags)) { |
1184 | cfg = hpet_readl(HPET_T1_CFG); | 1184 | cfg = hpet_readl(HPET_T1_CFG); |
1185 | cfg &= ~HPET_TN_ENABLE; | 1185 | cfg &= ~HPET_TN_ENABLE; |
1186 | hpet_writel(cfg, HPET_T1_CFG); | 1186 | hpet_writel(cfg, HPET_T1_CFG); |
1187 | return; | 1187 | return; |
1188 | } | 1188 | } |
1189 | 1189 | ||
1190 | if (!(hpet_rtc_flags & RTC_PIE) || hpet_pie_limit) | 1190 | if (!(hpet_rtc_flags & RTC_PIE) || hpet_pie_limit) |
1191 | delta = hpet_default_delta; | 1191 | delta = hpet_default_delta; |
1192 | else | 1192 | else |
1193 | delta = hpet_pie_delta; | 1193 | delta = hpet_pie_delta; |
1194 | 1194 | ||
1195 | /* | 1195 | /* |
1196 | * Increment the comparator value until we are ahead of the | 1196 | * Increment the comparator value until we are ahead of the |
1197 | * current count. | 1197 | * current count. |
1198 | */ | 1198 | */ |
1199 | do { | 1199 | do { |
1200 | hpet_t1_cmp += delta; | 1200 | hpet_t1_cmp += delta; |
1201 | hpet_writel(hpet_t1_cmp, HPET_T1_CMP); | 1201 | hpet_writel(hpet_t1_cmp, HPET_T1_CMP); |
1202 | lost_ints++; | 1202 | lost_ints++; |
1203 | } while (!hpet_cnt_ahead(hpet_t1_cmp, hpet_readl(HPET_COUNTER))); | 1203 | } while (!hpet_cnt_ahead(hpet_t1_cmp, hpet_readl(HPET_COUNTER))); |
1204 | 1204 | ||
1205 | if (lost_ints) { | 1205 | if (lost_ints) { |
1206 | if (hpet_rtc_flags & RTC_PIE) | 1206 | if (hpet_rtc_flags & RTC_PIE) |
1207 | hpet_pie_count += lost_ints; | 1207 | hpet_pie_count += lost_ints; |
1208 | if (printk_ratelimit()) | 1208 | if (printk_ratelimit()) |
1209 | printk(KERN_WARNING "hpet1: lost %d rtc interrupts\n", | 1209 | printk(KERN_WARNING "hpet1: lost %d rtc interrupts\n", |
1210 | lost_ints); | 1210 | lost_ints); |
1211 | } | 1211 | } |
1212 | } | 1212 | } |
1213 | 1213 | ||
1214 | irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id) | 1214 | irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id) |
1215 | { | 1215 | { |
1216 | struct rtc_time curr_time; | 1216 | struct rtc_time curr_time; |
1217 | unsigned long rtc_int_flag = 0; | 1217 | unsigned long rtc_int_flag = 0; |
1218 | 1218 | ||
1219 | hpet_rtc_timer_reinit(); | 1219 | hpet_rtc_timer_reinit(); |
1220 | memset(&curr_time, 0, sizeof(struct rtc_time)); | 1220 | memset(&curr_time, 0, sizeof(struct rtc_time)); |
1221 | 1221 | ||
1222 | if (hpet_rtc_flags & (RTC_UIE | RTC_AIE)) | 1222 | if (hpet_rtc_flags & (RTC_UIE | RTC_AIE)) |
1223 | get_rtc_time(&curr_time); | 1223 | get_rtc_time(&curr_time); |
1224 | 1224 | ||
1225 | if (hpet_rtc_flags & RTC_UIE && | 1225 | if (hpet_rtc_flags & RTC_UIE && |
1226 | curr_time.tm_sec != hpet_prev_update_sec) { | 1226 | curr_time.tm_sec != hpet_prev_update_sec) { |
1227 | if (hpet_prev_update_sec >= 0) | 1227 | if (hpet_prev_update_sec >= 0) |
1228 | rtc_int_flag = RTC_UF; | 1228 | rtc_int_flag = RTC_UF; |
1229 | hpet_prev_update_sec = curr_time.tm_sec; | 1229 | hpet_prev_update_sec = curr_time.tm_sec; |
1230 | } | 1230 | } |
1231 | 1231 | ||
1232 | if (hpet_rtc_flags & RTC_PIE && | 1232 | if (hpet_rtc_flags & RTC_PIE && |
1233 | ++hpet_pie_count >= hpet_pie_limit) { | 1233 | ++hpet_pie_count >= hpet_pie_limit) { |
1234 | rtc_int_flag |= RTC_PF; | 1234 | rtc_int_flag |= RTC_PF; |
1235 | hpet_pie_count = 0; | 1235 | hpet_pie_count = 0; |
1236 | } | 1236 | } |
1237 | 1237 | ||
1238 | if (hpet_rtc_flags & RTC_AIE && | 1238 | if (hpet_rtc_flags & RTC_AIE && |
1239 | (curr_time.tm_sec == hpet_alarm_time.tm_sec) && | 1239 | (curr_time.tm_sec == hpet_alarm_time.tm_sec) && |
1240 | (curr_time.tm_min == hpet_alarm_time.tm_min) && | 1240 | (curr_time.tm_min == hpet_alarm_time.tm_min) && |
1241 | (curr_time.tm_hour == hpet_alarm_time.tm_hour)) | 1241 | (curr_time.tm_hour == hpet_alarm_time.tm_hour)) |
1242 | rtc_int_flag |= RTC_AF; | 1242 | rtc_int_flag |= RTC_AF; |
1243 | 1243 | ||
1244 | if (rtc_int_flag) { | 1244 | if (rtc_int_flag) { |
1245 | rtc_int_flag |= (RTC_IRQF | (RTC_NUM_INTS << 8)); | 1245 | rtc_int_flag |= (RTC_IRQF | (RTC_NUM_INTS << 8)); |
1246 | if (irq_handler) | 1246 | if (irq_handler) |
1247 | irq_handler(rtc_int_flag, dev_id); | 1247 | irq_handler(rtc_int_flag, dev_id); |
1248 | } | 1248 | } |
1249 | return IRQ_HANDLED; | 1249 | return IRQ_HANDLED; |
1250 | } | 1250 | } |
1251 | EXPORT_SYMBOL_GPL(hpet_rtc_interrupt); | 1251 | EXPORT_SYMBOL_GPL(hpet_rtc_interrupt); |
1252 | #endif | 1252 | #endif |
1253 | 1253 |