diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2007-10-12 17:04:07 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@inhelltoy.tec.linutronix.de> | 2007-10-12 17:04:07 -0400 |
commit | ba7eda4c60e1d070b2f6586d42719ec1d5302d3b (patch) | |
tree | a7d54b9748825334b48d32af0a4b338d8f5be479 /arch/x86/kernel/apic_64.c | |
parent | 02290683343391a50f45599710295dafa2ddd018 (diff) |
x86_64: Add (not yet used) clock event functions
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Chris Wright <chrisw@sous-sol.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
Diffstat (limited to 'arch/x86/kernel/apic_64.c')
-rw-r--r-- | arch/x86/kernel/apic_64.c | 79 |
1 files changed, 79 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 | ||