aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/mrst.c
diff options
context:
space:
mode:
authorJacob Pan <jacob.jun.pan@linux.intel.com>2010-05-19 15:01:25 -0400
committerH. Peter Anvin <hpa@linux.intel.com>2010-05-19 16:45:39 -0400
commita875c01944f0d750eeb1ef3133feceb13f13c4b3 (patch)
treecdd39431457cdeed92d67420a89296cbfb23f620 /arch/x86/kernel/mrst.c
parenta0c173bd8a3fd0541be8e4ef962170e48d8811c7 (diff)
x86, mrst: add more timer config options
Always-on local APIC timer (ARAT) has been introduced to Medfield, along with the platform APB timers we have more timer configuration options between Moorestown and Medfield. This patch adds run-time detection of avaiable timer features so that we can treat Medfield as a variant of Moorestown and set up the optimal timer options for each platform. i.e. Medfield: per cpu always-on local APIC timer Moorestown: per cpu APB timer Manual override is possible via cmdline option x86_mrst_timer. Signed-off-by: Jacob Pan <jacob.jun.pan@linux.intel.com> LKML-Reference: <1274295685-6774-4-git-send-email-jacob.jun.pan@linux.intel.com> Acked-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Diffstat (limited to 'arch/x86/kernel/mrst.c')
-rw-r--r--arch/x86/kernel/mrst.c88
1 files changed, 63 insertions, 25 deletions
diff --git a/arch/x86/kernel/mrst.c b/arch/x86/kernel/mrst.c
index ceaebeb5866f..636b53bd4198 100644
--- a/arch/x86/kernel/mrst.c
+++ b/arch/x86/kernel/mrst.c
@@ -25,6 +25,29 @@
25#include <asm/i8259.h> 25#include <asm/i8259.h>
26#include <asm/apb_timer.h> 26#include <asm/apb_timer.h>
27 27
28/*
29 * the clockevent devices on Moorestown/Medfield can be APBT or LAPIC clock,
30 * cmdline option x86_mrst_timer can be used to override the configuration
31 * to prefer one or the other.
32 * at runtime, there are basically three timer configurations:
33 * 1. per cpu apbt clock only
34 * 2. per cpu always-on lapic clocks only, this is Penwell/Medfield only
35 * 3. per cpu lapic clock (C3STOP) and one apbt clock, with broadcast.
36 *
37 * by default (without cmdline option), platform code first detects cpu type
38 * to see if we are on lincroft or penwell, then set up both lapic or apbt
39 * clocks accordingly.
40 * i.e. by default, medfield uses configuration #2, moorestown uses #1.
41 * config #3 is supported but not recommended on medfield.
42 *
43 * rating and feature summary:
44 * lapic (with C3STOP) --------- 100
45 * apbt (always-on) ------------ 110
46 * lapic (always-on,ARAT) ------ 150
47 */
48
49int mrst_timer_options __cpuinitdata;
50
28static u32 sfi_mtimer_usage[SFI_MTMR_MAX_NUM]; 51static u32 sfi_mtimer_usage[SFI_MTMR_MAX_NUM];
29static struct sfi_timer_table_entry sfi_mtimer_array[SFI_MTMR_MAX_NUM]; 52static struct sfi_timer_table_entry sfi_mtimer_array[SFI_MTMR_MAX_NUM];
30static int mrst_cpu_chip; 53static int mrst_cpu_chip;
@@ -169,18 +192,6 @@ int __init sfi_parse_mrtc(struct sfi_table_header *table)
169 return 0; 192 return 0;
170} 193}
171 194
172/*
173 * the secondary clock in Moorestown can be APBT or LAPIC clock, default to
174 * APBT but cmdline option can also override it.
175 */
176static void __cpuinit mrst_setup_secondary_clock(void)
177{
178 /* restore default lapic clock if disabled by cmdline */
179 if (disable_apbt_percpu)
180 return setup_secondary_APIC_clock();
181 apbt_setup_secondary_clock();
182}
183
184static unsigned long __init mrst_calibrate_tsc(void) 195static unsigned long __init mrst_calibrate_tsc(void)
185{ 196{
186 unsigned long flags, fast_calibrate; 197 unsigned long flags, fast_calibrate;
@@ -197,6 +208,21 @@ static unsigned long __init mrst_calibrate_tsc(void)
197 208
198void __init mrst_time_init(void) 209void __init mrst_time_init(void)
199{ 210{
211 switch (mrst_timer_options) {
212 case MRST_TIMER_APBT_ONLY:
213 break;
214 case MRST_TIMER_LAPIC_APBT:
215 x86_init.timers.setup_percpu_clockev = setup_boot_APIC_clock;
216 x86_cpuinit.setup_percpu_clockev = setup_secondary_APIC_clock;
217 break;
218 default:
219 if (!boot_cpu_has(X86_FEATURE_ARAT))
220 break;
221 x86_init.timers.setup_percpu_clockev = setup_boot_APIC_clock;
222 x86_cpuinit.setup_percpu_clockev = setup_secondary_APIC_clock;
223 return;
224 }
225 /* we need at least one APB timer */
200 sfi_table_parse(SFI_SIG_MTMR, NULL, NULL, sfi_parse_mtmr); 226 sfi_table_parse(SFI_SIG_MTMR, NULL, NULL, sfi_parse_mtmr);
201 pre_init_apic_IRQ0(); 227 pre_init_apic_IRQ0();
202 apbt_time_init(); 228 apbt_time_init();
@@ -207,17 +233,6 @@ void __init mrst_rtc_init(void)
207 sfi_table_parse(SFI_SIG_MRTC, NULL, NULL, sfi_parse_mrtc); 233 sfi_table_parse(SFI_SIG_MRTC, NULL, NULL, sfi_parse_mrtc);
208} 234}
209 235
210/*
211 * if we use per cpu apb timer, the bootclock already setup. if we use lapic
212 * timer and one apbt timer for broadcast, we need to set up lapic boot clock.
213 */
214static void __init mrst_setup_boot_clock(void)
215{
216 pr_info("%s: per cpu apbt flag %d \n", __func__, disable_apbt_percpu);
217 if (disable_apbt_percpu)
218 setup_boot_APIC_clock();
219};
220
221int mrst_identify_cpu(void) 236int mrst_identify_cpu(void)
222{ 237{
223 return mrst_cpu_chip; 238 return mrst_cpu_chip;
@@ -250,13 +265,13 @@ void __init x86_mrst_early_setup(void)
250 x86_init.resources.reserve_resources = x86_init_noop; 265 x86_init.resources.reserve_resources = x86_init_noop;
251 266
252 x86_init.timers.timer_init = mrst_time_init; 267 x86_init.timers.timer_init = mrst_time_init;
253 x86_init.timers.setup_percpu_clockev = mrst_setup_boot_clock; 268 x86_init.timers.setup_percpu_clockev = x86_init_noop;
254 269
255 x86_init.irqs.pre_vector_init = x86_init_noop; 270 x86_init.irqs.pre_vector_init = x86_init_noop;
256 271
257 x86_init.oem.arch_setup = mrst_arch_setup; 272 x86_init.oem.arch_setup = mrst_arch_setup;
258 273
259 x86_cpuinit.setup_percpu_clockev = mrst_setup_secondary_clock; 274 x86_cpuinit.setup_percpu_clockev = apbt_setup_secondary_clock;
260 275
261 x86_platform.calibrate_tsc = mrst_calibrate_tsc; 276 x86_platform.calibrate_tsc = mrst_calibrate_tsc;
262 x86_init.pci.init = pci_mrst_init; 277 x86_init.pci.init = pci_mrst_init;
@@ -269,3 +284,26 @@ void __init x86_mrst_early_setup(void)
269 x86_init.mpparse.get_smp_config = x86_init_uint_noop; 284 x86_init.mpparse.get_smp_config = x86_init_uint_noop;
270 285
271} 286}
287
288/*
289 * if user does not want to use per CPU apb timer, just give it a lower rating
290 * than local apic timer and skip the late per cpu timer init.
291 */
292static inline int __init setup_x86_mrst_timer(char *arg)
293{
294 if (!arg)
295 return -EINVAL;
296
297 if (strcmp("apbt_only", arg) == 0)
298 mrst_timer_options = MRST_TIMER_APBT_ONLY;
299 else if (strcmp("lapic_and_apbt", arg) == 0)
300 mrst_timer_options = MRST_TIMER_LAPIC_APBT;
301 else {
302 pr_warning("X86 MRST timer option %s not recognised"
303 " use x86_mrst_timer=apbt_only or lapic_and_apbt\n",
304 arg);
305 return -EINVAL;
306 }
307 return 0;
308}
309__setup("x86_mrst_timer=", setup_x86_mrst_timer);