diff options
Diffstat (limited to 'arch/x86/kernel/mrst.c')
| -rw-r--r-- | arch/x86/kernel/mrst.c | 88 |
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 | |||
| 49 | int mrst_timer_options __cpuinitdata; | ||
| 50 | |||
| 28 | static u32 sfi_mtimer_usage[SFI_MTMR_MAX_NUM]; | 51 | static u32 sfi_mtimer_usage[SFI_MTMR_MAX_NUM]; |
| 29 | static struct sfi_timer_table_entry sfi_mtimer_array[SFI_MTMR_MAX_NUM]; | 52 | static struct sfi_timer_table_entry sfi_mtimer_array[SFI_MTMR_MAX_NUM]; |
| 30 | static int mrst_cpu_chip; | 53 | static 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 | */ | ||
| 176 | static 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 | |||
| 184 | static unsigned long __init mrst_calibrate_tsc(void) | 195 | static 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 | ||
| 198 | void __init mrst_time_init(void) | 209 | void __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 | */ | ||
| 214 | static 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 | |||
| 221 | int mrst_identify_cpu(void) | 236 | int 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 | */ | ||
| 292 | static 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); | ||
