diff options
-rw-r--r-- | arch/x86/kernel/apic_64.c | 79 | ||||
-rw-r--r-- | arch/x86_64/Kconfig | 6 |
2 files changed, 85 insertions, 0 deletions
diff --git a/arch/x86/kernel/apic_64.c b/arch/x86/kernel/apic_64.c index 40938ef99dc2..2c2807abe1d4 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> |
@@ -57,6 +58,77 @@ static struct resource lapic_resource = { | |||
57 | 58 | ||
58 | static unsigned int calibration_result; | 59 | static unsigned int calibration_result; |
59 | 60 | ||
61 | static int lapic_next_event(unsigned long delta, | ||
62 | struct clock_event_device *evt); | ||
63 | static void lapic_timer_setup(enum clock_event_mode mode, | ||
64 | struct clock_event_device *evt); | ||
65 | |||
66 | static void lapic_timer_broadcast(cpumask_t mask); | ||
67 | |||
68 | static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen); | ||
69 | |||
70 | static struct clock_event_device lapic_clockevent = { | ||
71 | .name = "lapic", | ||
72 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT | ||
73 | | CLOCK_EVT_FEAT_C3STOP | CLOCK_EVT_FEAT_DUMMY, | ||
74 | .shift = 32, | ||
75 | .set_mode = lapic_timer_setup, | ||
76 | .set_next_event = lapic_next_event, | ||
77 | .broadcast = lapic_timer_broadcast, | ||
78 | .rating = 100, | ||
79 | .irq = -1, | ||
80 | }; | ||
81 | static DEFINE_PER_CPU(struct clock_event_device, lapic_events); | ||
82 | |||
83 | static int lapic_next_event(unsigned long delta, | ||
84 | struct clock_event_device *evt) | ||
85 | { | ||
86 | apic_write(APIC_TMICT, delta); | ||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | static void lapic_timer_setup(enum clock_event_mode mode, | ||
91 | struct clock_event_device *evt) | ||
92 | { | ||
93 | unsigned long flags; | ||
94 | unsigned int v; | ||
95 | |||
96 | /* Lapic used as dummy for broadcast ? */ | ||
97 | if (evt->features & CLOCK_EVT_FEAT_DUMMY) | ||
98 | return; | ||
99 | |||
100 | local_irq_save(flags); | ||
101 | |||
102 | switch (mode) { | ||
103 | case CLOCK_EVT_MODE_PERIODIC: | ||
104 | case CLOCK_EVT_MODE_ONESHOT: | ||
105 | __setup_APIC_LVTT(calibration_result, | ||
106 | mode != CLOCK_EVT_MODE_PERIODIC, 1); | ||
107 | break; | ||
108 | case CLOCK_EVT_MODE_UNUSED: | ||
109 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
110 | v = apic_read(APIC_LVTT); | ||
111 | v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR); | ||
112 | apic_write(APIC_LVTT, v); | ||
113 | break; | ||
114 | case CLOCK_EVT_MODE_RESUME: | ||
115 | /* Nothing to do here */ | ||
116 | break; | ||
117 | } | ||
118 | |||
119 | local_irq_restore(flags); | ||
120 | } | ||
121 | |||
122 | /* | ||
123 | * Local APIC timer broadcast function | ||
124 | */ | ||
125 | static void lapic_timer_broadcast(cpumask_t mask) | ||
126 | { | ||
127 | #ifdef CONFIG_SMP | ||
128 | send_IPI_mask(mask, LOCAL_TIMER_VECTOR); | ||
129 | #endif | ||
130 | } | ||
131 | |||
60 | /* | 132 | /* |
61 | * cpu_mask that denotes the CPUs that needs timer interrupt coming in as | 133 | * cpu_mask that denotes the CPUs that needs timer interrupt coming in as |
62 | * IPIs in place of local APIC timers | 134 | * IPIs in place of local APIC timers |
@@ -866,6 +938,13 @@ static void __init calibrate_APIC_clock(void) | |||
866 | printk(KERN_INFO "Detected %d.%03d MHz APIC timer.\n", | 938 | printk(KERN_INFO "Detected %d.%03d MHz APIC timer.\n", |
867 | result / 1000 / 1000, result / 1000 % 1000); | 939 | result / 1000 / 1000, result / 1000 % 1000); |
868 | 940 | ||
941 | /* Calculate the scaled math multiplication factor */ | ||
942 | lapic_clockevent.mult = div_sc(result, NSEC_PER_SEC, 32); | ||
943 | lapic_clockevent.max_delta_ns = | ||
944 | clockevent_delta2ns(0x7FFFFF, &lapic_clockevent); | ||
945 | lapic_clockevent.min_delta_ns = | ||
946 | clockevent_delta2ns(0xF, &lapic_clockevent); | ||
947 | |||
869 | calibration_result = result / HZ; | 948 | calibration_result = result / HZ; |
870 | } | 949 | } |
871 | 950 | ||
diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig index 520f33b83bfc..a9534c21c306 100644 --- a/arch/x86_64/Kconfig +++ b/arch/x86_64/Kconfig | |||
@@ -40,6 +40,10 @@ config CLOCKSOURCE_WATCHDOG | |||
40 | bool | 40 | bool |
41 | default y | 41 | default y |
42 | 42 | ||
43 | config GENERIC_CLOCKEVENTS_MIGR | ||
44 | bool | ||
45 | default y | ||
46 | |||
43 | config ZONE_DMA32 | 47 | config ZONE_DMA32 |
44 | bool | 48 | bool |
45 | default y | 49 | default y |
@@ -134,6 +138,8 @@ source "init/Kconfig" | |||
134 | 138 | ||
135 | menu "Processor type and features" | 139 | menu "Processor type and features" |
136 | 140 | ||
141 | source "kernel/time/Kconfig" | ||
142 | |||
137 | choice | 143 | choice |
138 | prompt "Subarchitecture Type" | 144 | prompt "Subarchitecture Type" |
139 | default X86_PC | 145 | default X86_PC |