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.c59
1 files changed, 51 insertions, 8 deletions
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c
index ad0de0c2714..70bce5db1bb 100644
--- a/arch/x86/kernel/hpet.c
+++ b/arch/x86/kernel/hpet.c
@@ -319,8 +319,6 @@ static void hpet_set_mode(enum clock_event_mode mode,
319 now = hpet_readl(HPET_COUNTER); 319 now = hpet_readl(HPET_COUNTER);
320 cmp = now + (unsigned int) delta; 320 cmp = now + (unsigned int) delta;
321 cfg = hpet_readl(HPET_Tn_CFG(timer)); 321 cfg = hpet_readl(HPET_Tn_CFG(timer));
322 /* Make sure we use edge triggered interrupts */
323 cfg &= ~HPET_TN_LEVEL;
324 cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC | 322 cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC |
325 HPET_TN_SETVAL | HPET_TN_32BIT; 323 HPET_TN_SETVAL | HPET_TN_32BIT;
326 hpet_writel(cfg, HPET_Tn_CFG(timer)); 324 hpet_writel(cfg, HPET_Tn_CFG(timer));
@@ -787,15 +785,16 @@ static int hpet_clocksource_register(void)
787 return 0; 785 return 0;
788} 786}
789 787
788static u32 *hpet_boot_cfg;
789
790/** 790/**
791 * hpet_enable - Try to setup the HPET timer. Returns 1 on success. 791 * hpet_enable - Try to setup the HPET timer. Returns 1 on success.
792 */ 792 */
793int __init hpet_enable(void) 793int __init hpet_enable(void)
794{ 794{
795 unsigned long hpet_period; 795 u32 hpet_period, cfg, id;
796 unsigned int id;
797 u64 freq; 796 u64 freq;
798 int i; 797 unsigned int i, last;
799 798
800 if (!is_hpet_capable()) 799 if (!is_hpet_capable())
801 return 0; 800 return 0;
@@ -847,15 +846,45 @@ int __init hpet_enable(void)
847 id = hpet_readl(HPET_ID); 846 id = hpet_readl(HPET_ID);
848 hpet_print_config(); 847 hpet_print_config();
849 848
849 last = (id & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT;
850
850#ifdef CONFIG_HPET_EMULATE_RTC 851#ifdef CONFIG_HPET_EMULATE_RTC
851 /* 852 /*
852 * The legacy routing mode needs at least two channels, tick timer 853 * The legacy routing mode needs at least two channels, tick timer
853 * and the rtc emulation channel. 854 * and the rtc emulation channel.
854 */ 855 */
855 if (!(id & HPET_ID_NUMBER)) 856 if (!last)
856 goto out_nohpet; 857 goto out_nohpet;
857#endif 858#endif
858 859
860 cfg = hpet_readl(HPET_CFG);
861 hpet_boot_cfg = kmalloc((last + 2) * sizeof(*hpet_boot_cfg),
862 GFP_KERNEL);
863 if (hpet_boot_cfg)
864 *hpet_boot_cfg = cfg;
865 else
866 pr_warn("HPET initial state will not be saved\n");
867 cfg &= ~(HPET_CFG_ENABLE | HPET_CFG_LEGACY);
868 hpet_writel(cfg, HPET_Tn_CFG(i));
869 if (cfg)
870 pr_warn("HPET: Unrecognized bits %#x set in global cfg\n",
871 cfg);
872
873 for (i = 0; i <= last; ++i) {
874 cfg = hpet_readl(HPET_Tn_CFG(i));
875 if (hpet_boot_cfg)
876 hpet_boot_cfg[i + 1] = cfg;
877 cfg &= ~(HPET_TN_ENABLE | HPET_TN_LEVEL | HPET_TN_FSB);
878 hpet_writel(cfg, HPET_Tn_CFG(i));
879 cfg &= ~(HPET_TN_PERIODIC | HPET_TN_PERIODIC_CAP
880 | HPET_TN_64BIT_CAP | HPET_TN_32BIT | HPET_TN_ROUTE
881 | HPET_TN_FSB | HPET_TN_FSB_CAP);
882 if (cfg)
883 pr_warn("HPET: Unrecognized bits %#x set in cfg#%u\n",
884 cfg, i);
885 }
886 hpet_print_config();
887
859 if (hpet_clocksource_register()) 888 if (hpet_clocksource_register())
860 goto out_nohpet; 889 goto out_nohpet;
861 890
@@ -923,14 +952,28 @@ fs_initcall(hpet_late_init);
923void hpet_disable(void) 952void hpet_disable(void)
924{ 953{
925 if (is_hpet_capable() && hpet_virt_address) { 954 if (is_hpet_capable() && hpet_virt_address) {
926 unsigned int cfg = hpet_readl(HPET_CFG); 955 unsigned int cfg = hpet_readl(HPET_CFG), id, last;
927 956
928 if (hpet_legacy_int_enabled) { 957 if (hpet_boot_cfg)
958 cfg = *hpet_boot_cfg;
959 else if (hpet_legacy_int_enabled) {
929 cfg &= ~HPET_CFG_LEGACY; 960 cfg &= ~HPET_CFG_LEGACY;
930 hpet_legacy_int_enabled = 0; 961 hpet_legacy_int_enabled = 0;
931 } 962 }
932 cfg &= ~HPET_CFG_ENABLE; 963 cfg &= ~HPET_CFG_ENABLE;
933 hpet_writel(cfg, HPET_CFG); 964 hpet_writel(cfg, HPET_CFG);
965
966 if (!hpet_boot_cfg)
967 return;
968
969 id = hpet_readl(HPET_ID);
970 last = ((id & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT);
971
972 for (id = 0; id <= last; ++id)
973 hpet_writel(hpet_boot_cfg[id + 1], HPET_Tn_CFG(id));
974
975 if (*hpet_boot_cfg & HPET_CFG_ENABLE)
976 hpet_writel(*hpet_boot_cfg, HPET_CFG);
934 } 977 }
935} 978}
936 979