diff options
author | Christoph Lameter <cl@linux.com> | 2011-03-12 06:50:10 -0500 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2011-03-29 04:18:30 -0400 |
commit | 349c004e3d31fda23ad225b61861be38047fff16 (patch) | |
tree | 1600c1356f4b992d07e191492054619d03e7c9f7 /arch/x86 | |
parent | 89078d572eb9ce8d4c04264b8b0ba86de0d74c8f (diff) |
x86: A fast way to check capabilities of the current cpu
Add this_cpu_has() which determines if the current cpu has a certain
ability using a segment prefix and a bit test operation.
For that we need to add bit operations to x86s percpu.h.
Many uses of cpu_has use a pointer passed to a function to determine
the current flags. That is no longer necessary after this patch.
However, this patch only converts the straightforward cases where
cpu_has is used with this_cpu_ptr. The rest is work for later.
-tj: Rolled up patch to add x86_ prefix and use percpu_read() instead
of percpu_read_stable().
Signed-off-by: Christoph Lameter <cl@linux.com>
Acked-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'arch/x86')
-rw-r--r-- | arch/x86/include/asm/cpufeature.h | 13 | ||||
-rw-r--r-- | arch/x86/include/asm/percpu.h | 27 | ||||
-rw-r--r-- | arch/x86/kernel/apic/apic.c | 2 | ||||
-rw-r--r-- | arch/x86/kernel/process.c | 4 | ||||
-rw-r--r-- | arch/x86/kernel/smpboot.c | 4 |
5 files changed, 41 insertions, 9 deletions
diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h index 91f3e087cf21..50c0d30e676d 100644 --- a/arch/x86/include/asm/cpufeature.h +++ b/arch/x86/include/asm/cpufeature.h | |||
@@ -207,8 +207,7 @@ extern const char * const x86_power_flags[32]; | |||
207 | #define test_cpu_cap(c, bit) \ | 207 | #define test_cpu_cap(c, bit) \ |
208 | test_bit(bit, (unsigned long *)((c)->x86_capability)) | 208 | test_bit(bit, (unsigned long *)((c)->x86_capability)) |
209 | 209 | ||
210 | #define cpu_has(c, bit) \ | 210 | #define REQUIRED_MASK_BIT_SET(bit) \ |
211 | (__builtin_constant_p(bit) && \ | ||
212 | ( (((bit)>>5)==0 && (1UL<<((bit)&31) & REQUIRED_MASK0)) || \ | 211 | ( (((bit)>>5)==0 && (1UL<<((bit)&31) & REQUIRED_MASK0)) || \ |
213 | (((bit)>>5)==1 && (1UL<<((bit)&31) & REQUIRED_MASK1)) || \ | 212 | (((bit)>>5)==1 && (1UL<<((bit)&31) & REQUIRED_MASK1)) || \ |
214 | (((bit)>>5)==2 && (1UL<<((bit)&31) & REQUIRED_MASK2)) || \ | 213 | (((bit)>>5)==2 && (1UL<<((bit)&31) & REQUIRED_MASK2)) || \ |
@@ -218,10 +217,16 @@ extern const char * const x86_power_flags[32]; | |||
218 | (((bit)>>5)==6 && (1UL<<((bit)&31) & REQUIRED_MASK6)) || \ | 217 | (((bit)>>5)==6 && (1UL<<((bit)&31) & REQUIRED_MASK6)) || \ |
219 | (((bit)>>5)==7 && (1UL<<((bit)&31) & REQUIRED_MASK7)) || \ | 218 | (((bit)>>5)==7 && (1UL<<((bit)&31) & REQUIRED_MASK7)) || \ |
220 | (((bit)>>5)==8 && (1UL<<((bit)&31) & REQUIRED_MASK8)) || \ | 219 | (((bit)>>5)==8 && (1UL<<((bit)&31) & REQUIRED_MASK8)) || \ |
221 | (((bit)>>5)==9 && (1UL<<((bit)&31) & REQUIRED_MASK9)) ) \ | 220 | (((bit)>>5)==9 && (1UL<<((bit)&31) & REQUIRED_MASK9)) ) |
222 | ? 1 : \ | 221 | |
222 | #define cpu_has(c, bit) \ | ||
223 | (__builtin_constant_p(bit) && REQUIRED_MASK_BIT_SET(bit) ? 1 : \ | ||
223 | test_cpu_cap(c, bit)) | 224 | test_cpu_cap(c, bit)) |
224 | 225 | ||
226 | #define this_cpu_has(bit) \ | ||
227 | (__builtin_constant_p(bit) && REQUIRED_MASK_BIT_SET(bit) ? 1 : \ | ||
228 | x86_this_cpu_test_bit(bit, (unsigned long *)&cpu_info.x86_capability)) | ||
229 | |||
225 | #define boot_cpu_has(bit) cpu_has(&boot_cpu_data, bit) | 230 | #define boot_cpu_has(bit) cpu_has(&boot_cpu_data, bit) |
226 | 231 | ||
227 | #define set_cpu_cap(c, bit) set_bit(bit, (unsigned long *)((c)->x86_capability)) | 232 | #define set_cpu_cap(c, bit) set_bit(bit, (unsigned long *)((c)->x86_capability)) |
diff --git a/arch/x86/include/asm/percpu.h b/arch/x86/include/asm/percpu.h index d475b4398d8b..76042d981596 100644 --- a/arch/x86/include/asm/percpu.h +++ b/arch/x86/include/asm/percpu.h | |||
@@ -542,6 +542,33 @@ do { \ | |||
542 | old__; \ | 542 | old__; \ |
543 | }) | 543 | }) |
544 | 544 | ||
545 | static __always_inline int x86_this_cpu_constant_test_bit(unsigned int nr, | ||
546 | const unsigned long __percpu *addr) | ||
547 | { | ||
548 | unsigned long __percpu *a = (unsigned long *)addr + nr / BITS_PER_LONG; | ||
549 | |||
550 | return ((1UL << (nr % BITS_PER_LONG)) & percpu_read(*a)) != 0; | ||
551 | } | ||
552 | |||
553 | static inline int x86_this_cpu_variable_test_bit(int nr, | ||
554 | const unsigned long __percpu *addr) | ||
555 | { | ||
556 | int oldbit; | ||
557 | |||
558 | asm volatile("bt "__percpu_arg(2)",%1\n\t" | ||
559 | "sbb %0,%0" | ||
560 | : "=r" (oldbit) | ||
561 | : "m" (*(unsigned long *)addr), "Ir" (nr)); | ||
562 | |||
563 | return oldbit; | ||
564 | } | ||
565 | |||
566 | #define x86_this_cpu_test_bit(nr, addr) \ | ||
567 | (__builtin_constant_p((nr)) \ | ||
568 | ? x86_this_cpu_constant_test_bit((nr), (addr)) \ | ||
569 | : x86_this_cpu_variable_test_bit((nr), (addr))) | ||
570 | |||
571 | |||
545 | #include <asm-generic/percpu.h> | 572 | #include <asm-generic/percpu.h> |
546 | 573 | ||
547 | /* We can use this directly for local CPU (faster). */ | 574 | /* We can use this directly for local CPU (faster). */ |
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index fabf01eff771..2bc503bf9e99 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c | |||
@@ -505,7 +505,7 @@ static void __cpuinit setup_APIC_timer(void) | |||
505 | { | 505 | { |
506 | struct clock_event_device *levt = &__get_cpu_var(lapic_events); | 506 | struct clock_event_device *levt = &__get_cpu_var(lapic_events); |
507 | 507 | ||
508 | if (cpu_has(__this_cpu_ptr(&cpu_info), X86_FEATURE_ARAT)) { | 508 | if (this_cpu_has(X86_FEATURE_ARAT)) { |
509 | lapic_clockevent.features &= ~CLOCK_EVT_FEAT_C3STOP; | 509 | lapic_clockevent.features &= ~CLOCK_EVT_FEAT_C3STOP; |
510 | /* Make LAPIC timer preferrable over percpu HPET */ | 510 | /* Make LAPIC timer preferrable over percpu HPET */ |
511 | lapic_clockevent.rating = 150; | 511 | lapic_clockevent.rating = 150; |
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index d46cbe46b7ab..88a90a977f8e 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c | |||
@@ -449,7 +449,7 @@ EXPORT_SYMBOL_GPL(cpu_idle_wait); | |||
449 | void mwait_idle_with_hints(unsigned long ax, unsigned long cx) | 449 | void mwait_idle_with_hints(unsigned long ax, unsigned long cx) |
450 | { | 450 | { |
451 | if (!need_resched()) { | 451 | if (!need_resched()) { |
452 | if (cpu_has(__this_cpu_ptr(&cpu_info), X86_FEATURE_CLFLUSH_MONITOR)) | 452 | if (this_cpu_has(X86_FEATURE_CLFLUSH_MONITOR)) |
453 | clflush((void *)¤t_thread_info()->flags); | 453 | clflush((void *)¤t_thread_info()->flags); |
454 | 454 | ||
455 | __monitor((void *)¤t_thread_info()->flags, 0, 0); | 455 | __monitor((void *)¤t_thread_info()->flags, 0, 0); |
@@ -465,7 +465,7 @@ static void mwait_idle(void) | |||
465 | if (!need_resched()) { | 465 | if (!need_resched()) { |
466 | trace_power_start(POWER_CSTATE, 1, smp_processor_id()); | 466 | trace_power_start(POWER_CSTATE, 1, smp_processor_id()); |
467 | trace_cpu_idle(1, smp_processor_id()); | 467 | trace_cpu_idle(1, smp_processor_id()); |
468 | if (cpu_has(__this_cpu_ptr(&cpu_info), X86_FEATURE_CLFLUSH_MONITOR)) | 468 | if (this_cpu_has(X86_FEATURE_CLFLUSH_MONITOR)) |
469 | clflush((void *)¤t_thread_info()->flags); | 469 | clflush((void *)¤t_thread_info()->flags); |
470 | 470 | ||
471 | __monitor((void *)¤t_thread_info()->flags, 0, 0); | 471 | __monitor((void *)¤t_thread_info()->flags, 0, 0); |
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index c2871d3c71b6..a3c430bdfb60 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c | |||
@@ -1332,9 +1332,9 @@ static inline void mwait_play_dead(void) | |||
1332 | void *mwait_ptr; | 1332 | void *mwait_ptr; |
1333 | struct cpuinfo_x86 *c = __this_cpu_ptr(&cpu_info); | 1333 | struct cpuinfo_x86 *c = __this_cpu_ptr(&cpu_info); |
1334 | 1334 | ||
1335 | if (!(cpu_has(c, X86_FEATURE_MWAIT) && mwait_usable(c))) | 1335 | if (!this_cpu_has(X86_FEATURE_MWAIT) && mwait_usable(c)) |
1336 | return; | 1336 | return; |
1337 | if (!cpu_has(__this_cpu_ptr(&cpu_info), X86_FEATURE_CLFLSH)) | 1337 | if (!this_cpu_has(X86_FEATURE_CLFLSH)) |
1338 | return; | 1338 | return; |
1339 | if (__this_cpu_read(cpu_info.cpuid_level) < CPUID_MWAIT_LEAF) | 1339 | if (__this_cpu_read(cpu_info.cpuid_level) < CPUID_MWAIT_LEAF) |
1340 | return; | 1340 | return; |