Ben Cheng | 5a4eb4e | 2009-09-14 16:00:41 -0700 | [diff] [blame] | 1 | /* |
| 2 | * @file architecture specific interfaces |
| 3 | * @remark Copyright 2008 Intel Corporation |
| 4 | * @remark Read the file COPYING |
| 5 | * @author Andi Kleen |
| 6 | */ |
| 7 | |
| 8 | #if defined(__i386__) || defined(__x86_64__) |
| 9 | |
| 10 | /* Assume we run on the same host as the profilee */ |
| 11 | |
| 12 | #define num_to_mask(x) ((1U << (x)) - 1) |
| 13 | |
| 14 | static inline int cpuid_vendor(char *vnd) |
| 15 | { |
| 16 | union { |
| 17 | struct { |
| 18 | unsigned b,d,c; |
| 19 | }; |
| 20 | char v[12]; |
| 21 | } v; |
| 22 | unsigned eax; |
Bruce Beare | 751a443 | 2010-03-04 10:30:51 -0800 | [diff] [blame^] | 23 | asm volatile( "pushl %%ebx; cpuid; movl %%ebx, %1; popl %%ebx" |
| 24 | : "=a" (eax), "=S" (v.b), "=c" (v.c), "=d" (v.d) : "0" (0)); |
Ben Cheng | 5a4eb4e | 2009-09-14 16:00:41 -0700 | [diff] [blame] | 25 | return !strncmp(v.v, vnd, 12); |
| 26 | } |
| 27 | |
| 28 | /* Work around Nehalem spec update AAJ79: CPUID incorrectly indicates |
| 29 | unhalted reference cycle architectural event is supported. We assume |
| 30 | steppings after C0 report correct data in CPUID. */ |
| 31 | static inline void workaround_nehalem_aaj79(unsigned *ebx) |
| 32 | { |
| 33 | union { |
| 34 | unsigned eax; |
| 35 | struct { |
| 36 | unsigned stepping : 4; |
| 37 | unsigned model : 4; |
| 38 | unsigned family : 4; |
| 39 | unsigned type : 2; |
| 40 | unsigned res : 2; |
| 41 | unsigned ext_model : 4; |
| 42 | unsigned ext_family : 8; |
| 43 | unsigned res2 : 4; |
| 44 | }; |
| 45 | } v; |
| 46 | unsigned model; |
| 47 | |
| 48 | if (!cpuid_vendor("GenuineIntel")) |
| 49 | return; |
Bruce Beare | 751a443 | 2010-03-04 10:30:51 -0800 | [diff] [blame^] | 50 | asm volatile( "pushl %%ebx; cpuid; movl %%ebx, %1; popl %%ebx" |
| 51 | : "=a" (v.eax) : "0" (1) : "ecx","edx"); |
Ben Cheng | 5a4eb4e | 2009-09-14 16:00:41 -0700 | [diff] [blame] | 52 | model = (v.ext_model << 4) + v.model; |
| 53 | if (v.family != 6 || model != 26 || v.stepping > 4) |
| 54 | return; |
| 55 | *ebx |= (1 << 2); /* disable unsupported event */ |
| 56 | } |
| 57 | |
| 58 | static inline unsigned arch_get_filter(op_cpu cpu_type) |
| 59 | { |
| 60 | if (cpu_type == CPU_ARCH_PERFMON) { |
| 61 | unsigned ebx, eax; |
Bruce Beare | 751a443 | 2010-03-04 10:30:51 -0800 | [diff] [blame^] | 62 | asm volatile( "pushl %%ebx; cpuid; movl %%ebx, %1; popl %%ebx" |
| 63 | : "=a" (eax), "=S" (ebx) : "0" (0xa) : "ecx","edx"); |
Ben Cheng | 5a4eb4e | 2009-09-14 16:00:41 -0700 | [diff] [blame] | 64 | workaround_nehalem_aaj79(&ebx); |
| 65 | return ebx & num_to_mask(eax >> 24); |
| 66 | } |
| 67 | return -1U; |
| 68 | } |
| 69 | |
| 70 | static inline int arch_num_counters(op_cpu cpu_type) |
| 71 | { |
| 72 | if (cpu_type == CPU_ARCH_PERFMON) { |
| 73 | unsigned v; |
Bruce Beare | 751a443 | 2010-03-04 10:30:51 -0800 | [diff] [blame^] | 74 | asm volatile( "pushl %%ebx; cpuid; movl %%eax, %1; popl %%ebx" |
| 75 | : "=a" (v) : "0" (0xa) : "ecx","edx"); |
Ben Cheng | 5a4eb4e | 2009-09-14 16:00:41 -0700 | [diff] [blame] | 76 | return (v >> 8) & 0xff; |
| 77 | } |
| 78 | return -1; |
| 79 | } |
| 80 | |
| 81 | static inline unsigned arch_get_counter_mask(void) |
| 82 | { |
| 83 | unsigned v; |
Bruce Beare | 751a443 | 2010-03-04 10:30:51 -0800 | [diff] [blame^] | 84 | asm volatile( "pushl %%ebx; cpuid; movl %%ebx, %1; popl %%ebx" |
| 85 | : "=a" (v) : "0" (0xa) : "ecx","edx"); |
Ben Cheng | 5a4eb4e | 2009-09-14 16:00:41 -0700 | [diff] [blame] | 86 | return num_to_mask((v >> 8) & 0xff); |
| 87 | } |
| 88 | |
| 89 | #else |
| 90 | |
| 91 | static inline unsigned arch_get_filter(op_cpu cpu_type) |
| 92 | { |
| 93 | /* Do something with passed arg to shut up the compiler warning */ |
| 94 | if (cpu_type != CPU_NO_GOOD) |
| 95 | return 0; |
| 96 | return 0; |
| 97 | } |
| 98 | |
| 99 | static inline int arch_num_counters(op_cpu cpu_type) |
| 100 | { |
| 101 | /* Do something with passed arg to shut up the compiler warning */ |
| 102 | if (cpu_type != CPU_NO_GOOD) |
| 103 | return -1; |
| 104 | return -1; |
| 105 | } |
| 106 | |
| 107 | static inline unsigned arch_get_counter_mask(void) |
| 108 | { |
| 109 | return 0; |
| 110 | } |
| 111 | |
| 112 | #endif |