diff options
51 files changed, 1308 insertions, 1264 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index a57c1f216b21..f27cdd7125f2 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
| @@ -1009,6 +1009,10 @@ and is between 256 and 4096 characters. It is defined in the file | |||
| 1009 | meye.*= [HW] Set MotionEye Camera parameters | 1009 | meye.*= [HW] Set MotionEye Camera parameters |
| 1010 | See Documentation/video4linux/meye.txt. | 1010 | See Documentation/video4linux/meye.txt. |
| 1011 | 1011 | ||
| 1012 | mfgpt_irq= [IA-32] Specify the IRQ to use for the | ||
| 1013 | Multi-Function General Purpose Timers on AMD Geode | ||
| 1014 | platforms. | ||
| 1015 | |||
| 1012 | mga= [HW,DRM] | 1016 | mga= [HW,DRM] |
| 1013 | 1017 | ||
| 1014 | mousedev.tap_time= | 1018 | mousedev.tap_time= |
| @@ -1160,6 +1164,9 @@ and is between 256 and 4096 characters. It is defined in the file | |||
| 1160 | 1164 | ||
| 1161 | nomce [X86-32] Machine Check Exception | 1165 | nomce [X86-32] Machine Check Exception |
| 1162 | 1166 | ||
| 1167 | nomfgpt [X86-32] Disable Multi-Function General Purpose | ||
| 1168 | Timer usage (for AMD Geode machines). | ||
| 1169 | |||
| 1163 | noreplace-paravirt [X86-32,PV_OPS] Don't patch paravirt_ops | 1170 | noreplace-paravirt [X86-32,PV_OPS] Don't patch paravirt_ops |
| 1164 | 1171 | ||
| 1165 | noreplace-smp [X86-32,SMP] Don't replace SMP instructions | 1172 | noreplace-smp [X86-32,SMP] Don't replace SMP instructions |
diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig index 2d85e4b87307..6bbbc2755e44 100644 --- a/arch/i386/Kconfig +++ b/arch/i386/Kconfig | |||
| @@ -1206,6 +1206,16 @@ config SCx200HR_TIMER | |||
| 1206 | processor goes idle (as is done by the scheduler). The | 1206 | processor goes idle (as is done by the scheduler). The |
| 1207 | other workaround is idle=poll boot option. | 1207 | other workaround is idle=poll boot option. |
| 1208 | 1208 | ||
| 1209 | config GEODE_MFGPT_TIMER | ||
| 1210 | bool "Geode Multi-Function General Purpose Timer (MFGPT) events" | ||
| 1211 | depends on MGEODE_LX && GENERIC_TIME && GENERIC_CLOCKEVENTS | ||
| 1212 | default y | ||
| 1213 | help | ||
| 1214 | This driver provides a clock event source based on the MFGPT | ||
| 1215 | timer(s) in the CS5535 and CS5536 companion chip for the geode. | ||
| 1216 | MFGPTs have a better resolution and max interval than the | ||
| 1217 | generic PIT, and are suitable for use as high-res timers. | ||
| 1218 | |||
| 1209 | config K8_NB | 1219 | config K8_NB |
| 1210 | def_bool y | 1220 | def_bool y |
| 1211 | depends on AGP_AMD64 | 1221 | depends on AGP_AMD64 |
diff --git a/arch/x86/kernel/Makefile_32 b/arch/x86/kernel/Makefile_32 index c624193740fd..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,9 +37,9 @@ 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 | 42 | obj-$(CONFIG_MGEODE_LX) += geode_32.o mfgpt_32.o |
| 43 | 43 | ||
| 44 | obj-$(CONFIG_VMI) += vmi_32.o vmiclock_32.o | 44 | obj-$(CONFIG_VMI) += vmi_32.o vmiclock_32.o |
| 45 | obj-$(CONFIG_PARAVIRT) += paravirt_32.o | 45 | obj-$(CONFIG_PARAVIRT) += paravirt_32.o |
diff --git a/arch/x86/kernel/Makefile_64 b/arch/x86/kernel/Makefile_64 index 3ab017a0a3b9..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_64.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 | 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 925758dbca0c..395928de28ea 100644 --- a/arch/x86/kernel/apic_64.c +++ b/arch/x86/kernel/apic_64.c | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | #include <linux/sysdev.h> | 25 | #include <linux/sysdev.h> |
| 26 | #include <linux/module.h> | 26 | #include <linux/module.h> |
| 27 | #include <linux/ioport.h> | 27 | #include <linux/ioport.h> |
| 28 | #include <linux/clockchips.h> | ||
| 28 | 29 | ||
| 29 | #include <asm/atomic.h> | 30 | #include <asm/atomic.h> |
| 30 | #include <asm/smp.h> | 31 | #include <asm/smp.h> |
| @@ -39,12 +40,9 @@ | |||
| 39 | #include <asm/hpet.h> | 40 | #include <asm/hpet.h> |
| 40 | #include <asm/apic.h> | 41 | #include <asm/apic.h> |
| 41 | 42 | ||
| 42 | int apic_mapped; | ||
| 43 | int apic_verbosity; | 43 | int apic_verbosity; |
| 44 | int apic_runs_main_timer; | 44 | int disable_apic_timer __cpuinitdata; |
| 45 | int apic_calibrate_pmtmr __initdata; | 45 | static int apic_calibrate_pmtmr __initdata; |
| 46 | |||
| 47 | int disable_apic_timer __initdata; | ||
| 48 | 46 | ||
| 49 | /* Local APIC timer works in C2? */ | 47 | /* Local APIC timer works in C2? */ |
| 50 | int local_apic_timer_c2_ok; | 48 | int local_apic_timer_c2_ok; |
| @@ -56,14 +54,78 @@ static struct resource lapic_resource = { | |||
| 56 | .flags = IORESOURCE_MEM | IORESOURCE_BUSY, | 54 | .flags = IORESOURCE_MEM | IORESOURCE_BUSY, |
| 57 | }; | 55 | }; |
| 58 | 56 | ||
| 57 | static unsigned int calibration_result; | ||
| 58 | |||
| 59 | static int lapic_next_event(unsigned long delta, | ||
| 60 | struct clock_event_device *evt); | ||
| 61 | static void lapic_timer_setup(enum clock_event_mode mode, | ||
| 62 | struct clock_event_device *evt); | ||
| 63 | |||
| 64 | static void lapic_timer_broadcast(cpumask_t mask); | ||
| 65 | |||
| 66 | static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen); | ||
| 67 | |||
| 68 | static struct clock_event_device lapic_clockevent = { | ||
| 69 | .name = "lapic", | ||
| 70 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT | ||
| 71 | | CLOCK_EVT_FEAT_C3STOP | CLOCK_EVT_FEAT_DUMMY, | ||
| 72 | .shift = 32, | ||
| 73 | .set_mode = lapic_timer_setup, | ||
| 74 | .set_next_event = lapic_next_event, | ||
| 75 | .broadcast = lapic_timer_broadcast, | ||
| 76 | .rating = 100, | ||
| 77 | .irq = -1, | ||
| 78 | }; | ||
| 79 | static DEFINE_PER_CPU(struct clock_event_device, lapic_events); | ||
| 80 | |||
| 81 | static int lapic_next_event(unsigned long delta, | ||
| 82 | struct clock_event_device *evt) | ||
| 83 | { | ||
| 84 | apic_write(APIC_TMICT, delta); | ||
| 85 | return 0; | ||
| 86 | } | ||
| 87 | |||
| 88 | static void lapic_timer_setup(enum clock_event_mode mode, | ||
| 89 | struct clock_event_device *evt) | ||
| 90 | { | ||
| 91 | unsigned long flags; | ||
| 92 | unsigned int v; | ||
| 93 | |||
| 94 | /* Lapic used as dummy for broadcast ? */ | ||
| 95 | if (evt->features & CLOCK_EVT_FEAT_DUMMY) | ||
| 96 | return; | ||
| 97 | |||
| 98 | local_irq_save(flags); | ||
| 99 | |||
| 100 | switch (mode) { | ||
| 101 | case CLOCK_EVT_MODE_PERIODIC: | ||
| 102 | case CLOCK_EVT_MODE_ONESHOT: | ||
| 103 | __setup_APIC_LVTT(calibration_result, | ||
| 104 | mode != CLOCK_EVT_MODE_PERIODIC, 1); | ||
| 105 | break; | ||
| 106 | case CLOCK_EVT_MODE_UNUSED: | ||
| 107 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
| 108 | v = apic_read(APIC_LVTT); | ||
| 109 | v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR); | ||
| 110 | apic_write(APIC_LVTT, v); | ||
| 111 | break; | ||
| 112 | case CLOCK_EVT_MODE_RESUME: | ||
| 113 | /* Nothing to do here */ | ||
| 114 | break; | ||
| 115 | } | ||
| 116 | |||
| 117 | local_irq_restore(flags); | ||
| 118 | } | ||
| 119 | |||
| 59 | /* | 120 | /* |
| 60 | * cpu_mask that denotes the CPUs that needs timer interrupt coming in as | 121 | * Local APIC timer broadcast function |
| 61 | * IPIs in place of local APIC timers | ||
| 62 | */ | 122 | */ |
| 63 | static cpumask_t timer_interrupt_broadcast_ipi_mask; | 123 | static void lapic_timer_broadcast(cpumask_t mask) |
| 64 | 124 | { | |
| 65 | /* Using APIC to generate smp_local_timer_interrupt? */ | 125 | #ifdef CONFIG_SMP |
| 66 | int using_apic_timer __read_mostly = 0; | 126 | send_IPI_mask(mask, LOCAL_TIMER_VECTOR); |
| 127 | #endif | ||
| 128 | } | ||
| 67 | 129 | ||
| 68 | static void apic_pm_activate(void); | 130 | static void apic_pm_activate(void); |
| 69 | 131 | ||
| @@ -184,7 +246,10 @@ void disconnect_bsp_APIC(int virt_wire_setup) | |||
| 184 | apic_write(APIC_SPIV, value); | 246 | apic_write(APIC_SPIV, value); |
| 185 | 247 | ||
| 186 | if (!virt_wire_setup) { | 248 | if (!virt_wire_setup) { |
| 187 | /* For LVT0 make it edge triggered, active high, external and enabled */ | 249 | /* |
| 250 | * For LVT0 make it edge triggered, active high, | ||
| 251 | * external and enabled | ||
| 252 | */ | ||
| 188 | value = apic_read(APIC_LVT0); | 253 | value = apic_read(APIC_LVT0); |
| 189 | value &= ~(APIC_MODE_MASK | APIC_SEND_PENDING | | 254 | value &= ~(APIC_MODE_MASK | APIC_SEND_PENDING | |
| 190 | APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR | | 255 | APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR | |
| @@ -420,10 +485,12 @@ void __cpuinit setup_local_APIC (void) | |||
| 420 | value = apic_read(APIC_LVT0) & APIC_LVT_MASKED; | 485 | value = apic_read(APIC_LVT0) & APIC_LVT_MASKED; |
| 421 | if (!smp_processor_id() && !value) { | 486 | if (!smp_processor_id() && !value) { |
| 422 | value = APIC_DM_EXTINT; | 487 | value = APIC_DM_EXTINT; |
| 423 | apic_printk(APIC_VERBOSE, "enabled ExtINT on CPU#%d\n", smp_processor_id()); | 488 | apic_printk(APIC_VERBOSE, "enabled ExtINT on CPU#%d\n", |
| 489 | smp_processor_id()); | ||
| 424 | } else { | 490 | } else { |
| 425 | value = APIC_DM_EXTINT | APIC_LVT_MASKED; | 491 | value = APIC_DM_EXTINT | APIC_LVT_MASKED; |
| 426 | apic_printk(APIC_VERBOSE, "masked ExtINT on CPU#%d\n", smp_processor_id()); | 492 | apic_printk(APIC_VERBOSE, "masked ExtINT on CPU#%d\n", |
| 493 | smp_processor_id()); | ||
| 427 | } | 494 | } |
| 428 | apic_write(APIC_LVT0, value); | 495 | apic_write(APIC_LVT0, value); |
| 429 | 496 | ||
| @@ -706,8 +773,8 @@ void __init init_apic_mappings(void) | |||
| 706 | apic_phys = mp_lapic_addr; | 773 | apic_phys = mp_lapic_addr; |
| 707 | 774 | ||
| 708 | set_fixmap_nocache(FIX_APIC_BASE, apic_phys); | 775 | set_fixmap_nocache(FIX_APIC_BASE, apic_phys); |
| 709 | apic_mapped = 1; | 776 | apic_printk(APIC_VERBOSE, "mapped APIC to %16lx (%16lx)\n", |
| 710 | apic_printk(APIC_VERBOSE,"mapped APIC to %16lx (%16lx)\n", APIC_BASE, apic_phys); | 777 | APIC_BASE, apic_phys); |
| 711 | 778 | ||
| 712 | /* Put local APIC into the resource map. */ | 779 | /* Put local APIC into the resource map. */ |
| 713 | lapic_resource.start = apic_phys; | 780 | lapic_resource.start = apic_phys; |
| @@ -730,12 +797,14 @@ void __init init_apic_mappings(void) | |||
| 730 | if (smp_found_config) { | 797 | if (smp_found_config) { |
| 731 | ioapic_phys = mp_ioapics[i].mpc_apicaddr; | 798 | ioapic_phys = mp_ioapics[i].mpc_apicaddr; |
| 732 | } else { | 799 | } else { |
| 733 | ioapic_phys = (unsigned long) alloc_bootmem_pages(PAGE_SIZE); | 800 | ioapic_phys = (unsigned long) |
| 801 | alloc_bootmem_pages(PAGE_SIZE); | ||
| 734 | ioapic_phys = __pa(ioapic_phys); | 802 | ioapic_phys = __pa(ioapic_phys); |
| 735 | } | 803 | } |
| 736 | set_fixmap_nocache(idx, ioapic_phys); | 804 | set_fixmap_nocache(idx, ioapic_phys); |
| 737 | apic_printk(APIC_VERBOSE,"mapped IOAPIC to %016lx (%016lx)\n", | 805 | apic_printk(APIC_VERBOSE, |
| 738 | __fix_to_virt(idx), ioapic_phys); | 806 | "mapped IOAPIC to %016lx (%016lx)\n", |
| 807 | __fix_to_virt(idx), ioapic_phys); | ||
| 739 | idx++; | 808 | idx++; |
| 740 | 809 | ||
| 741 | if (ioapic_res != NULL) { | 810 | if (ioapic_res != NULL) { |
| @@ -758,16 +827,14 @@ void __init init_apic_mappings(void) | |||
| 758 | * P5 APIC double write bug. | 827 | * P5 APIC double write bug. |
| 759 | */ | 828 | */ |
| 760 | 829 | ||
| 761 | #define APIC_DIVISOR 16 | 830 | static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen) |
| 762 | |||
| 763 | static void __setup_APIC_LVTT(unsigned int clocks) | ||
| 764 | { | 831 | { |
| 765 | unsigned int lvtt_value, tmp_value; | 832 | unsigned int lvtt_value, tmp_value; |
| 766 | int cpu = smp_processor_id(); | ||
| 767 | 833 | ||
| 768 | lvtt_value = APIC_LVT_TIMER_PERIODIC | LOCAL_TIMER_VECTOR; | 834 | lvtt_value = LOCAL_TIMER_VECTOR; |
| 769 | 835 | if (!oneshot) | |
| 770 | if (cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask)) | 836 | lvtt_value |= APIC_LVT_TIMER_PERIODIC; |
| 837 | if (!irqen) | ||
| 771 | lvtt_value |= APIC_LVT_MASKED; | 838 | lvtt_value |= APIC_LVT_MASKED; |
| 772 | 839 | ||
| 773 | apic_write(APIC_LVTT, lvtt_value); | 840 | apic_write(APIC_LVTT, lvtt_value); |
| @@ -780,44 +847,18 @@ static void __setup_APIC_LVTT(unsigned int clocks) | |||
| 780 | & ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE)) | 847 | & ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE)) |
| 781 | | APIC_TDR_DIV_16); | 848 | | APIC_TDR_DIV_16); |
| 782 | 849 | ||
| 783 | apic_write(APIC_TMICT, clocks/APIC_DIVISOR); | 850 | if (!oneshot) |
| 851 | apic_write(APIC_TMICT, clocks); | ||
| 784 | } | 852 | } |
| 785 | 853 | ||
| 786 | static void setup_APIC_timer(unsigned int clocks) | 854 | static void setup_APIC_timer(void) |
| 787 | { | 855 | { |
| 788 | unsigned long flags; | 856 | struct clock_event_device *levt = &__get_cpu_var(lapic_events); |
| 789 | 857 | ||
| 790 | local_irq_save(flags); | 858 | memcpy(levt, &lapic_clockevent, sizeof(*levt)); |
| 859 | levt->cpumask = cpumask_of_cpu(smp_processor_id()); | ||
| 791 | 860 | ||
| 792 | /* wait for irq slice */ | 861 | clockevents_register_device(levt); |
| 793 | if (hpet_address && hpet_use_timer) { | ||
| 794 | u32 trigger = hpet_readl(HPET_T0_CMP); | ||
| 795 | while (hpet_readl(HPET_T0_CMP) == trigger) | ||
| 796 | /* do nothing */ ; | ||
| 797 | } else { | ||
| 798 | int c1, c2; | ||
| 799 | outb_p(0x00, 0x43); | ||
| 800 | c2 = inb_p(0x40); | ||
| 801 | c2 |= inb_p(0x40) << 8; | ||
| 802 | do { | ||
| 803 | c1 = c2; | ||
| 804 | outb_p(0x00, 0x43); | ||
| 805 | c2 = inb_p(0x40); | ||
| 806 | c2 |= inb_p(0x40) << 8; | ||
| 807 | } while (c2 - c1 < 300); | ||
| 808 | } | ||
| 809 | __setup_APIC_LVTT(clocks); | ||
| 810 | /* Turn off PIT interrupt if we use APIC timer as main timer. | ||
| 811 | Only works with the PM timer right now | ||
| 812 | TBD fix it for HPET too. */ | ||
| 813 | if ((pmtmr_ioport != 0) && | ||
| 814 | smp_processor_id() == boot_cpu_id && | ||
| 815 | apic_runs_main_timer == 1 && | ||
| 816 | !cpu_isset(boot_cpu_id, timer_interrupt_broadcast_ipi_mask)) { | ||
| 817 | stop_timer_interrupt(); | ||
| 818 | apic_runs_main_timer++; | ||
| 819 | } | ||
| 820 | local_irq_restore(flags); | ||
| 821 | } | 862 | } |
| 822 | 863 | ||
| 823 | /* | 864 | /* |
| @@ -835,17 +876,22 @@ static void setup_APIC_timer(unsigned int clocks) | |||
| 835 | 876 | ||
| 836 | #define TICK_COUNT 100000000 | 877 | #define TICK_COUNT 100000000 |
| 837 | 878 | ||
| 838 | static int __init calibrate_APIC_clock(void) | 879 | static void __init calibrate_APIC_clock(void) |
| 839 | { | 880 | { |
| 840 | unsigned apic, apic_start; | 881 | unsigned apic, apic_start; |
| 841 | unsigned long tsc, tsc_start; | 882 | unsigned long tsc, tsc_start; |
| 842 | int result; | 883 | int result; |
| 884 | |||
| 885 | local_irq_disable(); | ||
| 886 | |||
| 843 | /* | 887 | /* |
| 844 | * Put whatever arbitrary (but long enough) timeout | 888 | * Put whatever arbitrary (but long enough) timeout |
| 845 | * value into the APIC clock, we just want to get the | 889 | * value into the APIC clock, we just want to get the |
| 846 | * counter running for calibration. | 890 | * counter running for calibration. |
| 891 | * | ||
| 892 | * No interrupt enable ! | ||
| 847 | */ | 893 | */ |
| 848 | __setup_APIC_LVTT(4000000000); | 894 | __setup_APIC_LVTT(250000000, 0, 0); |
| 849 | 895 | ||
| 850 | apic_start = apic_read(APIC_TMCCT); | 896 | apic_start = apic_read(APIC_TMCCT); |
| 851 | #ifdef CONFIG_X86_PM_TIMER | 897 | #ifdef CONFIG_X86_PM_TIMER |
| @@ -867,123 +913,62 @@ static int __init calibrate_APIC_clock(void) | |||
| 867 | result = (apic_start - apic) * 1000L * tsc_khz / | 913 | result = (apic_start - apic) * 1000L * tsc_khz / |
| 868 | (tsc - tsc_start); | 914 | (tsc - tsc_start); |
| 869 | } | 915 | } |
| 870 | printk("result %d\n", result); | ||
| 871 | 916 | ||
| 917 | local_irq_enable(); | ||
| 918 | |||
| 919 | printk(KERN_DEBUG "APIC timer calibration result %d\n", result); | ||
| 872 | 920 | ||
| 873 | printk(KERN_INFO "Detected %d.%03d MHz APIC timer.\n", | 921 | printk(KERN_INFO "Detected %d.%03d MHz APIC timer.\n", |
| 874 | result / 1000 / 1000, result / 1000 % 1000); | 922 | result / 1000 / 1000, result / 1000 % 1000); |
| 875 | 923 | ||
| 876 | return result * APIC_DIVISOR / HZ; | 924 | /* Calculate the scaled math multiplication factor */ |
| 877 | } | 925 | lapic_clockevent.mult = div_sc(result, NSEC_PER_SEC, 32); |
| 926 | lapic_clockevent.max_delta_ns = | ||
| 927 | clockevent_delta2ns(0x7FFFFF, &lapic_clockevent); | ||
| 928 | lapic_clockevent.min_delta_ns = | ||
| 929 | clockevent_delta2ns(0xF, &lapic_clockevent); | ||
| 878 | 930 | ||
| 879 | static unsigned int calibration_result; | 931 | calibration_result = result / HZ; |
| 932 | } | ||
| 880 | 933 | ||
| 881 | void __init setup_boot_APIC_clock (void) | 934 | void __init setup_boot_APIC_clock (void) |
| 882 | { | 935 | { |
| 936 | /* | ||
| 937 | * The local apic timer can be disabled via the kernel commandline. | ||
| 938 | * Register the lapic timer as a dummy clock event source on SMP | ||
| 939 | * systems, so the broadcast mechanism is used. On UP systems simply | ||
| 940 | * ignore it. | ||
| 941 | */ | ||
| 883 | if (disable_apic_timer) { | 942 | if (disable_apic_timer) { |
| 884 | printk(KERN_INFO "Disabling APIC timer\n"); | 943 | printk(KERN_INFO "Disabling APIC timer\n"); |
| 944 | /* No broadcast on UP ! */ | ||
| 945 | if (num_possible_cpus() > 1) | ||
| 946 | setup_APIC_timer(); | ||
| 885 | return; | 947 | return; |
| 886 | } | 948 | } |
| 887 | 949 | ||
| 888 | printk(KERN_INFO "Using local APIC timer interrupts.\n"); | 950 | printk(KERN_INFO "Using local APIC timer interrupts.\n"); |
| 889 | using_apic_timer = 1; | 951 | calibrate_APIC_clock(); |
| 890 | |||
| 891 | local_irq_disable(); | ||
| 892 | 952 | ||
| 893 | calibration_result = calibrate_APIC_clock(); | ||
| 894 | /* | 953 | /* |
| 895 | * Now set up the timer for real. | 954 | * If nmi_watchdog is set to IO_APIC, we need the |
| 955 | * PIT/HPET going. Otherwise register lapic as a dummy | ||
| 956 | * device. | ||
| 896 | */ | 957 | */ |
| 897 | setup_APIC_timer(calibration_result); | 958 | if (nmi_watchdog != NMI_IO_APIC) |
| 959 | lapic_clockevent.features &= ~CLOCK_EVT_FEAT_DUMMY; | ||
| 960 | else | ||
| 961 | printk(KERN_WARNING "APIC timer registered as dummy," | ||
| 962 | " due to nmi_watchdog=1!\n"); | ||
| 898 | 963 | ||
| 899 | local_irq_enable(); | 964 | setup_APIC_timer(); |
| 900 | } | 965 | } |
| 901 | 966 | ||
| 902 | void __cpuinit setup_secondary_APIC_clock(void) | 967 | void __cpuinit setup_secondary_APIC_clock(void) |
| 903 | { | 968 | { |
| 904 | local_irq_disable(); /* FIXME: Do we need this? --RR */ | 969 | setup_APIC_timer(); |
| 905 | setup_APIC_timer(calibration_result); | ||
| 906 | local_irq_enable(); | ||
| 907 | } | 970 | } |
| 908 | 971 | ||
| 909 | void disable_APIC_timer(void) | ||
| 910 | { | ||
| 911 | if (using_apic_timer) { | ||
| 912 | unsigned long v; | ||
| 913 | |||
| 914 | v = apic_read(APIC_LVTT); | ||
| 915 | /* | ||
| 916 | * When an illegal vector value (0-15) is written to an LVT | ||
| 917 | * entry and delivery mode is Fixed, the APIC may signal an | ||
| 918 | * illegal vector error, with out regard to whether the mask | ||
| 919 | * bit is set or whether an interrupt is actually seen on input. | ||
| 920 | * | ||
| 921 | * Boot sequence might call this function when the LVTT has | ||
| 922 | * '0' vector value. So make sure vector field is set to | ||
| 923 | * valid value. | ||
| 924 | */ | ||
| 925 | v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR); | ||
| 926 | apic_write(APIC_LVTT, v); | ||
| 927 | } | ||
| 928 | } | ||
| 929 | |||
| 930 | void enable_APIC_timer(void) | ||
| 931 | { | ||
| 932 | int cpu = smp_processor_id(); | ||
| 933 | |||
| 934 | if (using_apic_timer && | ||
| 935 | !cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask)) { | ||
| 936 | unsigned long v; | ||
| 937 | |||
| 938 | v = apic_read(APIC_LVTT); | ||
| 939 | apic_write(APIC_LVTT, v & ~APIC_LVT_MASKED); | ||
| 940 | } | ||
| 941 | } | ||
| 942 | |||
| 943 | void switch_APIC_timer_to_ipi(void *cpumask) | ||
| 944 | { | ||
| 945 | cpumask_t mask = *(cpumask_t *)cpumask; | ||
| 946 | int cpu = smp_processor_id(); | ||
| 947 | |||
| 948 | if (cpu_isset(cpu, mask) && | ||
| 949 | !cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask)) { | ||
| 950 | disable_APIC_timer(); | ||
| 951 | cpu_set(cpu, timer_interrupt_broadcast_ipi_mask); | ||
| 952 | } | ||
| 953 | } | ||
| 954 | EXPORT_SYMBOL(switch_APIC_timer_to_ipi); | ||
| 955 | |||
| 956 | void smp_send_timer_broadcast_ipi(void) | ||
| 957 | { | ||
| 958 | int cpu = smp_processor_id(); | ||
| 959 | cpumask_t mask; | ||
| 960 | |||
| 961 | cpus_and(mask, cpu_online_map, timer_interrupt_broadcast_ipi_mask); | ||
| 962 | |||
| 963 | if (cpu_isset(cpu, mask)) { | ||
| 964 | cpu_clear(cpu, mask); | ||
| 965 | add_pda(apic_timer_irqs, 1); | ||
| 966 | smp_local_timer_interrupt(); | ||
| 967 | } | ||
| 968 | |||
| 969 | if (!cpus_empty(mask)) { | ||
| 970 | send_IPI_mask(mask, LOCAL_TIMER_VECTOR); | ||
| 971 | } | ||
| 972 | } | ||
| 973 | |||
| 974 | void switch_ipi_to_APIC_timer(void *cpumask) | ||
| 975 | { | ||
| 976 | cpumask_t mask = *(cpumask_t *)cpumask; | ||
| 977 | int cpu = smp_processor_id(); | ||
| 978 | |||
| 979 | if (cpu_isset(cpu, mask) && | ||
| 980 | cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask)) { | ||
| 981 | cpu_clear(cpu, timer_interrupt_broadcast_ipi_mask); | ||
| 982 | enable_APIC_timer(); | ||
| 983 | } | ||
| 984 | } | ||
| 985 | EXPORT_SYMBOL(switch_ipi_to_APIC_timer); | ||
| 986 | |||
| 987 | int setup_profiling_timer(unsigned int multiplier) | 972 | int setup_profiling_timer(unsigned int multiplier) |
| 988 | { | 973 | { |
| 989 | return -EINVAL; | 974 | return -EINVAL; |
| @@ -997,8 +982,6 @@ void setup_APIC_extended_lvt(unsigned char lvt_off, unsigned char vector, | |||
| 997 | apic_write(reg, v); | 982 | apic_write(reg, v); |
| 998 | } | 983 | } |
| 999 | 984 | ||
| 1000 | #undef APIC_DIVISOR | ||
| 1001 | |||
| 1002 | /* | 985 | /* |
| 1003 | * Local timer interrupt handler. It does both profiling and | 986 | * Local timer interrupt handler. It does both profiling and |
| 1004 | * process statistics/rescheduling. | 987 | * process statistics/rescheduling. |
| @@ -1011,22 +994,34 @@ void setup_APIC_extended_lvt(unsigned char lvt_off, unsigned char vector, | |||
| 1011 | 994 | ||
| 1012 | void smp_local_timer_interrupt(void) | 995 | void smp_local_timer_interrupt(void) |
| 1013 | { | 996 | { |
| 1014 | profile_tick(CPU_PROFILING); | 997 | int cpu = smp_processor_id(); |
| 1015 | #ifdef CONFIG_SMP | 998 | struct clock_event_device *evt = &per_cpu(lapic_events, cpu); |
| 1016 | update_process_times(user_mode(get_irq_regs())); | 999 | |
| 1017 | #endif | ||
| 1018 | if (apic_runs_main_timer > 1 && smp_processor_id() == boot_cpu_id) | ||
| 1019 | main_timer_handler(); | ||
| 1020 | /* | 1000 | /* |
| 1021 | * We take the 'long' return path, and there every subsystem | 1001 | * Normally we should not be here till LAPIC has been initialized but |
| 1022 | * grabs the appropriate locks (kernel lock/ irq lock). | 1002 | * in some cases like kdump, its possible that there is a pending LAPIC |
| 1003 | * timer interrupt from previous kernel's context and is delivered in | ||
| 1004 | * new kernel the moment interrupts are enabled. | ||
| 1023 | * | 1005 | * |
| 1024 | * We might want to decouple profiling from the 'long path', | 1006 | * Interrupts are enabled early and LAPIC is setup much later, hence |
| 1025 | * and do the profiling totally in assembly. | 1007 | * its possible that when we get here evt->event_handler is NULL. |
| 1026 | * | 1008 | * Check for event_handler being NULL and discard the interrupt as |
| 1027 | * Currently this isn't too much of an issue (performance wise), | 1009 | * spurious. |
| 1028 | * we can take more than 100K local irqs per second on a 100 MHz P5. | 1010 | */ |
| 1011 | if (!evt->event_handler) { | ||
| 1012 | printk(KERN_WARNING | ||
| 1013 | "Spurious LAPIC timer interrupt on cpu %d\n", cpu); | ||
| 1014 | /* Switch it off */ | ||
| 1015 | lapic_timer_setup(CLOCK_EVT_MODE_SHUTDOWN, evt); | ||
| 1016 | return; | ||
| 1017 | } | ||
| 1018 | |||
| 1019 | /* | ||
| 1020 | * the NMI deadlock-detector uses this. | ||
| 1029 | */ | 1021 | */ |
| 1022 | add_pda(apic_timer_irqs, 1); | ||
| 1023 | |||
| 1024 | evt->event_handler(evt); | ||
| 1030 | } | 1025 | } |
| 1031 | 1026 | ||
| 1032 | /* | 1027 | /* |
| @@ -1042,11 +1037,6 @@ void smp_apic_timer_interrupt(struct pt_regs *regs) | |||
| 1042 | struct pt_regs *old_regs = set_irq_regs(regs); | 1037 | struct pt_regs *old_regs = set_irq_regs(regs); |
| 1043 | 1038 | ||
| 1044 | /* | 1039 | /* |
| 1045 | * the NMI deadlock-detector uses this. | ||
| 1046 | */ | ||
| 1047 | add_pda(apic_timer_irqs, 1); | ||
| 1048 | |||
| 1049 | /* | ||
| 1050 | * NOTE! We'd better ACK the irq immediately, | 1040 | * NOTE! We'd better ACK the irq immediately, |
| 1051 | * because timer handling can be slow. | 1041 | * because timer handling can be slow. |
| 1052 | */ | 1042 | */ |
| @@ -1225,29 +1215,13 @@ static __init int setup_noapictimer(char *str) | |||
| 1225 | disable_apic_timer = 1; | 1215 | disable_apic_timer = 1; |
| 1226 | return 1; | 1216 | return 1; |
| 1227 | } | 1217 | } |
| 1228 | 1218 | __setup("noapictimer", setup_noapictimer); | |
| 1229 | static __init int setup_apicmaintimer(char *str) | ||
| 1230 | { | ||
| 1231 | apic_runs_main_timer = 1; | ||
| 1232 | nohpet = 1; | ||
| 1233 | return 1; | ||
| 1234 | } | ||
| 1235 | __setup("apicmaintimer", setup_apicmaintimer); | ||
| 1236 | |||
| 1237 | static __init int setup_noapicmaintimer(char *str) | ||
| 1238 | { | ||
| 1239 | apic_runs_main_timer = -1; | ||
| 1240 | return 1; | ||
| 1241 | } | ||
| 1242 | __setup("noapicmaintimer", setup_noapicmaintimer); | ||
| 1243 | 1219 | ||
| 1244 | static __init int setup_apicpmtimer(char *s) | 1220 | static __init int setup_apicpmtimer(char *s) |
| 1245 | { | 1221 | { |
| 1246 | apic_calibrate_pmtmr = 1; | 1222 | apic_calibrate_pmtmr = 1; |
| 1247 | notsc_setup(NULL); | 1223 | notsc_setup(NULL); |
| 1248 | return setup_apicmaintimer(NULL); | 1224 | return 0; |
| 1249 | } | 1225 | } |
| 1250 | __setup("apicpmtimer", setup_apicpmtimer); | 1226 | __setup("apicpmtimer", setup_apicpmtimer); |
| 1251 | 1227 | ||
| 1252 | __setup("noapictimer", setup_noapictimer); | ||
| 1253 | |||
diff --git a/arch/x86/kernel/geode_32.c b/arch/x86/kernel/geode_32.c index 41e8aec4c61d..f12d8c5d9809 100644 --- a/arch/x86/kernel/geode_32.c +++ b/arch/x86/kernel/geode_32.c | |||
| @@ -145,10 +145,14 @@ EXPORT_SYMBOL_GPL(geode_gpio_setup_event); | |||
| 145 | 145 | ||
| 146 | static int __init geode_southbridge_init(void) | 146 | static int __init geode_southbridge_init(void) |
| 147 | { | 147 | { |
| 148 | int timers; | ||
| 149 | |||
| 148 | if (!is_geode()) | 150 | if (!is_geode()) |
| 149 | return -ENODEV; | 151 | return -ENODEV; |
| 150 | 152 | ||
| 151 | init_lbars(); | 153 | init_lbars(); |
| 154 | timers = geode_mfgpt_detect(); | ||
| 155 | printk(KERN_INFO "geode: %d MFGPT timers available.\n", timers); | ||
| 152 | return 0; | 156 | return 0; |
| 153 | } | 157 | } |
| 154 | 158 | ||
diff --git a/arch/x86/kernel/hpet_32.c b/arch/x86/kernel/hpet.c index 533d4932bc79..f8367074da0d 100644 --- a/arch/x86/kernel/hpet_32.c +++ b/arch/x86/kernel/hpet.c | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | #include <linux/clocksource.h> | 1 | #include <linux/clocksource.h> |
| 2 | #include <linux/clockchips.h> | 2 | #include <linux/clockchips.h> |
| 3 | #include <linux/delay.h> | ||
| 3 | #include <linux/errno.h> | 4 | #include <linux/errno.h> |
| 4 | #include <linux/hpet.h> | 5 | #include <linux/hpet.h> |
| 5 | #include <linux/init.h> | 6 | #include <linux/init.h> |
| @@ -7,11 +8,11 @@ | |||
| 7 | #include <linux/pm.h> | 8 | #include <linux/pm.h> |
| 8 | #include <linux/delay.h> | 9 | #include <linux/delay.h> |
| 9 | 10 | ||
| 11 | #include <asm/fixmap.h> | ||
| 10 | #include <asm/hpet.h> | 12 | #include <asm/hpet.h> |
| 13 | #include <asm/i8253.h> | ||
| 11 | #include <asm/io.h> | 14 | #include <asm/io.h> |
| 12 | 15 | ||
| 13 | extern struct clock_event_device *global_clock_event; | ||
| 14 | |||
| 15 | #define HPET_MASK CLOCKSOURCE_MASK(32) | 16 | #define HPET_MASK CLOCKSOURCE_MASK(32) |
| 16 | #define HPET_SHIFT 22 | 17 | #define HPET_SHIFT 22 |
| 17 | 18 | ||
| @@ -22,9 +23,9 @@ extern struct clock_event_device *global_clock_event; | |||
| 22 | * HPET address is set in acpi/boot.c, when an ACPI entry exists | 23 | * HPET address is set in acpi/boot.c, when an ACPI entry exists |
| 23 | */ | 24 | */ |
| 24 | unsigned long hpet_address; | 25 | unsigned long hpet_address; |
| 25 | static void __iomem * hpet_virt_address; | 26 | static void __iomem *hpet_virt_address; |
| 26 | 27 | ||
| 27 | static inline unsigned long hpet_readl(unsigned long a) | 28 | unsigned long hpet_readl(unsigned long a) |
| 28 | { | 29 | { |
| 29 | return readl(hpet_virt_address + a); | 30 | return readl(hpet_virt_address + a); |
| 30 | } | 31 | } |
| @@ -34,6 +35,36 @@ static inline void hpet_writel(unsigned long d, unsigned long a) | |||
| 34 | writel(d, hpet_virt_address + a); | 35 | writel(d, hpet_virt_address + a); |
| 35 | } | 36 | } |
| 36 | 37 | ||
| 38 | #ifdef CONFIG_X86_64 | ||
| 39 | |||
| 40 | #include <asm/pgtable.h> | ||
| 41 | |||
| 42 | static inline void hpet_set_mapping(void) | ||
| 43 | { | ||
| 44 | set_fixmap_nocache(FIX_HPET_BASE, hpet_address); | ||
| 45 | __set_fixmap(VSYSCALL_HPET, hpet_address, PAGE_KERNEL_VSYSCALL_NOCACHE); | ||
| 46 | hpet_virt_address = (void __iomem *)fix_to_virt(FIX_HPET_BASE); | ||
| 47 | } | ||
| 48 | |||
| 49 | static inline void hpet_clear_mapping(void) | ||
| 50 | { | ||
| 51 | hpet_virt_address = NULL; | ||
| 52 | } | ||
| 53 | |||
| 54 | #else | ||
| 55 | |||
| 56 | static inline void hpet_set_mapping(void) | ||
| 57 | { | ||
| 58 | hpet_virt_address = ioremap_nocache(hpet_address, HPET_MMAP_SIZE); | ||
| 59 | } | ||
| 60 | |||
| 61 | static inline void hpet_clear_mapping(void) | ||
| 62 | { | ||
| 63 | iounmap(hpet_virt_address); | ||
| 64 | hpet_virt_address = NULL; | ||
| 65 | } | ||
| 66 | #endif | ||
| 67 | |||
| 37 | /* | 68 | /* |
| 38 | * HPET command line enable / disable | 69 | * HPET command line enable / disable |
| 39 | */ | 70 | */ |
| @@ -49,6 +80,13 @@ static int __init hpet_setup(char* str) | |||
| 49 | } | 80 | } |
| 50 | __setup("hpet=", hpet_setup); | 81 | __setup("hpet=", hpet_setup); |
| 51 | 82 | ||
| 83 | static int __init disable_hpet(char *str) | ||
| 84 | { | ||
| 85 | boot_hpet_disable = 1; | ||
| 86 | return 1; | ||
| 87 | } | ||
| 88 | __setup("nohpet", disable_hpet); | ||
| 89 | |||
| 52 | static inline int is_hpet_capable(void) | 90 | static inline int is_hpet_capable(void) |
| 53 | { | 91 | { |
| 54 | return (!boot_hpet_disable && hpet_address); | 92 | return (!boot_hpet_disable && hpet_address); |
| @@ -83,7 +121,7 @@ static void hpet_reserve_platform_timers(unsigned long id) | |||
| 83 | 121 | ||
| 84 | memset(&hd, 0, sizeof (hd)); | 122 | memset(&hd, 0, sizeof (hd)); |
| 85 | hd.hd_phys_address = hpet_address; | 123 | hd.hd_phys_address = hpet_address; |
| 86 | hd.hd_address = hpet_virt_address; | 124 | hd.hd_address = hpet; |
| 87 | hd.hd_nirqs = nrtimers; | 125 | hd.hd_nirqs = nrtimers; |
| 88 | hd.hd_flags = HPET_DATA_PLATFORM; | 126 | hd.hd_flags = HPET_DATA_PLATFORM; |
| 89 | hpet_reserve_timer(&hd, 0); | 127 | hpet_reserve_timer(&hd, 0); |
| @@ -111,9 +149,9 @@ static void hpet_reserve_platform_timers(unsigned long id) { } | |||
| 111 | */ | 149 | */ |
| 112 | static unsigned long hpet_period; | 150 | static unsigned long hpet_period; |
| 113 | 151 | ||
| 114 | static void hpet_set_mode(enum clock_event_mode mode, | 152 | static void hpet_legacy_set_mode(enum clock_event_mode mode, |
| 115 | struct clock_event_device *evt); | 153 | struct clock_event_device *evt); |
| 116 | static int hpet_next_event(unsigned long delta, | 154 | static int hpet_legacy_next_event(unsigned long delta, |
| 117 | struct clock_event_device *evt); | 155 | struct clock_event_device *evt); |
| 118 | 156 | ||
| 119 | /* | 157 | /* |
| @@ -122,10 +160,11 @@ static int hpet_next_event(unsigned long delta, | |||
| 122 | static struct clock_event_device hpet_clockevent = { | 160 | static struct clock_event_device hpet_clockevent = { |
| 123 | .name = "hpet", | 161 | .name = "hpet", |
| 124 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, | 162 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, |
| 125 | .set_mode = hpet_set_mode, | 163 | .set_mode = hpet_legacy_set_mode, |
| 126 | .set_next_event = hpet_next_event, | 164 | .set_next_event = hpet_legacy_next_event, |
| 127 | .shift = 32, | 165 | .shift = 32, |
| 128 | .irq = 0, | 166 | .irq = 0, |
| 167 | .rating = 50, | ||
| 129 | }; | 168 | }; |
| 130 | 169 | ||
| 131 | static void hpet_start_counter(void) | 170 | static void hpet_start_counter(void) |
| @@ -140,7 +179,18 @@ static void hpet_start_counter(void) | |||
| 140 | hpet_writel(cfg, HPET_CFG); | 179 | hpet_writel(cfg, HPET_CFG); |
| 141 | } | 180 | } |
| 142 | 181 | ||
| 143 | static void hpet_enable_int(void) | 182 | static void hpet_resume_device(void) |
| 183 | { | ||
| 184 | force_hpet_resume(); | ||
| 185 | } | ||
| 186 | |||
| 187 | static void hpet_restart_counter(void) | ||
| 188 | { | ||
| 189 | hpet_resume_device(); | ||
| 190 | hpet_start_counter(); | ||
| 191 | } | ||
| 192 | |||
| 193 | static void hpet_enable_legacy_int(void) | ||
| 144 | { | 194 | { |
| 145 | unsigned long cfg = hpet_readl(HPET_CFG); | 195 | unsigned long cfg = hpet_readl(HPET_CFG); |
| 146 | 196 | ||
| @@ -149,7 +199,39 @@ static void hpet_enable_int(void) | |||
| 149 | hpet_legacy_int_enabled = 1; | 199 | hpet_legacy_int_enabled = 1; |
| 150 | } | 200 | } |
| 151 | 201 | ||
| 152 | static void hpet_set_mode(enum clock_event_mode mode, | 202 | static void hpet_legacy_clockevent_register(void) |
| 203 | { | ||
| 204 | uint64_t hpet_freq; | ||
| 205 | |||
| 206 | /* Start HPET legacy interrupts */ | ||
| 207 | hpet_enable_legacy_int(); | ||
| 208 | |||
| 209 | /* | ||
| 210 | * The period is a femto seconds value. We need to calculate the | ||
| 211 | * scaled math multiplication factor for nanosecond to hpet tick | ||
| 212 | * conversion. | ||
| 213 | */ | ||
| 214 | hpet_freq = 1000000000000000ULL; | ||
| 215 | do_div(hpet_freq, hpet_period); | ||
| 216 | hpet_clockevent.mult = div_sc((unsigned long) hpet_freq, | ||
| 217 | NSEC_PER_SEC, 32); | ||
| 218 | /* Calculate the min / max delta */ | ||
| 219 | hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF, | ||
| 220 | &hpet_clockevent); | ||
| 221 | hpet_clockevent.min_delta_ns = clockevent_delta2ns(0x30, | ||
| 222 | &hpet_clockevent); | ||
| 223 | |||
| 224 | /* | ||
| 225 | * Start hpet with the boot cpu mask and make it | ||
| 226 | * global after the IO_APIC has been initialized. | ||
| 227 | */ | ||
| 228 | hpet_clockevent.cpumask = cpumask_of_cpu(smp_processor_id()); | ||
| 229 | clockevents_register_device(&hpet_clockevent); | ||
| 230 | global_clock_event = &hpet_clockevent; | ||
| 231 | printk(KERN_DEBUG "hpet clockevent registered\n"); | ||
| 232 | } | ||
| 233 | |||
| 234 | static void hpet_legacy_set_mode(enum clock_event_mode mode, | ||
| 153 | struct clock_event_device *evt) | 235 | struct clock_event_device *evt) |
| 154 | { | 236 | { |
| 155 | unsigned long cfg, cmp, now; | 237 | unsigned long cfg, cmp, now; |
| @@ -190,12 +272,12 @@ static void hpet_set_mode(enum clock_event_mode mode, | |||
| 190 | break; | 272 | break; |
| 191 | 273 | ||
| 192 | case CLOCK_EVT_MODE_RESUME: | 274 | case CLOCK_EVT_MODE_RESUME: |
| 193 | hpet_enable_int(); | 275 | hpet_enable_legacy_int(); |
| 194 | break; | 276 | break; |
| 195 | } | 277 | } |
| 196 | } | 278 | } |
| 197 | 279 | ||
| 198 | static int hpet_next_event(unsigned long delta, | 280 | static int hpet_legacy_next_event(unsigned long delta, |
| 199 | struct clock_event_device *evt) | 281 | struct clock_event_device *evt) |
| 200 | { | 282 | { |
| 201 | unsigned long cnt; | 283 | unsigned long cnt; |
| @@ -215,6 +297,13 @@ static cycle_t read_hpet(void) | |||
| 215 | return (cycle_t)hpet_readl(HPET_COUNTER); | 297 | return (cycle_t)hpet_readl(HPET_COUNTER); |
| 216 | } | 298 | } |
| 217 | 299 | ||
| 300 | #ifdef CONFIG_X86_64 | ||
| 301 | static cycle_t __vsyscall_fn vread_hpet(void) | ||
| 302 | { | ||
| 303 | return readl((const void __iomem *)fix_to_virt(VSYSCALL_HPET) + 0xf0); | ||
| 304 | } | ||
| 305 | #endif | ||
| 306 | |||
| 218 | static struct clocksource clocksource_hpet = { | 307 | static struct clocksource clocksource_hpet = { |
| 219 | .name = "hpet", | 308 | .name = "hpet", |
| 220 | .rating = 250, | 309 | .rating = 250, |
| @@ -222,61 +311,17 @@ static struct clocksource clocksource_hpet = { | |||
| 222 | .mask = HPET_MASK, | 311 | .mask = HPET_MASK, |
| 223 | .shift = HPET_SHIFT, | 312 | .shift = HPET_SHIFT, |
| 224 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | 313 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, |
| 225 | .resume = hpet_start_counter, | 314 | .resume = hpet_restart_counter, |
| 315 | #ifdef CONFIG_X86_64 | ||
| 316 | .vread = vread_hpet, | ||
| 317 | #endif | ||
| 226 | }; | 318 | }; |
| 227 | 319 | ||
| 228 | /* | 320 | static int hpet_clocksource_register(void) |
| 229 | * Try to setup the HPET timer | ||
| 230 | */ | ||
| 231 | int __init hpet_enable(void) | ||
| 232 | { | 321 | { |
| 233 | unsigned long id; | ||
| 234 | uint64_t hpet_freq; | ||
| 235 | u64 tmp, start, now; | 322 | u64 tmp, start, now; |
| 236 | cycle_t t1; | 323 | cycle_t t1; |
| 237 | 324 | ||
| 238 | if (!is_hpet_capable()) | ||
| 239 | return 0; | ||
| 240 | |||
| 241 | hpet_virt_address = ioremap_nocache(hpet_address, HPET_MMAP_SIZE); | ||
| 242 | |||
| 243 | /* | ||
| 244 | * Read the period and check for a sane value: | ||
| 245 | */ | ||
| 246 | hpet_period = hpet_readl(HPET_PERIOD); | ||
| 247 | if (hpet_period < HPET_MIN_PERIOD || hpet_period > HPET_MAX_PERIOD) | ||
| 248 | goto out_nohpet; | ||
| 249 | |||
| 250 | /* | ||
| 251 | * The period is a femto seconds value. We need to calculate the | ||
| 252 | * scaled math multiplication factor for nanosecond to hpet tick | ||
| 253 | * conversion. | ||
| 254 | */ | ||
| 255 | hpet_freq = 1000000000000000ULL; | ||
| 256 | do_div(hpet_freq, hpet_period); | ||
| 257 | hpet_clockevent.mult = div_sc((unsigned long) hpet_freq, | ||
| 258 | NSEC_PER_SEC, 32); | ||
| 259 | /* Calculate the min / max delta */ | ||
| 260 | hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF, | ||
| 261 | &hpet_clockevent); | ||
| 262 | hpet_clockevent.min_delta_ns = clockevent_delta2ns(0x30, | ||
| 263 | &hpet_clockevent); | ||
| 264 | |||
| 265 | /* | ||
| 266 | * Read the HPET ID register to retrieve the IRQ routing | ||
| 267 | * information and the number of channels | ||
| 268 | */ | ||
| 269 | id = hpet_readl(HPET_ID); | ||
| 270 | |||
| 271 | #ifdef CONFIG_HPET_EMULATE_RTC | ||
| 272 | /* | ||
| 273 | * The legacy routing mode needs at least two channels, tick timer | ||
| 274 | * and the rtc emulation channel. | ||
| 275 | */ | ||
| 276 | if (!(id & HPET_ID_NUMBER)) | ||
| 277 | goto out_nohpet; | ||
| 278 | #endif | ||
| 279 | |||
| 280 | /* Start the counter */ | 325 | /* Start the counter */ |
| 281 | hpet_start_counter(); | 326 | hpet_start_counter(); |
| 282 | 327 | ||
| @@ -298,7 +343,7 @@ int __init hpet_enable(void) | |||
| 298 | if (t1 == read_hpet()) { | 343 | if (t1 == read_hpet()) { |
| 299 | printk(KERN_WARNING | 344 | printk(KERN_WARNING |
| 300 | "HPET counter not counting. HPET disabled\n"); | 345 | "HPET counter not counting. HPET disabled\n"); |
| 301 | goto out_nohpet; | 346 | return -ENODEV; |
| 302 | } | 347 | } |
| 303 | 348 | ||
| 304 | /* Initialize and register HPET clocksource | 349 | /* Initialize and register HPET clocksource |
| @@ -319,27 +364,84 @@ int __init hpet_enable(void) | |||
| 319 | 364 | ||
| 320 | clocksource_register(&clocksource_hpet); | 365 | clocksource_register(&clocksource_hpet); |
| 321 | 366 | ||
| 367 | return 0; | ||
| 368 | } | ||
| 369 | |||
| 370 | /* | ||
| 371 | * Try to setup the HPET timer | ||
| 372 | */ | ||
| 373 | int __init hpet_enable(void) | ||
| 374 | { | ||
| 375 | unsigned long id; | ||
| 376 | |||
| 377 | if (!is_hpet_capable()) | ||
| 378 | return 0; | ||
| 379 | |||
| 380 | hpet_set_mapping(); | ||
| 381 | |||
| 382 | /* | ||
| 383 | * Read the period and check for a sane value: | ||
| 384 | */ | ||
| 385 | hpet_period = hpet_readl(HPET_PERIOD); | ||
| 386 | if (hpet_period < HPET_MIN_PERIOD || hpet_period > HPET_MAX_PERIOD) | ||
| 387 | goto out_nohpet; | ||
| 388 | |||
| 389 | /* | ||
| 390 | * Read the HPET ID register to retrieve the IRQ routing | ||
| 391 | * information and the number of channels | ||
| 392 | */ | ||
| 393 | id = hpet_readl(HPET_ID); | ||
| 394 | |||
| 395 | #ifdef CONFIG_HPET_EMULATE_RTC | ||
| 396 | /* | ||
| 397 | * The legacy routing mode needs at least two channels, tick timer | ||
| 398 | * and the rtc emulation channel. | ||
| 399 | */ | ||
| 400 | if (!(id & HPET_ID_NUMBER)) | ||
| 401 | goto out_nohpet; | ||
| 402 | #endif | ||
| 403 | |||
| 404 | if (hpet_clocksource_register()) | ||
| 405 | goto out_nohpet; | ||
| 406 | |||
| 322 | if (id & HPET_ID_LEGSUP) { | 407 | if (id & HPET_ID_LEGSUP) { |
| 323 | hpet_enable_int(); | 408 | hpet_legacy_clockevent_register(); |
| 324 | hpet_reserve_platform_timers(id); | ||
| 325 | /* | ||
| 326 | * Start hpet with the boot cpu mask and make it | ||
| 327 | * global after the IO_APIC has been initialized. | ||
| 328 | */ | ||
| 329 | hpet_clockevent.cpumask = cpumask_of_cpu(smp_processor_id()); | ||
| 330 | clockevents_register_device(&hpet_clockevent); | ||
| 331 | global_clock_event = &hpet_clockevent; | ||
| 332 | return 1; | 409 | return 1; |
| 333 | } | 410 | } |
| 334 | return 0; | 411 | return 0; |
| 335 | 412 | ||
| 336 | out_nohpet: | 413 | out_nohpet: |
| 337 | iounmap(hpet_virt_address); | 414 | hpet_clear_mapping(); |
| 338 | hpet_virt_address = NULL; | ||
| 339 | boot_hpet_disable = 1; | 415 | boot_hpet_disable = 1; |
| 340 | return 0; | 416 | return 0; |
| 341 | } | 417 | } |
| 342 | 418 | ||
| 419 | /* | ||
| 420 | * Needs to be late, as the reserve_timer code calls kalloc ! | ||
| 421 | * | ||
| 422 | * Not a problem on i386 as hpet_enable is called from late_time_init, | ||
| 423 | * but on x86_64 it is necessary ! | ||
| 424 | */ | ||
| 425 | static __init int hpet_late_init(void) | ||
| 426 | { | ||
| 427 | if (boot_hpet_disable) | ||
| 428 | return -ENODEV; | ||
| 429 | |||
| 430 | if (!hpet_address) { | ||
| 431 | if (!force_hpet_address) | ||
| 432 | return -ENODEV; | ||
| 433 | |||
| 434 | hpet_address = force_hpet_address; | ||
| 435 | hpet_enable(); | ||
| 436 | if (!hpet_virt_address) | ||
| 437 | return -ENODEV; | ||
| 438 | } | ||
| 439 | |||
| 440 | hpet_reserve_platform_timers(hpet_readl(HPET_ID)); | ||
| 441 | |||
| 442 | return 0; | ||
| 443 | } | ||
| 444 | fs_initcall(hpet_late_init); | ||
| 343 | 445 | ||
| 344 | #ifdef CONFIG_HPET_EMULATE_RTC | 446 | #ifdef CONFIG_HPET_EMULATE_RTC |
| 345 | 447 | ||
diff --git a/arch/x86/kernel/hpet_64.c b/arch/x86/kernel/hpet_64.c deleted file mode 100644 index e2d1b912e154..000000000000 --- a/arch/x86/kernel/hpet_64.c +++ /dev/null | |||
| @@ -1,493 +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 | /* | ||
| 188 | * calibrate_tsc() calibrates the processor TSC in a very simple way, comparing | ||
| 189 | * it to the HPET timer of known frequency. | ||
| 190 | */ | ||
| 191 | |||
| 192 | #define TICK_COUNT 100000000 | ||
| 193 | #define SMI_THRESHOLD 50000 | ||
| 194 | #define MAX_TRIES 5 | ||
| 195 | |||
| 196 | /* | ||
| 197 | * Some platforms take periodic SMI interrupts with 5ms duration. Make sure none | ||
| 198 | * occurs between the reads of the hpet & TSC. | ||
| 199 | */ | ||
| 200 | static void __init read_hpet_tsc(int *hpet, int *tsc) | ||
| 201 | { | ||
| 202 | int tsc1, tsc2, hpet1, i; | ||
| 203 | |||
| 204 | for (i = 0; i < MAX_TRIES; i++) { | ||
| 205 | tsc1 = get_cycles_sync(); | ||
| 206 | hpet1 = hpet_readl(HPET_COUNTER); | ||
| 207 | tsc2 = get_cycles_sync(); | ||
| 208 | if ((tsc2 - tsc1) < SMI_THRESHOLD) | ||
| 209 | break; | ||
| 210 | } | ||
| 211 | *hpet = hpet1; | ||
| 212 | *tsc = tsc2; | ||
| 213 | } | ||
| 214 | |||
| 215 | unsigned int __init hpet_calibrate_tsc(void) | ||
| 216 | { | ||
| 217 | int tsc_start, hpet_start; | ||
| 218 | int tsc_now, hpet_now; | ||
| 219 | unsigned long flags; | ||
| 220 | |||
| 221 | local_irq_save(flags); | ||
| 222 | |||
| 223 | read_hpet_tsc(&hpet_start, &tsc_start); | ||
| 224 | |||
| 225 | do { | ||
| 226 | local_irq_disable(); | ||
| 227 | read_hpet_tsc(&hpet_now, &tsc_now); | ||
| 228 | local_irq_restore(flags); | ||
| 229 | } while ((tsc_now - tsc_start) < TICK_COUNT && | ||
| 230 | (hpet_now - hpet_start) < TICK_COUNT); | ||
| 231 | |||
| 232 | return (tsc_now - tsc_start) * 1000000000L | ||
| 233 | / ((hpet_now - hpet_start) * hpet_period / 1000); | ||
| 234 | } | ||
| 235 | |||
| 236 | #ifdef CONFIG_HPET_EMULATE_RTC | ||
| 237 | /* HPET in LegacyReplacement Mode eats up RTC interrupt line. When, HPET | ||
| 238 | * is enabled, we support RTC interrupt functionality in software. | ||
| 239 | * RTC has 3 kinds of interrupts: | ||
| 240 | * 1) Update Interrupt - generate an interrupt, every sec, when RTC clock | ||
| 241 | * is updated | ||
| 242 | * 2) Alarm Interrupt - generate an interrupt at a specific time of day | ||
| 243 | * 3) Periodic Interrupt - generate periodic interrupt, with frequencies | ||
| 244 | * 2Hz-8192Hz (2Hz-64Hz for non-root user) (all freqs in powers of 2) | ||
| 245 | * (1) and (2) above are implemented using polling at a frequency of | ||
| 246 | * 64 Hz. The exact frequency is a tradeoff between accuracy and interrupt | ||
| 247 | * overhead. (DEFAULT_RTC_INT_FREQ) | ||
| 248 | * For (3), we use interrupts at 64Hz or user specified periodic | ||
| 249 | * frequency, whichever is higher. | ||
| 250 | */ | ||
| 251 | #include <linux/rtc.h> | ||
| 252 | |||
| 253 | #define DEFAULT_RTC_INT_FREQ 64 | ||
| 254 | #define RTC_NUM_INTS 1 | ||
| 255 | |||
| 256 | static unsigned long UIE_on; | ||
| 257 | static unsigned long prev_update_sec; | ||
| 258 | |||
| 259 | static unsigned long AIE_on; | ||
| 260 | static struct rtc_time alarm_time; | ||
| 261 | |||
| 262 | static unsigned long PIE_on; | ||
| 263 | static unsigned long PIE_freq = DEFAULT_RTC_INT_FREQ; | ||
| 264 | static unsigned long PIE_count; | ||
| 265 | |||
| 266 | static unsigned long hpet_rtc_int_freq; /* RTC interrupt frequency */ | ||
| 267 | static unsigned int hpet_t1_cmp; /* cached comparator register */ | ||
| 268 | |||
| 269 | int is_hpet_enabled(void) | ||
| 270 | { | ||
| 271 | return hpet_address != 0; | ||
| 272 | } | ||
| 273 | |||
| 274 | /* | ||
| 275 | * Timer 1 for RTC, we do not use periodic interrupt feature, | ||
| 276 | * even if HPET supports periodic interrupts on Timer 1. | ||
| 277 | * The reason being, to set up a periodic interrupt in HPET, we need to | ||
| 278 | * stop the main counter. And if we do that everytime someone diables/enables | ||
| 279 | * RTC, we will have adverse effect on main kernel timer running on Timer 0. | ||
| 280 | * So, for the time being, simulate the periodic interrupt in software. | ||
| 281 | * | ||
| 282 | * hpet_rtc_timer_init() is called for the first time and during subsequent | ||
| 283 | * interuppts reinit happens through hpet_rtc_timer_reinit(). | ||
| 284 | */ | ||
| 285 | int hpet_rtc_timer_init(void) | ||
| 286 | { | ||
| 287 | unsigned int cfg, cnt; | ||
| 288 | unsigned long flags; | ||
| 289 | |||
| 290 | if (!is_hpet_enabled()) | ||
| 291 | return 0; | ||
| 292 | /* | ||
| 293 | * Set the counter 1 and enable the interrupts. | ||
| 294 | */ | ||
| 295 | if (PIE_on && (PIE_freq > DEFAULT_RTC_INT_FREQ)) | ||
| 296 | hpet_rtc_int_freq = PIE_freq; | ||
| 297 | else | ||
| 298 | hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ; | ||
| 299 | |||
| 300 | local_irq_save(flags); | ||
| 301 | |||
| 302 | cnt = hpet_readl(HPET_COUNTER); | ||
| 303 | cnt += ((hpet_tick*HZ)/hpet_rtc_int_freq); | ||
| 304 | hpet_writel(cnt, HPET_T1_CMP); | ||
| 305 | hpet_t1_cmp = cnt; | ||
| 306 | |||
| 307 | cfg = hpet_readl(HPET_T1_CFG); | ||
| 308 | cfg &= ~HPET_TN_PERIODIC; | ||
| 309 | cfg |= HPET_TN_ENABLE | HPET_TN_32BIT; | ||
| 310 | hpet_writel(cfg, HPET_T1_CFG); | ||
| 311 | |||
| 312 | local_irq_restore(flags); | ||
| 313 | |||
| 314 | return 1; | ||
| 315 | } | ||
| 316 | |||
| 317 | static void hpet_rtc_timer_reinit(void) | ||
| 318 | { | ||
| 319 | unsigned int cfg, cnt, ticks_per_int, lost_ints; | ||
| 320 | |||
| 321 | if (unlikely(!(PIE_on | AIE_on | UIE_on))) { | ||
| 322 | cfg = hpet_readl(HPET_T1_CFG); | ||
| 323 | cfg &= ~HPET_TN_ENABLE; | ||
| 324 | hpet_writel(cfg, HPET_T1_CFG); | ||
| 325 | return; | ||
| 326 | } | ||
| 327 | |||
| 328 | if (PIE_on && (PIE_freq > DEFAULT_RTC_INT_FREQ)) | ||
| 329 | hpet_rtc_int_freq = PIE_freq; | ||
| 330 | else | ||
| 331 | hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ; | ||
| 332 | |||
| 333 | /* It is more accurate to use the comparator value than current count.*/ | ||
| 334 | ticks_per_int = hpet_tick * HZ / hpet_rtc_int_freq; | ||
| 335 | hpet_t1_cmp += ticks_per_int; | ||
| 336 | hpet_writel(hpet_t1_cmp, HPET_T1_CMP); | ||
| 337 | |||
| 338 | /* | ||
| 339 | * If the interrupt handler was delayed too long, the write above tries | ||
| 340 | * to schedule the next interrupt in the past and the hardware would | ||
| 341 | * not interrupt until the counter had wrapped around. | ||
| 342 | * So we have to check that the comparator wasn't set to a past time. | ||
| 343 | */ | ||
| 344 | cnt = hpet_readl(HPET_COUNTER); | ||
| 345 | if (unlikely((int)(cnt - hpet_t1_cmp) > 0)) { | ||
| 346 | lost_ints = (cnt - hpet_t1_cmp) / ticks_per_int + 1; | ||
| 347 | /* Make sure that, even with the time needed to execute | ||
| 348 | * this code, the next scheduled interrupt has been moved | ||
| 349 | * back to the future: */ | ||
| 350 | lost_ints++; | ||
| 351 | |||
| 352 | hpet_t1_cmp += lost_ints * ticks_per_int; | ||
| 353 | hpet_writel(hpet_t1_cmp, HPET_T1_CMP); | ||
| 354 | |||
| 355 | if (PIE_on) | ||
| 356 | PIE_count += lost_ints; | ||
| 357 | |||
| 358 | if (printk_ratelimit()) | ||
| 359 | printk(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n", | ||
| 360 | hpet_rtc_int_freq); | ||
| 361 | } | ||
| 362 | } | ||
| 363 | |||
| 364 | /* | ||
| 365 | * The functions below are called from rtc driver. | ||
| 366 | * Return 0 if HPET is not being used. | ||
| 367 | * Otherwise do the necessary changes and return 1. | ||
| 368 | */ | ||
| 369 | int hpet_mask_rtc_irq_bit(unsigned long bit_mask) | ||
| 370 | { | ||
| 371 | if (!is_hpet_enabled()) | ||
| 372 | return 0; | ||
| 373 | |||
| 374 | if (bit_mask & RTC_UIE) | ||
| 375 | UIE_on = 0; | ||
| 376 | if (bit_mask & RTC_PIE) | ||
| 377 | PIE_on = 0; | ||
| 378 | if (bit_mask & RTC_AIE) | ||
| 379 | AIE_on = 0; | ||
| 380 | |||
| 381 | return 1; | ||
| 382 | } | ||
| 383 | |||
| 384 | int hpet_set_rtc_irq_bit(unsigned long bit_mask) | ||
| 385 | { | ||
| 386 | int timer_init_reqd = 0; | ||
| 387 | |||
| 388 | if (!is_hpet_enabled()) | ||
| 389 | return 0; | ||
| 390 | |||
| 391 | if (!(PIE_on | AIE_on | UIE_on)) | ||
| 392 | timer_init_reqd = 1; | ||
| 393 | |||
| 394 | if (bit_mask & RTC_UIE) { | ||
| 395 | UIE_on = 1; | ||
| 396 | } | ||
| 397 | if (bit_mask & RTC_PIE) { | ||
| 398 | PIE_on = 1; | ||
| 399 | PIE_count = 0; | ||
| 400 | } | ||
| 401 | if (bit_mask & RTC_AIE) { | ||
| 402 | AIE_on = 1; | ||
| 403 | } | ||
| 404 | |||
| 405 | if (timer_init_reqd) | ||
| 406 | hpet_rtc_timer_init(); | ||
| 407 | |||
| 408 | return 1; | ||
| 409 | } | ||
| 410 | |||
| 411 | int hpet_set_alarm_time(unsigned char hrs, unsigned char min, unsigned char sec) | ||
| 412 | { | ||
| 413 | if (!is_hpet_enabled()) | ||
| 414 | return 0; | ||
| 415 | |||
| 416 | alarm_time.tm_hour = hrs; | ||
| 417 | alarm_time.tm_min = min; | ||
| 418 | alarm_time.tm_sec = sec; | ||
| 419 | |||
| 420 | return 1; | ||
| 421 | } | ||
| 422 | |||
| 423 | int hpet_set_periodic_freq(unsigned long freq) | ||
| 424 | { | ||
| 425 | if (!is_hpet_enabled()) | ||
| 426 | return 0; | ||
| 427 | |||
| 428 | PIE_freq = freq; | ||
| 429 | PIE_count = 0; | ||
| 430 | |||
| 431 | return 1; | ||
| 432 | } | ||
| 433 | |||
| 434 | int hpet_rtc_dropped_irq(void) | ||
| 435 | { | ||
| 436 | if (!is_hpet_enabled()) | ||
| 437 | return 0; | ||
| 438 | |||
| 439 | return 1; | ||
| 440 | } | ||
| 441 | |||
| 442 | irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id) | ||
| 443 | { | ||
| 444 | struct rtc_time curr_time; | ||
| 445 | unsigned long rtc_int_flag = 0; | ||
| 446 | int call_rtc_interrupt = 0; | ||
| 447 | |||
| 448 | hpet_rtc_timer_reinit(); | ||
| 449 | |||
| 450 | if (UIE_on | AIE_on) { | ||
| 451 | rtc_get_rtc_time(&curr_time); | ||
| 452 | } | ||
| 453 | if (UIE_on) { | ||
| 454 | if (curr_time.tm_sec != prev_update_sec) { | ||
| 455 | /* Set update int info, call real rtc int routine */ | ||
| 456 | call_rtc_interrupt = 1; | ||
| 457 | rtc_int_flag = RTC_UF; | ||
| 458 | prev_update_sec = curr_time.tm_sec; | ||
| 459 | } | ||
| 460 | } | ||
| 461 | if (PIE_on) { | ||
| 462 | PIE_count++; | ||
| 463 | if (PIE_count >= hpet_rtc_int_freq/PIE_freq) { | ||
| 464 | /* Set periodic int info, call real rtc int routine */ | ||
| 465 | call_rtc_interrupt = 1; | ||
| 466 | rtc_int_flag |= RTC_PF; | ||
| 467 | PIE_count = 0; | ||
| 468 | } | ||
| 469 | } | ||
| 470 | if (AIE_on) { | ||
| 471 | if ((curr_time.tm_sec == alarm_time.tm_sec) && | ||
| 472 | (curr_time.tm_min == alarm_time.tm_min) && | ||
| 473 | (curr_time.tm_hour == alarm_time.tm_hour)) { | ||
| 474 | /* Set alarm int info, call real rtc int routine */ | ||
| 475 | call_rtc_interrupt = 1; | ||
| 476 | rtc_int_flag |= RTC_AF; | ||
| 477 | } | ||
| 478 | } | ||
| 479 | if (call_rtc_interrupt) { | ||
| 480 | rtc_int_flag |= (RTC_IRQF | (RTC_NUM_INTS << 8)); | ||
| 481 | rtc_interrupt(rtc_int_flag, dev_id); | ||
| 482 | } | ||
| 483 | return IRQ_HANDLED; | ||
| 484 | } | ||
| 485 | #endif | ||
| 486 | |||
| 487 | static int __init nohpet_setup(char *s) | ||
| 488 | { | ||
| 489 | nohpet = 1; | ||
| 490 | return 1; | ||
| 491 | } | ||
| 492 | |||
| 493 | __setup("nohpet", nohpet_setup); | ||
diff --git a/arch/x86/kernel/i8253_32.c b/arch/x86/kernel/i8253.c index 6d839f2f1b1a..ac15e4cbd9c1 100644 --- a/arch/x86/kernel/i8253_32.c +++ b/arch/x86/kernel/i8253.c | |||
| @@ -13,7 +13,6 @@ | |||
| 13 | #include <asm/delay.h> | 13 | #include <asm/delay.h> |
| 14 | #include <asm/i8253.h> | 14 | #include <asm/i8253.h> |
| 15 | #include <asm/io.h> | 15 | #include <asm/io.h> |
| 16 | #include <asm/timer.h> | ||
| 17 | 16 | ||
| 18 | DEFINE_SPINLOCK(i8253_lock); | 17 | DEFINE_SPINLOCK(i8253_lock); |
| 19 | EXPORT_SYMBOL(i8253_lock); | 18 | EXPORT_SYMBOL(i8253_lock); |
| @@ -120,6 +119,7 @@ void __init setup_pit_timer(void) | |||
| 120 | global_clock_event = &pit_clockevent; | 119 | global_clock_event = &pit_clockevent; |
| 121 | } | 120 | } |
| 122 | 121 | ||
| 122 | #ifndef CONFIG_X86_64 | ||
| 123 | /* | 123 | /* |
| 124 | * Since the PIT overflows every tick, its not very useful | 124 | * Since the PIT overflows every tick, its not very useful |
| 125 | * to just read by itself. So use jiffies to emulate a free | 125 | * to just read by itself. So use jiffies to emulate a free |
| @@ -204,3 +204,5 @@ static int __init init_pit_clocksource(void) | |||
| 204 | return clocksource_register(&clocksource_pit); | 204 | return clocksource_register(&clocksource_pit); |
| 205 | } | 205 | } |
| 206 | arch_initcall(init_pit_clocksource); | 206 | arch_initcall(init_pit_clocksource); |
| 207 | |||
| 208 | #endif | ||
diff --git a/arch/x86/kernel/i8259_32.c b/arch/x86/kernel/i8259_32.c index 0499cbe9871a..679bb33acbf1 100644 --- a/arch/x86/kernel/i8259_32.c +++ b/arch/x86/kernel/i8259_32.c | |||
| @@ -10,7 +10,6 @@ | |||
| 10 | #include <linux/sysdev.h> | 10 | #include <linux/sysdev.h> |
| 11 | #include <linux/bitops.h> | 11 | #include <linux/bitops.h> |
| 12 | 12 | ||
| 13 | #include <asm/8253pit.h> | ||
| 14 | #include <asm/atomic.h> | 13 | #include <asm/atomic.h> |
| 15 | #include <asm/system.h> | 14 | #include <asm/system.h> |
| 16 | #include <asm/io.h> | 15 | #include <asm/io.h> |
diff --git a/arch/x86/kernel/i8259_64.c b/arch/x86/kernel/i8259_64.c index 948cae646099..eb72976cc13c 100644 --- a/arch/x86/kernel/i8259_64.c +++ b/arch/x86/kernel/i8259_64.c | |||
| @@ -444,46 +444,6 @@ void __init init_ISA_irqs (void) | |||
| 444 | } | 444 | } |
| 445 | } | 445 | } |
| 446 | 446 | ||
| 447 | static void setup_timer_hardware(void) | ||
| 448 | { | ||
| 449 | outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */ | ||
| 450 | udelay(10); | ||
| 451 | outb_p(LATCH & 0xff , 0x40); /* LSB */ | ||
| 452 | udelay(10); | ||
| 453 | outb(LATCH >> 8 , 0x40); /* MSB */ | ||
| 454 | } | ||
| 455 | |||
| 456 | static int timer_resume(struct sys_device *dev) | ||
| 457 | { | ||
| 458 | setup_timer_hardware(); | ||
| 459 | return 0; | ||
| 460 | } | ||
| 461 | |||
| 462 | void i8254_timer_resume(void) | ||
| 463 | { | ||
| 464 | setup_timer_hardware(); | ||
| 465 | } | ||
| 466 | |||
| 467 | static struct sysdev_class timer_sysclass = { | ||
| 468 | set_kset_name("timer_pit"), | ||
| 469 | .resume = timer_resume, | ||
| 470 | }; | ||
| 471 | |||
| 472 | static struct sys_device device_timer = { | ||
| 473 | .id = 0, | ||
| 474 | .cls = &timer_sysclass, | ||
| 475 | }; | ||
| 476 | |||
| 477 | static int __init init_timer_sysfs(void) | ||
| 478 | { | ||
| 479 | int error = sysdev_class_register(&timer_sysclass); | ||
| 480 | if (!error) | ||
| 481 | error = sysdev_register(&device_timer); | ||
| 482 | return error; | ||
| 483 | } | ||
| 484 | |||
| 485 | device_initcall(init_timer_sysfs); | ||
| 486 | |||
| 487 | void __init init_IRQ(void) | 447 | void __init init_IRQ(void) |
| 488 | { | 448 | { |
| 489 | int i; | 449 | int i; |
| @@ -533,12 +493,6 @@ void __init init_IRQ(void) | |||
| 533 | set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt); | 493 | set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt); |
| 534 | set_intr_gate(ERROR_APIC_VECTOR, error_interrupt); | 494 | set_intr_gate(ERROR_APIC_VECTOR, error_interrupt); |
| 535 | 495 | ||
| 536 | /* | ||
| 537 | * Set the clock to HZ Hz, we already have a valid | ||
| 538 | * vector now: | ||
| 539 | */ | ||
| 540 | setup_timer_hardware(); | ||
| 541 | |||
| 542 | if (!acpi_ioapic) | 496 | if (!acpi_ioapic) |
| 543 | setup_irq(2, &irq2); | 497 | setup_irq(2, &irq2); |
| 544 | } | 498 | } |
diff --git a/arch/x86/kernel/mfgpt_32.c b/arch/x86/kernel/mfgpt_32.c new file mode 100644 index 000000000000..0ab680f2d9db --- /dev/null +++ b/arch/x86/kernel/mfgpt_32.c | |||
| @@ -0,0 +1,362 @@ | |||
| 1 | /* | ||
| 2 | * Driver/API for AMD Geode Multi-Function General Purpose Timers (MFGPT) | ||
| 3 | * | ||
| 4 | * Copyright (C) 2006, Advanced Micro Devices, Inc. | ||
| 5 | * Copyright (C) 2007, Andres Salomon <dilinger@debian.org> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of version 2 of the GNU General Public License | ||
| 9 | * as published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * The MFGPTs are documented in AMD Geode CS5536 Companion Device Data Book. | ||
| 12 | */ | ||
| 13 | |||
| 14 | /* | ||
| 15 | * We are using the 32Khz input clock - its the only one that has the | ||
| 16 | * ranges we find desirable. The following table lists the suitable | ||
| 17 | * divisors and the associated hz, minimum interval | ||
| 18 | * and the maximum interval: | ||
| 19 | * | ||
| 20 | * Divisor Hz Min Delta (S) Max Delta (S) | ||
| 21 | * 1 32000 .0005 2.048 | ||
| 22 | * 2 16000 .001 4.096 | ||
| 23 | * 4 8000 .002 8.192 | ||
| 24 | * 8 4000 .004 16.384 | ||
| 25 | * 16 2000 .008 32.768 | ||
| 26 | * 32 1000 .016 65.536 | ||
| 27 | * 64 500 .032 131.072 | ||
| 28 | * 128 250 .064 262.144 | ||
| 29 | * 256 125 .128 524.288 | ||
| 30 | */ | ||
| 31 | |||
| 32 | #include <linux/kernel.h> | ||
| 33 | #include <linux/interrupt.h> | ||
| 34 | #include <linux/module.h> | ||
| 35 | #include <asm/geode.h> | ||
| 36 | |||
| 37 | #define F_AVAIL 0x01 | ||
| 38 | |||
| 39 | static struct mfgpt_timer_t { | ||
| 40 | int flags; | ||
| 41 | struct module *owner; | ||
| 42 | } mfgpt_timers[MFGPT_MAX_TIMERS]; | ||
| 43 | |||
| 44 | /* Selected from the table above */ | ||
| 45 | |||
| 46 | #define MFGPT_DIVISOR 16 | ||
| 47 | #define MFGPT_SCALE 4 /* divisor = 2^(scale) */ | ||
| 48 | #define MFGPT_HZ (32000 / MFGPT_DIVISOR) | ||
| 49 | #define MFGPT_PERIODIC (MFGPT_HZ / HZ) | ||
| 50 | |||
| 51 | #ifdef CONFIG_GEODE_MFGPT_TIMER | ||
| 52 | static int __init mfgpt_timer_setup(void); | ||
| 53 | #else | ||
| 54 | #define mfgpt_timer_setup() (0) | ||
| 55 | #endif | ||
| 56 | |||
| 57 | /* Allow for disabling of MFGPTs */ | ||
| 58 | static int disable; | ||
| 59 | static int __init mfgpt_disable(char *s) | ||
| 60 | { | ||
| 61 | disable = 1; | ||
| 62 | return 1; | ||
| 63 | } | ||
| 64 | __setup("nomfgpt", mfgpt_disable); | ||
| 65 | |||
| 66 | /* | ||
| 67 | * Check whether any MFGPTs are available for the kernel to use. In most | ||
| 68 | * cases, firmware that uses AMD's VSA code will claim all timers during | ||
| 69 | * bootup; we certainly don't want to take them if they're already in use. | ||
| 70 | * In other cases (such as with VSAless OpenFirmware), the system firmware | ||
| 71 | * leaves timers available for us to use. | ||
| 72 | */ | ||
| 73 | int __init geode_mfgpt_detect(void) | ||
| 74 | { | ||
| 75 | int count = 0, i; | ||
| 76 | u16 val; | ||
| 77 | |||
| 78 | if (disable) { | ||
| 79 | printk(KERN_INFO "geode-mfgpt: Skipping MFGPT setup\n"); | ||
| 80 | return 0; | ||
| 81 | } | ||
| 82 | |||
| 83 | for (i = 0; i < MFGPT_MAX_TIMERS; i++) { | ||
| 84 | val = geode_mfgpt_read(i, MFGPT_REG_SETUP); | ||
| 85 | if (!(val & MFGPT_SETUP_SETUP)) { | ||
| 86 | mfgpt_timers[i].flags = F_AVAIL; | ||
| 87 | count++; | ||
| 88 | } | ||
| 89 | } | ||
| 90 | |||
| 91 | /* set up clock event device, if desired */ | ||
| 92 | i = mfgpt_timer_setup(); | ||
| 93 | |||
| 94 | return count; | ||
| 95 | } | ||
| 96 | |||
| 97 | int geode_mfgpt_toggle_event(int timer, int cmp, int event, int enable) | ||
| 98 | { | ||
| 99 | u32 msr, mask, value, dummy; | ||
| 100 | int shift = (cmp == MFGPT_CMP1) ? 0 : 8; | ||
| 101 | |||
| 102 | if (timer < 0 || timer >= MFGPT_MAX_TIMERS) | ||
| 103 | return -EIO; | ||
| 104 | |||
| 105 | /* | ||
| 106 | * The register maps for these are described in sections 6.17.1.x of | ||
| 107 | * the AMD Geode CS5536 Companion Device Data Book. | ||
| 108 | */ | ||
| 109 | switch (event) { | ||
| 110 | case MFGPT_EVENT_RESET: | ||
| 111 | /* | ||
| 112 | * XXX: According to the docs, we cannot reset timers above | ||
| 113 | * 6; that is, resets for 7 and 8 will be ignored. Is this | ||
| 114 | * a problem? -dilinger | ||
| 115 | */ | ||
| 116 | msr = MFGPT_NR_MSR; | ||
| 117 | mask = 1 << (timer + 24); | ||
| 118 | break; | ||
| 119 | |||
| 120 | case MFGPT_EVENT_NMI: | ||
| 121 | msr = MFGPT_NR_MSR; | ||
| 122 | mask = 1 << (timer + shift); | ||
| 123 | break; | ||
| 124 | |||
| 125 | case MFGPT_EVENT_IRQ: | ||
| 126 | msr = MFGPT_IRQ_MSR; | ||
| 127 | mask = 1 << (timer + shift); | ||
| 128 | break; | ||
| 129 | |||
| 130 | default: | ||
| 131 | return -EIO; | ||
| 132 | } | ||
| 133 | |||
| 134 | rdmsr(msr, value, dummy); | ||
| 135 | |||
| 136 | if (enable) | ||
| 137 | value |= mask; | ||
| 138 | else | ||
| 139 | value &= ~mask; | ||
| 140 | |||
| 141 | wrmsr(msr, value, dummy); | ||
| 142 | return 0; | ||
| 143 | } | ||
| 144 | |||
| 145 | int geode_mfgpt_set_irq(int timer, int cmp, int irq, int enable) | ||
| 146 | { | ||
| 147 | u32 val, dummy; | ||
| 148 | int offset; | ||
| 149 | |||
| 150 | if (timer < 0 || timer >= MFGPT_MAX_TIMERS) | ||
| 151 | return -EIO; | ||
| 152 | |||
| 153 | if (geode_mfgpt_toggle_event(timer, cmp, MFGPT_EVENT_IRQ, enable)) | ||
| 154 | return -EIO; | ||
| 155 | |||
| 156 | rdmsr(MSR_PIC_ZSEL_LOW, val, dummy); | ||
| 157 | |||
| 158 | offset = (timer % 4) * 4; | ||
| 159 | |||
| 160 | val &= ~((0xF << offset) | (0xF << (offset + 16))); | ||
| 161 | |||
| 162 | if (enable) { | ||
| 163 | val |= (irq & 0x0F) << (offset); | ||
| 164 | val |= (irq & 0x0F) << (offset + 16); | ||
| 165 | } | ||
| 166 | |||
| 167 | wrmsr(MSR_PIC_ZSEL_LOW, val, dummy); | ||
| 168 | return 0; | ||
| 169 | } | ||
| 170 | |||
| 171 | static int mfgpt_get(int timer, struct module *owner) | ||
| 172 | { | ||
| 173 | mfgpt_timers[timer].flags &= ~F_AVAIL; | ||
| 174 | mfgpt_timers[timer].owner = owner; | ||
| 175 | printk(KERN_INFO "geode-mfgpt: Registered timer %d\n", timer); | ||
| 176 | return timer; | ||
| 177 | } | ||
| 178 | |||
| 179 | int geode_mfgpt_alloc_timer(int timer, int domain, struct module *owner) | ||
| 180 | { | ||
| 181 | int i; | ||
| 182 | |||
| 183 | if (!geode_get_dev_base(GEODE_DEV_MFGPT)) | ||
| 184 | return -ENODEV; | ||
| 185 | if (timer >= MFGPT_MAX_TIMERS) | ||
| 186 | return -EIO; | ||
| 187 | |||
| 188 | if (timer < 0) { | ||
| 189 | /* Try to find an available timer */ | ||
| 190 | for (i = 0; i < MFGPT_MAX_TIMERS; i++) { | ||
| 191 | if (mfgpt_timers[i].flags & F_AVAIL) | ||
| 192 | return mfgpt_get(i, owner); | ||
| 193 | |||
| 194 | if (i == 5 && domain == MFGPT_DOMAIN_WORKING) | ||
| 195 | break; | ||
| 196 | } | ||
| 197 | } else { | ||
| 198 | /* If they requested a specific timer, try to honor that */ | ||
| 199 | if (mfgpt_timers[timer].flags & F_AVAIL) | ||
| 200 | return mfgpt_get(timer, owner); | ||
| 201 | } | ||
| 202 | |||
| 203 | /* No timers available - too bad */ | ||
| 204 | return -1; | ||
| 205 | } | ||
| 206 | |||
| 207 | |||
| 208 | #ifdef CONFIG_GEODE_MFGPT_TIMER | ||
| 209 | |||
| 210 | /* | ||
| 211 | * The MFPGT timers on the CS5536 provide us with suitable timers to use | ||
| 212 | * as clock event sources - not as good as a HPET or APIC, but certainly | ||
| 213 | * better then the PIT. This isn't a general purpose MFGPT driver, but | ||
| 214 | * a simplified one designed specifically to act as a clock event source. | ||
| 215 | * For full details about the MFGPT, please consult the CS5536 data sheet. | ||
| 216 | */ | ||
| 217 | |||
| 218 | #include <linux/clocksource.h> | ||
| 219 | #include <linux/clockchips.h> | ||
| 220 | |||
| 221 | static unsigned int mfgpt_tick_mode = CLOCK_EVT_MODE_SHUTDOWN; | ||
| 222 | static u16 mfgpt_event_clock; | ||
| 223 | |||
| 224 | static int irq = 7; | ||
| 225 | static int __init mfgpt_setup(char *str) | ||
| 226 | { | ||
| 227 | get_option(&str, &irq); | ||
| 228 | return 1; | ||
| 229 | } | ||
| 230 | __setup("mfgpt_irq=", mfgpt_setup); | ||
| 231 | |||
| 232 | static inline void mfgpt_disable_timer(u16 clock) | ||
| 233 | { | ||
| 234 | u16 val = geode_mfgpt_read(clock, MFGPT_REG_SETUP); | ||
| 235 | geode_mfgpt_write(clock, MFGPT_REG_SETUP, val & ~MFGPT_SETUP_CNTEN); | ||
| 236 | } | ||
| 237 | |||
| 238 | static int mfgpt_next_event(unsigned long, struct clock_event_device *); | ||
| 239 | static void mfgpt_set_mode(enum clock_event_mode, struct clock_event_device *); | ||
| 240 | |||
| 241 | static struct clock_event_device mfgpt_clockevent = { | ||
| 242 | .name = "mfgpt-timer", | ||
| 243 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, | ||
| 244 | .set_mode = mfgpt_set_mode, | ||
| 245 | .set_next_event = mfgpt_next_event, | ||
| 246 | .rating = 250, | ||
| 247 | .cpumask = CPU_MASK_ALL, | ||
| 248 | .shift = 32 | ||
| 249 | }; | ||
| 250 | |||
| 251 | static inline void mfgpt_start_timer(u16 clock, u16 delta) | ||
| 252 | { | ||
| 253 | geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_CMP2, (u16) delta); | ||
| 254 | geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_COUNTER, 0); | ||
| 255 | |||
| 256 | geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_SETUP, | ||
| 257 | MFGPT_SETUP_CNTEN | MFGPT_SETUP_CMP2); | ||
| 258 | } | ||
| 259 | |||
| 260 | static void mfgpt_set_mode(enum clock_event_mode mode, | ||
| 261 | struct clock_event_device *evt) | ||
| 262 | { | ||
| 263 | mfgpt_disable_timer(mfgpt_event_clock); | ||
| 264 | |||
| 265 | if (mode == CLOCK_EVT_MODE_PERIODIC) | ||
| 266 | mfgpt_start_timer(mfgpt_event_clock, MFGPT_PERIODIC); | ||
| 267 | |||
| 268 | mfgpt_tick_mode = mode; | ||
| 269 | } | ||
| 270 | |||
| 271 | static int mfgpt_next_event(unsigned long delta, struct clock_event_device *evt) | ||
| 272 | { | ||
| 273 | mfgpt_start_timer(mfgpt_event_clock, delta); | ||
| 274 | return 0; | ||
| 275 | } | ||
| 276 | |||
| 277 | /* Assume (foolishly?), that this interrupt was due to our tick */ | ||
| 278 | |||
| 279 | static irqreturn_t mfgpt_tick(int irq, void *dev_id) | ||
| 280 | { | ||
| 281 | if (mfgpt_tick_mode == CLOCK_EVT_MODE_SHUTDOWN) | ||
| 282 | return IRQ_HANDLED; | ||
| 283 | |||
| 284 | /* Turn off the clock */ | ||
| 285 | mfgpt_disable_timer(mfgpt_event_clock); | ||
| 286 | |||
| 287 | /* Clear the counter */ | ||
| 288 | geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_COUNTER, 0); | ||
| 289 | |||
| 290 | /* Restart the clock in periodic mode */ | ||
| 291 | |||
| 292 | if (mfgpt_tick_mode == CLOCK_EVT_MODE_PERIODIC) { | ||
| 293 | geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_SETUP, | ||
| 294 | MFGPT_SETUP_CNTEN | MFGPT_SETUP_CMP2); | ||
| 295 | } | ||
| 296 | |||
| 297 | mfgpt_clockevent.event_handler(&mfgpt_clockevent); | ||
| 298 | return IRQ_HANDLED; | ||
| 299 | } | ||
| 300 | |||
| 301 | static struct irqaction mfgptirq = { | ||
| 302 | .handler = mfgpt_tick, | ||
| 303 | .flags = IRQF_DISABLED | IRQF_NOBALANCING, | ||
| 304 | .mask = CPU_MASK_NONE, | ||
| 305 | .name = "mfgpt-timer" | ||
| 306 | }; | ||
| 307 | |||
| 308 | static int __init mfgpt_timer_setup(void) | ||
| 309 | { | ||
| 310 | int timer, ret; | ||
| 311 | u16 val; | ||
| 312 | |||
| 313 | timer = geode_mfgpt_alloc_timer(MFGPT_TIMER_ANY, MFGPT_DOMAIN_WORKING, | ||
| 314 | THIS_MODULE); | ||
| 315 | if (timer < 0) { | ||
| 316 | printk(KERN_ERR | ||
| 317 | "mfgpt-timer: Could not allocate a MFPGT timer\n"); | ||
| 318 | return -ENODEV; | ||
| 319 | } | ||
| 320 | |||
| 321 | mfgpt_event_clock = timer; | ||
| 322 | /* Set the clock scale and enable the event mode for CMP2 */ | ||
| 323 | val = MFGPT_SCALE | (3 << 8); | ||
| 324 | |||
| 325 | geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_SETUP, val); | ||
| 326 | |||
| 327 | /* Set up the IRQ on the MFGPT side */ | ||
| 328 | if (geode_mfgpt_setup_irq(mfgpt_event_clock, MFGPT_CMP2, irq)) { | ||
| 329 | printk(KERN_ERR "mfgpt-timer: Could not set up IRQ %d\n", irq); | ||
| 330 | return -EIO; | ||
| 331 | } | ||
| 332 | |||
| 333 | /* And register it with the kernel */ | ||
| 334 | ret = setup_irq(irq, &mfgptirq); | ||
| 335 | |||
| 336 | if (ret) { | ||
| 337 | printk(KERN_ERR | ||
| 338 | "mfgpt-timer: Unable to set up the interrupt.\n"); | ||
| 339 | goto err; | ||
| 340 | } | ||
| 341 | |||
| 342 | /* Set up the clock event */ | ||
| 343 | mfgpt_clockevent.mult = div_sc(MFGPT_HZ, NSEC_PER_SEC, 32); | ||
| 344 | mfgpt_clockevent.min_delta_ns = clockevent_delta2ns(0xF, | ||
| 345 | &mfgpt_clockevent); | ||
| 346 | mfgpt_clockevent.max_delta_ns = clockevent_delta2ns(0xFFFE, | ||
| 347 | &mfgpt_clockevent); | ||
| 348 | |||
| 349 | printk(KERN_INFO | ||
| 350 | "mfgpt-timer: registering the MFGT timer as a clock event.\n"); | ||
| 351 | clockevents_register_device(&mfgpt_clockevent); | ||
| 352 | |||
| 353 | return 0; | ||
| 354 | |||
| 355 | err: | ||
| 356 | geode_mfgpt_release_irq(mfgpt_event_clock, MFGPT_CMP2, irq); | ||
| 357 | printk(KERN_ERR | ||
| 358 | "mfgpt-timer: Unable to set up the MFGPT clock source\n"); | ||
| 359 | return -EIO; | ||
| 360 | } | ||
| 361 | |||
| 362 | #endif | ||
diff --git a/arch/x86/kernel/nmi_32.c b/arch/x86/kernel/nmi_32.c index c7227e2180f8..95d3fc203cf7 100644 --- a/arch/x86/kernel/nmi_32.c +++ b/arch/x86/kernel/nmi_32.c | |||
| @@ -353,7 +353,8 @@ __kprobes int nmi_watchdog_tick(struct pt_regs * regs, unsigned reason) | |||
| 353 | * Take the local apic timer and PIT/HPET into account. We don't | 353 | * Take the local apic timer and PIT/HPET into account. We don't |
| 354 | * know which one is active, when we have highres/dyntick on | 354 | * know which one is active, when we have highres/dyntick on |
| 355 | */ | 355 | */ |
| 356 | sum = per_cpu(irq_stat, cpu).apic_timer_irqs + kstat_cpu(cpu).irqs[0]; | 356 | sum = per_cpu(irq_stat, cpu).apic_timer_irqs + |
| 357 | per_cpu(irq_stat, cpu).irq0_irqs; | ||
| 357 | 358 | ||
| 358 | /* if the none of the timers isn't firing, this cpu isn't doing much */ | 359 | /* if the none of the timers isn't firing, this cpu isn't doing much */ |
| 359 | if (!touched && last_irq_sums[cpu] == sum) { | 360 | if (!touched && last_irq_sums[cpu] == sum) { |
diff --git a/arch/x86/kernel/nmi_64.c b/arch/x86/kernel/nmi_64.c index 0ec6d2ddb931..e60ac0da5283 100644 --- a/arch/x86/kernel/nmi_64.c +++ b/arch/x86/kernel/nmi_64.c | |||
| @@ -329,7 +329,7 @@ int __kprobes nmi_watchdog_tick(struct pt_regs * regs, unsigned reason) | |||
| 329 | touched = 1; | 329 | touched = 1; |
| 330 | } | 330 | } |
| 331 | 331 | ||
| 332 | sum = read_pda(apic_timer_irqs); | 332 | sum = read_pda(apic_timer_irqs) + read_pda(irq0_irqs); |
| 333 | if (__get_cpu_var(nmi_touch)) { | 333 | if (__get_cpu_var(nmi_touch)) { |
| 334 | __get_cpu_var(nmi_touch) = 0; | 334 | __get_cpu_var(nmi_touch) = 0; |
| 335 | touched = 1; | 335 | touched = 1; |
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index 98956555450b..6f9dbbe65eef 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c | |||
| @@ -38,6 +38,7 @@ | |||
| 38 | #include <linux/notifier.h> | 38 | #include <linux/notifier.h> |
| 39 | #include <linux/kprobes.h> | 39 | #include <linux/kprobes.h> |
| 40 | #include <linux/kdebug.h> | 40 | #include <linux/kdebug.h> |
| 41 | #include <linux/tick.h> | ||
| 41 | 42 | ||
| 42 | #include <asm/uaccess.h> | 43 | #include <asm/uaccess.h> |
| 43 | #include <asm/pgtable.h> | 44 | #include <asm/pgtable.h> |
| @@ -208,6 +209,8 @@ void cpu_idle (void) | |||
| 208 | if (__get_cpu_var(cpu_idle_state)) | 209 | if (__get_cpu_var(cpu_idle_state)) |
| 209 | __get_cpu_var(cpu_idle_state) = 0; | 210 | __get_cpu_var(cpu_idle_state) = 0; |
| 210 | 211 | ||
| 212 | tick_nohz_stop_sched_tick(); | ||
| 213 | |||
| 211 | rmb(); | 214 | rmb(); |
| 212 | idle = pm_idle; | 215 | idle = pm_idle; |
| 213 | if (!idle) | 216 | if (!idle) |
| @@ -228,6 +231,7 @@ void cpu_idle (void) | |||
| 228 | __exit_idle(); | 231 | __exit_idle(); |
| 229 | } | 232 | } |
| 230 | 233 | ||
| 234 | tick_nohz_restart_sched_tick(); | ||
| 231 | preempt_enable_no_resched(); | 235 | preempt_enable_no_resched(); |
| 232 | schedule(); | 236 | schedule(); |
| 233 | preempt_disable(); | 237 | preempt_disable(); |
diff --git a/arch/x86/kernel/quirks.c b/arch/x86/kernel/quirks.c index 6722469c2633..d769e204f942 100644 --- a/arch/x86/kernel/quirks.c +++ b/arch/x86/kernel/quirks.c | |||
| @@ -4,6 +4,8 @@ | |||
| 4 | #include <linux/pci.h> | 4 | #include <linux/pci.h> |
| 5 | #include <linux/irq.h> | 5 | #include <linux/irq.h> |
| 6 | 6 | ||
| 7 | #include <asm/hpet.h> | ||
| 8 | |||
| 7 | #if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_SMP) && defined(CONFIG_PCI) | 9 | #if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_SMP) && defined(CONFIG_PCI) |
| 8 | 10 | ||
| 9 | static void __devinit quirk_intel_irqbalance(struct pci_dev *dev) | 11 | static void __devinit quirk_intel_irqbalance(struct pci_dev *dev) |
| @@ -47,3 +49,206 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7320_MCH, quir | |||
| 47 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7525_MCH, quirk_intel_irqbalance); | 49 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7525_MCH, quirk_intel_irqbalance); |
| 48 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, quirk_intel_irqbalance); | 50 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, quirk_intel_irqbalance); |
| 49 | #endif | 51 | #endif |
| 52 | |||
| 53 | #if defined(CONFIG_HPET_TIMER) | ||
| 54 | unsigned long force_hpet_address; | ||
| 55 | |||
| 56 | static enum { | ||
| 57 | NONE_FORCE_HPET_RESUME, | ||
| 58 | OLD_ICH_FORCE_HPET_RESUME, | ||
| 59 | ICH_FORCE_HPET_RESUME | ||
| 60 | } force_hpet_resume_type; | ||
| 61 | |||
| 62 | static void __iomem *rcba_base; | ||
| 63 | |||
| 64 | static void ich_force_hpet_resume(void) | ||
| 65 | { | ||
| 66 | u32 val; | ||
| 67 | |||
| 68 | if (!force_hpet_address) | ||
| 69 | return; | ||
| 70 | |||
| 71 | if (rcba_base == NULL) | ||
| 72 | BUG(); | ||
| 73 | |||
| 74 | /* read the Function Disable register, dword mode only */ | ||
| 75 | val = readl(rcba_base + 0x3404); | ||
| 76 | if (!(val & 0x80)) { | ||
| 77 | /* HPET disabled in HPTC. Trying to enable */ | ||
| 78 | writel(val | 0x80, rcba_base + 0x3404); | ||
| 79 | } | ||
| 80 | |||
| 81 | val = readl(rcba_base + 0x3404); | ||
| 82 | if (!(val & 0x80)) | ||
| 83 | BUG(); | ||
| 84 | else | ||
| 85 | printk(KERN_DEBUG "Force enabled HPET at resume\n"); | ||
| 86 | |||
| 87 | return; | ||
| 88 | } | ||
| 89 | |||
| 90 | static void ich_force_enable_hpet(struct pci_dev *dev) | ||
| 91 | { | ||
| 92 | u32 val; | ||
| 93 | u32 uninitialized_var(rcba); | ||
| 94 | int err = 0; | ||
| 95 | |||
| 96 | if (hpet_address || force_hpet_address) | ||
| 97 | return; | ||
| 98 | |||
| 99 | pci_read_config_dword(dev, 0xF0, &rcba); | ||
| 100 | rcba &= 0xFFFFC000; | ||
| 101 | if (rcba == 0) { | ||
| 102 | printk(KERN_DEBUG "RCBA disabled. Cannot force enable HPET\n"); | ||
| 103 | return; | ||
| 104 | } | ||
| 105 | |||
| 106 | /* use bits 31:14, 16 kB aligned */ | ||
| 107 | rcba_base = ioremap_nocache(rcba, 0x4000); | ||
| 108 | if (rcba_base == NULL) { | ||
| 109 | printk(KERN_DEBUG "ioremap failed. Cannot force enable HPET\n"); | ||
| 110 | return; | ||
| 111 | } | ||
| 112 | |||
| 113 | /* read the Function Disable register, dword mode only */ | ||
| 114 | val = readl(rcba_base + 0x3404); | ||
| 115 | |||
| 116 | if (val & 0x80) { | ||
| 117 | /* HPET is enabled in HPTC. Just not reported by BIOS */ | ||
| 118 | val = val & 0x3; | ||
| 119 | force_hpet_address = 0xFED00000 | (val << 12); | ||
| 120 | printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n", | ||
| 121 | force_hpet_address); | ||
| 122 | iounmap(rcba_base); | ||
| 123 | return; | ||
| 124 | } | ||
| 125 | |||
| 126 | /* HPET disabled in HPTC. Trying to enable */ | ||
| 127 | writel(val | 0x80, rcba_base + 0x3404); | ||
| 128 | |||
| 129 | val = readl(rcba_base + 0x3404); | ||
| 130 | if (!(val & 0x80)) { | ||
| 131 | err = 1; | ||
| 132 | } else { | ||
| 133 | val = val & 0x3; | ||
| 134 | force_hpet_address = 0xFED00000 | (val << 12); | ||
| 135 | } | ||
| 136 | |||
| 137 | if (err) { | ||
| 138 | force_hpet_address = 0; | ||
| 139 | iounmap(rcba_base); | ||
| 140 | printk(KERN_DEBUG "Failed to force enable HPET\n"); | ||
| 141 | } else { | ||
| 142 | force_hpet_resume_type = ICH_FORCE_HPET_RESUME; | ||
| 143 | printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n", | ||
| 144 | force_hpet_address); | ||
| 145 | } | ||
| 146 | } | ||
| 147 | |||
| 148 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_0, | ||
| 149 | ich_force_enable_hpet); | ||
| 150 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, | ||
| 151 | ich_force_enable_hpet); | ||
| 152 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0, | ||
| 153 | ich_force_enable_hpet); | ||
| 154 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1, | ||
| 155 | ich_force_enable_hpet); | ||
| 156 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31, | ||
| 157 | ich_force_enable_hpet); | ||
| 158 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_1, | ||
| 159 | ich_force_enable_hpet); | ||
| 160 | |||
| 161 | |||
| 162 | static struct pci_dev *cached_dev; | ||
| 163 | |||
| 164 | static void old_ich_force_hpet_resume(void) | ||
| 165 | { | ||
| 166 | u32 val; | ||
| 167 | u32 uninitialized_var(gen_cntl); | ||
| 168 | |||
| 169 | if (!force_hpet_address || !cached_dev) | ||
| 170 | return; | ||
| 171 | |||
| 172 | pci_read_config_dword(cached_dev, 0xD0, &gen_cntl); | ||
| 173 | gen_cntl &= (~(0x7 << 15)); | ||
| 174 | gen_cntl |= (0x4 << 15); | ||
| 175 | |||
| 176 | pci_write_config_dword(cached_dev, 0xD0, gen_cntl); | ||
| 177 | pci_read_config_dword(cached_dev, 0xD0, &gen_cntl); | ||
| 178 | val = gen_cntl >> 15; | ||
| 179 | val &= 0x7; | ||
| 180 | if (val == 0x4) | ||
| 181 | printk(KERN_DEBUG "Force enabled HPET at resume\n"); | ||
| 182 | else | ||
| 183 | BUG(); | ||
| 184 | } | ||
| 185 | |||
| 186 | static void old_ich_force_enable_hpet(struct pci_dev *dev) | ||
| 187 | { | ||
| 188 | u32 val; | ||
| 189 | u32 uninitialized_var(gen_cntl); | ||
| 190 | |||
| 191 | if (hpet_address || force_hpet_address) | ||
| 192 | return; | ||
| 193 | |||
| 194 | pci_read_config_dword(dev, 0xD0, &gen_cntl); | ||
| 195 | /* | ||
| 196 | * Bit 17 is HPET enable bit. | ||
| 197 | * Bit 16:15 control the HPET base address. | ||
| 198 | */ | ||
| 199 | val = gen_cntl >> 15; | ||
| 200 | val &= 0x7; | ||
| 201 | if (val & 0x4) { | ||
| 202 | val &= 0x3; | ||
| 203 | force_hpet_address = 0xFED00000 | (val << 12); | ||
| 204 | printk(KERN_DEBUG "HPET at base address 0x%lx\n", | ||
| 205 | force_hpet_address); | ||
| 206 | return; | ||
| 207 | } | ||
| 208 | |||
| 209 | /* | ||
| 210 | * HPET is disabled. Trying enabling at FED00000 and check | ||
| 211 | * whether it sticks | ||
| 212 | */ | ||
| 213 | gen_cntl &= (~(0x7 << 15)); | ||
| 214 | gen_cntl |= (0x4 << 15); | ||
| 215 | pci_write_config_dword(dev, 0xD0, gen_cntl); | ||
| 216 | |||
| 217 | pci_read_config_dword(dev, 0xD0, &gen_cntl); | ||
| 218 | |||
| 219 | val = gen_cntl >> 15; | ||
| 220 | val &= 0x7; | ||
| 221 | if (val & 0x4) { | ||
| 222 | /* HPET is enabled in HPTC. Just not reported by BIOS */ | ||
| 223 | val &= 0x3; | ||
| 224 | force_hpet_address = 0xFED00000 | (val << 12); | ||
| 225 | printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n", | ||
| 226 | force_hpet_address); | ||
| 227 | cached_dev = dev; | ||
| 228 | force_hpet_resume_type = OLD_ICH_FORCE_HPET_RESUME; | ||
| 229 | return; | ||
| 230 | } | ||
| 231 | |||
| 232 | printk(KERN_DEBUG "Failed to force enable HPET\n"); | ||
| 233 | } | ||
| 234 | |||
| 235 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, | ||
| 236 | old_ich_force_enable_hpet); | ||
| 237 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_12, | ||
| 238 | old_ich_force_enable_hpet); | ||
| 239 | |||
| 240 | void force_hpet_resume(void) | ||
| 241 | { | ||
| 242 | switch (force_hpet_resume_type) { | ||
| 243 | case ICH_FORCE_HPET_RESUME: | ||
| 244 | return ich_force_hpet_resume(); | ||
| 245 | |||
| 246 | case OLD_ICH_FORCE_HPET_RESUME: | ||
| 247 | return old_ich_force_hpet_resume(); | ||
| 248 | |||
| 249 | default: | ||
| 250 | break; | ||
| 251 | } | ||
| 252 | } | ||
| 253 | |||
| 254 | #endif | ||
diff --git a/arch/x86/kernel/setup_64.c b/arch/x86/kernel/setup_64.c index af838f6b0b7f..32054bf5ba40 100644 --- a/arch/x86/kernel/setup_64.c +++ b/arch/x86/kernel/setup_64.c | |||
| @@ -546,6 +546,37 @@ static void __init amd_detect_cmp(struct cpuinfo_x86 *c) | |||
| 546 | #endif | 546 | #endif |
| 547 | } | 547 | } |
| 548 | 548 | ||
| 549 | #define ENABLE_C1E_MASK 0x18000000 | ||
| 550 | #define CPUID_PROCESSOR_SIGNATURE 1 | ||
| 551 | #define CPUID_XFAM 0x0ff00000 | ||
| 552 | #define CPUID_XFAM_K8 0x00000000 | ||
| 553 | #define CPUID_XFAM_10H 0x00100000 | ||
| 554 | #define CPUID_XFAM_11H 0x00200000 | ||
| 555 | #define CPUID_XMOD 0x000f0000 | ||
| 556 | #define CPUID_XMOD_REV_F 0x00040000 | ||
| 557 | |||
| 558 | /* AMD systems with C1E don't have a working lAPIC timer. Check for that. */ | ||
| 559 | static __cpuinit int amd_apic_timer_broken(void) | ||
| 560 | { | ||
| 561 | u32 lo, hi; | ||
| 562 | u32 eax = cpuid_eax(CPUID_PROCESSOR_SIGNATURE); | ||
| 563 | switch (eax & CPUID_XFAM) { | ||
| 564 | case CPUID_XFAM_K8: | ||
| 565 | if ((eax & CPUID_XMOD) < CPUID_XMOD_REV_F) | ||
| 566 | break; | ||
| 567 | case CPUID_XFAM_10H: | ||
| 568 | case CPUID_XFAM_11H: | ||
| 569 | rdmsr(MSR_K8_ENABLE_C1E, lo, hi); | ||
| 570 | if (lo & ENABLE_C1E_MASK) | ||
| 571 | return 1; | ||
| 572 | break; | ||
| 573 | default: | ||
| 574 | /* err on the side of caution */ | ||
| 575 | return 1; | ||
| 576 | } | ||
| 577 | return 0; | ||
| 578 | } | ||
| 579 | |||
| 549 | static void __cpuinit init_amd(struct cpuinfo_x86 *c) | 580 | static void __cpuinit init_amd(struct cpuinfo_x86 *c) |
| 550 | { | 581 | { |
| 551 | unsigned level; | 582 | unsigned level; |
| @@ -617,6 +648,9 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c) | |||
| 617 | /* Family 10 doesn't support C states in MWAIT so don't use it */ | 648 | /* Family 10 doesn't support C states in MWAIT so don't use it */ |
| 618 | if (c->x86 == 0x10 && !force_mwait) | 649 | if (c->x86 == 0x10 && !force_mwait) |
| 619 | clear_bit(X86_FEATURE_MWAIT, &c->x86_capability); | 650 | clear_bit(X86_FEATURE_MWAIT, &c->x86_capability); |
| 651 | |||
| 652 | if (amd_apic_timer_broken()) | ||
| 653 | disable_apic_timer = 1; | ||
| 620 | } | 654 | } |
| 621 | 655 | ||
| 622 | static void __cpuinit detect_ht(struct cpuinfo_x86 *c) | 656 | static void __cpuinit detect_ht(struct cpuinfo_x86 *c) |
diff --git a/arch/x86/kernel/smpboot_64.c b/arch/x86/kernel/smpboot_64.c index 32f50783edc8..57ccf7cb6b91 100644 --- a/arch/x86/kernel/smpboot_64.c +++ b/arch/x86/kernel/smpboot_64.c | |||
| @@ -223,8 +223,6 @@ void __cpuinit smp_callin(void) | |||
| 223 | local_irq_disable(); | 223 | local_irq_disable(); |
| 224 | Dprintk("Stack at about %p\n",&cpuid); | 224 | Dprintk("Stack at about %p\n",&cpuid); |
| 225 | 225 | ||
| 226 | disable_APIC_timer(); | ||
| 227 | |||
| 228 | /* | 226 | /* |
| 229 | * Save our processor parameters | 227 | * Save our processor parameters |
| 230 | */ | 228 | */ |
| @@ -348,8 +346,6 @@ void __cpuinit start_secondary(void) | |||
| 348 | enable_8259A_irq(0); | 346 | enable_8259A_irq(0); |
| 349 | } | 347 | } |
| 350 | 348 | ||
| 351 | enable_APIC_timer(); | ||
| 352 | |||
| 353 | /* | 349 | /* |
| 354 | * The sibling maps must be set before turing the online map on for | 350 | * The sibling maps must be set before turing the online map on for |
| 355 | * this cpu | 351 | * this cpu |
diff --git a/arch/x86/kernel/time_32.c b/arch/x86/kernel/time_32.c index 19a6c678d02e..56dadfc2f41c 100644 --- a/arch/x86/kernel/time_32.c +++ b/arch/x86/kernel/time_32.c | |||
| @@ -157,6 +157,9 @@ EXPORT_SYMBOL(profile_pc); | |||
| 157 | */ | 157 | */ |
| 158 | irqreturn_t timer_interrupt(int irq, void *dev_id) | 158 | irqreturn_t timer_interrupt(int irq, void *dev_id) |
| 159 | { | 159 | { |
| 160 | /* Keep nmi watchdog up to date */ | ||
| 161 | per_cpu(irq_stat, smp_processor_id()).irq0_irqs++; | ||
| 162 | |||
| 160 | #ifdef CONFIG_X86_IO_APIC | 163 | #ifdef CONFIG_X86_IO_APIC |
| 161 | if (timer_ack) { | 164 | if (timer_ack) { |
| 162 | /* | 165 | /* |
diff --git a/arch/x86/kernel/time_64.c b/arch/x86/kernel/time_64.c index 6d48a4e826d9..e0134d6c88da 100644 --- a/arch/x86/kernel/time_64.c +++ b/arch/x86/kernel/time_64.c | |||
| @@ -28,11 +28,12 @@ | |||
| 28 | #include <linux/cpu.h> | 28 | #include <linux/cpu.h> |
| 29 | #include <linux/kallsyms.h> | 29 | #include <linux/kallsyms.h> |
| 30 | #include <linux/acpi.h> | 30 | #include <linux/acpi.h> |
| 31 | #include <linux/clockchips.h> | ||
| 32 | |||
| 31 | #ifdef CONFIG_ACPI | 33 | #ifdef CONFIG_ACPI |
| 32 | #include <acpi/achware.h> /* for PM timer frequency */ | 34 | #include <acpi/achware.h> /* for PM timer frequency */ |
| 33 | #include <acpi/acpi_bus.h> | 35 | #include <acpi/acpi_bus.h> |
| 34 | #endif | 36 | #endif |
| 35 | #include <asm/8253pit.h> | ||
| 36 | #include <asm/i8253.h> | 37 | #include <asm/i8253.h> |
| 37 | #include <asm/pgtable.h> | 38 | #include <asm/pgtable.h> |
| 38 | #include <asm/vsyscall.h> | 39 | #include <asm/vsyscall.h> |
| @@ -47,12 +48,8 @@ | |||
| 47 | #include <asm/nmi.h> | 48 | #include <asm/nmi.h> |
| 48 | #include <asm/vgtod.h> | 49 | #include <asm/vgtod.h> |
| 49 | 50 | ||
| 50 | static char *timename = NULL; | ||
| 51 | |||
| 52 | DEFINE_SPINLOCK(rtc_lock); | 51 | DEFINE_SPINLOCK(rtc_lock); |
| 53 | EXPORT_SYMBOL(rtc_lock); | 52 | EXPORT_SYMBOL(rtc_lock); |
| 54 | DEFINE_SPINLOCK(i8253_lock); | ||
| 55 | EXPORT_SYMBOL(i8253_lock); | ||
| 56 | 53 | ||
| 57 | volatile unsigned long __jiffies __section_jiffies = INITIAL_JIFFIES; | 54 | volatile unsigned long __jiffies __section_jiffies = INITIAL_JIFFIES; |
| 58 | 55 | ||
| @@ -153,45 +150,12 @@ int update_persistent_clock(struct timespec now) | |||
| 153 | return set_rtc_mmss(now.tv_sec); | 150 | return set_rtc_mmss(now.tv_sec); |
| 154 | } | 151 | } |
| 155 | 152 | ||
| 156 | void main_timer_handler(void) | 153 | static irqreturn_t timer_event_interrupt(int irq, void *dev_id) |
| 157 | { | 154 | { |
| 158 | /* | 155 | add_pda(irq0_irqs, 1); |
| 159 | * Here we are in the timer irq handler. We have irqs locally disabled (so we | ||
| 160 | * don't need spin_lock_irqsave()) but we don't know if the timer_bh is running | ||
| 161 | * on the other CPU, so we need a lock. We also need to lock the vsyscall | ||
| 162 | * variables, because both do_timer() and us change them -arca+vojtech | ||
| 163 | */ | ||
| 164 | |||
| 165 | write_seqlock(&xtime_lock); | ||
| 166 | 156 | ||
| 167 | /* | 157 | global_clock_event->event_handler(global_clock_event); |
| 168 | * Do the timer stuff. | ||
| 169 | */ | ||
| 170 | |||
| 171 | do_timer(1); | ||
| 172 | #ifndef CONFIG_SMP | ||
| 173 | update_process_times(user_mode(get_irq_regs())); | ||
| 174 | #endif | ||
| 175 | 158 | ||
| 176 | /* | ||
| 177 | * In the SMP case we use the local APIC timer interrupt to do the profiling, | ||
| 178 | * except when we simulate SMP mode on a uniprocessor system, in that case we | ||
| 179 | * have to call the local interrupt handler. | ||
| 180 | */ | ||
| 181 | |||
| 182 | if (!using_apic_timer) | ||
| 183 | smp_local_timer_interrupt(); | ||
| 184 | |||
| 185 | write_sequnlock(&xtime_lock); | ||
| 186 | } | ||
| 187 | |||
| 188 | static irqreturn_t timer_interrupt(int irq, void *dev_id) | ||
| 189 | { | ||
| 190 | if (apic_runs_main_timer > 1) | ||
| 191 | return IRQ_HANDLED; | ||
| 192 | main_timer_handler(); | ||
| 193 | if (using_apic_timer) | ||
| 194 | smp_send_timer_broadcast_ipi(); | ||
| 195 | return IRQ_HANDLED; | 159 | return IRQ_HANDLED; |
| 196 | } | 160 | } |
| 197 | 161 | ||
| @@ -292,97 +256,21 @@ static unsigned int __init tsc_calibrate_cpu_khz(void) | |||
| 292 | return pmc_now * tsc_khz / (tsc_now - tsc_start); | 256 | return pmc_now * tsc_khz / (tsc_now - tsc_start); |
| 293 | } | 257 | } |
| 294 | 258 | ||
| 295 | /* | ||
| 296 | * pit_calibrate_tsc() uses the speaker output (channel 2) of | ||
| 297 | * the PIT. This is better than using the timer interrupt output, | ||
| 298 | * because we can read the value of the speaker with just one inb(), | ||
| 299 | * where we need three i/o operations for the interrupt channel. | ||
| 300 | * We count how many ticks the TSC does in 50 ms. | ||
| 301 | */ | ||
| 302 | |||
| 303 | static unsigned int __init pit_calibrate_tsc(void) | ||
| 304 | { | ||
| 305 | unsigned long start, end; | ||
| 306 | unsigned long flags; | ||
| 307 | |||
| 308 | spin_lock_irqsave(&i8253_lock, flags); | ||
| 309 | |||
| 310 | outb((inb(0x61) & ~0x02) | 0x01, 0x61); | ||
| 311 | |||
| 312 | outb(0xb0, 0x43); | ||
| 313 | outb((PIT_TICK_RATE / (1000 / 50)) & 0xff, 0x42); | ||
| 314 | outb((PIT_TICK_RATE / (1000 / 50)) >> 8, 0x42); | ||
| 315 | start = get_cycles_sync(); | ||
| 316 | while ((inb(0x61) & 0x20) == 0); | ||
| 317 | end = get_cycles_sync(); | ||
| 318 | |||
| 319 | spin_unlock_irqrestore(&i8253_lock, flags); | ||
| 320 | |||
| 321 | return (end - start) / 50; | ||
| 322 | } | ||
| 323 | |||
| 324 | #define PIT_MODE 0x43 | ||
| 325 | #define PIT_CH0 0x40 | ||
| 326 | |||
| 327 | static void __pit_init(int val, u8 mode) | ||
| 328 | { | ||
| 329 | unsigned long flags; | ||
| 330 | |||
| 331 | spin_lock_irqsave(&i8253_lock, flags); | ||
| 332 | outb_p(mode, PIT_MODE); | ||
| 333 | outb_p(val & 0xff, PIT_CH0); /* LSB */ | ||
| 334 | outb_p(val >> 8, PIT_CH0); /* MSB */ | ||
| 335 | spin_unlock_irqrestore(&i8253_lock, flags); | ||
| 336 | } | ||
| 337 | |||
| 338 | void __init pit_init(void) | ||
| 339 | { | ||
| 340 | __pit_init(LATCH, 0x34); /* binary, mode 2, LSB/MSB, ch 0 */ | ||
| 341 | } | ||
| 342 | |||
| 343 | void pit_stop_interrupt(void) | ||
| 344 | { | ||
| 345 | __pit_init(0, 0x30); /* mode 0 */ | ||
| 346 | } | ||
| 347 | |||
| 348 | void stop_timer_interrupt(void) | ||
| 349 | { | ||
| 350 | char *name; | ||
| 351 | if (hpet_address) { | ||
| 352 | name = "HPET"; | ||
| 353 | hpet_timer_stop_set_go(0); | ||
| 354 | } else { | ||
| 355 | name = "PIT"; | ||
| 356 | pit_stop_interrupt(); | ||
| 357 | } | ||
| 358 | printk(KERN_INFO "timer: %s interrupt stopped.\n", name); | ||
| 359 | } | ||
| 360 | |||
| 361 | static struct irqaction irq0 = { | 259 | static struct irqaction irq0 = { |
| 362 | .handler = timer_interrupt, | 260 | .handler = timer_event_interrupt, |
| 363 | .flags = IRQF_DISABLED | IRQF_IRQPOLL, | 261 | .flags = IRQF_DISABLED | IRQF_IRQPOLL | IRQF_NOBALANCING, |
| 364 | .mask = CPU_MASK_NONE, | 262 | .mask = CPU_MASK_NONE, |
| 365 | .name = "timer" | 263 | .name = "timer" |
| 366 | }; | 264 | }; |
| 367 | 265 | ||
| 368 | void __init time_init(void) | 266 | void __init time_init(void) |
| 369 | { | 267 | { |
| 370 | if (nohpet) | 268 | if (!hpet_enable()) |
| 371 | hpet_address = 0; | 269 | setup_pit_timer(); |
| 372 | 270 | ||
| 373 | if (hpet_arch_init()) | 271 | setup_irq(0, &irq0); |
| 374 | hpet_address = 0; | ||
| 375 | 272 | ||
| 376 | if (hpet_use_timer) { | 273 | tsc_calibrate(); |
| 377 | /* set tick_nsec to use the proper rate for HPET */ | ||
| 378 | tick_nsec = TICK_NSEC_HPET; | ||
| 379 | tsc_khz = hpet_calibrate_tsc(); | ||
| 380 | timename = "HPET"; | ||
| 381 | } else { | ||
| 382 | pit_init(); | ||
| 383 | tsc_khz = pit_calibrate_tsc(); | ||
| 384 | timename = "PIT"; | ||
| 385 | } | ||
| 386 | 274 | ||
| 387 | cpu_khz = tsc_khz; | 275 | cpu_khz = tsc_khz; |
| 388 | if (cpu_has(&boot_cpu_data, X86_FEATURE_CONSTANT_TSC) && | 276 | if (cpu_has(&boot_cpu_data, X86_FEATURE_CONSTANT_TSC) && |
| @@ -398,50 +286,7 @@ void __init time_init(void) | |||
| 398 | else | 286 | else |
| 399 | vgetcpu_mode = VGETCPU_LSL; | 287 | vgetcpu_mode = VGETCPU_LSL; |
| 400 | 288 | ||
| 401 | set_cyc2ns_scale(tsc_khz); | ||
| 402 | printk(KERN_INFO "time.c: Detected %d.%03d MHz processor.\n", | 289 | printk(KERN_INFO "time.c: Detected %d.%03d MHz processor.\n", |
| 403 | cpu_khz / 1000, cpu_khz % 1000); | 290 | cpu_khz / 1000, cpu_khz % 1000); |
| 404 | init_tsc_clocksource(); | 291 | init_tsc_clocksource(); |
| 405 | |||
| 406 | setup_irq(0, &irq0); | ||
| 407 | } | ||
| 408 | |||
| 409 | /* | ||
| 410 | * sysfs support for the timer. | ||
| 411 | */ | ||
| 412 | |||
| 413 | static int timer_suspend(struct sys_device *dev, pm_message_t state) | ||
| 414 | { | ||
| 415 | return 0; | ||
| 416 | } | ||
| 417 | |||
| 418 | static int timer_resume(struct sys_device *dev) | ||
| 419 | { | ||
| 420 | if (hpet_address) | ||
| 421 | hpet_reenable(); | ||
| 422 | else | ||
| 423 | i8254_timer_resume(); | ||
| 424 | return 0; | ||
| 425 | } | 292 | } |
| 426 | |||
| 427 | static struct sysdev_class timer_sysclass = { | ||
| 428 | .resume = timer_resume, | ||
| 429 | .suspend = timer_suspend, | ||
| 430 | set_kset_name("timer"), | ||
| 431 | }; | ||
| 432 | |||
| 433 | /* XXX this sysfs stuff should probably go elsewhere later -john */ | ||
| 434 | static struct sys_device device_timer = { | ||
| 435 | .id = 0, | ||
| 436 | .cls = &timer_sysclass, | ||
| 437 | }; | ||
| 438 | |||
| 439 | static int time_init_device(void) | ||
| 440 | { | ||
| 441 | int error = sysdev_class_register(&timer_sysclass); | ||
| 442 | if (!error) | ||
| 443 | error = sysdev_register(&device_timer); | ||
| 444 | return error; | ||
| 445 | } | ||
| 446 | |||
| 447 | device_initcall(time_init_device); | ||
diff --git a/arch/x86/kernel/tsc_64.c b/arch/x86/kernel/tsc_64.c index 2a59bde663f2..9f22e542c374 100644 --- a/arch/x86/kernel/tsc_64.c +++ b/arch/x86/kernel/tsc_64.c | |||
| @@ -6,7 +6,9 @@ | |||
| 6 | #include <linux/time.h> | 6 | #include <linux/time.h> |
| 7 | #include <linux/acpi.h> | 7 | #include <linux/acpi.h> |
| 8 | #include <linux/cpufreq.h> | 8 | #include <linux/cpufreq.h> |
| 9 | #include <linux/acpi_pmtmr.h> | ||
| 9 | 10 | ||
| 11 | #include <asm/hpet.h> | ||
| 10 | #include <asm/timex.h> | 12 | #include <asm/timex.h> |
| 11 | 13 | ||
| 12 | static int notsc __initdata = 0; | 14 | static int notsc __initdata = 0; |
| @@ -18,7 +20,7 @@ EXPORT_SYMBOL(tsc_khz); | |||
| 18 | 20 | ||
| 19 | static unsigned int cyc2ns_scale __read_mostly; | 21 | static unsigned int cyc2ns_scale __read_mostly; |
| 20 | 22 | ||
| 21 | void set_cyc2ns_scale(unsigned long khz) | 23 | static inline void set_cyc2ns_scale(unsigned long khz) |
| 22 | { | 24 | { |
| 23 | cyc2ns_scale = (NSEC_PER_MSEC << NS_SCALE) / khz; | 25 | cyc2ns_scale = (NSEC_PER_MSEC << NS_SCALE) / khz; |
| 24 | } | 26 | } |
| @@ -118,6 +120,95 @@ core_initcall(cpufreq_tsc); | |||
| 118 | 120 | ||
| 119 | #endif | 121 | #endif |
| 120 | 122 | ||
| 123 | #define MAX_RETRIES 5 | ||
| 124 | #define SMI_TRESHOLD 50000 | ||
| 125 | |||
| 126 | /* | ||
| 127 | * Read TSC and the reference counters. Take care of SMI disturbance | ||
| 128 | */ | ||
| 129 | static unsigned long __init tsc_read_refs(unsigned long *pm, | ||
| 130 | unsigned long *hpet) | ||
| 131 | { | ||
| 132 | unsigned long t1, t2; | ||
| 133 | int i; | ||
| 134 | |||
| 135 | for (i = 0; i < MAX_RETRIES; i++) { | ||
| 136 | t1 = get_cycles_sync(); | ||
| 137 | if (hpet) | ||
| 138 | *hpet = hpet_readl(HPET_COUNTER) & 0xFFFFFFFF; | ||
| 139 | else | ||
| 140 | *pm = acpi_pm_read_early(); | ||
| 141 | t2 = get_cycles_sync(); | ||
| 142 | if ((t2 - t1) < SMI_TRESHOLD) | ||
| 143 | return t2; | ||
| 144 | } | ||
| 145 | return ULONG_MAX; | ||
| 146 | } | ||
| 147 | |||
| 148 | /** | ||
| 149 | * tsc_calibrate - calibrate the tsc on boot | ||
| 150 | */ | ||
| 151 | void __init tsc_calibrate(void) | ||
| 152 | { | ||
| 153 | unsigned long flags, tsc1, tsc2, tr1, tr2, pm1, pm2, hpet1, hpet2; | ||
| 154 | int hpet = is_hpet_enabled(); | ||
| 155 | |||
| 156 | local_irq_save(flags); | ||
| 157 | |||
| 158 | tsc1 = tsc_read_refs(&pm1, hpet ? &hpet1 : NULL); | ||
| 159 | |||
| 160 | outb((inb(0x61) & ~0x02) | 0x01, 0x61); | ||
| 161 | |||
| 162 | outb(0xb0, 0x43); | ||
| 163 | outb((CLOCK_TICK_RATE / (1000 / 50)) & 0xff, 0x42); | ||
| 164 | outb((CLOCK_TICK_RATE / (1000 / 50)) >> 8, 0x42); | ||
| 165 | tr1 = get_cycles_sync(); | ||
| 166 | while ((inb(0x61) & 0x20) == 0); | ||
| 167 | tr2 = get_cycles_sync(); | ||
| 168 | |||
| 169 | tsc2 = tsc_read_refs(&pm2, hpet ? &hpet2 : NULL); | ||
| 170 | |||
| 171 | local_irq_restore(flags); | ||
| 172 | |||
| 173 | /* | ||
| 174 | * Preset the result with the raw and inaccurate PIT | ||
| 175 | * calibration value | ||
| 176 | */ | ||
| 177 | tsc_khz = (tr2 - tr1) / 50; | ||
| 178 | |||
| 179 | /* hpet or pmtimer available ? */ | ||
| 180 | if (!hpet && !pm1 && !pm2) { | ||
| 181 | printk(KERN_INFO "TSC calibrated against PIT\n"); | ||
| 182 | return; | ||
| 183 | } | ||
| 184 | |||
| 185 | /* Check, whether the sampling was disturbed by an SMI */ | ||
| 186 | if (tsc1 == ULONG_MAX || tsc2 == ULONG_MAX) { | ||
| 187 | printk(KERN_WARNING "TSC calibration disturbed by SMI, " | ||
| 188 | "using PIT calibration result\n"); | ||
| 189 | return; | ||
| 190 | } | ||
| 191 | |||
| 192 | tsc2 = (tsc2 - tsc1) * 1000000L; | ||
| 193 | |||
| 194 | if (hpet) { | ||
| 195 | printk(KERN_INFO "TSC calibrated against HPET\n"); | ||
| 196 | if (hpet2 < hpet1) | ||
| 197 | hpet2 += 0x100000000; | ||
| 198 | hpet2 -= hpet1; | ||
| 199 | tsc1 = (hpet2 * hpet_readl(HPET_PERIOD)) / 1000000; | ||
| 200 | } else { | ||
| 201 | printk(KERN_INFO "TSC calibrated against PM_TIMER\n"); | ||
| 202 | if (pm2 < pm1) | ||
| 203 | pm2 += ACPI_PM_OVRRUN; | ||
| 204 | pm2 -= pm1; | ||
| 205 | tsc1 = (pm2 * 1000000000) / PMTMR_TICKS_PER_SEC; | ||
| 206 | } | ||
| 207 | |||
| 208 | tsc_khz = tsc2 / tsc1; | ||
| 209 | set_cyc2ns_scale(tsc_khz); | ||
| 210 | } | ||
| 211 | |||
| 121 | /* | 212 | /* |
| 122 | * Make an educated guess if the TSC is trustworthy and synchronized | 213 | * Make an educated guess if the TSC is trustworthy and synchronized |
| 123 | * over all CPUs. | 214 | * over all CPUs. |
diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig index b1b98e614f7c..eb80f5aca54e 100644 --- a/arch/x86_64/Kconfig +++ b/arch/x86_64/Kconfig | |||
| @@ -36,6 +36,18 @@ config GENERIC_CMOS_UPDATE | |||
| 36 | bool | 36 | bool |
| 37 | default y | 37 | default y |
| 38 | 38 | ||
| 39 | config CLOCKSOURCE_WATCHDOG | ||
| 40 | bool | ||
| 41 | default y | ||
| 42 | |||
| 43 | config GENERIC_CLOCKEVENTS | ||
| 44 | bool | ||
| 45 | default y | ||
| 46 | |||
| 47 | config GENERIC_CLOCKEVENTS_BROADCAST | ||
| 48 | bool | ||
| 49 | default y | ||
| 50 | |||
| 39 | config ZONE_DMA32 | 51 | config ZONE_DMA32 |
| 40 | bool | 52 | bool |
| 41 | default y | 53 | default y |
| @@ -130,6 +142,8 @@ source "init/Kconfig" | |||
| 130 | 142 | ||
| 131 | menu "Processor type and features" | 143 | menu "Processor type and features" |
| 132 | 144 | ||
| 145 | source "kernel/time/Kconfig" | ||
| 146 | |||
| 133 | choice | 147 | choice |
| 134 | prompt "Subarchitecture Type" | 148 | prompt "Subarchitecture Type" |
| 135 | default X86_PC | 149 | default X86_PC |
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 1e8287b4f40c..1f6fb38de017 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c | |||
| @@ -276,21 +276,12 @@ static void acpi_timer_check_state(int state, struct acpi_processor *pr, | |||
| 276 | 276 | ||
| 277 | static void acpi_propagate_timer_broadcast(struct acpi_processor *pr) | 277 | static void acpi_propagate_timer_broadcast(struct acpi_processor *pr) |
| 278 | { | 278 | { |
| 279 | #ifdef CONFIG_GENERIC_CLOCKEVENTS | ||
| 280 | unsigned long reason; | 279 | unsigned long reason; |
| 281 | 280 | ||
| 282 | reason = pr->power.timer_broadcast_on_state < INT_MAX ? | 281 | reason = pr->power.timer_broadcast_on_state < INT_MAX ? |
| 283 | CLOCK_EVT_NOTIFY_BROADCAST_ON : CLOCK_EVT_NOTIFY_BROADCAST_OFF; | 282 | CLOCK_EVT_NOTIFY_BROADCAST_ON : CLOCK_EVT_NOTIFY_BROADCAST_OFF; |
| 284 | 283 | ||
| 285 | clockevents_notify(reason, &pr->id); | 284 | clockevents_notify(reason, &pr->id); |
| 286 | #else | ||
| 287 | cpumask_t mask = cpumask_of_cpu(pr->id); | ||
| 288 | |||
| 289 | if (pr->power.timer_broadcast_on_state < INT_MAX) | ||
| 290 | on_each_cpu(switch_APIC_timer_to_ipi, &mask, 1, 1); | ||
| 291 | else | ||
| 292 | on_each_cpu(switch_ipi_to_APIC_timer, &mask, 1, 1); | ||
| 293 | #endif | ||
| 294 | } | 285 | } |
| 295 | 286 | ||
| 296 | /* Power(C) State timer broadcast control */ | 287 | /* Power(C) State timer broadcast control */ |
| @@ -298,8 +289,6 @@ static void acpi_state_timer_broadcast(struct acpi_processor *pr, | |||
| 298 | struct acpi_processor_cx *cx, | 289 | struct acpi_processor_cx *cx, |
| 299 | int broadcast) | 290 | int broadcast) |
| 300 | { | 291 | { |
| 301 | #ifdef CONFIG_GENERIC_CLOCKEVENTS | ||
| 302 | |||
| 303 | int state = cx - pr->power.states; | 292 | int state = cx - pr->power.states; |
| 304 | 293 | ||
| 305 | if (state >= pr->power.timer_broadcast_on_state) { | 294 | if (state >= pr->power.timer_broadcast_on_state) { |
| @@ -309,7 +298,6 @@ static void acpi_state_timer_broadcast(struct acpi_processor *pr, | |||
| 309 | CLOCK_EVT_NOTIFY_BROADCAST_EXIT; | 298 | CLOCK_EVT_NOTIFY_BROADCAST_EXIT; |
| 310 | clockevents_notify(reason, &pr->id); | 299 | clockevents_notify(reason, &pr->id); |
| 311 | } | 300 | } |
| 312 | #endif | ||
| 313 | } | 301 | } |
| 314 | 302 | ||
| 315 | #else | 303 | #else |
diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c index 906bf5e8de89..4e2ca6f0ab18 100644 --- a/drivers/input/misc/pcspkr.c +++ b/drivers/input/misc/pcspkr.c | |||
| @@ -17,7 +17,6 @@ | |||
| 17 | #include <linux/init.h> | 17 | #include <linux/init.h> |
| 18 | #include <linux/input.h> | 18 | #include <linux/input.h> |
| 19 | #include <linux/platform_device.h> | 19 | #include <linux/platform_device.h> |
| 20 | #include <asm/8253pit.h> | ||
| 21 | #include <asm/io.h> | 20 | #include <asm/io.h> |
| 22 | 21 | ||
| 23 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | 22 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); |
| @@ -28,6 +27,7 @@ MODULE_LICENSE("GPL"); | |||
| 28 | /* Use the global PIT lock ! */ | 27 | /* Use the global PIT lock ! */ |
| 29 | #include <asm/i8253.h> | 28 | #include <asm/i8253.h> |
| 30 | #else | 29 | #else |
| 30 | #include <asm/8253pit.h> | ||
| 31 | static DEFINE_SPINLOCK(i8253_lock); | 31 | static DEFINE_SPINLOCK(i8253_lock); |
| 32 | #endif | 32 | #endif |
| 33 | 33 | ||
diff --git a/include/asm-x86/8253pit.h b/include/asm-x86/8253pit.h deleted file mode 100644 index d3c2b38a6618..000000000000 --- a/include/asm-x86/8253pit.h +++ /dev/null | |||
| @@ -1,5 +0,0 @@ | |||
| 1 | #ifdef CONFIG_X86_32 | ||
| 2 | # include "8253pit_32.h" | ||
| 3 | #else | ||
| 4 | # include "8253pit_64.h" | ||
| 5 | #endif | ||
diff --git a/include/asm-x86/8253pit_32.h b/include/asm-x86/8253pit_32.h deleted file mode 100644 index 96c7c3592daf..000000000000 --- a/include/asm-x86/8253pit_32.h +++ /dev/null | |||
| @@ -1,12 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * 8253/8254 Programmable Interval Timer | ||
| 3 | */ | ||
| 4 | |||
| 5 | #ifndef _8253PIT_H | ||
| 6 | #define _8253PIT_H | ||
| 7 | |||
| 8 | #include <asm/timex.h> | ||
| 9 | |||
| 10 | #define PIT_TICK_RATE CLOCK_TICK_RATE | ||
| 11 | |||
| 12 | #endif | ||
diff --git a/include/asm-x86/8253pit_64.h b/include/asm-x86/8253pit_64.h deleted file mode 100644 index 285f78488ccb..000000000000 --- a/include/asm-x86/8253pit_64.h +++ /dev/null | |||
| @@ -1,10 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * 8253/8254 Programmable Interval Timer | ||
| 3 | */ | ||
| 4 | |||
| 5 | #ifndef _8253PIT_H | ||
| 6 | #define _8253PIT_H | ||
| 7 | |||
| 8 | #define PIT_TICK_RATE 1193182UL | ||
| 9 | |||
| 10 | #endif | ||
diff --git a/include/asm-x86/apic_64.h b/include/asm-x86/apic_64.h index 85125ef3c414..3c8f21eef0be 100644 --- a/include/asm-x86/apic_64.h +++ b/include/asm-x86/apic_64.h | |||
| @@ -19,7 +19,7 @@ | |||
| 19 | extern int apic_verbosity; | 19 | extern int apic_verbosity; |
| 20 | extern int apic_runs_main_timer; | 20 | extern int apic_runs_main_timer; |
| 21 | extern int ioapic_force; | 21 | extern int ioapic_force; |
| 22 | extern int apic_mapped; | 22 | extern int disable_apic_timer; |
| 23 | 23 | ||
| 24 | /* | 24 | /* |
| 25 | * Define the default level of output to be very little | 25 | * Define the default level of output to be very little |
| @@ -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/geode.h b/include/asm-x86/geode.h index 6da4bbbea3dc..d94898831bac 100644 --- a/include/asm-x86/geode.h +++ b/include/asm-x86/geode.h | |||
| @@ -156,4 +156,54 @@ static inline int is_geode(void) | |||
| 156 | return (is_geode_gx() || is_geode_lx()); | 156 | return (is_geode_gx() || is_geode_lx()); |
| 157 | } | 157 | } |
| 158 | 158 | ||
| 159 | /* MFGPTs */ | ||
| 160 | |||
| 161 | #define MFGPT_MAX_TIMERS 8 | ||
| 162 | #define MFGPT_TIMER_ANY -1 | ||
| 163 | |||
| 164 | #define MFGPT_DOMAIN_WORKING 1 | ||
| 165 | #define MFGPT_DOMAIN_STANDBY 2 | ||
| 166 | #define MFGPT_DOMAIN_ANY (MFGPT_DOMAIN_WORKING | MFGPT_DOMAIN_STANDBY) | ||
| 167 | |||
| 168 | #define MFGPT_CMP1 0 | ||
| 169 | #define MFGPT_CMP2 1 | ||
| 170 | |||
| 171 | #define MFGPT_EVENT_IRQ 0 | ||
| 172 | #define MFGPT_EVENT_NMI 1 | ||
| 173 | #define MFGPT_EVENT_RESET 3 | ||
| 174 | |||
| 175 | #define MFGPT_REG_CMP1 0 | ||
| 176 | #define MFGPT_REG_CMP2 2 | ||
| 177 | #define MFGPT_REG_COUNTER 4 | ||
| 178 | #define MFGPT_REG_SETUP 6 | ||
| 179 | |||
| 180 | #define MFGPT_SETUP_CNTEN (1 << 15) | ||
| 181 | #define MFGPT_SETUP_CMP2 (1 << 14) | ||
| 182 | #define MFGPT_SETUP_CMP1 (1 << 13) | ||
| 183 | #define MFGPT_SETUP_SETUP (1 << 12) | ||
| 184 | #define MFGPT_SETUP_STOPEN (1 << 11) | ||
| 185 | #define MFGPT_SETUP_EXTEN (1 << 10) | ||
| 186 | #define MFGPT_SETUP_REVEN (1 << 5) | ||
| 187 | #define MFGPT_SETUP_CLKSEL (1 << 4) | ||
| 188 | |||
| 189 | static inline void geode_mfgpt_write(int timer, u16 reg, u16 value) | ||
| 190 | { | ||
| 191 | u32 base = geode_get_dev_base(GEODE_DEV_MFGPT); | ||
| 192 | outw(value, base + reg + (timer * 8)); | ||
| 193 | } | ||
| 194 | |||
| 195 | static inline u16 geode_mfgpt_read(int timer, u16 reg) | ||
| 196 | { | ||
| 197 | u32 base = geode_get_dev_base(GEODE_DEV_MFGPT); | ||
| 198 | return inw(base + reg + (timer * 8)); | ||
| 199 | } | ||
| 200 | |||
| 201 | extern int __init geode_mfgpt_detect(void); | ||
| 202 | extern int geode_mfgpt_toggle_event(int timer, int cmp, int event, int enable); | ||
| 203 | extern int geode_mfgpt_set_irq(int timer, int cmp, int irq, int enable); | ||
| 204 | extern int geode_mfgpt_alloc_timer(int timer, int domain, struct module *owner); | ||
| 205 | |||
| 206 | #define geode_mfgpt_setup_irq(t, c, i) geode_mfgpt_set_irq((t), (c), (i), 1) | ||
| 207 | #define geode_mfgpt_release_irq(t, c, i) geode_mfgpt_set_irq((t), (c), (i), 0) | ||
| 208 | |||
| 159 | #endif | 209 | #endif |
diff --git a/include/asm-x86/hardirq_32.h b/include/asm-x86/hardirq_32.h index 0e358dc405f8..34649585bb59 100644 --- a/include/asm-x86/hardirq_32.h +++ b/include/asm-x86/hardirq_32.h | |||
| @@ -9,6 +9,7 @@ typedef struct { | |||
| 9 | unsigned long idle_timestamp; | 9 | unsigned long idle_timestamp; |
| 10 | unsigned int __nmi_count; /* arch dependent */ | 10 | unsigned int __nmi_count; /* arch dependent */ |
| 11 | unsigned int apic_timer_irqs; /* arch dependent */ | 11 | unsigned int apic_timer_irqs; /* arch dependent */ |
| 12 | unsigned int irq0_irqs; | ||
| 12 | } ____cacheline_aligned irq_cpustat_t; | 13 | } ____cacheline_aligned irq_cpustat_t; |
| 13 | 14 | ||
| 14 | DECLARE_PER_CPU(irq_cpustat_t, irq_stat); | 15 | DECLARE_PER_CPU(irq_cpustat_t, irq_stat); |
diff --git a/include/asm-x86/hpet.h b/include/asm-x86/hpet.h index 9eff48601254..d4ab6db050b6 100644 --- a/include/asm-x86/hpet.h +++ b/include/asm-x86/hpet.h | |||
| @@ -1,5 +1,93 @@ | |||
| 1 | #ifdef CONFIG_X86_32 | 1 | #ifndef ASM_X86_HPET_H |
| 2 | # include "hpet_32.h" | 2 | #define ASM_X86_HPET_H |
| 3 | |||
| 4 | #ifdef CONFIG_HPET_TIMER | ||
| 5 | |||
| 6 | /* | ||
| 7 | * Documentation on HPET can be found at: | ||
| 8 | * http://www.intel.com/ial/home/sp/pcmmspec.htm | ||
| 9 | * ftp://download.intel.com/ial/home/sp/mmts098.pdf | ||
| 10 | */ | ||
| 11 | |||
| 12 | #define HPET_MMAP_SIZE 1024 | ||
| 13 | |||
| 14 | #define HPET_ID 0x000 | ||
| 15 | #define HPET_PERIOD 0x004 | ||
| 16 | #define HPET_CFG 0x010 | ||
| 17 | #define HPET_STATUS 0x020 | ||
| 18 | #define HPET_COUNTER 0x0f0 | ||
| 19 | #define HPET_T0_CFG 0x100 | ||
| 20 | #define HPET_T0_CMP 0x108 | ||
| 21 | #define HPET_T0_ROUTE 0x110 | ||
| 22 | #define HPET_T1_CFG 0x120 | ||
| 23 | #define HPET_T1_CMP 0x128 | ||
| 24 | #define HPET_T1_ROUTE 0x130 | ||
| 25 | #define HPET_T2_CFG 0x140 | ||
| 26 | #define HPET_T2_CMP 0x148 | ||
| 27 | #define HPET_T2_ROUTE 0x150 | ||
| 28 | |||
| 29 | #define HPET_ID_REV 0x000000ff | ||
| 30 | #define HPET_ID_NUMBER 0x00001f00 | ||
| 31 | #define HPET_ID_64BIT 0x00002000 | ||
| 32 | #define HPET_ID_LEGSUP 0x00008000 | ||
| 33 | #define HPET_ID_VENDOR 0xffff0000 | ||
| 34 | #define HPET_ID_NUMBER_SHIFT 8 | ||
| 35 | #define HPET_ID_VENDOR_SHIFT 16 | ||
| 36 | |||
| 37 | #define HPET_ID_VENDOR_8086 0x8086 | ||
| 38 | |||
| 39 | #define HPET_CFG_ENABLE 0x001 | ||
| 40 | #define HPET_CFG_LEGACY 0x002 | ||
| 41 | #define HPET_LEGACY_8254 2 | ||
| 42 | #define HPET_LEGACY_RTC 8 | ||
| 43 | |||
| 44 | #define HPET_TN_LEVEL 0x0002 | ||
| 45 | #define HPET_TN_ENABLE 0x0004 | ||
| 46 | #define HPET_TN_PERIODIC 0x0008 | ||
| 47 | #define HPET_TN_PERIODIC_CAP 0x0010 | ||
| 48 | #define HPET_TN_64BIT_CAP 0x0020 | ||
| 49 | #define HPET_TN_SETVAL 0x0040 | ||
| 50 | #define HPET_TN_32BIT 0x0100 | ||
| 51 | #define HPET_TN_ROUTE 0x3e00 | ||
| 52 | #define HPET_TN_FSB 0x4000 | ||
| 53 | #define HPET_TN_FSB_CAP 0x8000 | ||
| 54 | #define HPET_TN_ROUTE_SHIFT 9 | ||
| 55 | |||
| 56 | /* Max HPET Period is 10^8 femto sec as in HPET spec */ | ||
| 57 | #define HPET_MAX_PERIOD 100000000UL | ||
| 58 | /* | ||
| 59 | * Min HPET period is 10^5 femto sec just for safety. If it is less than this, | ||
| 60 | * then 32 bit HPET counter wrapsaround in less than 0.5 sec. | ||
| 61 | */ | ||
| 62 | #define HPET_MIN_PERIOD 100000UL | ||
| 63 | |||
| 64 | /* hpet memory map physical address */ | ||
| 65 | extern unsigned long hpet_address; | ||
| 66 | extern unsigned long force_hpet_address; | ||
| 67 | extern int is_hpet_enabled(void); | ||
| 68 | extern int hpet_enable(void); | ||
| 69 | extern unsigned long hpet_readl(unsigned long a); | ||
| 70 | extern void force_hpet_resume(void); | ||
| 71 | |||
| 72 | #ifdef CONFIG_HPET_EMULATE_RTC | ||
| 73 | |||
| 74 | #include <linux/interrupt.h> | ||
| 75 | |||
| 76 | extern int hpet_mask_rtc_irq_bit(unsigned long bit_mask); | ||
| 77 | extern int hpet_set_rtc_irq_bit(unsigned long bit_mask); | ||
| 78 | extern int hpet_set_alarm_time(unsigned char hrs, unsigned char min, | ||
| 79 | unsigned char sec); | ||
| 80 | extern int hpet_set_periodic_freq(unsigned long freq); | ||
| 81 | extern int hpet_rtc_dropped_irq(void); | ||
| 82 | extern int hpet_rtc_timer_init(void); | ||
| 83 | extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id); | ||
| 84 | |||
| 85 | #endif /* CONFIG_HPET_EMULATE_RTC */ | ||
| 86 | |||
| 3 | #else | 87 | #else |
| 4 | # include "hpet_64.h" | 88 | |
| 5 | #endif | 89 | static inline int hpet_enable(void) { return 0; } |
| 90 | static inline unsigned long hpet_readl(unsigned long a) { return 0; } | ||
| 91 | |||
| 92 | #endif /* CONFIG_HPET_TIMER */ | ||
| 93 | #endif /* ASM_X86_HPET_H */ | ||
diff --git a/include/asm-x86/hpet_32.h b/include/asm-x86/hpet_32.h deleted file mode 100644 index c82dc7ed96b3..000000000000 --- a/include/asm-x86/hpet_32.h +++ /dev/null | |||
| @@ -1,90 +0,0 @@ | |||
| 1 | |||
| 2 | #ifndef _I386_HPET_H | ||
| 3 | #define _I386_HPET_H | ||
| 4 | |||
| 5 | #ifdef CONFIG_HPET_TIMER | ||
| 6 | |||
| 7 | /* | ||
| 8 | * Documentation on HPET can be found at: | ||
| 9 | * http://www.intel.com/ial/home/sp/pcmmspec.htm | ||
| 10 | * ftp://download.intel.com/ial/home/sp/mmts098.pdf | ||
| 11 | */ | ||
| 12 | |||
| 13 | #define HPET_MMAP_SIZE 1024 | ||
| 14 | |||
| 15 | #define HPET_ID 0x000 | ||
| 16 | #define HPET_PERIOD 0x004 | ||
| 17 | #define HPET_CFG 0x010 | ||
| 18 | #define HPET_STATUS 0x020 | ||
| 19 | #define HPET_COUNTER 0x0f0 | ||
| 20 | #define HPET_T0_CFG 0x100 | ||
| 21 | #define HPET_T0_CMP 0x108 | ||
| 22 | #define HPET_T0_ROUTE 0x110 | ||
| 23 | #define HPET_T1_CFG 0x120 | ||
| 24 | #define HPET_T1_CMP 0x128 | ||
| 25 | #define HPET_T1_ROUTE 0x130 | ||
| 26 | #define HPET_T2_CFG 0x140 | ||
| 27 | #define HPET_T2_CMP 0x148 | ||
| 28 | #define HPET_T2_ROUTE 0x150 | ||
| 29 | |||
| 30 | #define HPET_ID_REV 0x000000ff | ||
| 31 | #define HPET_ID_NUMBER 0x00001f00 | ||
| 32 | #define HPET_ID_64BIT 0x00002000 | ||
| 33 | #define HPET_ID_LEGSUP 0x00008000 | ||
| 34 | #define HPET_ID_VENDOR 0xffff0000 | ||
| 35 | #define HPET_ID_NUMBER_SHIFT 8 | ||
| 36 | #define HPET_ID_VENDOR_SHIFT 16 | ||
| 37 | |||
| 38 | #define HPET_ID_VENDOR_8086 0x8086 | ||
| 39 | |||
| 40 | #define HPET_CFG_ENABLE 0x001 | ||
| 41 | #define HPET_CFG_LEGACY 0x002 | ||
| 42 | #define HPET_LEGACY_8254 2 | ||
| 43 | #define HPET_LEGACY_RTC 8 | ||
| 44 | |||
| 45 | #define HPET_TN_LEVEL 0x0002 | ||
| 46 | #define HPET_TN_ENABLE 0x0004 | ||
| 47 | #define HPET_TN_PERIODIC 0x0008 | ||
| 48 | #define HPET_TN_PERIODIC_CAP 0x0010 | ||
| 49 | #define HPET_TN_64BIT_CAP 0x0020 | ||
| 50 | #define HPET_TN_SETVAL 0x0040 | ||
| 51 | #define HPET_TN_32BIT 0x0100 | ||
| 52 | #define HPET_TN_ROUTE 0x3e00 | ||
| 53 | #define HPET_TN_FSB 0x4000 | ||
| 54 | #define HPET_TN_FSB_CAP 0x8000 | ||
| 55 | #define HPET_TN_ROUTE_SHIFT 9 | ||
| 56 | |||
| 57 | /* Max HPET Period is 10^8 femto sec as in HPET spec */ | ||
| 58 | #define HPET_MAX_PERIOD 100000000UL | ||
| 59 | /* | ||
| 60 | * Min HPET period is 10^5 femto sec just for safety. If it is less than this, | ||
| 61 | * then 32 bit HPET counter wrapsaround in less than 0.5 sec. | ||
| 62 | */ | ||
| 63 | #define HPET_MIN_PERIOD 100000UL | ||
| 64 | |||
| 65 | /* hpet memory map physical address */ | ||
| 66 | extern unsigned long hpet_address; | ||
| 67 | extern int is_hpet_enabled(void); | ||
| 68 | extern int hpet_enable(void); | ||
| 69 | |||
| 70 | #ifdef CONFIG_HPET_EMULATE_RTC | ||
| 71 | |||
| 72 | #include <linux/interrupt.h> | ||
| 73 | |||
| 74 | extern int hpet_mask_rtc_irq_bit(unsigned long bit_mask); | ||
| 75 | extern int hpet_set_rtc_irq_bit(unsigned long bit_mask); | ||
| 76 | extern int hpet_set_alarm_time(unsigned char hrs, unsigned char min, | ||
| 77 | unsigned char sec); | ||
| 78 | extern int hpet_set_periodic_freq(unsigned long freq); | ||
| 79 | extern int hpet_rtc_dropped_irq(void); | ||
| 80 | extern int hpet_rtc_timer_init(void); | ||
| 81 | extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id); | ||
| 82 | |||
| 83 | #endif /* CONFIG_HPET_EMULATE_RTC */ | ||
| 84 | |||
| 85 | #else | ||
| 86 | |||
| 87 | static inline int hpet_enable(void) { return 0; } | ||
| 88 | |||
| 89 | #endif /* CONFIG_HPET_TIMER */ | ||
| 90 | #endif /* _I386_HPET_H */ | ||
diff --git a/include/asm-x86/hpet_64.h b/include/asm-x86/hpet_64.h deleted file mode 100644 index fd4decac93a8..000000000000 --- a/include/asm-x86/hpet_64.h +++ /dev/null | |||
| @@ -1,18 +0,0 @@ | |||
| 1 | #ifndef _ASM_X8664_HPET_H | ||
| 2 | #define _ASM_X8664_HPET_H 1 | ||
| 3 | |||
| 4 | #include <asm/hpet_32.h> | ||
| 5 | |||
| 6 | #define HPET_TICK_RATE (HZ * 100000UL) | ||
| 7 | |||
| 8 | extern int hpet_rtc_timer_init(void); | ||
| 9 | extern int hpet_arch_init(void); | ||
| 10 | extern int hpet_timer_stop_set_go(unsigned long tick); | ||
| 11 | extern int hpet_reenable(void); | ||
| 12 | extern unsigned int hpet_calibrate_tsc(void); | ||
| 13 | |||
| 14 | extern int hpet_use_timer; | ||
| 15 | extern unsigned long hpet_period; | ||
| 16 | extern unsigned long hpet_tick; | ||
| 17 | |||
| 18 | #endif | ||
diff --git a/include/asm-x86/i8253.h b/include/asm-x86/i8253.h index b2a4f995a33f..747548ec5d1d 100644 --- a/include/asm-x86/i8253.h +++ b/include/asm-x86/i8253.h | |||
| @@ -1,5 +1,15 @@ | |||
| 1 | #ifdef CONFIG_X86_32 | 1 | #ifndef __ASM_I8253_H__ |
| 2 | # include "i8253_32.h" | 2 | #define __ASM_I8253_H__ |
| 3 | #else | 3 | |
| 4 | # include "i8253_64.h" | 4 | /* i8253A PIT registers */ |
| 5 | #endif | 5 | #define PIT_MODE 0x43 |
| 6 | #define PIT_CH0 0x40 | ||
| 7 | #define PIT_CH2 0x42 | ||
| 8 | |||
| 9 | extern spinlock_t i8253_lock; | ||
| 10 | |||
| 11 | extern struct clock_event_device *global_clock_event; | ||
| 12 | |||
| 13 | extern void setup_pit_timer(void); | ||
| 14 | |||
| 15 | #endif /* __ASM_I8253_H__ */ | ||
diff --git a/include/asm-x86/i8253_32.h b/include/asm-x86/i8253_32.h deleted file mode 100644 index 7577d058d86e..000000000000 --- a/include/asm-x86/i8253_32.h +++ /dev/null | |||
| @@ -1,17 +0,0 @@ | |||
| 1 | #ifndef __ASM_I8253_H__ | ||
| 2 | #define __ASM_I8253_H__ | ||
| 3 | |||
| 4 | #include <linux/clockchips.h> | ||
| 5 | |||
| 6 | /* i8253A PIT registers */ | ||
| 7 | #define PIT_MODE 0x43 | ||
| 8 | #define PIT_CH0 0x40 | ||
| 9 | #define PIT_CH2 0x42 | ||
| 10 | |||
| 11 | extern spinlock_t i8253_lock; | ||
| 12 | |||
| 13 | extern struct clock_event_device *global_clock_event; | ||
| 14 | |||
| 15 | extern void setup_pit_timer(void); | ||
| 16 | |||
| 17 | #endif /* __ASM_I8253_H__ */ | ||
diff --git a/include/asm-x86/i8253_64.h b/include/asm-x86/i8253_64.h deleted file mode 100644 index 015d8df07690..000000000000 --- a/include/asm-x86/i8253_64.h +++ /dev/null | |||
| @@ -1,6 +0,0 @@ | |||
| 1 | #ifndef __ASM_I8253_H__ | ||
| 2 | #define __ASM_I8253_H__ | ||
| 3 | |||
| 4 | extern spinlock_t i8253_lock; | ||
| 5 | |||
| 6 | #endif /* __ASM_I8253_H__ */ | ||
diff --git a/include/asm-x86/pda.h b/include/asm-x86/pda.h index 5642634843c4..fb49f80eb94f 100644 --- a/include/asm-x86/pda.h +++ b/include/asm-x86/pda.h | |||
| @@ -29,6 +29,7 @@ struct x8664_pda { | |||
| 29 | short isidle; | 29 | short isidle; |
| 30 | struct mm_struct *active_mm; | 30 | struct mm_struct *active_mm; |
| 31 | unsigned apic_timer_irqs; | 31 | unsigned apic_timer_irqs; |
| 32 | unsigned irq0_irqs; | ||
| 32 | } ____cacheline_aligned_in_smp; | 33 | } ____cacheline_aligned_in_smp; |
| 33 | 34 | ||
| 34 | extern struct x8664_pda *_cpu_pda[]; | 35 | extern struct x8664_pda *_cpu_pda[]; |
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 | ||
diff --git a/include/asm-x86/timex.h b/include/asm-x86/timex.h index d01c18cfccef..39a21ab030f0 100644 --- a/include/asm-x86/timex.h +++ b/include/asm-x86/timex.h | |||
| @@ -1,5 +1,18 @@ | |||
| 1 | #ifdef CONFIG_X86_32 | 1 | /* x86 architecture timex specifications */ |
| 2 | # include "timex_32.h" | 2 | #ifndef _ASM_X86_TIMEX_H |
| 3 | #define _ASM_X86_TIMEX_H | ||
| 4 | |||
| 5 | #include <asm/processor.h> | ||
| 6 | #include <asm/tsc.h> | ||
| 7 | |||
| 8 | #ifdef CONFIG_X86_ELAN | ||
| 9 | # define PIT_TICK_RATE 1189200 /* AMD Elan has different frequency! */ | ||
| 3 | #else | 10 | #else |
| 4 | # include "timex_64.h" | 11 | # define PIT_TICK_RATE 1193182 /* Underlying HZ */ |
| 12 | #endif | ||
| 13 | #define CLOCK_TICK_RATE PIT_TICK_RATE | ||
| 14 | |||
| 15 | extern int read_current_timer(unsigned long *timer_value); | ||
| 16 | #define ARCH_HAS_READ_CURRENT_TIMER 1 | ||
| 17 | |||
| 5 | #endif | 18 | #endif |
diff --git a/include/asm-x86/timex_32.h b/include/asm-x86/timex_32.h deleted file mode 100644 index 3666044409f0..000000000000 --- a/include/asm-x86/timex_32.h +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * linux/include/asm-i386/timex.h | ||
| 3 | * | ||
| 4 | * i386 architecture timex specifications | ||
| 5 | */ | ||
| 6 | #ifndef _ASMi386_TIMEX_H | ||
| 7 | #define _ASMi386_TIMEX_H | ||
| 8 | |||
| 9 | #include <asm/processor.h> | ||
| 10 | #include <asm/tsc.h> | ||
| 11 | |||
| 12 | #ifdef CONFIG_X86_ELAN | ||
| 13 | # define CLOCK_TICK_RATE 1189200 /* AMD Elan has different frequency! */ | ||
| 14 | #else | ||
| 15 | # define CLOCK_TICK_RATE 1193182 /* Underlying HZ */ | ||
| 16 | #endif | ||
| 17 | |||
| 18 | |||
| 19 | extern int read_current_timer(unsigned long *timer_value); | ||
| 20 | #define ARCH_HAS_READ_CURRENT_TIMER 1 | ||
| 21 | |||
| 22 | #endif | ||
diff --git a/include/asm-x86/timex_64.h b/include/asm-x86/timex_64.h deleted file mode 100644 index 6ed21f44d308..000000000000 --- a/include/asm-x86/timex_64.h +++ /dev/null | |||
| @@ -1,31 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * linux/include/asm-x86_64/timex.h | ||
| 3 | * | ||
| 4 | * x86-64 architecture timex specifications | ||
| 5 | */ | ||
| 6 | #ifndef _ASMx8664_TIMEX_H | ||
| 7 | #define _ASMx8664_TIMEX_H | ||
| 8 | |||
| 9 | #include <asm/8253pit.h> | ||
| 10 | #include <asm/msr.h> | ||
| 11 | #include <asm/vsyscall.h> | ||
| 12 | #include <asm/system.h> | ||
| 13 | #include <asm/processor.h> | ||
| 14 | #include <asm/tsc.h> | ||
| 15 | #include <linux/compiler.h> | ||
| 16 | |||
| 17 | #define CLOCK_TICK_RATE PIT_TICK_RATE /* Underlying HZ */ | ||
| 18 | |||
| 19 | extern int read_current_timer(unsigned long *timer_value); | ||
| 20 | #define ARCH_HAS_READ_CURRENT_TIMER 1 | ||
| 21 | |||
| 22 | #define USEC_PER_TICK (USEC_PER_SEC / HZ) | ||
| 23 | #define NSEC_PER_TICK (NSEC_PER_SEC / HZ) | ||
| 24 | #define FSEC_PER_TICK (FSEC_PER_SEC / HZ) | ||
| 25 | |||
| 26 | #define NS_SCALE 10 /* 2^10, carefully chosen */ | ||
| 27 | #define US_SCALE 32 /* 2^32, arbitralrily chosen */ | ||
| 28 | |||
| 29 | extern void mark_tsc_unstable(char *msg); | ||
| 30 | extern void set_cyc2ns_scale(unsigned long khz); | ||
| 31 | #endif | ||
diff --git a/include/asm-x86/tsc.h b/include/asm-x86/tsc.h index a4d806610b7f..6baab30dc2c8 100644 --- a/include/asm-x86/tsc.h +++ b/include/asm-x86/tsc.h | |||
| @@ -1,13 +1,14 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * linux/include/asm-i386/tsc.h | 2 | * x86 TSC related functions |
| 3 | * | ||
| 4 | * i386 TSC related functions | ||
| 5 | */ | 3 | */ |
| 6 | #ifndef _ASM_i386_TSC_H | 4 | #ifndef _ASM_X86_TSC_H |
| 7 | #define _ASM_i386_TSC_H | 5 | #define _ASM_X86_TSC_H |
| 8 | 6 | ||
| 9 | #include <asm/processor.h> | 7 | #include <asm/processor.h> |
| 10 | 8 | ||
| 9 | #define NS_SCALE 10 /* 2^10, carefully chosen */ | ||
| 10 | #define US_SCALE 32 /* 2^32, arbitralrily chosen */ | ||
| 11 | |||
| 11 | /* | 12 | /* |
| 12 | * Standard way to access the cycle counter. | 13 | * Standard way to access the cycle counter. |
| 13 | */ | 14 | */ |
| @@ -72,4 +73,8 @@ int check_tsc_unstable(void); | |||
| 72 | extern void check_tsc_sync_source(int cpu); | 73 | extern void check_tsc_sync_source(int cpu); |
| 73 | extern void check_tsc_sync_target(void); | 74 | extern void check_tsc_sync_target(void); |
| 74 | 75 | ||
| 76 | #ifdef CONFIG_X86_64 | ||
| 77 | extern void tsc_calibrate(void); | ||
| 78 | #endif | ||
| 79 | |||
| 75 | #endif | 80 | #endif |
diff --git a/include/asm-x86/vsyscall.h b/include/asm-x86/vsyscall.h index 3b8ceb4af2cf..f01c49f5d108 100644 --- a/include/asm-x86/vsyscall.h +++ b/include/asm-x86/vsyscall.h | |||
| @@ -29,9 +29,6 @@ enum vsyscall_num { | |||
| 29 | #define VGETCPU_RDTSCP 1 | 29 | #define VGETCPU_RDTSCP 1 |
| 30 | #define VGETCPU_LSL 2 | 30 | #define VGETCPU_LSL 2 |
| 31 | 31 | ||
| 32 | #define hpet_readl(a) readl((const void __iomem *)fix_to_virt(FIX_HPET_BASE) + a) | ||
| 33 | #define hpet_writel(d,a) writel(d, (void __iomem *)fix_to_virt(FIX_HPET_BASE) + a) | ||
| 34 | |||
| 35 | extern int __vgetcpu_mode; | 32 | extern int __vgetcpu_mode; |
| 36 | extern volatile unsigned long __jiffies; | 33 | extern volatile unsigned long __jiffies; |
| 37 | 34 | ||
diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h index def5a659b8a5..d2ddea926895 100644 --- a/include/linux/clockchips.h +++ b/include/linux/clockchips.h | |||
| @@ -8,7 +8,7 @@ | |||
| 8 | #ifndef _LINUX_CLOCKCHIPS_H | 8 | #ifndef _LINUX_CLOCKCHIPS_H |
| 9 | #define _LINUX_CLOCKCHIPS_H | 9 | #define _LINUX_CLOCKCHIPS_H |
| 10 | 10 | ||
| 11 | #ifdef CONFIG_GENERIC_CLOCKEVENTS | 11 | #ifdef CONFIG_GENERIC_CLOCKEVENTS_BUILD |
| 12 | 12 | ||
| 13 | #include <linux/clocksource.h> | 13 | #include <linux/clocksource.h> |
| 14 | #include <linux/cpumask.h> | 14 | #include <linux/cpumask.h> |
| @@ -126,11 +126,14 @@ extern int clockevents_register_notifier(struct notifier_block *nb); | |||
| 126 | extern int clockevents_program_event(struct clock_event_device *dev, | 126 | extern int clockevents_program_event(struct clock_event_device *dev, |
| 127 | ktime_t expires, ktime_t now); | 127 | ktime_t expires, ktime_t now); |
| 128 | 128 | ||
| 129 | #ifdef CONFIG_GENERIC_CLOCKEVENTS | ||
| 129 | extern void clockevents_notify(unsigned long reason, void *arg); | 130 | extern void clockevents_notify(unsigned long reason, void *arg); |
| 130 | |||
| 131 | #else | 131 | #else |
| 132 | # define clockevents_notify(reason, arg) do { } while (0) | ||
| 133 | #endif | ||
| 134 | |||
| 135 | #else /* CONFIG_GENERIC_CLOCKEVENTS_BUILD */ | ||
| 132 | 136 | ||
| 133 | static inline void clockevents_resume_events(void) { } | ||
| 134 | #define clockevents_notify(reason, arg) do { } while (0) | 137 | #define clockevents_notify(reason, arg) do { } while (0) |
| 135 | 138 | ||
| 136 | #endif | 139 | #endif |
diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h index c080f61fb024..d7a5e034c3a2 100644 --- a/include/linux/jiffies.h +++ b/include/linux/jiffies.h | |||
| @@ -36,8 +36,6 @@ | |||
| 36 | /* LATCH is used in the interval timer and ftape setup. */ | 36 | /* LATCH is used in the interval timer and ftape setup. */ |
| 37 | #define LATCH ((CLOCK_TICK_RATE + HZ/2) / HZ) /* For divider */ | 37 | #define LATCH ((CLOCK_TICK_RATE + HZ/2) / HZ) /* For divider */ |
| 38 | 38 | ||
| 39 | #define LATCH_HPET ((HPET_TICK_RATE + HZ/2) / HZ) | ||
| 40 | |||
| 41 | /* Suppose we want to devide two numbers NOM and DEN: NOM/DEN, the we can | 39 | /* Suppose we want to devide two numbers NOM and DEN: NOM/DEN, the we can |
| 42 | * improve accuracy by shifting LSH bits, hence calculating: | 40 | * improve accuracy by shifting LSH bits, hence calculating: |
| 43 | * (NOM << LSH) / DEN | 41 | * (NOM << LSH) / DEN |
| @@ -53,13 +51,9 @@ | |||
| 53 | /* HZ is the requested value. ACTHZ is actual HZ ("<< 8" is for accuracy) */ | 51 | /* HZ is the requested value. ACTHZ is actual HZ ("<< 8" is for accuracy) */ |
| 54 | #define ACTHZ (SH_DIV (CLOCK_TICK_RATE, LATCH, 8)) | 52 | #define ACTHZ (SH_DIV (CLOCK_TICK_RATE, LATCH, 8)) |
| 55 | 53 | ||
| 56 | #define ACTHZ_HPET (SH_DIV (HPET_TICK_RATE, LATCH_HPET, 8)) | ||
| 57 | |||
| 58 | /* TICK_NSEC is the time between ticks in nsec assuming real ACTHZ */ | 54 | /* TICK_NSEC is the time between ticks in nsec assuming real ACTHZ */ |
| 59 | #define TICK_NSEC (SH_DIV (1000000UL * 1000, ACTHZ, 8)) | 55 | #define TICK_NSEC (SH_DIV (1000000UL * 1000, ACTHZ, 8)) |
| 60 | 56 | ||
| 61 | #define TICK_NSEC_HPET (SH_DIV(1000000UL * 1000, ACTHZ_HPET, 8)) | ||
| 62 | |||
| 63 | /* TICK_USEC is the time between ticks in usec assuming fake USER_HZ */ | 57 | /* TICK_USEC is the time between ticks in usec assuming fake USER_HZ */ |
| 64 | #define TICK_USEC ((1000000UL + USER_HZ/2) / USER_HZ) | 58 | #define TICK_USEC ((1000000UL + USER_HZ/2) / USER_HZ) |
| 65 | 59 | ||
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 3948708c42ca..584741bb73b3 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h | |||
| @@ -2242,6 +2242,7 @@ | |||
| 2242 | #define PCI_DEVICE_ID_INTEL_82801EB_5 0x24d5 | 2242 | #define PCI_DEVICE_ID_INTEL_82801EB_5 0x24d5 |
| 2243 | #define PCI_DEVICE_ID_INTEL_82801EB_6 0x24d6 | 2243 | #define PCI_DEVICE_ID_INTEL_82801EB_6 0x24d6 |
| 2244 | #define PCI_DEVICE_ID_INTEL_82801EB_11 0x24db | 2244 | #define PCI_DEVICE_ID_INTEL_82801EB_11 0x24db |
| 2245 | #define PCI_DEVICE_ID_INTEL_82801EB_12 0x24dc | ||
| 2245 | #define PCI_DEVICE_ID_INTEL_82801EB_13 0x24dd | 2246 | #define PCI_DEVICE_ID_INTEL_82801EB_13 0x24dd |
| 2246 | #define PCI_DEVICE_ID_INTEL_ESB_1 0x25a1 | 2247 | #define PCI_DEVICE_ID_INTEL_ESB_1 0x25a1 |
| 2247 | #define PCI_DEVICE_ID_INTEL_ESB_2 0x25a2 | 2248 | #define PCI_DEVICE_ID_INTEL_ESB_2 0x25a2 |
diff --git a/kernel/time/Kconfig b/kernel/time/Kconfig index f66351126544..8d53106a0a92 100644 --- a/kernel/time/Kconfig +++ b/kernel/time/Kconfig | |||
| @@ -23,3 +23,8 @@ config HIGH_RES_TIMERS | |||
| 23 | hardware is not capable then this option only increases | 23 | hardware is not capable then this option only increases |
| 24 | the size of the kernel image. | 24 | the size of the kernel image. |
| 25 | 25 | ||
| 26 | config GENERIC_CLOCKEVENTS_BUILD | ||
| 27 | bool | ||
| 28 | default y | ||
| 29 | depends on GENERIC_CLOCKEVENTS || GENERIC_CLOCKEVENTS_MIGR | ||
| 30 | |||
diff --git a/kernel/time/Makefile b/kernel/time/Makefile index 99b6034fc86b..905b0b50792d 100644 --- a/kernel/time/Makefile +++ b/kernel/time/Makefile | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o | 1 | obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o |
| 2 | 2 | ||
| 3 | obj-$(CONFIG_GENERIC_CLOCKEVENTS) += clockevents.o | 3 | obj-$(CONFIG_GENERIC_CLOCKEVENTS_BUILD) += clockevents.o |
| 4 | obj-$(CONFIG_GENERIC_CLOCKEVENTS) += tick-common.o | 4 | obj-$(CONFIG_GENERIC_CLOCKEVENTS) += tick-common.o |
| 5 | obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) += tick-broadcast.o | 5 | obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) += tick-broadcast.o |
| 6 | obj-$(CONFIG_TICK_ONESHOT) += tick-oneshot.o | 6 | obj-$(CONFIG_TICK_ONESHOT) += tick-oneshot.o |
diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c index 41dd3105ce7f..822beebe664a 100644 --- a/kernel/time/clockevents.c +++ b/kernel/time/clockevents.c | |||
| @@ -194,6 +194,7 @@ void clockevents_exchange_device(struct clock_event_device *old, | |||
| 194 | local_irq_restore(flags); | 194 | local_irq_restore(flags); |
| 195 | } | 195 | } |
| 196 | 196 | ||
| 197 | #ifdef CONFIG_GENERIC_CLOCKEVENTS | ||
| 197 | /** | 198 | /** |
| 198 | * clockevents_notify - notification about relevant events | 199 | * clockevents_notify - notification about relevant events |
| 199 | */ | 200 | */ |
| @@ -222,4 +223,4 @@ void clockevents_notify(unsigned long reason, void *arg) | |||
| 222 | spin_unlock(&clockevents_lock); | 223 | spin_unlock(&clockevents_lock); |
| 223 | } | 224 | } |
| 224 | EXPORT_SYMBOL_GPL(clockevents_notify); | 225 | EXPORT_SYMBOL_GPL(clockevents_notify); |
| 225 | 226 | #endif | |
diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c index 0962e0577660..298bc7c6f09f 100644 --- a/kernel/time/tick-broadcast.c +++ b/kernel/time/tick-broadcast.c | |||
| @@ -64,8 +64,9 @@ static void tick_broadcast_start_periodic(struct clock_event_device *bc) | |||
| 64 | */ | 64 | */ |
| 65 | int tick_check_broadcast_device(struct clock_event_device *dev) | 65 | int tick_check_broadcast_device(struct clock_event_device *dev) |
| 66 | { | 66 | { |
| 67 | if (tick_broadcast_device.evtdev || | 67 | if ((tick_broadcast_device.evtdev && |
| 68 | (dev->features & CLOCK_EVT_FEAT_C3STOP)) | 68 | tick_broadcast_device.evtdev->rating >= dev->rating) || |
| 69 | (dev->features & CLOCK_EVT_FEAT_C3STOP)) | ||
| 69 | return 0; | 70 | return 0; |
| 70 | 71 | ||
| 71 | clockevents_exchange_device(NULL, dev); | 72 | clockevents_exchange_device(NULL, dev); |
| @@ -176,8 +177,6 @@ static void tick_do_periodic_broadcast(void) | |||
| 176 | */ | 177 | */ |
| 177 | static void tick_handle_periodic_broadcast(struct clock_event_device *dev) | 178 | static void tick_handle_periodic_broadcast(struct clock_event_device *dev) |
| 178 | { | 179 | { |
| 179 | dev->next_event.tv64 = KTIME_MAX; | ||
| 180 | |||
| 181 | tick_do_periodic_broadcast(); | 180 | tick_do_periodic_broadcast(); |
| 182 | 181 | ||
| 183 | /* | 182 | /* |
| @@ -515,11 +514,9 @@ static void tick_broadcast_clear_oneshot(int cpu) | |||
| 515 | */ | 514 | */ |
| 516 | void tick_broadcast_setup_oneshot(struct clock_event_device *bc) | 515 | void tick_broadcast_setup_oneshot(struct clock_event_device *bc) |
| 517 | { | 516 | { |
| 518 | if (bc->mode != CLOCK_EVT_MODE_ONESHOT) { | 517 | bc->event_handler = tick_handle_oneshot_broadcast; |
| 519 | bc->event_handler = tick_handle_oneshot_broadcast; | 518 | clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT); |
| 520 | clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT); | 519 | bc->next_event.tv64 = KTIME_MAX; |
| 521 | bc->next_event.tv64 = KTIME_MAX; | ||
| 522 | } | ||
| 523 | } | 520 | } |
| 524 | 521 | ||
| 525 | /* | 522 | /* |
diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c index 77a21abc8716..3f3ae3907830 100644 --- a/kernel/time/tick-common.c +++ b/kernel/time/tick-common.c | |||
| @@ -200,7 +200,7 @@ static int tick_check_new_device(struct clock_event_device *newdev) | |||
| 200 | 200 | ||
| 201 | cpu = smp_processor_id(); | 201 | cpu = smp_processor_id(); |
| 202 | if (!cpu_isset(cpu, newdev->cpumask)) | 202 | if (!cpu_isset(cpu, newdev->cpumask)) |
| 203 | goto out; | 203 | goto out_bc; |
| 204 | 204 | ||
| 205 | td = &per_cpu(tick_cpu_device, cpu); | 205 | td = &per_cpu(tick_cpu_device, cpu); |
| 206 | curdev = td->evtdev; | 206 | curdev = td->evtdev; |
| @@ -265,7 +265,7 @@ out_bc: | |||
| 265 | */ | 265 | */ |
| 266 | if (tick_check_broadcast_device(newdev)) | 266 | if (tick_check_broadcast_device(newdev)) |
| 267 | ret = NOTIFY_STOP; | 267 | ret = NOTIFY_STOP; |
| 268 | out: | 268 | |
| 269 | spin_unlock_irqrestore(&tick_device_lock, flags); | 269 | spin_unlock_irqrestore(&tick_device_lock, flags); |
| 270 | 270 | ||
| 271 | return ret; | 271 | return ret; |
