aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/hpet.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kernel/hpet.c')
-rw-r--r--arch/x86/kernel/hpet.c85
1 files changed, 57 insertions, 28 deletions
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c
index dedc2bddf7a5..ad80a1c718c6 100644
--- a/arch/x86/kernel/hpet.c
+++ b/arch/x86/kernel/hpet.c
@@ -33,6 +33,9 @@
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 */
35unsigned long hpet_address; 35unsigned long hpet_address;
36u8 hpet_blockid; /* OS timer block num */
37u8 hpet_msi_disable;
38
36#ifdef CONFIG_PCI_MSI 39#ifdef CONFIG_PCI_MSI
37static unsigned long hpet_num_timers; 40static unsigned long hpet_num_timers;
38#endif 41#endif
@@ -47,12 +50,12 @@ struct hpet_dev {
47 char name[10]; 50 char name[10];
48}; 51};
49 52
50unsigned long hpet_readl(unsigned long a) 53inline unsigned int hpet_readl(unsigned int a)
51{ 54{
52 return readl(hpet_virt_address + a); 55 return readl(hpet_virt_address + a);
53} 56}
54 57
55static inline void hpet_writel(unsigned long d, unsigned long a) 58static inline void hpet_writel(unsigned int d, unsigned int a)
56{ 59{
57 writel(d, hpet_virt_address + a); 60 writel(d, hpet_virt_address + a);
58} 61}
@@ -167,7 +170,7 @@ do { \
167 170
168static void hpet_reserve_msi_timers(struct hpet_data *hd); 171static void hpet_reserve_msi_timers(struct hpet_data *hd);
169 172
170static void hpet_reserve_platform_timers(unsigned long id) 173static void hpet_reserve_platform_timers(unsigned int id)
171{ 174{
172 struct hpet __iomem *hpet = hpet_virt_address; 175 struct hpet __iomem *hpet = hpet_virt_address;
173 struct hpet_timer __iomem *timer = &hpet->hpet_timers[2]; 176 struct hpet_timer __iomem *timer = &hpet->hpet_timers[2];
@@ -205,7 +208,7 @@ static void hpet_reserve_platform_timers(unsigned long id)
205 208
206} 209}
207#else 210#else
208static void hpet_reserve_platform_timers(unsigned long id) { } 211static void hpet_reserve_platform_timers(unsigned int id) { }
209#endif 212#endif
210 213
211/* 214/*
@@ -246,7 +249,7 @@ static void hpet_reset_counter(void)
246 249
247static void hpet_start_counter(void) 250static void hpet_start_counter(void)
248{ 251{
249 unsigned long cfg = hpet_readl(HPET_CFG); 252 unsigned int cfg = hpet_readl(HPET_CFG);
250 cfg |= HPET_CFG_ENABLE; 253 cfg |= HPET_CFG_ENABLE;
251 hpet_writel(cfg, HPET_CFG); 254 hpet_writel(cfg, HPET_CFG);
252} 255}
@@ -271,7 +274,7 @@ static void hpet_resume_counter(void)
271 274
272static void hpet_enable_legacy_int(void) 275static void hpet_enable_legacy_int(void)
273{ 276{
274 unsigned long cfg = hpet_readl(HPET_CFG); 277 unsigned int cfg = hpet_readl(HPET_CFG);
275 278
276 cfg |= HPET_CFG_LEGACY; 279 cfg |= HPET_CFG_LEGACY;
277 hpet_writel(cfg, HPET_CFG); 280 hpet_writel(cfg, HPET_CFG);
@@ -314,7 +317,7 @@ static int hpet_setup_msi_irq(unsigned int irq);
314static void hpet_set_mode(enum clock_event_mode mode, 317static void hpet_set_mode(enum clock_event_mode mode,
315 struct clock_event_device *evt, int timer) 318 struct clock_event_device *evt, int timer)
316{ 319{
317 unsigned long cfg, cmp, now; 320 unsigned int cfg, cmp, now;
318 uint64_t delta; 321 uint64_t delta;
319 322
320 switch (mode) { 323 switch (mode) {
@@ -323,7 +326,7 @@ static void hpet_set_mode(enum clock_event_mode mode,
323 delta = ((uint64_t)(NSEC_PER_SEC/HZ)) * evt->mult; 326 delta = ((uint64_t)(NSEC_PER_SEC/HZ)) * evt->mult;
324 delta >>= evt->shift; 327 delta >>= evt->shift;
325 now = hpet_readl(HPET_COUNTER); 328 now = hpet_readl(HPET_COUNTER);
326 cmp = now + (unsigned long) delta; 329 cmp = now + (unsigned int) delta;
327 cfg = hpet_readl(HPET_Tn_CFG(timer)); 330 cfg = hpet_readl(HPET_Tn_CFG(timer));
328 /* Make sure we use edge triggered interrupts */ 331 /* Make sure we use edge triggered interrupts */
329 cfg &= ~HPET_TN_LEVEL; 332 cfg &= ~HPET_TN_LEVEL;
@@ -339,7 +342,7 @@ static void hpet_set_mode(enum clock_event_mode mode,
339 * (See AMD-8111 HyperTransport I/O Hub Data Sheet, 342 * (See AMD-8111 HyperTransport I/O Hub Data Sheet,
340 * Publication # 24674) 343 * Publication # 24674)
341 */ 344 */
342 hpet_writel((unsigned long) delta, HPET_Tn_CMP(timer)); 345 hpet_writel((unsigned int) delta, HPET_Tn_CMP(timer));
343 hpet_start_counter(); 346 hpet_start_counter();
344 hpet_print_config(); 347 hpet_print_config();
345 break; 348 break;
@@ -383,13 +386,24 @@ static int hpet_next_event(unsigned long delta,
383 hpet_writel(cnt, HPET_Tn_CMP(timer)); 386 hpet_writel(cnt, HPET_Tn_CMP(timer));
384 387
385 /* 388 /*
386 * We need to read back the CMP register to make sure that 389 * We need to read back the CMP register on certain HPET
387 * what we wrote hit the chip before we compare it to the 390 * implementations (ATI chipsets) which seem to delay the
388 * counter. 391 * transfer of the compare register into the internal compare
392 * logic. With small deltas this might actually be too late as
393 * the counter could already be higher than the compare value
394 * at that point and we would wait for the next hpet interrupt
395 * forever. We found out that reading the CMP register back
396 * forces the transfer so we can rely on the comparison with
397 * the counter register below. If the read back from the
398 * compare register does not match the value we programmed
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
401 * a prominent warning.
389 */ 402 */
390 WARN_ON_ONCE((u32)hpet_readl(HPET_Tn_CMP(timer)) != cnt); 403 WARN_ONCE(hpet_readl(HPET_Tn_CMP(timer)) != cnt,
404 KERN_WARNING "hpet: compare register read back failed.\n");
391 405
392 return (s32)((u32)hpet_readl(HPET_COUNTER) - cnt) >= 0 ? -ETIME : 0; 406 return (s32)(hpet_readl(HPET_COUNTER) - cnt) >= 0 ? -ETIME : 0;
393} 407}
394 408
395static void hpet_legacy_set_mode(enum clock_event_mode mode, 409static void hpet_legacy_set_mode(enum clock_event_mode mode,
@@ -415,7 +429,7 @@ static struct hpet_dev *hpet_devs;
415void hpet_msi_unmask(unsigned int irq) 429void hpet_msi_unmask(unsigned int irq)
416{ 430{
417 struct hpet_dev *hdev = get_irq_data(irq); 431 struct hpet_dev *hdev = get_irq_data(irq);
418 unsigned long cfg; 432 unsigned int cfg;
419 433
420 /* unmask it */ 434 /* unmask it */
421 cfg = hpet_readl(HPET_Tn_CFG(hdev->num)); 435 cfg = hpet_readl(HPET_Tn_CFG(hdev->num));
@@ -425,7 +439,7 @@ void hpet_msi_unmask(unsigned int irq)
425 439
426void hpet_msi_mask(unsigned int irq) 440void hpet_msi_mask(unsigned int irq)
427{ 441{
428 unsigned long cfg; 442 unsigned int cfg;
429 struct hpet_dev *hdev = get_irq_data(irq); 443 struct hpet_dev *hdev = get_irq_data(irq);
430 444
431 /* mask it */ 445 /* mask it */
@@ -467,7 +481,7 @@ static int hpet_msi_next_event(unsigned long delta,
467 481
468static int hpet_setup_msi_irq(unsigned int irq) 482static int hpet_setup_msi_irq(unsigned int irq)
469{ 483{
470 if (arch_setup_hpet_msi(irq)) { 484 if (arch_setup_hpet_msi(irq, hpet_blockid)) {
471 destroy_irq(irq); 485 destroy_irq(irq);
472 return -EINVAL; 486 return -EINVAL;
473 } 487 }
@@ -584,6 +598,11 @@ static void hpet_msi_capability_lookup(unsigned int start_timer)
584 unsigned int num_timers_used = 0; 598 unsigned int num_timers_used = 0;
585 int i; 599 int i;
586 600
601 if (hpet_msi_disable)
602 return;
603
604 if (boot_cpu_has(X86_FEATURE_ARAT))
605 return;
587 id = hpet_readl(HPET_ID); 606 id = hpet_readl(HPET_ID);
588 607
589 num_timers = ((id & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT); 608 num_timers = ((id & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT);
@@ -598,7 +617,7 @@ static void hpet_msi_capability_lookup(unsigned int start_timer)
598 617
599 for (i = start_timer; i < num_timers - RESERVE_TIMERS; i++) { 618 for (i = start_timer; i < num_timers - RESERVE_TIMERS; i++) {
600 struct hpet_dev *hdev = &hpet_devs[num_timers_used]; 619 struct hpet_dev *hdev = &hpet_devs[num_timers_used];
601 unsigned long cfg = hpet_readl(HPET_Tn_CFG(i)); 620 unsigned int cfg = hpet_readl(HPET_Tn_CFG(i));
602 621
603 /* Only consider HPET timer with MSI support */ 622 /* Only consider HPET timer with MSI support */
604 if (!(cfg & HPET_TN_FSB_CAP)) 623 if (!(cfg & HPET_TN_FSB_CAP))
@@ -813,7 +832,7 @@ static int hpet_clocksource_register(void)
813 */ 832 */
814int __init hpet_enable(void) 833int __init hpet_enable(void)
815{ 834{
816 unsigned long id; 835 unsigned int id;
817 int i; 836 int i;
818 837
819 if (!is_hpet_capable()) 838 if (!is_hpet_capable())
@@ -872,10 +891,8 @@ int __init hpet_enable(void)
872 891
873 if (id & HPET_ID_LEGSUP) { 892 if (id & HPET_ID_LEGSUP) {
874 hpet_legacy_clockevent_register(); 893 hpet_legacy_clockevent_register();
875 hpet_msi_capability_lookup(2);
876 return 1; 894 return 1;
877 } 895 }
878 hpet_msi_capability_lookup(0);
879 return 0; 896 return 0;
880 897
881out_nohpet: 898out_nohpet:
@@ -908,9 +925,20 @@ static __init int hpet_late_init(void)
908 if (!hpet_virt_address) 925 if (!hpet_virt_address)
909 return -ENODEV; 926 return -ENODEV;
910 927
928 if (hpet_readl(HPET_ID) & HPET_ID_LEGSUP)
929 hpet_msi_capability_lookup(2);
930 else
931 hpet_msi_capability_lookup(0);
932
911 hpet_reserve_platform_timers(hpet_readl(HPET_ID)); 933 hpet_reserve_platform_timers(hpet_readl(HPET_ID));
912 hpet_print_config(); 934 hpet_print_config();
913 935
936 if (hpet_msi_disable)
937 return 0;
938
939 if (boot_cpu_has(X86_FEATURE_ARAT))
940 return 0;
941
914 for_each_online_cpu(cpu) { 942 for_each_online_cpu(cpu) {
915 hpet_cpuhp_notify(NULL, CPU_ONLINE, (void *)(long)cpu); 943 hpet_cpuhp_notify(NULL, CPU_ONLINE, (void *)(long)cpu);
916 } 944 }
@@ -925,7 +953,7 @@ fs_initcall(hpet_late_init);
925void hpet_disable(void) 953void hpet_disable(void)
926{ 954{
927 if (is_hpet_capable()) { 955 if (is_hpet_capable()) {
928 unsigned long cfg = hpet_readl(HPET_CFG); 956 unsigned int cfg = hpet_readl(HPET_CFG);
929 957
930 if (hpet_legacy_int_enabled) { 958 if (hpet_legacy_int_enabled) {
931 cfg &= ~HPET_CFG_LEGACY; 959 cfg &= ~HPET_CFG_LEGACY;
@@ -965,8 +993,8 @@ static int hpet_prev_update_sec;
965static struct rtc_time hpet_alarm_time; 993static struct rtc_time hpet_alarm_time;
966static unsigned long hpet_pie_count; 994static unsigned long hpet_pie_count;
967static u32 hpet_t1_cmp; 995static u32 hpet_t1_cmp;
968static unsigned long hpet_default_delta; 996static u32 hpet_default_delta;
969static unsigned long hpet_pie_delta; 997static u32 hpet_pie_delta;
970static unsigned long hpet_pie_limit; 998static unsigned long hpet_pie_limit;
971 999
972static rtc_irq_handler irq_handler; 1000static rtc_irq_handler irq_handler;
@@ -1017,7 +1045,8 @@ EXPORT_SYMBOL_GPL(hpet_unregister_irq_handler);
1017 */ 1045 */
1018int hpet_rtc_timer_init(void) 1046int hpet_rtc_timer_init(void)
1019{ 1047{
1020 unsigned long cfg, cnt, delta, flags; 1048 unsigned int cfg, cnt, delta;
1049 unsigned long flags;
1021 1050
1022 if (!is_hpet_enabled()) 1051 if (!is_hpet_enabled())
1023 return 0; 1052 return 0;
@@ -1027,7 +1056,7 @@ int hpet_rtc_timer_init(void)
1027 1056
1028 clc = (uint64_t) hpet_clockevent.mult * NSEC_PER_SEC; 1057 clc = (uint64_t) hpet_clockevent.mult * NSEC_PER_SEC;
1029 clc >>= hpet_clockevent.shift + DEFAULT_RTC_SHIFT; 1058 clc >>= hpet_clockevent.shift + DEFAULT_RTC_SHIFT;
1030 hpet_default_delta = (unsigned long) clc; 1059 hpet_default_delta = clc;
1031 } 1060 }
1032 1061
1033 if (!(hpet_rtc_flags & RTC_PIE) || hpet_pie_limit) 1062 if (!(hpet_rtc_flags & RTC_PIE) || hpet_pie_limit)
@@ -1113,7 +1142,7 @@ int hpet_set_periodic_freq(unsigned long freq)
1113 clc = (uint64_t) hpet_clockevent.mult * NSEC_PER_SEC; 1142 clc = (uint64_t) hpet_clockevent.mult * NSEC_PER_SEC;
1114 do_div(clc, freq); 1143 do_div(clc, freq);
1115 clc >>= hpet_clockevent.shift; 1144 clc >>= hpet_clockevent.shift;
1116 hpet_pie_delta = (unsigned long) clc; 1145 hpet_pie_delta = clc;
1117 } 1146 }
1118 return 1; 1147 return 1;
1119} 1148}
@@ -1127,7 +1156,7 @@ EXPORT_SYMBOL_GPL(hpet_rtc_dropped_irq);
1127 1156
1128static void hpet_rtc_timer_reinit(void) 1157static void hpet_rtc_timer_reinit(void)
1129{ 1158{
1130 unsigned long cfg, delta; 1159 unsigned int cfg, delta;
1131 int lost_ints = -1; 1160 int lost_ints = -1;
1132 1161
1133 if (unlikely(!hpet_rtc_flags)) { 1162 if (unlikely(!hpet_rtc_flags)) {