diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-08-06 13:06:28 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-08-06 13:06:28 -0400 |
| commit | f7ddc2b6cd880a259db338925d03bdc01f1d26c1 (patch) | |
| tree | fdc28aeb2219d683f88df96e55297ac84aa8c129 | |
| parent | a5e11599da95fbe8425db0cfd01a581d7412d0c9 (diff) | |
| parent | 14671386dcbafb3086bbda3cb6f9f27d34c7bf6d (diff) | |
Merge branch 'x86-mrst-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'x86-mrst-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
x86, mrst: make mrst_timer_options an enum
x86, mrst: make mrst_identify_cpu() an inline returning enum
x86, mrst: add more timer config options
x86, mrst: add cpu type detection
x86: detect scattered cpuid features earlier
| -rw-r--r-- | arch/x86/include/asm/apb_timer.h | 1 | ||||
| -rw-r--r-- | arch/x86/include/asm/mrst.h | 26 | ||||
| -rw-r--r-- | arch/x86/kernel/apb_timer.c | 37 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/common.c | 2 | ||||
| -rw-r--r-- | arch/x86/kernel/mrst.c | 105 |
5 files changed, 117 insertions, 54 deletions
diff --git a/arch/x86/include/asm/apb_timer.h b/arch/x86/include/asm/apb_timer.h index c74a2eebe570..a69b1ac9eaf8 100644 --- a/arch/x86/include/asm/apb_timer.h +++ b/arch/x86/include/asm/apb_timer.h | |||
| @@ -55,7 +55,6 @@ extern unsigned long apbt_quick_calibrate(void); | |||
| 55 | extern int arch_setup_apbt_irqs(int irq, int trigger, int mask, int cpu); | 55 | extern int arch_setup_apbt_irqs(int irq, int trigger, int mask, int cpu); |
| 56 | extern void apbt_setup_secondary_clock(void); | 56 | extern void apbt_setup_secondary_clock(void); |
| 57 | extern unsigned int boot_cpu_id; | 57 | extern unsigned int boot_cpu_id; |
| 58 | extern int disable_apbt_percpu; | ||
| 59 | 58 | ||
| 60 | extern struct sfi_timer_table_entry *sfi_get_mtmr(int hint); | 59 | extern struct sfi_timer_table_entry *sfi_get_mtmr(int hint); |
| 61 | extern void sfi_free_mtmr(struct sfi_timer_table_entry *mtmr); | 60 | extern void sfi_free_mtmr(struct sfi_timer_table_entry *mtmr); |
diff --git a/arch/x86/include/asm/mrst.h b/arch/x86/include/asm/mrst.h index 451d30e7f62d..16350740edf6 100644 --- a/arch/x86/include/asm/mrst.h +++ b/arch/x86/include/asm/mrst.h | |||
| @@ -13,6 +13,32 @@ | |||
| 13 | extern int pci_mrst_init(void); | 13 | extern int pci_mrst_init(void); |
| 14 | int __init sfi_parse_mrtc(struct sfi_table_header *table); | 14 | int __init sfi_parse_mrtc(struct sfi_table_header *table); |
| 15 | 15 | ||
| 16 | /* | ||
| 17 | * Medfield is the follow-up of Moorestown, it combines two chip solution into | ||
| 18 | * one. Other than that it also added always-on and constant tsc and lapic | ||
| 19 | * timers. Medfield is the platform name, and the chip name is called Penwell | ||
| 20 | * we treat Medfield/Penwell as a variant of Moorestown. Penwell can be | ||
| 21 | * identified via MSRs. | ||
| 22 | */ | ||
| 23 | enum mrst_cpu_type { | ||
| 24 | MRST_CPU_CHIP_LINCROFT = 1, | ||
| 25 | MRST_CPU_CHIP_PENWELL, | ||
| 26 | }; | ||
| 27 | |||
| 28 | extern enum mrst_cpu_type __mrst_cpu_chip; | ||
| 29 | static enum mrst_cpu_type mrst_identify_cpu(void) | ||
| 30 | { | ||
| 31 | return __mrst_cpu_chip; | ||
| 32 | } | ||
| 33 | |||
| 34 | enum mrst_timer_options { | ||
| 35 | MRST_TIMER_DEFAULT, | ||
| 36 | MRST_TIMER_APBT_ONLY, | ||
| 37 | MRST_TIMER_LAPIC_APBT, | ||
| 38 | }; | ||
| 39 | |||
| 40 | extern enum mrst_timer_options mrst_timer_options; | ||
| 41 | |||
| 16 | #define SFI_MTMR_MAX_NUM 8 | 42 | #define SFI_MTMR_MAX_NUM 8 |
| 17 | #define SFI_MRTC_MAX 8 | 43 | #define SFI_MRTC_MAX 8 |
| 18 | 44 | ||
diff --git a/arch/x86/kernel/apb_timer.c b/arch/x86/kernel/apb_timer.c index a35347501d36..8dd77800ff5d 100644 --- a/arch/x86/kernel/apb_timer.c +++ b/arch/x86/kernel/apb_timer.c | |||
| @@ -43,10 +43,11 @@ | |||
| 43 | 43 | ||
| 44 | #include <asm/fixmap.h> | 44 | #include <asm/fixmap.h> |
| 45 | #include <asm/apb_timer.h> | 45 | #include <asm/apb_timer.h> |
| 46 | #include <asm/mrst.h> | ||
| 46 | 47 | ||
| 47 | #define APBT_MASK CLOCKSOURCE_MASK(32) | 48 | #define APBT_MASK CLOCKSOURCE_MASK(32) |
| 48 | #define APBT_SHIFT 22 | 49 | #define APBT_SHIFT 22 |
| 49 | #define APBT_CLOCKEVENT_RATING 150 | 50 | #define APBT_CLOCKEVENT_RATING 110 |
| 50 | #define APBT_CLOCKSOURCE_RATING 250 | 51 | #define APBT_CLOCKSOURCE_RATING 250 |
| 51 | #define APBT_MIN_DELTA_USEC 200 | 52 | #define APBT_MIN_DELTA_USEC 200 |
| 52 | 53 | ||
| @@ -83,8 +84,6 @@ struct apbt_dev { | |||
| 83 | char name[10]; | 84 | char name[10]; |
| 84 | }; | 85 | }; |
| 85 | 86 | ||
| 86 | int disable_apbt_percpu __cpuinitdata; | ||
| 87 | |||
| 88 | static DEFINE_PER_CPU(struct apbt_dev, cpu_apbt_dev); | 87 | static DEFINE_PER_CPU(struct apbt_dev, cpu_apbt_dev); |
| 89 | 88 | ||
| 90 | #ifdef CONFIG_SMP | 89 | #ifdef CONFIG_SMP |
| @@ -195,29 +194,6 @@ static struct clock_event_device apbt_clockevent = { | |||
| 195 | }; | 194 | }; |
| 196 | 195 | ||
| 197 | /* | 196 | /* |
| 198 | * if user does not want to use per CPU apb timer, just give it a lower rating | ||
| 199 | * than local apic timer and skip the late per cpu timer init. | ||
| 200 | */ | ||
| 201 | static inline int __init setup_x86_mrst_timer(char *arg) | ||
| 202 | { | ||
| 203 | if (!arg) | ||
| 204 | return -EINVAL; | ||
| 205 | |||
| 206 | if (strcmp("apbt_only", arg) == 0) | ||
| 207 | disable_apbt_percpu = 0; | ||
| 208 | else if (strcmp("lapic_and_apbt", arg) == 0) | ||
| 209 | disable_apbt_percpu = 1; | ||
| 210 | else { | ||
| 211 | pr_warning("X86 MRST timer option %s not recognised" | ||
| 212 | " use x86_mrst_timer=apbt_only or lapic_and_apbt\n", | ||
| 213 | arg); | ||
| 214 | return -EINVAL; | ||
| 215 | } | ||
| 216 | return 0; | ||
| 217 | } | ||
| 218 | __setup("x86_mrst_timer=", setup_x86_mrst_timer); | ||
| 219 | |||
| 220 | /* | ||
| 221 | * start count down from 0xffff_ffff. this is done by toggling the enable bit | 197 | * start count down from 0xffff_ffff. this is done by toggling the enable bit |
| 222 | * then load initial load count to ~0. | 198 | * then load initial load count to ~0. |
| 223 | */ | 199 | */ |
| @@ -335,7 +311,7 @@ static int __init apbt_clockevent_register(void) | |||
| 335 | adev->num = smp_processor_id(); | 311 | adev->num = smp_processor_id(); |
| 336 | memcpy(&adev->evt, &apbt_clockevent, sizeof(struct clock_event_device)); | 312 | memcpy(&adev->evt, &apbt_clockevent, sizeof(struct clock_event_device)); |
| 337 | 313 | ||
| 338 | if (disable_apbt_percpu) { | 314 | if (mrst_timer_options == MRST_TIMER_LAPIC_APBT) { |
| 339 | apbt_clockevent.rating = APBT_CLOCKEVENT_RATING - 100; | 315 | apbt_clockevent.rating = APBT_CLOCKEVENT_RATING - 100; |
| 340 | global_clock_event = &adev->evt; | 316 | global_clock_event = &adev->evt; |
| 341 | printk(KERN_DEBUG "%s clockevent registered as global\n", | 317 | printk(KERN_DEBUG "%s clockevent registered as global\n", |
| @@ -429,7 +405,8 @@ static int apbt_cpuhp_notify(struct notifier_block *n, | |||
| 429 | 405 | ||
| 430 | static __init int apbt_late_init(void) | 406 | static __init int apbt_late_init(void) |
| 431 | { | 407 | { |
| 432 | if (disable_apbt_percpu || !apb_timer_block_enabled) | 408 | if (mrst_timer_options == MRST_TIMER_LAPIC_APBT || |
| 409 | !apb_timer_block_enabled) | ||
| 433 | return 0; | 410 | return 0; |
| 434 | /* This notifier should be called after workqueue is ready */ | 411 | /* This notifier should be called after workqueue is ready */ |
| 435 | hotcpu_notifier(apbt_cpuhp_notify, -20); | 412 | hotcpu_notifier(apbt_cpuhp_notify, -20); |
| @@ -450,6 +427,8 @@ static void apbt_set_mode(enum clock_event_mode mode, | |||
| 450 | int timer_num; | 427 | int timer_num; |
| 451 | struct apbt_dev *adev = EVT_TO_APBT_DEV(evt); | 428 | struct apbt_dev *adev = EVT_TO_APBT_DEV(evt); |
| 452 | 429 | ||
| 430 | BUG_ON(!apbt_virt_address); | ||
| 431 | |||
| 453 | timer_num = adev->num; | 432 | timer_num = adev->num; |
| 454 | pr_debug("%s CPU %d timer %d mode=%d\n", | 433 | pr_debug("%s CPU %d timer %d mode=%d\n", |
| 455 | __func__, first_cpu(*evt->cpumask), timer_num, mode); | 434 | __func__, first_cpu(*evt->cpumask), timer_num, mode); |
| @@ -676,7 +655,7 @@ void __init apbt_time_init(void) | |||
| 676 | } | 655 | } |
| 677 | #ifdef CONFIG_SMP | 656 | #ifdef CONFIG_SMP |
| 678 | /* kernel cmdline disable apb timer, so we will use lapic timers */ | 657 | /* kernel cmdline disable apb timer, so we will use lapic timers */ |
| 679 | if (disable_apbt_percpu) { | 658 | if (mrst_timer_options == MRST_TIMER_LAPIC_APBT) { |
| 680 | printk(KERN_INFO "apbt: disabled per cpu timer\n"); | 659 | printk(KERN_INFO "apbt: disabled per cpu timer\n"); |
| 681 | return; | 660 | return; |
| 682 | } | 661 | } |
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index c7358303d8cd..f10273138382 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c | |||
| @@ -586,6 +586,7 @@ static void __cpuinit get_cpu_cap(struct cpuinfo_x86 *c) | |||
| 586 | if (c->extended_cpuid_level >= 0x80000007) | 586 | if (c->extended_cpuid_level >= 0x80000007) |
| 587 | c->x86_power = cpuid_edx(0x80000007); | 587 | c->x86_power = cpuid_edx(0x80000007); |
| 588 | 588 | ||
| 589 | init_scattered_cpuid_features(c); | ||
| 589 | } | 590 | } |
| 590 | 591 | ||
| 591 | static void __cpuinit identify_cpu_without_cpuid(struct cpuinfo_x86 *c) | 592 | static void __cpuinit identify_cpu_without_cpuid(struct cpuinfo_x86 *c) |
| @@ -741,7 +742,6 @@ static void __cpuinit generic_identify(struct cpuinfo_x86 *c) | |||
| 741 | 742 | ||
| 742 | get_model_name(c); /* Default name */ | 743 | get_model_name(c); /* Default name */ |
| 743 | 744 | ||
| 744 | init_scattered_cpuid_features(c); | ||
| 745 | detect_nopl(c); | 745 | detect_nopl(c); |
| 746 | } | 746 | } |
| 747 | 747 | ||
diff --git a/arch/x86/kernel/mrst.c b/arch/x86/kernel/mrst.c index 5915e0b33303..79ae68154e87 100644 --- a/arch/x86/kernel/mrst.c +++ b/arch/x86/kernel/mrst.c | |||
| @@ -25,8 +25,34 @@ | |||
| 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 | __cpuinitdata enum mrst_timer_options mrst_timer_options; | ||
| 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]; |
| 53 | enum mrst_cpu_type __mrst_cpu_chip; | ||
| 54 | EXPORT_SYMBOL_GPL(__mrst_cpu_chip); | ||
| 55 | |||
| 30 | int sfi_mtimer_num; | 56 | int sfi_mtimer_num; |
| 31 | 57 | ||
| 32 | struct sfi_rtc_table_entry sfi_mrtc_array[SFI_MRTC_MAX]; | 58 | struct sfi_rtc_table_entry sfi_mrtc_array[SFI_MRTC_MAX]; |
| @@ -167,18 +193,6 @@ int __init sfi_parse_mrtc(struct sfi_table_header *table) | |||
| 167 | return 0; | 193 | return 0; |
| 168 | } | 194 | } |
| 169 | 195 | ||
| 170 | /* | ||
| 171 | * the secondary clock in Moorestown can be APBT or LAPIC clock, default to | ||
| 172 | * APBT but cmdline option can also override it. | ||
| 173 | */ | ||
| 174 | static void __cpuinit mrst_setup_secondary_clock(void) | ||
| 175 | { | ||
| 176 | /* restore default lapic clock if disabled by cmdline */ | ||
| 177 | if (disable_apbt_percpu) | ||
| 178 | return setup_secondary_APIC_clock(); | ||
| 179 | apbt_setup_secondary_clock(); | ||
| 180 | } | ||
| 181 | |||
| 182 | static unsigned long __init mrst_calibrate_tsc(void) | 196 | static unsigned long __init mrst_calibrate_tsc(void) |
| 183 | { | 197 | { |
| 184 | unsigned long flags, fast_calibrate; | 198 | unsigned long flags, fast_calibrate; |
| @@ -195,6 +209,21 @@ static unsigned long __init mrst_calibrate_tsc(void) | |||
| 195 | 209 | ||
| 196 | void __init mrst_time_init(void) | 210 | void __init mrst_time_init(void) |
| 197 | { | 211 | { |
| 212 | switch (mrst_timer_options) { | ||
| 213 | case MRST_TIMER_APBT_ONLY: | ||
| 214 | break; | ||
| 215 | case MRST_TIMER_LAPIC_APBT: | ||
| 216 | x86_init.timers.setup_percpu_clockev = setup_boot_APIC_clock; | ||
| 217 | x86_cpuinit.setup_percpu_clockev = setup_secondary_APIC_clock; | ||
| 218 | break; | ||
| 219 | default: | ||
| 220 | if (!boot_cpu_has(X86_FEATURE_ARAT)) | ||
| 221 | break; | ||
| 222 | x86_init.timers.setup_percpu_clockev = setup_boot_APIC_clock; | ||
| 223 | x86_cpuinit.setup_percpu_clockev = setup_secondary_APIC_clock; | ||
| 224 | return; | ||
| 225 | } | ||
| 226 | /* we need at least one APB timer */ | ||
| 198 | sfi_table_parse(SFI_SIG_MTMR, NULL, NULL, sfi_parse_mtmr); | 227 | sfi_table_parse(SFI_SIG_MTMR, NULL, NULL, sfi_parse_mtmr); |
| 199 | pre_init_apic_IRQ0(); | 228 | pre_init_apic_IRQ0(); |
| 200 | apbt_time_init(); | 229 | apbt_time_init(); |
| @@ -205,16 +234,21 @@ void __init mrst_rtc_init(void) | |||
| 205 | sfi_table_parse(SFI_SIG_MRTC, NULL, NULL, sfi_parse_mrtc); | 234 | sfi_table_parse(SFI_SIG_MRTC, NULL, NULL, sfi_parse_mrtc); |
| 206 | } | 235 | } |
| 207 | 236 | ||
| 208 | /* | 237 | void __cpuinit mrst_arch_setup(void) |
| 209 | * if we use per cpu apb timer, the bootclock already setup. if we use lapic | ||
| 210 | * timer and one apbt timer for broadcast, we need to set up lapic boot clock. | ||
| 211 | */ | ||
| 212 | static void __init mrst_setup_boot_clock(void) | ||
| 213 | { | 238 | { |
| 214 | pr_info("%s: per cpu apbt flag %d \n", __func__, disable_apbt_percpu); | 239 | if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 0x27) |
| 215 | if (disable_apbt_percpu) | 240 | __mrst_cpu_chip = MRST_CPU_CHIP_PENWELL; |
| 216 | setup_boot_APIC_clock(); | 241 | else if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 0x26) |
| 217 | }; | 242 | __mrst_cpu_chip = MRST_CPU_CHIP_LINCROFT; |
| 243 | else { | ||
| 244 | pr_err("Unknown Moorestown CPU (%d:%d), default to Lincroft\n", | ||
| 245 | boot_cpu_data.x86, boot_cpu_data.x86_model); | ||
| 246 | __mrst_cpu_chip = MRST_CPU_CHIP_LINCROFT; | ||
| 247 | } | ||
| 248 | pr_debug("Moorestown CPU %s identified\n", | ||
| 249 | (__mrst_cpu_chip == MRST_CPU_CHIP_LINCROFT) ? | ||
| 250 | "Lincroft" : "Penwell"); | ||
| 251 | } | ||
| 218 | 252 | ||
| 219 | /* MID systems don't have i8042 controller */ | 253 | /* MID systems don't have i8042 controller */ |
| 220 | static int mrst_i8042_detect(void) | 254 | static int mrst_i8042_detect(void) |
| @@ -232,11 +266,13 @@ void __init x86_mrst_early_setup(void) | |||
| 232 | x86_init.resources.reserve_resources = x86_init_noop; | 266 | x86_init.resources.reserve_resources = x86_init_noop; |
| 233 | 267 | ||
| 234 | x86_init.timers.timer_init = mrst_time_init; | 268 | x86_init.timers.timer_init = mrst_time_init; |
| 235 | x86_init.timers.setup_percpu_clockev = mrst_setup_boot_clock; | 269 | x86_init.timers.setup_percpu_clockev = x86_init_noop; |
| 236 | 270 | ||
| 237 | x86_init.irqs.pre_vector_init = x86_init_noop; | 271 | x86_init.irqs.pre_vector_init = x86_init_noop; |
| 238 | 272 | ||
| 239 | x86_cpuinit.setup_percpu_clockev = mrst_setup_secondary_clock; | 273 | x86_init.oem.arch_setup = mrst_arch_setup; |
| 274 | |||
| 275 | x86_cpuinit.setup_percpu_clockev = apbt_setup_secondary_clock; | ||
| 240 | 276 | ||
| 241 | x86_platform.calibrate_tsc = mrst_calibrate_tsc; | 277 | x86_platform.calibrate_tsc = mrst_calibrate_tsc; |
| 242 | x86_platform.i8042_detect = mrst_i8042_detect; | 278 | x86_platform.i8042_detect = mrst_i8042_detect; |
| @@ -250,3 +286,26 @@ void __init x86_mrst_early_setup(void) | |||
| 250 | x86_init.mpparse.get_smp_config = x86_init_uint_noop; | 286 | x86_init.mpparse.get_smp_config = x86_init_uint_noop; |
| 251 | 287 | ||
| 252 | } | 288 | } |
| 289 | |||
| 290 | /* | ||
| 291 | * if user does not want to use per CPU apb timer, just give it a lower rating | ||
| 292 | * than local apic timer and skip the late per cpu timer init. | ||
| 293 | */ | ||
| 294 | static inline int __init setup_x86_mrst_timer(char *arg) | ||
| 295 | { | ||
| 296 | if (!arg) | ||
| 297 | return -EINVAL; | ||
| 298 | |||
| 299 | if (strcmp("apbt_only", arg) == 0) | ||
| 300 | mrst_timer_options = MRST_TIMER_APBT_ONLY; | ||
| 301 | else if (strcmp("lapic_and_apbt", arg) == 0) | ||
| 302 | mrst_timer_options = MRST_TIMER_LAPIC_APBT; | ||
| 303 | else { | ||
| 304 | pr_warning("X86 MRST timer option %s not recognised" | ||
| 305 | " use x86_mrst_timer=apbt_only or lapic_and_apbt\n", | ||
| 306 | arg); | ||
| 307 | return -EINVAL; | ||
| 308 | } | ||
| 309 | return 0; | ||
| 310 | } | ||
| 311 | __setup("x86_mrst_timer=", setup_x86_mrst_timer); | ||
