diff options
| -rw-r--r-- | arch/x86/kernel/Makefile_32 | 4 | ||||
| -rw-r--r-- | arch/x86/kernel/Makefile_64 | 4 | ||||
| -rw-r--r-- | arch/x86/kernel/apic_64.c | 106 | ||||
| -rw-r--r-- | arch/x86/kernel/hpet.c (renamed from arch/x86/kernel/hpet_32.c) | 0 | ||||
| -rw-r--r-- | arch/x86/kernel/hpet_64.c | 444 | ||||
| -rw-r--r-- | arch/x86/kernel/i8253.c (renamed from arch/x86/kernel/i8253_32.c) | 0 | ||||
| -rw-r--r-- | arch/x86/kernel/time_64.c | 42 | ||||
| -rw-r--r-- | include/asm-x86/apic_64.h | 6 | ||||
| -rw-r--r-- | include/asm-x86/proto.h | 7 |
9 files changed, 5 insertions, 608 deletions
diff --git a/arch/x86/kernel/Makefile_32 b/arch/x86/kernel/Makefile_32 index 10356443998e..7ff02063b858 100644 --- a/arch/x86/kernel/Makefile_32 +++ b/arch/x86/kernel/Makefile_32 | |||
| @@ -7,7 +7,7 @@ extra-y := head_32.o init_task_32.o vmlinux.lds | |||
| 7 | obj-y := process_32.o signal_32.o entry_32.o traps_32.o irq_32.o \ | 7 | obj-y := process_32.o signal_32.o entry_32.o traps_32.o irq_32.o \ |
| 8 | ptrace_32.o time_32.o ioport_32.o ldt_32.o setup_32.o i8259_32.o sys_i386_32.o \ | 8 | ptrace_32.o time_32.o ioport_32.o ldt_32.o setup_32.o i8259_32.o sys_i386_32.o \ |
| 9 | pci-dma_32.o i386_ksyms_32.o i387_32.o bootflag.o e820_32.o\ | 9 | pci-dma_32.o i386_ksyms_32.o i387_32.o bootflag.o e820_32.o\ |
| 10 | quirks.o i8237.o topology.o alternative.o i8253_32.o tsc_32.o | 10 | quirks.o i8237.o topology.o alternative.o i8253.o tsc_32.o |
| 11 | 11 | ||
| 12 | obj-$(CONFIG_STACKTRACE) += stacktrace.o | 12 | obj-$(CONFIG_STACKTRACE) += stacktrace.o |
| 13 | obj-y += cpu/ | 13 | obj-y += cpu/ |
| @@ -37,7 +37,7 @@ obj-$(CONFIG_EFI) += efi_32.o efi_stub_32.o | |||
| 37 | obj-$(CONFIG_DOUBLEFAULT) += doublefault_32.o | 37 | obj-$(CONFIG_DOUBLEFAULT) += doublefault_32.o |
| 38 | obj-$(CONFIG_VM86) += vm86_32.o | 38 | obj-$(CONFIG_VM86) += vm86_32.o |
| 39 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o | 39 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o |
| 40 | obj-$(CONFIG_HPET_TIMER) += hpet_32.o | 40 | obj-$(CONFIG_HPET_TIMER) += hpet.o |
| 41 | obj-$(CONFIG_K8_NB) += k8.o | 41 | obj-$(CONFIG_K8_NB) += k8.o |
| 42 | obj-$(CONFIG_MGEODE_LX) += geode_32.o mfgpt_32.o | 42 | obj-$(CONFIG_MGEODE_LX) += geode_32.o mfgpt_32.o |
| 43 | 43 | ||
diff --git a/arch/x86/kernel/Makefile_64 b/arch/x86/kernel/Makefile_64 index 080154e31502..43da66213a47 100644 --- a/arch/x86/kernel/Makefile_64 +++ b/arch/x86/kernel/Makefile_64 | |||
| @@ -8,8 +8,8 @@ obj-y := process_64.o signal_64.o entry_64.o traps_64.o irq_64.o \ | |||
| 8 | ptrace_64.o time_64.o ioport_64.o ldt_64.o setup_64.o i8259_64.o sys_x86_64.o \ | 8 | ptrace_64.o time_64.o ioport_64.o ldt_64.o setup_64.o i8259_64.o sys_x86_64.o \ |
| 9 | x8664_ksyms_64.o i387_64.o syscall_64.o vsyscall_64.o \ | 9 | x8664_ksyms_64.o i387_64.o syscall_64.o vsyscall_64.o \ |
| 10 | setup64.o bootflag.o e820_64.o reboot_64.o quirks.o i8237.o \ | 10 | setup64.o bootflag.o e820_64.o reboot_64.o quirks.o i8237.o \ |
| 11 | pci-dma_64.o pci-nommu_64.o alternative.o hpet_32.o tsc_64.o bugs_64.o \ | 11 | pci-dma_64.o pci-nommu_64.o alternative.o hpet.o tsc_64.o bugs_64.o \ |
| 12 | perfctr-watchdog.o i8253_32.o | 12 | perfctr-watchdog.o i8253.o |
| 13 | 13 | ||
| 14 | obj-$(CONFIG_STACKTRACE) += stacktrace.o | 14 | obj-$(CONFIG_STACKTRACE) += stacktrace.o |
| 15 | obj-$(CONFIG_X86_MCE) += mce_64.o therm_throt.o | 15 | obj-$(CONFIG_X86_MCE) += mce_64.o therm_throt.o |
diff --git a/arch/x86/kernel/apic_64.c b/arch/x86/kernel/apic_64.c index 118830cba1ae..1231365404c4 100644 --- a/arch/x86/kernel/apic_64.c +++ b/arch/x86/kernel/apic_64.c | |||
| @@ -41,7 +41,6 @@ | |||
| 41 | #include <asm/apic.h> | 41 | #include <asm/apic.h> |
| 42 | 42 | ||
| 43 | int apic_verbosity; | 43 | int apic_verbosity; |
| 44 | int apic_runs_main_timer; | ||
| 45 | int apic_calibrate_pmtmr __initdata; | 44 | int apic_calibrate_pmtmr __initdata; |
| 46 | 45 | ||
| 47 | int disable_apic_timer __cpuinitdata; | 46 | int disable_apic_timer __cpuinitdata; |
| @@ -129,15 +128,6 @@ static void lapic_timer_broadcast(cpumask_t mask) | |||
| 129 | #endif | 128 | #endif |
| 130 | } | 129 | } |
| 131 | 130 | ||
| 132 | /* | ||
| 133 | * cpu_mask that denotes the CPUs that needs timer interrupt coming in as | ||
| 134 | * IPIs in place of local APIC timers | ||
| 135 | */ | ||
| 136 | static cpumask_t timer_interrupt_broadcast_ipi_mask; | ||
| 137 | |||
| 138 | /* Using APIC to generate smp_local_timer_interrupt? */ | ||
| 139 | int using_apic_timer __read_mostly = 0; | ||
| 140 | |||
| 141 | static void apic_pm_activate(void); | 131 | static void apic_pm_activate(void); |
| 142 | 132 | ||
| 143 | void apic_wait_icr_idle(void) | 133 | void apic_wait_icr_idle(void) |
| @@ -973,84 +963,6 @@ void __cpuinit setup_secondary_APIC_clock(void) | |||
| 973 | setup_APIC_timer(); | 963 | setup_APIC_timer(); |
| 974 | } | 964 | } |
| 975 | 965 | ||
| 976 | void disable_APIC_timer(void) | ||
| 977 | { | ||
| 978 | if (using_apic_timer) { | ||
| 979 | unsigned long v; | ||
| 980 | |||
| 981 | v = apic_read(APIC_LVTT); | ||
| 982 | /* | ||
| 983 | * When an illegal vector value (0-15) is written to an LVT | ||
| 984 | * entry and delivery mode is Fixed, the APIC may signal an | ||
| 985 | * illegal vector error, with out regard to whether the mask | ||
| 986 | * bit is set or whether an interrupt is actually seen on input. | ||
| 987 | * | ||
| 988 | * Boot sequence might call this function when the LVTT has | ||
| 989 | * '0' vector value. So make sure vector field is set to | ||
| 990 | * valid value. | ||
| 991 | */ | ||
| 992 | v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR); | ||
| 993 | apic_write(APIC_LVTT, v); | ||
| 994 | } | ||
| 995 | } | ||
| 996 | |||
| 997 | void enable_APIC_timer(void) | ||
| 998 | { | ||
| 999 | int cpu = smp_processor_id(); | ||
| 1000 | |||
| 1001 | if (using_apic_timer && | ||
| 1002 | !cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask)) { | ||
| 1003 | unsigned long v; | ||
| 1004 | |||
| 1005 | v = apic_read(APIC_LVTT); | ||
| 1006 | apic_write(APIC_LVTT, v & ~APIC_LVT_MASKED); | ||
| 1007 | } | ||
| 1008 | } | ||
| 1009 | |||
| 1010 | void switch_APIC_timer_to_ipi(void *cpumask) | ||
| 1011 | { | ||
| 1012 | cpumask_t mask = *(cpumask_t *)cpumask; | ||
| 1013 | int cpu = smp_processor_id(); | ||
| 1014 | |||
| 1015 | if (cpu_isset(cpu, mask) && | ||
| 1016 | !cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask)) { | ||
| 1017 | disable_APIC_timer(); | ||
| 1018 | cpu_set(cpu, timer_interrupt_broadcast_ipi_mask); | ||
| 1019 | } | ||
| 1020 | } | ||
| 1021 | EXPORT_SYMBOL(switch_APIC_timer_to_ipi); | ||
| 1022 | |||
| 1023 | void smp_send_timer_broadcast_ipi(void) | ||
| 1024 | { | ||
| 1025 | int cpu = smp_processor_id(); | ||
| 1026 | cpumask_t mask; | ||
| 1027 | |||
| 1028 | cpus_and(mask, cpu_online_map, timer_interrupt_broadcast_ipi_mask); | ||
| 1029 | |||
| 1030 | if (cpu_isset(cpu, mask)) { | ||
| 1031 | cpu_clear(cpu, mask); | ||
| 1032 | add_pda(apic_timer_irqs, 1); | ||
| 1033 | smp_local_timer_interrupt(); | ||
| 1034 | } | ||
| 1035 | |||
| 1036 | if (!cpus_empty(mask)) { | ||
| 1037 | send_IPI_mask(mask, LOCAL_TIMER_VECTOR); | ||
| 1038 | } | ||
| 1039 | } | ||
| 1040 | |||
| 1041 | void switch_ipi_to_APIC_timer(void *cpumask) | ||
| 1042 | { | ||
| 1043 | cpumask_t mask = *(cpumask_t *)cpumask; | ||
| 1044 | int cpu = smp_processor_id(); | ||
| 1045 | |||
| 1046 | if (cpu_isset(cpu, mask) && | ||
| 1047 | cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask)) { | ||
| 1048 | cpu_clear(cpu, timer_interrupt_broadcast_ipi_mask); | ||
| 1049 | enable_APIC_timer(); | ||
| 1050 | } | ||
| 1051 | } | ||
| 1052 | EXPORT_SYMBOL(switch_ipi_to_APIC_timer); | ||
| 1053 | |||
| 1054 | int setup_profiling_timer(unsigned int multiplier) | 966 | int setup_profiling_timer(unsigned int multiplier) |
| 1055 | { | 967 | { |
| 1056 | return -EINVAL; | 968 | return -EINVAL; |
| @@ -1297,21 +1209,7 @@ static __init int setup_noapictimer(char *str) | |||
| 1297 | disable_apic_timer = 1; | 1209 | disable_apic_timer = 1; |
| 1298 | return 1; | 1210 | return 1; |
| 1299 | } | 1211 | } |
| 1300 | 1212 | __setup("noapictimer", setup_noapictimer); | |
| 1301 | static __init int setup_apicmaintimer(char *str) | ||
| 1302 | { | ||
| 1303 | apic_runs_main_timer = 1; | ||
| 1304 | |||
| 1305 | return 1; | ||
| 1306 | } | ||
| 1307 | __setup("apicmaintimer", setup_apicmaintimer); | ||
| 1308 | |||
| 1309 | static __init int setup_noapicmaintimer(char *str) | ||
| 1310 | { | ||
| 1311 | apic_runs_main_timer = -1; | ||
| 1312 | return 1; | ||
| 1313 | } | ||
| 1314 | __setup("noapicmaintimer", setup_noapicmaintimer); | ||
| 1315 | 1213 | ||
| 1316 | static __init int setup_apicpmtimer(char *s) | 1214 | static __init int setup_apicpmtimer(char *s) |
| 1317 | { | 1215 | { |
| @@ -1321,5 +1219,3 @@ static __init int setup_apicpmtimer(char *s) | |||
| 1321 | } | 1219 | } |
| 1322 | __setup("apicpmtimer", setup_apicpmtimer); | 1220 | __setup("apicpmtimer", setup_apicpmtimer); |
| 1323 | 1221 | ||
| 1324 | __setup("noapictimer", setup_noapictimer); | ||
| 1325 | |||
diff --git a/arch/x86/kernel/hpet_32.c b/arch/x86/kernel/hpet.c index dbe0e1d44113..dbe0e1d44113 100644 --- a/arch/x86/kernel/hpet_32.c +++ b/arch/x86/kernel/hpet.c | |||
diff --git a/arch/x86/kernel/hpet_64.c b/arch/x86/kernel/hpet_64.c deleted file mode 100644 index 1ebce2ec7eaf..000000000000 --- a/arch/x86/kernel/hpet_64.c +++ /dev/null | |||
| @@ -1,444 +0,0 @@ | |||
| 1 | #include <linux/kernel.h> | ||
| 2 | #include <linux/sched.h> | ||
| 3 | #include <linux/init.h> | ||
| 4 | #include <linux/mc146818rtc.h> | ||
| 5 | #include <linux/time.h> | ||
| 6 | #include <linux/clocksource.h> | ||
| 7 | #include <linux/ioport.h> | ||
| 8 | #include <linux/acpi.h> | ||
| 9 | #include <linux/hpet.h> | ||
| 10 | #include <asm/pgtable.h> | ||
| 11 | #include <asm/vsyscall.h> | ||
| 12 | #include <asm/timex.h> | ||
| 13 | #include <asm/hpet.h> | ||
| 14 | |||
| 15 | #define HPET_MASK 0xFFFFFFFF | ||
| 16 | #define HPET_SHIFT 22 | ||
| 17 | |||
| 18 | /* FSEC = 10^-15 NSEC = 10^-9 */ | ||
| 19 | #define FSEC_PER_NSEC 1000000 | ||
| 20 | |||
| 21 | int nohpet __initdata; | ||
| 22 | |||
| 23 | unsigned long hpet_address; | ||
| 24 | unsigned long hpet_period; /* fsecs / HPET clock */ | ||
| 25 | unsigned long hpet_tick; /* HPET clocks / interrupt */ | ||
| 26 | |||
| 27 | int hpet_use_timer; /* Use counter of hpet for time keeping, | ||
| 28 | * otherwise PIT | ||
| 29 | */ | ||
| 30 | |||
| 31 | #ifdef CONFIG_HPET | ||
| 32 | static __init int late_hpet_init(void) | ||
| 33 | { | ||
| 34 | struct hpet_data hd; | ||
| 35 | unsigned int ntimer; | ||
| 36 | |||
| 37 | if (!hpet_address) | ||
| 38 | return 0; | ||
| 39 | |||
| 40 | memset(&hd, 0, sizeof(hd)); | ||
| 41 | |||
| 42 | ntimer = hpet_readl(HPET_ID); | ||
| 43 | ntimer = (ntimer & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT; | ||
| 44 | ntimer++; | ||
| 45 | |||
| 46 | /* | ||
| 47 | * Register with driver. | ||
| 48 | * Timer0 and Timer1 is used by platform. | ||
| 49 | */ | ||
| 50 | hd.hd_phys_address = hpet_address; | ||
| 51 | hd.hd_address = (void __iomem *)fix_to_virt(FIX_HPET_BASE); | ||
| 52 | hd.hd_nirqs = ntimer; | ||
| 53 | hd.hd_flags = HPET_DATA_PLATFORM; | ||
| 54 | hpet_reserve_timer(&hd, 0); | ||
| 55 | #ifdef CONFIG_HPET_EMULATE_RTC | ||
| 56 | hpet_reserve_timer(&hd, 1); | ||
| 57 | #endif | ||
| 58 | hd.hd_irq[0] = HPET_LEGACY_8254; | ||
| 59 | hd.hd_irq[1] = HPET_LEGACY_RTC; | ||
| 60 | if (ntimer > 2) { | ||
| 61 | struct hpet *hpet; | ||
| 62 | struct hpet_timer *timer; | ||
| 63 | int i; | ||
| 64 | |||
| 65 | hpet = (struct hpet *) fix_to_virt(FIX_HPET_BASE); | ||
| 66 | timer = &hpet->hpet_timers[2]; | ||
| 67 | for (i = 2; i < ntimer; timer++, i++) | ||
| 68 | hd.hd_irq[i] = (timer->hpet_config & | ||
| 69 | Tn_INT_ROUTE_CNF_MASK) >> | ||
| 70 | Tn_INT_ROUTE_CNF_SHIFT; | ||
| 71 | |||
| 72 | } | ||
| 73 | |||
| 74 | hpet_alloc(&hd); | ||
| 75 | return 0; | ||
| 76 | } | ||
| 77 | fs_initcall(late_hpet_init); | ||
| 78 | #endif | ||
| 79 | |||
| 80 | int hpet_timer_stop_set_go(unsigned long tick) | ||
| 81 | { | ||
| 82 | unsigned int cfg; | ||
| 83 | |||
| 84 | /* | ||
| 85 | * Stop the timers and reset the main counter. | ||
| 86 | */ | ||
| 87 | |||
| 88 | cfg = hpet_readl(HPET_CFG); | ||
| 89 | cfg &= ~(HPET_CFG_ENABLE | HPET_CFG_LEGACY); | ||
| 90 | hpet_writel(cfg, HPET_CFG); | ||
| 91 | hpet_writel(0, HPET_COUNTER); | ||
| 92 | hpet_writel(0, HPET_COUNTER + 4); | ||
| 93 | |||
| 94 | /* | ||
| 95 | * Set up timer 0, as periodic with first interrupt to happen at hpet_tick, | ||
| 96 | * and period also hpet_tick. | ||
| 97 | */ | ||
| 98 | if (hpet_use_timer) { | ||
| 99 | hpet_writel(HPET_TN_ENABLE | HPET_TN_PERIODIC | HPET_TN_SETVAL | | ||
| 100 | HPET_TN_32BIT, HPET_T0_CFG); | ||
| 101 | hpet_writel(hpet_tick, HPET_T0_CMP); /* next interrupt */ | ||
| 102 | hpet_writel(hpet_tick, HPET_T0_CMP); /* period */ | ||
| 103 | cfg |= HPET_CFG_LEGACY; | ||
| 104 | } | ||
| 105 | /* | ||
| 106 | * Go! | ||
| 107 | */ | ||
| 108 | |||
| 109 | cfg |= HPET_CFG_ENABLE; | ||
| 110 | hpet_writel(cfg, HPET_CFG); | ||
| 111 | |||
| 112 | return 0; | ||
| 113 | } | ||
| 114 | |||
| 115 | static cycle_t read_hpet(void) | ||
| 116 | { | ||
| 117 | return (cycle_t)hpet_readl(HPET_COUNTER); | ||
| 118 | } | ||
| 119 | |||
| 120 | static cycle_t __vsyscall_fn vread_hpet(void) | ||
| 121 | { | ||
| 122 | return readl((void __iomem *)fix_to_virt(VSYSCALL_HPET) + 0xf0); | ||
| 123 | } | ||
| 124 | |||
| 125 | struct clocksource clocksource_hpet = { | ||
| 126 | .name = "hpet", | ||
| 127 | .rating = 250, | ||
| 128 | .read = read_hpet, | ||
| 129 | .mask = (cycle_t)HPET_MASK, | ||
| 130 | .mult = 0, /* set below */ | ||
| 131 | .shift = HPET_SHIFT, | ||
| 132 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
| 133 | .vread = vread_hpet, | ||
| 134 | }; | ||
| 135 | |||
| 136 | int __init hpet_arch_init(void) | ||
| 137 | { | ||
| 138 | unsigned int id; | ||
| 139 | u64 tmp; | ||
| 140 | |||
| 141 | if (!hpet_address) | ||
| 142 | return -1; | ||
| 143 | set_fixmap_nocache(FIX_HPET_BASE, hpet_address); | ||
| 144 | __set_fixmap(VSYSCALL_HPET, hpet_address, PAGE_KERNEL_VSYSCALL_NOCACHE); | ||
| 145 | |||
| 146 | /* | ||
| 147 | * Read the period, compute tick and quotient. | ||
| 148 | */ | ||
| 149 | |||
| 150 | id = hpet_readl(HPET_ID); | ||
| 151 | |||
| 152 | if (!(id & HPET_ID_VENDOR) || !(id & HPET_ID_NUMBER)) | ||
| 153 | return -1; | ||
| 154 | |||
| 155 | hpet_period = hpet_readl(HPET_PERIOD); | ||
| 156 | if (hpet_period < 100000 || hpet_period > 100000000) | ||
| 157 | return -1; | ||
| 158 | |||
| 159 | hpet_tick = (FSEC_PER_TICK + hpet_period / 2) / hpet_period; | ||
| 160 | |||
| 161 | hpet_use_timer = (id & HPET_ID_LEGSUP); | ||
| 162 | |||
| 163 | /* | ||
| 164 | * hpet period is in femto seconds per cycle | ||
| 165 | * so we need to convert this to ns/cyc units | ||
| 166 | * aproximated by mult/2^shift | ||
| 167 | * | ||
| 168 | * fsec/cyc * 1nsec/1000000fsec = nsec/cyc = mult/2^shift | ||
| 169 | * fsec/cyc * 1ns/1000000fsec * 2^shift = mult | ||
| 170 | * fsec/cyc * 2^shift * 1nsec/1000000fsec = mult | ||
| 171 | * (fsec/cyc << shift)/1000000 = mult | ||
| 172 | * (hpet_period << shift)/FSEC_PER_NSEC = mult | ||
| 173 | */ | ||
| 174 | tmp = (u64)hpet_period << HPET_SHIFT; | ||
| 175 | do_div(tmp, FSEC_PER_NSEC); | ||
| 176 | clocksource_hpet.mult = (u32)tmp; | ||
| 177 | clocksource_register(&clocksource_hpet); | ||
| 178 | |||
| 179 | return hpet_timer_stop_set_go(hpet_tick); | ||
| 180 | } | ||
| 181 | |||
| 182 | int hpet_reenable(void) | ||
| 183 | { | ||
| 184 | return hpet_timer_stop_set_go(hpet_tick); | ||
| 185 | } | ||
| 186 | |||
| 187 | #ifdef CONFIG_HPET_EMULATE_RTC | ||
| 188 | /* HPET in LegacyReplacement Mode eats up RTC interrupt line. When, HPET | ||
| 189 | * is enabled, we support RTC interrupt functionality in software. | ||
| 190 | * RTC has 3 kinds of interrupts: | ||
| 191 | * 1) Update Interrupt - generate an interrupt, every sec, when RTC clock | ||
| 192 | * is updated | ||
| 193 | * 2) Alarm Interrupt - generate an interrupt at a specific time of day | ||
| 194 | * 3) Periodic Interrupt - generate periodic interrupt, with frequencies | ||
| 195 | * 2Hz-8192Hz (2Hz-64Hz for non-root user) (all freqs in powers of 2) | ||
| 196 | * (1) and (2) above are implemented using polling at a frequency of | ||
| 197 | * 64 Hz. The exact frequency is a tradeoff between accuracy and interrupt | ||
| 198 | * overhead. (DEFAULT_RTC_INT_FREQ) | ||
| 199 | * For (3), we use interrupts at 64Hz or user specified periodic | ||
| 200 | * frequency, whichever is higher. | ||
| 201 | */ | ||
| 202 | #include <linux/rtc.h> | ||
| 203 | |||
| 204 | #define DEFAULT_RTC_INT_FREQ 64 | ||
| 205 | #define RTC_NUM_INTS 1 | ||
| 206 | |||
| 207 | static unsigned long UIE_on; | ||
| 208 | static unsigned long prev_update_sec; | ||
| 209 | |||
| 210 | static unsigned long AIE_on; | ||
| 211 | static struct rtc_time alarm_time; | ||
| 212 | |||
| 213 | static unsigned long PIE_on; | ||
| 214 | static unsigned long PIE_freq = DEFAULT_RTC_INT_FREQ; | ||
| 215 | static unsigned long PIE_count; | ||
| 216 | |||
| 217 | static unsigned long hpet_rtc_int_freq; /* RTC interrupt frequency */ | ||
| 218 | static unsigned int hpet_t1_cmp; /* cached comparator register */ | ||
| 219 | |||
| 220 | int is_hpet_enabled(void) | ||
| 221 | { | ||
| 222 | return hpet_address != 0; | ||
| 223 | } | ||
| 224 | |||
| 225 | /* | ||
| 226 | * Timer 1 for RTC, we do not use periodic interrupt feature, | ||
| 227 | * even if HPET supports periodic interrupts on Timer 1. | ||
| 228 | * The reason being, to set up a periodic interrupt in HPET, we need to | ||
| 229 | * stop the main counter. And if we do that everytime someone diables/enables | ||
| 230 | * RTC, we will have adverse effect on main kernel timer running on Timer 0. | ||
| 231 | * So, for the time being, simulate the periodic interrupt in software. | ||
| 232 | * | ||
| 233 | * hpet_rtc_timer_init() is called for the first time and during subsequent | ||
| 234 | * interuppts reinit happens through hpet_rtc_timer_reinit(). | ||
| 235 | */ | ||
| 236 | int hpet_rtc_timer_init(void) | ||
| 237 | { | ||
| 238 | unsigned int cfg, cnt; | ||
| 239 | unsigned long flags; | ||
| 240 | |||
| 241 | if (!is_hpet_enabled()) | ||
| 242 | return 0; | ||
| 243 | /* | ||
| 244 | * Set the counter 1 and enable the interrupts. | ||
| 245 | */ | ||
| 246 | if (PIE_on && (PIE_freq > DEFAULT_RTC_INT_FREQ)) | ||
| 247 | hpet_rtc_int_freq = PIE_freq; | ||
| 248 | else | ||
| 249 | hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ; | ||
| 250 | |||
| 251 | local_irq_save(flags); | ||
| 252 | |||
| 253 | cnt = hpet_readl(HPET_COUNTER); | ||
| 254 | cnt += ((hpet_tick*HZ)/hpet_rtc_int_freq); | ||
| 255 | hpet_writel(cnt, HPET_T1_CMP); | ||
| 256 | hpet_t1_cmp = cnt; | ||
| 257 | |||
| 258 | cfg = hpet_readl(HPET_T1_CFG); | ||
| 259 | cfg &= ~HPET_TN_PERIODIC; | ||
| 260 | cfg |= HPET_TN_ENABLE | HPET_TN_32BIT; | ||
| 261 | hpet_writel(cfg, HPET_T1_CFG); | ||
| 262 | |||
| 263 | local_irq_restore(flags); | ||
| 264 | |||
| 265 | return 1; | ||
| 266 | } | ||
| 267 | |||
| 268 | static void hpet_rtc_timer_reinit(void) | ||
| 269 | { | ||
| 270 | unsigned int cfg, cnt, ticks_per_int, lost_ints; | ||
| 271 | |||
| 272 | if (unlikely(!(PIE_on | AIE_on | UIE_on))) { | ||
| 273 | cfg = hpet_readl(HPET_T1_CFG); | ||
| 274 | cfg &= ~HPET_TN_ENABLE; | ||
| 275 | hpet_writel(cfg, HPET_T1_CFG); | ||
| 276 | return; | ||
| 277 | } | ||
| 278 | |||
| 279 | if (PIE_on && (PIE_freq > DEFAULT_RTC_INT_FREQ)) | ||
| 280 | hpet_rtc_int_freq = PIE_freq; | ||
| 281 | else | ||
| 282 | hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ; | ||
| 283 | |||
| 284 | /* It is more accurate to use the comparator value than current count.*/ | ||
| 285 | ticks_per_int = hpet_tick * HZ / hpet_rtc_int_freq; | ||
| 286 | hpet_t1_cmp += ticks_per_int; | ||
| 287 | hpet_writel(hpet_t1_cmp, HPET_T1_CMP); | ||
| 288 | |||
| 289 | /* | ||
| 290 | * If the interrupt handler was delayed too long, the write above tries | ||
| 291 | * to schedule the next interrupt in the past and the hardware would | ||
| 292 | * not interrupt until the counter had wrapped around. | ||
| 293 | * So we have to check that the comparator wasn't set to a past time. | ||
| 294 | */ | ||
| 295 | cnt = hpet_readl(HPET_COUNTER); | ||
| 296 | if (unlikely((int)(cnt - hpet_t1_cmp) > 0)) { | ||
| 297 | lost_ints = (cnt - hpet_t1_cmp) / ticks_per_int + 1; | ||
| 298 | /* Make sure that, even with the time needed to execute | ||
| 299 | * this code, the next scheduled interrupt has been moved | ||
| 300 | * back to the future: */ | ||
| 301 | lost_ints++; | ||
| 302 | |||
| 303 | hpet_t1_cmp += lost_ints * ticks_per_int; | ||
| 304 | hpet_writel(hpet_t1_cmp, HPET_T1_CMP); | ||
| 305 | |||
| 306 | if (PIE_on) | ||
| 307 | PIE_count += lost_ints; | ||
| 308 | |||
| 309 | if (printk_ratelimit()) | ||
| 310 | printk(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n", | ||
| 311 | hpet_rtc_int_freq); | ||
| 312 | } | ||
| 313 | } | ||
| 314 | |||
| 315 | /* | ||
| 316 | * The functions below are called from rtc driver. | ||
| 317 | * Return 0 if HPET is not being used. | ||
| 318 | * Otherwise do the necessary changes and return 1. | ||
| 319 | */ | ||
| 320 | int hpet_mask_rtc_irq_bit(unsigned long bit_mask) | ||
| 321 | { | ||
| 322 | if (!is_hpet_enabled()) | ||
| 323 | return 0; | ||
| 324 | |||
| 325 | if (bit_mask & RTC_UIE) | ||
| 326 | UIE_on = 0; | ||
| 327 | if (bit_mask & RTC_PIE) | ||
| 328 | PIE_on = 0; | ||
| 329 | if (bit_mask & RTC_AIE) | ||
| 330 | AIE_on = 0; | ||
| 331 | |||
| 332 | return 1; | ||
| 333 | } | ||
| 334 | |||
| 335 | int hpet_set_rtc_irq_bit(unsigned long bit_mask) | ||
| 336 | { | ||
| 337 | int timer_init_reqd = 0; | ||
| 338 | |||
| 339 | if (!is_hpet_enabled()) | ||
| 340 | return 0; | ||
| 341 | |||
| 342 | if (!(PIE_on | AIE_on | UIE_on)) | ||
| 343 | timer_init_reqd = 1; | ||
| 344 | |||
| 345 | if (bit_mask & RTC_UIE) { | ||
| 346 | UIE_on = 1; | ||
| 347 | } | ||
| 348 | if (bit_mask & RTC_PIE) { | ||
| 349 | PIE_on = 1; | ||
| 350 | PIE_count = 0; | ||
| 351 | } | ||
| 352 | if (bit_mask & RTC_AIE) { | ||
| 353 | AIE_on = 1; | ||
| 354 | } | ||
| 355 | |||
| 356 | if (timer_init_reqd) | ||
| 357 | hpet_rtc_timer_init(); | ||
| 358 | |||
| 359 | return 1; | ||
| 360 | } | ||
| 361 | |||
| 362 | int hpet_set_alarm_time(unsigned char hrs, unsigned char min, unsigned char sec) | ||
| 363 | { | ||
| 364 | if (!is_hpet_enabled()) | ||
| 365 | return 0; | ||
| 366 | |||
| 367 | alarm_time.tm_hour = hrs; | ||
| 368 | alarm_time.tm_min = min; | ||
| 369 | alarm_time.tm_sec = sec; | ||
| 370 | |||
| 371 | return 1; | ||
| 372 | } | ||
| 373 | |||
| 374 | int hpet_set_periodic_freq(unsigned long freq) | ||
| 375 | { | ||
| 376 | if (!is_hpet_enabled()) | ||
| 377 | return 0; | ||
| 378 | |||
| 379 | PIE_freq = freq; | ||
| 380 | PIE_count = 0; | ||
| 381 | |||
| 382 | return 1; | ||
| 383 | } | ||
| 384 | |||
| 385 | int hpet_rtc_dropped_irq(void) | ||
| 386 | { | ||
| 387 | if (!is_hpet_enabled()) | ||
| 388 | return 0; | ||
| 389 | |||
| 390 | return 1; | ||
| 391 | } | ||
| 392 | |||
| 393 | irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id) | ||
| 394 | { | ||
| 395 | struct rtc_time curr_time; | ||
| 396 | unsigned long rtc_int_flag = 0; | ||
| 397 | int call_rtc_interrupt = 0; | ||
| 398 | |||
| 399 | hpet_rtc_timer_reinit(); | ||
| 400 | |||
| 401 | if (UIE_on | AIE_on) { | ||
| 402 | rtc_get_rtc_time(&curr_time); | ||
| 403 | } | ||
| 404 | if (UIE_on) { | ||
| 405 | if (curr_time.tm_sec != prev_update_sec) { | ||
| 406 | /* Set update int info, call real rtc int routine */ | ||
| 407 | call_rtc_interrupt = 1; | ||
| 408 | rtc_int_flag = RTC_UF; | ||
| 409 | prev_update_sec = curr_time.tm_sec; | ||
| 410 | } | ||
| 411 | } | ||
| 412 | if (PIE_on) { | ||
| 413 | PIE_count++; | ||
| 414 | if (PIE_count >= hpet_rtc_int_freq/PIE_freq) { | ||
| 415 | /* Set periodic int info, call real rtc int routine */ | ||
| 416 | call_rtc_interrupt = 1; | ||
| 417 | rtc_int_flag |= RTC_PF; | ||
| 418 | PIE_count = 0; | ||
| 419 | } | ||
| 420 | } | ||
| 421 | if (AIE_on) { | ||
| 422 | if ((curr_time.tm_sec == alarm_time.tm_sec) && | ||
| 423 | (curr_time.tm_min == alarm_time.tm_min) && | ||
| 424 | (curr_time.tm_hour == alarm_time.tm_hour)) { | ||
| 425 | /* Set alarm int info, call real rtc int routine */ | ||
| 426 | call_rtc_interrupt = 1; | ||
| 427 | rtc_int_flag |= RTC_AF; | ||
| 428 | } | ||
| 429 | } | ||
| 430 | if (call_rtc_interrupt) { | ||
| 431 | rtc_int_flag |= (RTC_IRQF | (RTC_NUM_INTS << 8)); | ||
| 432 | rtc_interrupt(rtc_int_flag, dev_id); | ||
| 433 | } | ||
| 434 | return IRQ_HANDLED; | ||
| 435 | } | ||
| 436 | #endif | ||
| 437 | |||
| 438 | static int __init nohpet_setup(char *s) | ||
| 439 | { | ||
| 440 | nohpet = 1; | ||
| 441 | return 1; | ||
| 442 | } | ||
| 443 | |||
| 444 | __setup("nohpet", nohpet_setup); | ||
diff --git a/arch/x86/kernel/i8253_32.c b/arch/x86/kernel/i8253.c index ac15e4cbd9c1..ac15e4cbd9c1 100644 --- a/arch/x86/kernel/i8253_32.c +++ b/arch/x86/kernel/i8253.c | |||
diff --git a/arch/x86/kernel/time_64.c b/arch/x86/kernel/time_64.c index aca081c37884..e0134d6c88da 100644 --- a/arch/x86/kernel/time_64.c +++ b/arch/x86/kernel/time_64.c | |||
| @@ -150,48 +150,6 @@ int update_persistent_clock(struct timespec now) | |||
| 150 | return set_rtc_mmss(now.tv_sec); | 150 | return set_rtc_mmss(now.tv_sec); |
| 151 | } | 151 | } |
| 152 | 152 | ||
| 153 | void main_timer_handler(void) | ||
| 154 | { | ||
| 155 | /* | ||
| 156 | * Here we are in the timer irq handler. We have irqs locally disabled (so we | ||
| 157 | * don't need spin_lock_irqsave()) but we don't know if the timer_bh is running | ||
| 158 | * on the other CPU, so we need a lock. We also need to lock the vsyscall | ||
| 159 | * variables, because both do_timer() and us change them -arca+vojtech | ||
| 160 | */ | ||
| 161 | |||
| 162 | write_seqlock(&xtime_lock); | ||
| 163 | |||
| 164 | /* | ||
| 165 | * Do the timer stuff. | ||
| 166 | */ | ||
| 167 | |||
| 168 | do_timer(1); | ||
| 169 | #ifndef CONFIG_SMP | ||
| 170 | update_process_times(user_mode(get_irq_regs())); | ||
| 171 | #endif | ||
| 172 | |||
| 173 | /* | ||
| 174 | * In the SMP case we use the local APIC timer interrupt to do the profiling, | ||
| 175 | * except when we simulate SMP mode on a uniprocessor system, in that case we | ||
| 176 | * have to call the local interrupt handler. | ||
| 177 | */ | ||
| 178 | |||
| 179 | if (!using_apic_timer) | ||
| 180 | smp_local_timer_interrupt(); | ||
| 181 | |||
| 182 | write_sequnlock(&xtime_lock); | ||
| 183 | } | ||
| 184 | |||
| 185 | static irqreturn_t timer_interrupt(int irq, void *dev_id) | ||
| 186 | { | ||
| 187 | if (apic_runs_main_timer > 1) | ||
| 188 | return IRQ_HANDLED; | ||
| 189 | main_timer_handler(); | ||
| 190 | if (using_apic_timer) | ||
| 191 | smp_send_timer_broadcast_ipi(); | ||
| 192 | return IRQ_HANDLED; | ||
| 193 | } | ||
| 194 | |||
| 195 | static irqreturn_t timer_event_interrupt(int irq, void *dev_id) | 153 | static irqreturn_t timer_event_interrupt(int irq, void *dev_id) |
| 196 | { | 154 | { |
| 197 | add_pda(irq0_irqs, 1); | 155 | add_pda(irq0_irqs, 1); |
diff --git a/include/asm-x86/apic_64.h b/include/asm-x86/apic_64.h index f32f654d1f96..3c8f21eef0be 100644 --- a/include/asm-x86/apic_64.h +++ b/include/asm-x86/apic_64.h | |||
| @@ -79,8 +79,6 @@ extern void smp_local_timer_interrupt (void); | |||
| 79 | extern void setup_boot_APIC_clock (void); | 79 | extern void setup_boot_APIC_clock (void); |
| 80 | extern void setup_secondary_APIC_clock (void); | 80 | extern void setup_secondary_APIC_clock (void); |
| 81 | extern int APIC_init_uniprocessor (void); | 81 | extern int APIC_init_uniprocessor (void); |
| 82 | extern void disable_APIC_timer(void); | ||
| 83 | extern void enable_APIC_timer(void); | ||
| 84 | extern void setup_apic_routing(void); | 82 | extern void setup_apic_routing(void); |
| 85 | 83 | ||
| 86 | extern void setup_APIC_extended_lvt(unsigned char lvt_off, unsigned char vector, | 84 | extern void setup_APIC_extended_lvt(unsigned char lvt_off, unsigned char vector, |
| @@ -95,10 +93,6 @@ extern int apic_is_clustered_box(void); | |||
| 95 | #define K8_APIC_EXT_INT_MSG_EXT 0x7 | 93 | #define K8_APIC_EXT_INT_MSG_EXT 0x7 |
| 96 | #define K8_APIC_EXT_LVT_ENTRY_THRESHOLD 0 | 94 | #define K8_APIC_EXT_LVT_ENTRY_THRESHOLD 0 |
| 97 | 95 | ||
| 98 | void smp_send_timer_broadcast_ipi(void); | ||
| 99 | void switch_APIC_timer_to_ipi(void *cpumask); | ||
| 100 | void switch_ipi_to_APIC_timer(void *cpumask); | ||
| 101 | |||
| 102 | #define ARCH_APICTIMER_STOPS_ON_C3 1 | 96 | #define ARCH_APICTIMER_STOPS_ON_C3 1 |
| 103 | 97 | ||
| 104 | extern unsigned boot_cpu_id; | 98 | extern unsigned boot_cpu_id; |
diff --git a/include/asm-x86/proto.h b/include/asm-x86/proto.h index 31f20ad65876..c44a3a93b5a4 100644 --- a/include/asm-x86/proto.h +++ b/include/asm-x86/proto.h | |||
| @@ -51,9 +51,6 @@ extern void reserve_bootmem_generic(unsigned long phys, unsigned len); | |||
| 51 | 51 | ||
| 52 | extern void load_gs_index(unsigned gs); | 52 | extern void load_gs_index(unsigned gs); |
| 53 | 53 | ||
| 54 | extern void stop_timer_interrupt(void); | ||
| 55 | extern void main_timer_handler(void); | ||
| 56 | |||
| 57 | extern unsigned long end_pfn_map; | 54 | extern unsigned long end_pfn_map; |
| 58 | 55 | ||
| 59 | extern void show_trace(struct task_struct *, struct pt_regs *, unsigned long * rsp); | 56 | extern void show_trace(struct task_struct *, struct pt_regs *, unsigned long * rsp); |
| @@ -90,14 +87,10 @@ extern int timer_over_8254; | |||
| 90 | 87 | ||
| 91 | extern int gsi_irq_sharing(int gsi); | 88 | extern int gsi_irq_sharing(int gsi); |
| 92 | 89 | ||
| 93 | extern void smp_local_timer_interrupt(void); | ||
| 94 | |||
| 95 | extern int force_mwait; | 90 | extern int force_mwait; |
| 96 | 91 | ||
| 97 | long do_arch_prctl(struct task_struct *task, int code, unsigned long addr); | 92 | long do_arch_prctl(struct task_struct *task, int code, unsigned long addr); |
| 98 | 93 | ||
| 99 | void i8254_timer_resume(void); | ||
| 100 | |||
| 101 | #define round_up(x,y) (((x) + (y) - 1) & ~((y)-1)) | 94 | #define round_up(x,y) (((x) + (y) - 1) & ~((y)-1)) |
| 102 | #define round_down(x,y) ((x) & ~((y)-1)) | 95 | #define round_down(x,y) ((x) & ~((y)-1)) |
| 103 | 96 | ||
